Author SHA1 Message Date
Outis 556aee1d6d Merge pull request #80 from outis1one/claude/fix-firefox-signing-2qWJd
Bump version to 0.9.47
2026-04-20 21:19:19 -04:00
Claude 20250278bc Bump version to 0.9.47
https://claude.ai/code/session_01G6wo3QBwKjEgAM7j5hQkx4
2026-04-21 01:17:52 +00:00
Outis 5666348c57 Merge pull request #79 from outis1one/claude/fix-firefox-signing-2qWJd
fix: force IPv4 DNS in web-ext sign to fix fetch failed error
2026-04-20 21:17:08 -04:00
Claude 459130b049 fix: force IPv4 DNS in web-ext sign to fix fetch failed error
Node.js 18+ resolves DNS with IPv6 preference by default. On Linux systems
where IPv6 routing to addons.mozilla.org is broken or unavailable, this causes
web-ext's fetch to silently fail. Setting --dns-result-order=ipv4first via
NODE_OPTIONS ensures IPv4 is tried first.

https://claude.ai/code/session_01G6wo3QBwKjEgAM7j5hQkx4
2026-04-21 01:14:57 +00:00
Outis 03dd61d8bd Merge pull request #78 from outis1one/clDemoe/fix-pii-mapping-persist-5qJzt
Cl demoe/fix pii mapping persist 5q jzt
2026-04-04 11:26:24 -04:00
Claude a69c39e8e7 Bump version to 0.9.46
https://claude.ai/code/session_01RfzvB5sHah326acr8Xa7Jn
2026-04-04 15:22:27 +00:00
Claude fb237c91a8 Fix substitute values being re-detected as PII after adding mapping
Two issues fixed:

1. autoDetectPII only skipped identity values (names, emails, etc.) but not
   mapping values. After clicking "+" to map e.g. an IP address, the fake
   substitute IP was immediately re-detected as PII, causing the notification
   to reappear. Now autoDetectPII accepts opts.mappings and adds both real
   and substitute values to the skip set.

2. The local mappings array was only updated after the async background
   round-trip completed. The 150ms re-scan could fire before that, missing
   the new mapping. Now an optimistic temp mapping is added to the local
   array immediately so the re-scan already knows to skip both values.

https://claude.ai/code/session_01RfzvB5sHah326acr8Xa7Jn
2026-04-04 15:18:51 +00:00
Outis 357c7d208b Merge pull request #77 from outis1one/clDemoe/fix-pii-mapping-persist-5qJzt
Bump manifest.firefox.json version to 0.9.45
2026-04-04 10:42:09 -04:00
Claude d8a4e3a668 Bump manifest.firefox.json version to 0.9.45
https://claude.ai/code/session_01RfzvB5sHah326acr8Xa7Jn
2026-04-04 14:24:52 +00:00
Outis 09a279f62f Merge pull request #76 from outis1one/clDemoe/fix-pii-mapping-persist-5qJzt
Cl demoe/fix pii mapping persist 5q jzt
2026-04-04 10:22:24 -04:00
Claude 36b7bf34e9 Bump version to 0.9.45
https://claude.ai/code/session_01RfzvB5sHah326acr8Xa7Jn
2026-04-04 14:21:00 +00:00
Claude 909bb3a847 Fix PII mapping add (plus button) not persisting and not dismissing notification
The plus button handler in the pre-send PII warning had two bugs:

1. It read/wrote mappings directly via the storage bridge (api.storage.local),
   bypassing the Storage module's encryption layer. When at-rest encryption was
   enabled, getStorageData returned an encrypted blob instead of an array,
   causing .push() to throw a TypeError that silently aborted the handler —
   the mapping was never saved and replaceInInput never ran.

2. Unlike the ignore button which immediately removes the DOM item, the plus
   button relied on a re-scan at 150ms to dismiss the notification. If
   replaceInInput didn't stick (e.g. React-controlled inputs), the re-scan
   found PII again and the notification persisted.

Fix: Route mapping creation through the background service worker via a new
'add:mapping' message handler (which uses Storage.addMapping with proper
encryption support), and immediately dismiss the notification item from the
DOM like the ignore button does.

https://claude.ai/code/session_01RfzvB5sHah326acr8Xa7Jn
2026-04-04 14:14:15 +00:00
Outis f6ebb3dc15 Merge pull request #75 from outis1one/claude/review-silent-send-gHgCS
Fix encryption enable by removing broken org UI references, bump to 0…
2026-04-02 10:25:29 -04:00
Outis 22c90f28e8 Merge pull request #74 from outis1one/claude/review-silent-send-gHgCS
Claude/review silent send g hg cs
2026-04-02 09:28:26 -04:00
Outis 3c37309a1e Merge pull request #73 from outis1one/claude/review-silent-send-gHgCS
Claude/review silent send g hg cs
2026-04-02 09:14:21 -04:00
Outis 993aadaad5 Merge pull request #72 from outis1one/claude/review-silent-send-gHgCS
Fix fresh-install pull blocked by saveSettings timestamp
2026-04-01 20:38:52 -04:00
Outis 70c154a5d3 Merge pull request #71 from outis1one/clDemoe/review-silent-send-gHgCS
Bump version to 0.9.41
2026-04-01 16:05:26 -04:00
Outis 05c9b299c9 Merge pull request #70 from outis1one/clDemoe/review-silent-send-gHgCS
Add Ignore button to auto-detect warnings for permanent per-value dis…
2026-04-01 16:04:23 -04:00
Outis abecb2fdd1 Merge pull request #69 from outis1one/clDemoe/review-silent-send-gHgCS
ClDemoe/review silent send g hg cs
2026-04-01 12:14:47 -04:00
Outis 4ce884e9de Merge pull request #68 from outis1one/clDemoe/review-silent-send-gHgCS
Bump version to 0.9.39
2026-04-01 11:03:53 -04:00
Outis 5ce7fd610a Merge pull request #67 from outis1one/claude/review-silent-send-gHgCS
Fix race condition: vault:unlocked message lost when service worker r…
2026-04-01 10:52:47 -04:00
7 changed files with 73 additions and 19 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Silent Send",
"version": "0.9.44",
"version": "0.9.47",
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
"browser_specific_settings": {
"gecko": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Silent Send",
"version": "0.9.44",
"version": "0.9.47",
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
"permissions": [
"storage",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "silent-send",
"version": "0.9.44",
"version": "0.9.47",
"private": true,
"license": "MIT",
"description": "Browser extension that substitutes personal data before sending to AI services",
+3 -1
View File
@@ -86,7 +86,9 @@ for attempt in $(seq 1 $MAX_ATTEMPTS); do
echo "=== Attempt $attempt: signing v$NEW_VERSION ==="
# Capture output to check for specific errors
OUTPUT=$(npx web-ext sign \
# NODE_OPTIONS forces IPv4 DNS resolution first — Node.js 18+ defaults to IPv6,
# which silently fails when the system can't reach addons.mozilla.org over IPv6.
OUTPUT=$(NODE_OPTIONS='--dns-result-order=ipv4first' npx web-ext sign \
--no-config-discovery \
--source-dir "$SCRIPT_DIR/dist/firefox" \
--artifacts-dir "$SCRIPT_DIR/dist/firefox-signed" \
+6
View File
@@ -138,6 +138,12 @@ const messageHandlers = {
sendResponse({ mappings });
},
async 'add:mapping'(message, _sender, sendResponse) {
const newMapping = await Storage.addMapping(message.mapping);
const mappings = await Storage.getMappings();
sendResponse({ mapping: newMapping, mappings });
},
async 'get:settings'(_message, _sender, sendResponse) {
const settings = await Storage.getSettings();
sendResponse({ settings });
+41 -15
View File
@@ -280,7 +280,7 @@
// 4. Auto-detect: scan the FINAL text for unconfigured PII
// Auto-redact if enabled, otherwise just warn
if (settings.autoDetect !== false) {
const warnings = autoDetectPII(finalText, identity, { detectProperNouns: settings.detectProperNouns === true })
const warnings = autoDetectPII(finalText, identity, { detectProperNouns: settings.detectProperNouns === true, mappings })
.filter(w => !ignoredDetections.has(w.value));
if (warnings.length > 0) {
// Auto-redact detected PII in the outbound text
@@ -471,6 +471,14 @@
addAll(ident.names); addAll(ident.emails);
addAll(ident.usernames); addAll(ident.hostnames); addAll(ident.phones);
}
// Also skip values covered by mappings (both real and substitute)
if (opts?.mappings) {
for (const m of opts.mappings) {
if (!m.enabled) continue;
if (m.real) configured.add(m.real.toLowerCase());
if (m.substitute) configured.add(m.substitute.toLowerCase());
}
}
const findings = [];
for (const pat of PII_PATTERNS) {
@@ -1406,21 +1414,29 @@
const fake = decodeURIComponent(btn.dataset.fake);
const cat = btn.dataset.cat || 'general';
// Add to mappings via storage
const result = await getStorageData('ss_mappings');
const currentMappings = result || [];
currentMappings.push({
// Immediately dismiss this notification item (same as ignore)
btn.closest('.ss-ps-item').remove();
if (!preSendWarningEl.querySelector('.ss-ps-item')) {
preSendWarningEl.classList.remove('visible');
}
// Optimistically add to local mappings so re-scan skips this value
const tempMapping = {
id: crypto.randomUUID(),
real, substitute: fake,
category: cat,
caseSensitive: false,
enabled: true,
createdAt: Date.now(),
});
await setStorageData('ss_mappings', currentMappings);
};
mappings = [...mappings, tempMapping];
// Update local mappings so the fetch interceptor uses them immediately
mappings = currentMappings;
// Persist via background script (handles encryption);
// update local mappings with the authoritative list on success
addMappingViaBackground({ real, substitute: fake, category: cat })
.then(updatedMappings => {
if (updatedMappings.length) mappings = updatedMappings;
});
// Replace the PII value in the current input right now
if (inputEl) {
@@ -1429,11 +1445,6 @@
if (inputScanTimer) clearTimeout(inputScanTimer);
inputScanTimer = setTimeout(() => scanInputForPII(inputEl), 150);
}
// Visual feedback
btn.textContent = '\u2714';
btn.style.color = '#4ade80';
btn.disabled = true;
});
});
@@ -1493,6 +1504,21 @@
window.postMessage({ type: 'ss:storage-set', key, value }, '*');
}
function addMappingViaBackground(mapping) {
return new Promise(resolve => {
const id = 'ss-add-' + Math.random();
const handler = (event) => {
if (event.data?.type === 'ss:add-mapping-result' && event.data.id === id) {
window.removeEventListener('message', handler);
resolve(event.data.mappings || []);
}
};
window.addEventListener('message', handler);
window.postMessage({ type: 'ss:add-mapping', mapping, id }, '*');
setTimeout(() => { window.removeEventListener('message', handler); resolve([]); }, 2000);
});
}
// Scan input on type and paste
let inputScanTimer = null;
@@ -1503,7 +1529,7 @@
return;
}
const warnings = autoDetectPII(text, identity, { detectProperNouns: settings.detectProperNouns === true })
const warnings = autoDetectPII(text, identity, { detectProperNouns: settings.detectProperNouns === true, mappings })
.filter(w => !ignoredDetections.has(w.value));
if (warnings.length > 0) {
showPreSendWarning(warnings, target);
+20
View File
@@ -193,6 +193,26 @@
if (event.data?.type === 'ss:storage-set') {
await api.storage.local.set({ [event.data.key]: event.data.value });
}
if (event.data?.type === 'ss:add-mapping') {
try {
const response = await api.runtime.sendMessage({
type: 'add:mapping',
mapping: event.data.mapping,
});
window.postMessage({
type: 'ss:add-mapping-result',
id: event.data.id,
mappings: response?.mappings || [],
}, '*');
} catch {
window.postMessage({
type: 'ss:add-mapping-result',
id: event.data.id,
mappings: [],
}, '*');
}
}
});
}