Adding a nonce for higher security
#2625
NicholasBoll
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A nonce is a Content Security Policy feature and is supported by Emotion. This is fine for
@emotion/reactor@emotion/styledwhere theCacheProvidercan be used.Our new style utilities (
createStylesandcreateStencil) use@emotion/csswhich doesn't have a runtime dependency injection framework. If you importcachefrom@emotion/css, you'll get a reference that is stable, but does not include anonceor any other way of changing the behavior ofstylisor Emotion.In v10, we introduced static styling an simply used
@emotion/cssfor easier backwards compatibility with SSR and client styling merging. We simply re-use everything given by@emotion/csswhich already creates the Emotion cache. The Emotion cache is what holds references tostylisplugins, including thenonce. Supporting anoncemeans we'll have to keep access to an Emotion cache within@workday/canvas-kit-stylingand export a function to get the cache rather than exporting a reference to a cache.In most cases, this change won't be noticeable, but if you import
cachefrom@emotion/cssin any way, AND you make a call to create a nonced cache, this will effect you. This should be fine as this is an opt-in feature, but it is possible for style merging to not work across versions of this change.Breaking changes
Emotion uses a cache to track all styles injected into the browser. Our
CanvasProviderinjects the@emotion/csscache and our style utilities use the same cache. This means if you use theCanvasProviderand don't use Emotion's ownCacheProviderand inject your own cache, Canvas Kit will always have access to the same cache. The cache is only important when style merging.Style Merging (and "compat" mode)
Our static style utility functions don't have a runtime and will inject styles when defined rather than during React's render cycle. This has performance benefits. Style mering is done by the browser's style merging rules via CSS specificity. Emotion doesn't use the browser's style merging rules and instead creates it's own. Emotion tries to merge styles predictably and in a way a developer expects it to. Emotion needs to be as efficient as possible. Injecting a new style rule into the browser's StyleSheetList causes the browser to flush it's Style Recalculation cache which is inefficient. Emotion keeps track of styles by creating a hash for each style and using this hash as the cache key. If a cache key is a hit, the style is not injected. Emotion also tries to have a flat specificity of
(0,1,0). But since styles are injected in the order they are rendered, style injection order can be non-deterministic. If the specificity of styles are the same, injection order is used - last defined wins. Emotion "fixes" this by keeping track of all the cache keys encountered. When you override the styles by usingstyled(SomeStyledComponent)or<SomeStyledComponent css=, Emotion will run an algorithm against theclassNameprop. If theclassNamelooks something likeclassName="css-abc123 css-xyz890", it will collect all the CSS class names and extract the cache key and see if there's a cache hit. All cache hit styles are then combined into a new style. The resultingclassNameis something likeclassName="css-axy170"and that new style is injected into the page. JavaScript is used to merge styles and specificity is again thwarted to do what a developer expects to do. Thecsprop works the same way when a dynamic style is encountered. We call this compat mode. Our components will not use Emotion's style merging by default, but will use it if you add some dynamic style to a component with static styling. For example,<PrimaryButton css=,<PrimaryButton cs={{padding:10}}>,const StyledPrimaryButton = styled(PrimaryButton). This compat mode ensures that our styles stay as fast as possible, but styling still looks correct.This compat mode can only work for styles of the same cache. If your components uses a different cache than our components, there won't be a cache hit and styles may not be merged properly and you'll notice strange visual artifacts.
This will create a style merge conflict across Canvas Kit v10 versions though. Versions before this change will reference the cache from
@emotion/csswhile versions after will reference the cache created bycreateCacheif called. IfcreateCacheis never called, there's no incompatibility. IfcreateCacheis called, there may be a version split for style merging.Mitigation
The plan is to have
getCacheandcreateCachefunctions exported from@workday/canvas-kit-styling. ThegetCachewill always need to be used to make sure you're getting the correct cache reference. ThecreateCacheis the opt-in. If called, the internal cache reference will point to this cache. If it is not used,getCachewill point to@emotion/css's cache. ThecreateStylesandcreateStencilfunctions will add an extra bit of functionality to belay the creating of a cache to allow a different cache to be created. IfcreateCacheis not called by the timecreateStylesorcreateStencilis called, thecacheexported from@emotion/csswill be used. This should mean introducing this change should have no backwards breaking issues. It will be up to whoever callscreateCacheto make sure there's no direct reference to@emotion/cssused anywhere. If you usewithEmotionCache, you should be fine. If you use Emotion'sCacheProvider, there might be issues, but that's already an incompatibility with Canvas Kit v10.There may be a period of time that
createCacheshould not be called by any application code if you expect multiple versions of Canvas Kit to exist on the page at the same time. This will be to the discretion of application developers.Beta Was this translation helpful? Give feedback.
All reactions