From 28d3db80394fd9de95bc19391e1aab57cfc37918 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Tue, 1 Sep 2026 18:49:28 +0000 Subject: [PATCH] Extension: request host permission dynamically instead of relying on CORS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend CORS is disabled by default (origin: false), and an unpacked extension's ID isn't fixed/predictable per install anyway, so allowlisting it server-side would be awkward. options.js now calls chrome.permissions.request() for the entered base URL on Save — once granted, the extension's own fetches bypass CORS entirely for that origin. Co-Authored-By: Claude Sonnet 5 --- backend/extension-src/manifest.json | 2 ++ backend/extension-src/options/options.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/backend/extension-src/manifest.json b/backend/extension-src/manifest.json index 183a46d..6cdbc42 100644 --- a/backend/extension-src/manifest.json +++ b/backend/extension-src/manifest.json @@ -11,6 +11,8 @@ "https://login.newbook.cloud/*" ], + "optional_host_permissions": ["http://*/*", "https://*/*"], + "background": { "service_worker": "background.js" }, diff --git a/backend/extension-src/options/options.js b/backend/extension-src/options/options.js index 6a1d5dc..1336e62 100644 --- a/backend/extension-src/options/options.js +++ b/backend/extension-src/options/options.js @@ -9,9 +9,27 @@ async function load() { // not the popup) so the value can be corrected without regenerating the key. } +// tablet-checkin's own base URL isn't known in advance (dev today, a +// different production URL later), so it can't be pre-declared in the +// manifest's host_permissions — Chrome would need republishing/reloading +// every time the URL changed. Requesting it dynamically here instead (needs +// a user gesture, which this Save click provides) means the extension's own +// fetches bypass CORS entirely for that origin once granted, rather than +// depending on the server sending back Access-Control-Allow-Origin for an +// extension origin ID that isn't fixed/predictable per install anyway. async function save() { const baseUrl = baseUrlInput.value.trim().replace(/\/$/, ''); const apiKey = apiKeyInput.value.trim(); + + if (baseUrl) { + const granted = await chrome.permissions.request({ origins: [`${baseUrl}/*`] }); + if (!granted) { + statusEl.textContent = 'Not saved — permission for that URL was denied. This extension needs it to talk to tablet-checkin.'; + statusEl.style.color = '#dc2626'; + return; + } + } + await chrome.storage.local.set({ baseUrl, apiKey }); statusEl.textContent = 'Saved.'; statusEl.style.color = '#16a34a';