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
This commit is contained in:
@@ -264,9 +264,20 @@ function generateIcon(color, size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateIcon(settings) {
|
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;
|
let color;
|
||||||
if (!settings.enabled) {
|
if (!settings.enabled) {
|
||||||
color = '#dc2626'; // red — disabled
|
color = '#dc2626'; // red — disabled
|
||||||
|
} else if (!configured) {
|
||||||
|
color = '#9ca3af'; // gray — not configured, effectively disabled
|
||||||
} else if (settings.revealMode) {
|
} else if (settings.revealMode) {
|
||||||
color = '#1d4ed8'; // blue — reveal mode
|
color = '#1d4ed8'; // blue — reveal mode
|
||||||
} else {
|
} 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) => {
|
api.storage.onChanged.addListener(async (changes) => {
|
||||||
if (changes.ss_settings) {
|
if (changes.ss_settings || changes.ss_identity || changes.ss_mappings) {
|
||||||
const settings = { ...(changes.ss_settings.newValue || {}) };
|
const settings = await Storage.getSettings();
|
||||||
await updateIcon(settings);
|
await updateIcon(settings);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+10
-2
@@ -446,12 +446,20 @@
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
// Check if we have anything to substitute
|
// 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 ||
|
return mappings.length > 0 ||
|
||||||
(identity.emails || []).length > 0 ||
|
(identity.emails || []).length > 0 ||
|
||||||
(identity.names || []).length > 0 ||
|
(identity.names || []).length > 0 ||
|
||||||
(identity.usernames || []).length > 0 ||
|
(identity.usernames || []).length > 0 ||
|
||||||
(identity.phones || []).length > 0;
|
(identity.hostnames || []).length > 0 ||
|
||||||
|
(identity.phones || []).length > 0 ||
|
||||||
|
!!identity.catchAllEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSubstitutions() {
|
||||||
|
return isConfigured();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
<button class="btn btn-primary" id="btnAddDomain">Add Domain</button>
|
<button class="btn btn-primary" id="btnAddDomain">Add Domain</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="section-desc" style="margin-top:8px;margin-bottom:0">
|
<p class="section-desc" style="margin-top:8px;margin-bottom:0">
|
||||||
After adding a domain in Chrome, you also need to grant permission: <code>chrome://extensions/</code> → 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.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Storage from '../lib/storage.js';
|
import Storage from '../lib/storage.js';
|
||||||
|
import api from '../lib/browser-polyfill.js';
|
||||||
|
|
||||||
let mappings = [];
|
let mappings = [];
|
||||||
let settings = {};
|
let settings = {};
|
||||||
@@ -206,6 +207,20 @@ async function addDomain() {
|
|||||||
return;
|
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);
|
domains.push(domain);
|
||||||
settings.customDomains = domains;
|
settings.customDomains = domains;
|
||||||
await Storage.saveSettings({ customDomains: domains });
|
await Storage.saveSettings({ customDomains: domains });
|
||||||
|
|||||||
Reference in New Issue
Block a user