diff --git a/manifest.firefox.json b/manifest.firefox.json index 25eab8a..9d8c897 100644 --- a/manifest.firefox.json +++ b/manifest.firefox.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Silent Send", - "version": "0.9.13", + "version": "0.9.14", "description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.", "browser_specific_settings": { "gecko": { diff --git a/manifest.json b/manifest.json index 5c677f7..53c33d1 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Silent Send", - "version": "0.9.13", + "version": "0.9.14", "description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.", "permissions": [ "storage", diff --git a/package.json b/package.json index c0bf710..8a74f3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "silent-send", - "version": "0.9.13", + "version": "0.9.14", "private": true, "license": "MIT", "description": "Browser extension that substitutes personal data before sending to AI services", diff --git a/src/content/content.js b/src/content/content.js index 4996968..b75822d 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -1473,13 +1473,17 @@ // session, preventing false positives (e.g. "user" in AI prose). function buildRevealPairs() { const pairs = []; + const added = new Set(); // Helper: only add if this substitute was actually sent function addIfUsed(from, to, caseSensitive) { if (!from || !to) return; - const entry = sessionSubstitutions.get(from.toLowerCase()); + const key = from.toLowerCase(); + if (added.has(key)) return; + const entry = sessionSubstitutions.get(key); if (entry) { pairs.push({ from, to, caseSensitive }); + added.add(key); } } @@ -1492,9 +1496,9 @@ for (const e of (identity.emails || [])) { addIfUsed(e.substitute, e.real); } - for (const n of (identity.names || [])) { - addIfUsed(n.substitute, n.real); - } + // For names: DON'T add individual first/last — the smart pattern engine + // combines them (e.g. "Ademo Demo" for "John Smith"). The catch-all + // below picks up the combined form from sessionSubstitutions. for (const u of (identity.usernames || [])) { addIfUsed(u.substitute, u.real); } @@ -1506,10 +1510,13 @@ } } - // Also add auto-detect and auto-redact substitutions from this session + // Catch-all: add any session substitution not already covered above. + // This picks up combined names ("Ademo Demo" → "John Smith"), + // auto-detected PII, and auto-redacted secrets. for (const [key, entry] of sessionSubstitutions) { - if (!pairs.some(p => p.from.toLowerCase() === key)) { + if (!added.has(key)) { pairs.push({ from: entry.replaced, to: entry.original }); + added.add(key); } } @@ -1517,11 +1524,13 @@ return pairs; } - // Cache — invalidate when config changes or new substitutions happen + // Cache — invalidate when identity/mappings change or new substitutions happen + // Settings-only updates (e.g. reveal toggle) do NOT invalidate let _revealPairsCache = null; - let _revealPairsCacheSize = 0; window.addEventListener('message', (event) => { - if (event.data?.type === 'ss:config-updated') _revealPairsCache = null; + if (event.data?.type === 'ss:config-updated') { + if (event.data.mappings || event.data.identity) _revealPairsCache = null; + } if (event.data?.type === 'ss:substitution-performed') _revealPairsCache = null; }); diff --git a/src/options/options.html b/src/options/options.html index 1426a98..fb0ec40 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -631,7 +631,7 @@