diff --git a/.changeset/heavy-coins-tickle.md b/.changeset/heavy-coins-tickle.md index 508963e44d..03b8eb3c96 100644 --- a/.changeset/heavy-coins-tickle.md +++ b/.changeset/heavy-coins-tickle.md @@ -1,18 +1,5 @@ --- -'@shopify/hydrogen': patch +'@shopify/hydrogen': minor --- -✨ add `applyDefault` option to `createContentSecurityPolicy` which automatically adds Shopify domains to the content security policy, extending whatever rules are passed instead of overriding them. The default value of `applyDefault` option is false which is the current behavior. - -Example usage: - -```diff -const {nonce, header, NonceProvider} = createContentSecurityPolicy( - {connectSrc: 'wss://public-domain:*'}, -+ {applyDefault: true}, -); -``` - -Result of connect-src when `applyDefault=false` is "wss://public-domain:\*" - -Result of connect-src when `applyDefault=true` is "wss://public-domain:\* 'self' 'https://cdn.shopify.com' 'https://shopify.com'" +💥 Change the behaviour of `createContentSecurityPolicy` where the custom rules passed in will extends the default Shopify and development domains instead of overriding them. diff --git a/packages/hydrogen/src/csp/csp.test.ts b/packages/hydrogen/src/csp/csp.test.ts index d36e1e75ba..9f2783e90c 100644 --- a/packages/hydrogen/src/csp/csp.test.ts +++ b/packages/hydrogen/src/csp/csp.test.ts @@ -25,28 +25,20 @@ describe('createContentSecurityPolicy', () => { it('adds custom directives', () => { expect( createContentSecurityPolicy({ - styleSrc: [ - "'self'", - 'https://cdn.shopify.com', - 'https://some-custom-css.cdn', - ], + styleSrc: ['https://some-custom-css.cdn'], }).header, ).toBe( - `base-uri 'self'; default-src 'self' 'nonce-somenonce' https://cdn.shopify.com https://shopify.com; frame-ancestors none; style-src 'self' https://cdn.shopify.com https://some-custom-css.cdn; connect-src 'self' https://monorail-edge.shopifysvc.com`, + `base-uri 'self'; default-src 'self' 'nonce-somenonce' https://cdn.shopify.com https://shopify.com; frame-ancestors none; style-src https://some-custom-css.cdn 'self' 'unsafe-inline' https://cdn.shopify.com; connect-src 'self' https://monorail-edge.shopifysvc.com`, ); }); it('adds nonce to custom directives', () => { expect( createContentSecurityPolicy({ - scriptSrc: [ - "'self'", - 'https://cdn.shopify.com', - 'https://some-custom-css.cdn', - ], + scriptSrc: ['https://some-custom-css.cdn'], }).header, ).toBe( - `base-uri 'self'; default-src 'self' 'nonce-somenonce' https://cdn.shopify.com https://shopify.com; frame-ancestors none; style-src 'self' 'unsafe-inline' https://cdn.shopify.com; connect-src 'self' https://monorail-edge.shopifysvc.com; script-src 'self' https://cdn.shopify.com https://some-custom-css.cdn 'nonce-somenonce'`, + `base-uri 'self'; default-src 'self' 'nonce-somenonce' https://cdn.shopify.com https://shopify.com; frame-ancestors none; style-src 'self' 'unsafe-inline' https://cdn.shopify.com; connect-src 'self' https://monorail-edge.shopifysvc.com; script-src https://some-custom-css.cdn 'nonce-somenonce'`, ); }); }); diff --git a/packages/hydrogen/src/csp/csp.ts b/packages/hydrogen/src/csp/csp.ts index c35f5b3c83..38a0cc6d8e 100644 --- a/packages/hydrogen/src/csp/csp.ts +++ b/packages/hydrogen/src/csp/csp.ts @@ -26,10 +26,9 @@ type ContentSecurityPolicy = { */ export function createContentSecurityPolicy( directives: Record = {}, - options: {applyDefault?: boolean} = {}, ): ContentSecurityPolicy { const nonce = generateNonce(); - const header = createCSPHeader(nonce, directives, options?.applyDefault); + const header = createCSPHeader(nonce, directives); const Provider = ({children}: {children: ReactNode}) => { return createElement(NonceProvider, {value: nonce}, children); @@ -45,7 +44,6 @@ export function createContentSecurityPolicy( function createCSPHeader( nonce: string, directives: Record = {}, - applyDefault = false, ): string { const nonceString = `'nonce-${nonce}'`; const styleSrc = ["'self'", "'unsafe-inline'", 'https://cdn.shopify.com']; @@ -80,8 +78,10 @@ function createCSPHeader( } const combinedDirectives = Object.assign({}, defaultDirectives, directives); - if (applyDefault) { - for (const key in defaultDirectives) { + + //add defaults if it was override + for (const key in defaultDirectives) { + if (directives[key]) { combinedDirectives[key] = addCspDirective( directives[key], defaultDirectives[key],