From eed885ed47428b34e3f85649e5935c0a7b56783f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 26 Mar 2026 02:49:03 +0000 Subject: [PATCH] feat: disable until configured + auto permission request for custom domains Interception is now completely inactive until the user configures at least one identity field or explicit mapping. Before that: - Icon shows gray (unconfigured) - No fetch/XHR hooks fire - First-run banner tells user to set up Custom domains: clicking "Add Domain" in Options now triggers the browser's native permission prompt via permissions.request(). No more manual chrome://extensions site access step. Icon states are now: - Gray = unconfigured (nothing will happen) - Black = active and protecting - Blue = reveal mode on - Red = manually disabled https://claude.ai/code/session_01Dvgwe7XMoSxnWXkih8p1Cw --- src/background/service-worker.js | 17 ++++++++++++++--- src/content/content.js | 12 ++++++++++-- src/options/options.html | 2 +- src/options/options.js | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/background/service-worker.js b/src/background/service-worker.js index e3dc304..bf9fd66 100644 --- a/src/background/service-worker.js +++ b/src/background/service-worker.js @@ -264,9 +264,20 @@ function generateIcon(color, size) { } async function updateIcon(settings) { + // Check if identity is configured + const identity = await Storage.getIdentity(); + const mappings = await Storage.getMappings(); + const configured = mappings.length > 0 || + (identity.emails || []).length > 0 || + (identity.names || []).length > 0 || + (identity.usernames || []).length > 0 || + !!identity.catchAllEmail; + let color; if (!settings.enabled) { color = '#dc2626'; // red — disabled + } else if (!configured) { + color = '#9ca3af'; // gray — not configured, effectively disabled } else if (settings.revealMode) { color = '#1d4ed8'; // blue — reveal mode } else { @@ -285,10 +296,10 @@ async function updateIcon(settings) { } } -// Update icon when settings change +// Update icon when settings, identity, or mappings change api.storage.onChanged.addListener(async (changes) => { - if (changes.ss_settings) { - const settings = { ...(changes.ss_settings.newValue || {}) }; + if (changes.ss_settings || changes.ss_identity || changes.ss_mappings) { + const settings = await Storage.getSettings(); await updateIcon(settings); } }); diff --git a/src/content/content.js b/src/content/content.js index 7981a2b..6089b87 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -446,12 +446,20 @@ // ============================================================ // Check if we have anything to substitute // ============================================================ - function hasSubstitutions() { + // Check if the user has configured anything at all. + // If not, the extension is effectively disabled — no interception. + function isConfigured() { return mappings.length > 0 || (identity.emails || []).length > 0 || (identity.names || []).length > 0 || (identity.usernames || []).length > 0 || - (identity.phones || []).length > 0; + (identity.hostnames || []).length > 0 || + (identity.phones || []).length > 0 || + !!identity.catchAllEmail; + } + + function hasSubstitutions() { + return isConfigured(); } // ============================================================ diff --git a/src/options/options.html b/src/options/options.html index 3c5a8ba..4c9627d 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -121,7 +121,7 @@

- After adding a domain in Chrome, you also need to grant permission: chrome://extensions/ → Silent Send → Details → Site access → add the domain. + When you click "Add Domain", your browser will ask you to confirm access. No extra steps needed.

diff --git a/src/options/options.js b/src/options/options.js index 30674cc..9983aa4 100644 --- a/src/options/options.js +++ b/src/options/options.js @@ -1,4 +1,5 @@ import Storage from '../lib/storage.js'; +import api from '../lib/browser-polyfill.js'; let mappings = []; let settings = {}; @@ -206,6 +207,20 @@ async function addDomain() { return; } + // Request browser permission for this domain + try { + const granted = await api.permissions.request({ + origins: [domain + '/*'], + }); + if (!granted) { + alert('Permission denied. The extension needs access to this domain to work.'); + return; + } + } catch (e) { + // Firefox or older Chrome may not support optional permissions this way + console.warn('[Silent Send] Could not request permission:', e); + } + domains.push(domain); settings.customDomains = domains; await Storage.saveSettings({ customDomains: domains });