From 1f8acd7b6ab0aa78e2a882e59cf69887109504be Mon Sep 17 00:00:00 2001
From: Bret Little
Date: Wed, 30 Aug 2023 14:32:41 -0400
Subject: [PATCH] Add a content security policy implementation and update
templates (#1235)
---
.changeset/two-carrots-relax.md | 7 +
examples/customer-api/app/entry.server.tsx | 9 +-
examples/customer-api/app/root.tsx | 8 +-
examples/express/app/entry.server.tsx | 33 ++-
examples/express/app/root.tsx | 8 +-
package-lock.json | 15 ++
.../docs/generated/generated_docs_data.json | 210 ++++++++++++++++++
packages/hydrogen/package.json | 3 +-
packages/hydrogen/src/csp/Script.doc.ts | 48 ++++
packages/hydrogen/src/csp/Script.example.jsx | 32 +++
packages/hydrogen/src/csp/Script.example.tsx | 32 +++
packages/hydrogen/src/csp/Script.test.ts | 29 +++
packages/hydrogen/src/csp/Script.tsx | 11 +
.../csp/createContentSecurityPolicy.doc.ts | 48 ++++
.../createContentSecurityPolicy.example.jsx | 46 ++++
.../createContentSecurityPolicy.example.tsx | 47 ++++
packages/hydrogen/src/csp/csp.test.ts | 80 +++++++
packages/hydrogen/src/csp/csp.ts | 88 ++++++++
packages/hydrogen/src/csp/nonce.ts | 17 ++
packages/hydrogen/src/csp/useNonce.doc.ts | 48 ++++
.../hydrogen/src/csp/useNonce.example.jsx | 30 +++
.../hydrogen/src/csp/useNonce.example.tsx | 30 +++
packages/hydrogen/src/index.ts | 3 +
templates/demo-store/app/entry.server.tsx | 8 +-
templates/demo-store/app/root.tsx | 15 +-
templates/hello-world/app/entry.server.tsx | 9 +-
templates/hello-world/app/root.tsx | 8 +-
templates/skeleton/app/entry.server.tsx | 10 +-
templates/skeleton/app/root.tsx | 15 +-
29 files changed, 911 insertions(+), 36 deletions(-)
create mode 100644 .changeset/two-carrots-relax.md
create mode 100644 packages/hydrogen/src/csp/Script.doc.ts
create mode 100644 packages/hydrogen/src/csp/Script.example.jsx
create mode 100644 packages/hydrogen/src/csp/Script.example.tsx
create mode 100644 packages/hydrogen/src/csp/Script.test.ts
create mode 100644 packages/hydrogen/src/csp/Script.tsx
create mode 100644 packages/hydrogen/src/csp/createContentSecurityPolicy.doc.ts
create mode 100644 packages/hydrogen/src/csp/createContentSecurityPolicy.example.jsx
create mode 100644 packages/hydrogen/src/csp/createContentSecurityPolicy.example.tsx
create mode 100644 packages/hydrogen/src/csp/csp.test.ts
create mode 100644 packages/hydrogen/src/csp/csp.ts
create mode 100644 packages/hydrogen/src/csp/nonce.ts
create mode 100644 packages/hydrogen/src/csp/useNonce.doc.ts
create mode 100644 packages/hydrogen/src/csp/useNonce.example.jsx
create mode 100644 packages/hydrogen/src/csp/useNonce.example.tsx
diff --git a/.changeset/two-carrots-relax.md b/.changeset/two-carrots-relax.md
new file mode 100644
index 0000000000..baa8149769
--- /dev/null
+++ b/.changeset/two-carrots-relax.md
@@ -0,0 +1,7 @@
+---
+'@shopify/cli-hydrogen': patch
+'@shopify/create-hydrogen': patch
+'@shopify/hydrogen': patch
+---
+
+Add functionality for creating a Content Security Policy. See the [guide on Content Security Policies](https://shopify.dev/docs/custom-storefronts/hydrogen/content-security-policy) for more details.
diff --git a/examples/customer-api/app/entry.server.tsx b/examples/customer-api/app/entry.server.tsx
index 05b0c9a587..61db2b9507 100644
--- a/examples/customer-api/app/entry.server.tsx
+++ b/examples/customer-api/app/entry.server.tsx
@@ -2,6 +2,7 @@ import type {EntryContext} from '@shopify/remix-oxygen';
import {RemixServer} from '@remix-run/react';
import isbot from 'isbot';
import {renderToReadableStream} from 'react-dom/server';
+import {createContentSecurityPolicy} from '@shopify/hydrogen';
export default async function handleRequest(
request: Request,
@@ -9,9 +10,14 @@ export default async function handleRequest(
responseHeaders: Headers,
remixContext: EntryContext,
) {
+ const {nonce, header, NonceProvider} = createContentSecurityPolicy();
+
const body = await renderToReadableStream(
- ,
+
+
+ ,
{
+ nonce,
signal: request.signal,
onError(error) {
// eslint-disable-next-line no-console
@@ -26,6 +32,7 @@ export default async function handleRequest(
}
responseHeaders.set('Content-Type', 'text/html');
+ responseHeaders.set('Content-Security-Policy', header);
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
diff --git a/examples/customer-api/app/root.tsx b/examples/customer-api/app/root.tsx
index 5c29ed1b97..d1a90880ec 100644
--- a/examples/customer-api/app/root.tsx
+++ b/examples/customer-api/app/root.tsx
@@ -11,6 +11,7 @@ import {
import type {Shop} from '@shopify/hydrogen/storefront-api-types';
import styles from './styles/app.css';
import favicon from '../public/favicon.svg';
+import {useNonce} from '@shopify/hydrogen';
export const links: LinksFunction = () => {
return [
@@ -34,6 +35,7 @@ export async function loader({context}: LoaderArgs) {
export default function App() {
const data = useLoaderData();
+ const nonce = useNonce();
const {name} = data.layout.shop;
@@ -51,9 +53,9 @@ export default function App() {
This is an example of Hydrogen using the Customer API
-
-
-
+
+
+