From e739531cee4ac2370ee7354b33661c56ab91583d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 27 Mar 2026 03:16:56 +0000 Subject: [PATCH] fix: catch concatenated name forms (JohnSmith, john.smith, etc.) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Smart patterns now catch all concatenated combinations of first+last names with common separators: | Pattern | Example real | Example replaced | |---------|-------------|-----------------| | FirstLast | JohnSmith | AdemoDem | | firstlast | johnsmith | ademodemo | | first.last | john.smith | ademo.demo | | first_last | john_smith | ademo_demo | | first-last | john-smith | ademo-demo | | LastFirst | SmithJohn | DemoAdemo | | last.first | smith.john | demo.ademo | Case is preserved: all-lowercase input → lowercase output, ALL-UPPERCASE → uppercase, mixed case → as configured. Also bumped all versions to 2.0.5. https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn --- manifest.firefox.json | 2 +- manifest.json | 2 +- package.json | 2 +- src/content/content.js | 26 ++++++++++++++++++++++++++ src/options/options.html | 2 +- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/manifest.firefox.json b/manifest.firefox.json index 27d0ca1..f0c056e 100644 --- a/manifest.firefox.json +++ b/manifest.firefox.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Silent Send", - "version": "2.0.3", + "version": "2.0.5", "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 034e60e..ad9d1fa 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Silent Send", - "version": "2.0.3", + "version": "2.0.5", "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 a203aae..e33f7f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "silent-send", - "version": "2.0.3", + "version": "2.0.5", "private": true, "license": "BSL-1.1", "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 384ca10..47fd4e5 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -182,6 +182,32 @@ replacements.push({ original: matched, replaced: sub, category: 'name', pattern: 'smart' }); return sub; }); + // Concatenated forms: JohnSmith, johnsmith, john.smith, john_smith, john-smith + // Also reversed: SmithJohn, smithjohn, smith.john, etc. + const f = first.real, l = last.real; + const fs = first.substitute, ls = last.substitute; + const concatPatterns = [ + // first+last + [f + l, fs + ls], + [f + '.' + l, fs + '.' + ls], + [f + '_' + l, fs + '_' + ls], + [f + '-' + l, fs + '-' + ls], + // last+first + [l + f, ls + fs], + [l + '.' + f, ls + '.' + fs], + [l + '_' + f, ls + '_' + fs], + [l + '-' + f, ls + '-' + fs], + ]; + for (const [real, sub] of concatPatterns) { + result = result.replace(new RegExp('\\b' + esc(real) + '\\b', 'gi'), (matched) => { + // Preserve case: all-lower→lower, ALL-UPPER→upper, else use sub as-is + let replacement = sub; + if (matched === matched.toLowerCase()) replacement = sub.toLowerCase(); + else if (matched === matched.toUpperCase()) replacement = sub.toUpperCase(); + replacements.push({ original: matched, replaced: replacement, category: 'name', pattern: 'smart-concat' }); + return replacement; + }); + } } } diff --git a/src/options/options.html b/src/options/options.html index abe7481..ea8ce0a 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -589,7 +589,7 @@