From 2cda16527b9a114fd66a507e299012a118fb5177 Mon Sep 17 00:00:00 2001 From: Gorka Date: Tue, 2 Jun 2026 12:00:49 -0300 Subject: [PATCH] fix: allow http://localhost in dev-build CSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #18 added a tight `connect-src 'self' https://us.i.posthog.com https://*` to extension_pages CSP. Chromium MV3 applies this to the background service worker, blocking every wallet→chain fetch against http (incl. localhost). Local-dev / recording / pairing flows hit http://localhost:8000/soroban/rpc, so the wallet's add-channel auth() read fails with `SIM_002` and downstream deposit/send/withdraw inherit the same Failed-to-fetch. Widen connect-src with `http://localhost:*` only when DEV=1. Production builds (build-prod / release.yml) ship the manifest unchanged, so the CWS / AMO artifact stays restricted to https. --- src/build.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/build.ts b/src/build.ts index debc0e0..26fdd48 100644 --- a/src/build.ts +++ b/src/build.ts @@ -78,6 +78,30 @@ function loadSeedDefines(): Record { return defines; } +// Production manifest ships a tight `connect-src` (self + PostHog + https://*). +// Local-dev's Soroban RPC at http://localhost:8000 falls outside that whitelist, +// so dev builds widen connect-src with `http://localhost:*` and the shipped +// production extension stays untouched. +async function writeManifest(dir: string, dev: boolean): Promise { + const src = await Deno.readTextFile("manifest.json"); + if (!dev) { + await Deno.writeTextFile(`${dir}/manifest.json`, src); + return; + } + const manifest = JSON.parse(src); + const csp = manifest.content_security_policy?.extension_pages; + if (typeof csp === "string" && !csp.includes("http://localhost:*")) { + manifest.content_security_policy.extension_pages = csp.replace( + /connect-src ([^;]*);/, + "connect-src $1 http://localhost:*;", + ); + } + await Deno.writeTextFile( + `${dir}/manifest.json`, + JSON.stringify(manifest, null, 2) + "\n", + ); +} + async function preBuildChecks() { console.log("🔍 Running pre-build checks..."); @@ -196,7 +220,7 @@ async function build() { } // Copy static assets - await copy("manifest.json", `${buildDir}/manifest.json`, { overwrite: true }); + await writeManifest(buildDir, DEV); await copy("src/popup/index.html", `${buildDir}/popup.html`, { overwrite: true, });