Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(injectBaseStylesheet): address style injection issue #605

Closed
wants to merge 3 commits into from

Conversation

luqven
Copy link
Contributor

@luqven luqven commented Feb 22, 2021

Description

  • Fix a bug where getElementByTagName() was attempting to access an attribute, .innerHTML, that was not defined.

  • Instead updates stylesheet by using the .item() method for HTMLCollections to then access .innerHTML.

Checklist

Bug Fix

  • All existing unit tests are still passing (if applicable)
  • Add new passing unit tests to cover the code introduced by your PR
  • Update the readme
  • Update or add any necessary API documentation
  • Add some steps so we can test your bug fix
  • The PR title is in the conventional commit format: e.g. fix(<area>): fixed bug #issue-number
  • Add your info to the contributors array in package.json!

Steps to Test

Clone the repo, npm run build, and open /index.html in your default browser.

Related issue: [e.g. #603 ]

Code:

const allHeadElements = head.getElementsByTagName("*");
-  allHeadElements.innerHTML = styleEl + allHeadElements.innerHTML;
+  const styleTag = headElements.item(headElements.length - 1);
+  styleTag.innerHTML = styleEl.innerHTML + styleTag.innerHTML;

Discussion

In future, Cypress testing (or the like) integration is recommended to catch this type of bugs. Hard to detect without browser testing.

@luqven luqven requested a review from a team February 22, 2021 18:52
@luqven luqven self-assigned this Feb 22, 2021
@commit-lint
Copy link

commit-lint bot commented Feb 22, 2021

Bug Fixes

  • injectBaseStylesheet: address style injection issue (34a0d61)

Chore

  • prettier format file and remove unused hash (0c47e9a)

Contributors

luqven

Commit-Lint commands

You can trigger Commit-Lint actions by commenting on this PR:

  • @Commit-Lint merge patch will merge dependabot PR on "patch" versions (X.X.Y - Y change)
  • @Commit-Lint merge minor will merge dependabot PR on "minor" versions (X.Y.Y - Y change)
  • @Commit-Lint merge major will merge dependabot PR on "major" versions (Y.Y.Y - Y change)
  • @Commit-Lint merge disable will desactivate merge dependabot PR
  • @Commit-Lint review will approve dependabot PR
  • @Commit-Lint stop review will stop approve dependabot PR

@luqven luqven changed the title bug(injectBaseStylesheet): fix style injection issue fix(injectBaseStylesheet): address style injection issue Feb 22, 2021
Comment on lines 66 to 67
const styleTag = allHeadElements.item(allHeadElements.length - 1);
styleTag.innerHTML = styleEl.innerHTML + styleTag.innerHTML;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will definitely work in the context of the local demo since the last child element happens to be a <style> element, but I don't think we can assume that will be the case for all of our users. We should prepend a completely separate <style> element into the list of allHeadElements to ensure we don't accidentally cause any errors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const styleTag = allHeadElements.item(allHeadElements.length - 1);
styleTag.innerHTML = styleEl.innerHTML + styleTag.innerHTML;
const styleTag = allHeadElements.item(allHeadElements.length - 1);
styleTag.outerHTML = styleEl.outerHTML + styleTag.outerHTML;

I don't know if this is the correct way to do this... but it works 🤷

Copy link
Contributor

@frederickfogerty frederickfogerty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to clear up that this works well for other configurations and resolve the comments before merging, but otherwise LGTM.

@@ -63,5 +63,6 @@ export default function injectBaseStylesheet() {
const head = document.head;

const allHeadElements = head.getElementsByTagName("*");
allHeadElements.innerHTML = styleEl + allHeadElements.innerHTML;
const styleTag = allHeadElements.item(allHeadElements.length - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const styleTag = allHeadElements.item(allHeadElements.length - 1);
const styleTag = allHeadElements.item(0);

We want to select the first element, not the last one (afaik)

@luqven
Copy link
Contributor Author

luqven commented Feb 23, 2021

I think we need to clear up that this works well for other configurations and resolve the comments before merging, but otherwise LGTM.

Made use of the Node.insertBefore API to achieve the desired effect. Also removed references to deprecated type parameter for Style nodes.

Tested locally on index.html and confirmed the new Style tag gets added as the first child to the document head element.

@luqven luqven requested a review from sherwinski February 23, 2021 21:28
@sherwinski
Copy link
Contributor

Hey @luqven we actually can't use insertBefore here because it can trigger a CSP violation. Here is the PR where we removed it (#598). I think you'll need to use some combination of the two recommendations @frederickfogerty mentioned to do this without insertBefore.

@luqven
Copy link
Contributor Author

luqven commented Feb 23, 2021

Hey @luqven we actually can't use insertBefore here because it can trigger a CSP violation. Here is the PR where we removed it (#598). I think you'll need to use some combination of the two recommendations @frederickfogerty mentioned to do this without insertBefore.

🤦🏼 right my bad. Ugh really wanted to avoid magic numbers or .innerHTML... will think on this.

index.html Outdated
Comment on lines 10 to 14
<!-- If CSP style policies, ensure SHA, nonce, or unsafe-inline are enabled -->
<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width">
<meta
http-equiv="Content-Security-Policy"
content="style-src 'self' 'sha256-W+PadZMOYbQi3EzR/NC+KcPx3bNLCz0OtfWwp+LK9b4=' 'sha256-OdI56ZW769BKGaLghLr3uZVaaWfqyRwyccMiu8gXf0w=' 'sha256-W+PadZMOYbQi3EzR/NC+KcPx3bNLCz0OtfWwp+LK9b4=' 'sha256-cG/+JJX3ZZs6snnMipxMnaYWATXBcyQw3vFWJF1zmAM='"
/>
Copy link
Contributor Author

@luqven luqven Feb 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this is the only way I successfully got around the CSP violation issues. We had to generate a SHA value for the style tags that violated the policy and add them to the csp. We also had to add self as an src to avoid the library's inline styles from getting blocked as well.

This will have to be done by an end user as well. Ie, they'll have to implement some combination of the recommended options for style-src that allows our script and or styles to be set.

We could host the stylesheets in question on a CDN, but that seems like overkill when the user can do the above.

@luqven
Copy link
Contributor Author

luqven commented Feb 26, 2021

After looking into this some more, I don't think there's a better way to solve the CSP issues. The user would have to modify their CSPs to accommodate for Drift's behavior.

edit: to be clear, this would mean some combination of creating a hash of the script and or style tags, allowing unsafe-inline, or using some other style-src CSP that allows for this type of stylesheet modification to take place on their site.

@luqven luqven force-pushed the luis/styleBugfix branch 2 times, most recently from 144e71f to 08b5538 Compare March 1, 2021 14:38
luqven added 3 commits March 1, 2021 09:48
Fix a bug where getElementByTagName() was attempting to access an attr, .innerHTML, that was not defined.

Instead, create and inject a new style tag as a child to the head.
Add styles hash to csp to avoid it getting blocked by browser
@luqven luqven force-pushed the luis/styleBugfix branch from 08b5538 to 0c47e9a Compare March 1, 2021 14:49
@luqven
Copy link
Contributor Author

luqven commented Mar 1, 2021

Apols for all the force pushes, forgot there was 1 outstanding PR before this one 😬

@frederickfogerty
Copy link
Contributor

@all-contributors add @luqven for maintenance

@allcontributors
Copy link
Contributor

@frederickfogerty

I've put up a pull request to add @luqven! 🎉

Copy link
Contributor

@frederickfogerty frederickfogerty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good if the discussion is resolved.

Comment on lines +63 to +67
// prepend them to the document head's first child
const head = document.head;
const allHeadElements = head.getElementsByTagName("*");
allHeadElements.innerHTML = styleEl + allHeadElements.innerHTML;
const firstItem = allHeadElements.item(0);
firstItem.outerHTML = styleEl.outerHTML + firstItem.outerHTML;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't get around the CSP violation anyway, is it cleaner to go back to using .insertBefore() rather than this method? i.e. reverting the changes introduced here?

Copy link
Contributor Author

@luqven luqven Mar 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I do think this read easier that way..

It might then be better to close this PR altogether and create two new ones:

  1. rolling back that change and then
  2. adding the CSP to index.html as an example / check for handling those issues.

I'll discuss w/ @sherwinski offline and circle back.

@luqven
Copy link
Contributor Author

luqven commented Mar 1, 2021

After chatting I think it's best to close and split this PR into two. Will make sure to reference this discussion so context isn't lost.

@luqven luqven deleted the luis/styleBugfix branch August 2, 2021 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants