summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-25 04:47:29 -0500
committerAdam <[email protected]>2026-03-25 05:59:06 -0500
commit53d0b58ebf3468bd161dcfcdc67cd66b6508e9f8 (patch)
treeca5515910ad01f76639577ef8e3a991b644a5ade
parent2b0baf97bd176dfbb9afe81931c90bc6288ada34 (diff)
downloadopencode-53d0b58ebf3468bd161dcfcdc67cd66b6508e9f8.tar.gz
opencode-53d0b58ebf3468bd161dcfcdc67cd66b6508e9f8.zip
fix(app): hash inline script for csp
-rw-r--r--packages/opencode/src/server/server.ts15
1 files changed, 11 insertions, 4 deletions
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index 7ead4df8a..e4c98c609 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -1,3 +1,4 @@
+import { createHash } from "node:crypto"
import { Log } from "../util/log"
import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
import { Hono } from "hono"
@@ -47,6 +48,9 @@ import { lazy } from "@/util/lazy"
// @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85
globalThis.AI_SDK_LOG_WARNINGS = false
+const csp = (hash = "") =>
+ `default-src 'self'; script-src 'self' 'wasm-unsafe-eval'${hash ? ` 'sha256-${hash}'` : ""}; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:`
+
export namespace Server {
const log = Log.create({ service: "server" })
@@ -506,10 +510,13 @@ export namespace Server {
host: "app.opencode.ai",
},
})
- response.headers.set(
- "Content-Security-Policy",
- "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:",
- )
+ const match = response.headers.get("content-type")?.includes("text/html")
+ ? (await response.clone().text()).match(
+ /<script\b(?![^>]*\bsrc\s*=)[^>]*\bid=(['"])oc-theme-preload-script\1[^>]*>([\s\S]*?)<\/script>/i,
+ )
+ : undefined
+ const hash = match ? createHash("sha256").update(match[2]).digest("base64") : ""
+ response.headers.set("Content-Security-Policy", csp(hash))
return response
})
}