Commit Graph
265 Commits
Author SHA1 Message Date
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
Claude 44f9d9444c Fix encryption enable by removing broken org UI references, bump to 0.9.44
Removed Organization section JS (initOrgUI, showOrgJoined, showOrgNotJoined,
setOrgStatus) and OrgPolicy import from options.js. These referenced DOM
elements deleted in a prior commit, causing DOMContentLoaded init to fail
before the encryption button listener could be registered.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 13:55:04 +00: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
Claude 450688a787 Bump version to 0.9.43
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 13:27:01 +00:00
Claude 617a2d10eb Wrap fetch interceptor in top-level try/catch to prevent breaking page requests
If anything in Silent Send's substitution logic throws (bad mapping,
regex error, unexpected body format, etc.), the exception was propagating
up to the caller instead of falling through to the original fetch. This
broke Claude Code's web interface (claude.ai/code) when a bad mapping
caused a substitution error mid-request.

The inner try/catch on JSON.parse only covered the JSON path — the outer
logic (hasSubstitutions, processBody, notifySubstitutions, etc.) had no
protection. Added a top-level try/catch that catches any unhandled error
and falls through to originalFetch, logging a warning so the error is
still visible in the console.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 13:23:33 +00:00
Claude 3d8642db52 Fix whitespace-only mappings highlighting every space on the page
A mapping imported with real: " " (single space) passed the !m.real
guard (space is truthy), producing new RegExp(" ", "gi") which matched
every space character in the DOM and highlighted them all.

- Added .trim() to all real/substitute guard conditions in content.js
  (inline substitute, reveal functions) and substitution-engine.js so
  whitespace-only values are treated as empty and skipped
- Added the same guard in highlightMatches so the CSS Highlight API
  never creates ranges for blank search terms
- Added trim + blank-check to the bulk import path in options.js so
  whitespace-only real values are dropped at import time rather than
  saved to storage

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 13:19:14 +00: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
Claude abeb79a93f Wrap long mapping values instead of truncating with ellipsis
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 12:12:08 +00:00
Claude 0b4fbe1efc Remove Organization section; fix mappings table column layout
- Removed the Organization section from options page (unused feature)
- Fixed mapping table columns spreading Real Value and Substitute to
  opposite ends of the row. Added table-layout: fixed with explicit
  column widths (35/35/12/8/6/4%) so columns are evenly distributed.
  Added text-overflow: ellipsis on td so long values truncate cleanly.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 12:09:00 +00:00
Claude deacfd5907 Bump version to 0.9.42
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-02 00:39:49 +00: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
Claude e93e27012e Fix fresh-install pull blocked by saveSettings timestamp
After a browser restart with no extension data, enabling encryption calls
saveSettings() which writes ss_lastModified = Date.now(). All pull paths
then compare that fresh timestamp against the remote's older timestamp,
see local >= remote, and skip the pull with "already on latest version" —
even though local is completely empty.

Fix: add _hasRealLocalData() which returns true only if local storage
contains actual identity profiles or mappings with real values. The
timestamp skip condition now requires BOTH a newer local timestamp AND
real local data. An empty/fresh install always falls through to pull.

Affects pullFromGist, pullFromUrl, pullFromSyncStorage, and importSyncCode.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 23:45:10 +00: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
Claude dbf178937f Bump version to 0.9.41
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 20:04:51 +00: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
Claude 1b224fb233 Add Ignore button to auto-detect warnings for permanent per-value dismissal
The × close button only hid the warning for the current send — the same
detection reappeared on every subsequent send with no way to silence it.

Added an Ignore button to each item in both the on-send warning
(showAutoDetectWarning) and the pre-send input scanner warning
(showPreSendWarning). Clicking Ignore:
- Adds the specific value to an in-memory Set (ignoredDetections)
- Persists it to ss_ignored_detections in storage
- Removes that item from the current warning; closes the popup if empty

On page load, ss_ignored_detections is read from storage so ignores
survive page reloads. Ignored values are also filtered before
auto-redaction in the fetch interceptor, so they are not redacted either.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 18:25:13 +00: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
Claude ed8d094320 Bump version to 0.9.40
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 16:08:30 +00:00
Claude ed92b07703 Add grok.com; fix fetch hook on React/Next.js sites (Reddit, Grok, etc.)
Two fixes:

1. grok.com missing from manifest
   Grok moved from grok.x.ai to grok.com. The extension wasn't activating
   on grok.com at all (no content script injected). Added to host_permissions
   and content_scripts in both manifests.

2. Fetch hook bypassed on React/Next.js sites
   content.js was injected async (after awaiting the document-scanner),
   so by the time it replaced window.fetch, React/Next.js had already stored
   a reference to the original. All fetch calls from framework code bypassed
   the hook entirely.

   Fix: load early-hook.js as a "world": "MAIN" content script at
   document_start. This runs synchronously before any page JavaScript,
   captures the real fetch in window.__ssOriginalFetch, and replaces
   window.fetch with a lightweight wrapper. When content.js eventually
   loads, it sets window.__ssInterceptFetch (the real substitution logic)
   and window.__ssReady = true, activating the wrapper. React's stored
   fetch reference now routes through the interceptor.

   Falls back to direct window.fetch replacement if early-hook.js somehow
   didn't run (e.g. older browser without world: MAIN support).

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 16:07:01 +00: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
Claude 9af92a24aa Bump version to 0.9.39
https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 14:56:40 +00: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
Claude 1c4b8b0cdd Fix race condition: vault:unlocked message lost when service worker responds before content.js loads
Two related races caused substitution to silently fail with at-rest encryption:

1. vault:request-unlock was sent at the top of init(), but the runtime.onMessage
   listener that handles the vault:unlocked response was registered only after
   await-ing the document-scanner script. A warm service worker (e.g. freshly
   woken by a sync operation) could respond before the listener existed, dropping
   the message permanently.

2. Even if the listener was registered in time, it posted to window immediately,
   but content.js hadn't been injected yet, so its window.addEventListener('message')
   handler wasn't live and the message went nowhere.

Fix: register api.runtime.onMessage before injecting content.js, and move the
vault:request-unlock send into script.onload — by that point content.js has fully
executed and its message listener is live.

Also stop passing the encrypted settings blob as initial config. When isLocked,
ss_settings is { _ssLocalEncrypted: true, data: '...' }; passing it to content.js
as the initial settings object clutters the settings with encrypted garbage.
Now falls back to { enabled: true } like mappings/identity already did.

https://claude.ai/code/session_01CwcZK8nqL8pyBH9AxDs9qo
2026-04-01 14:48:19 +00:00
Outis 1f869f2ff0 Merge pull request #66 from outis1one/claude/read-repo-yLNcT
Claude/read repo y l nc t
2026-04-01 00:57:04 -04:00
Claude b3dc4f7abd Bump version to 0.9.34
https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:56:22 +00:00
Claude 7028f60b56 Fix fresh-install pull skipping due to empty-profile timestamp pollution
Root cause: when the popup opens for the first time it calls
addProfile('Personal') + updateProfile(...) to create a default empty
profile. Both call saveProfiles, which was unconditionally setting
ss_lastModified: Date.now(). This made the new browser's local
timestamp look like right now — newer than any Gist data pushed by
the source browser — so every pull returned "Already up to date"
without ever prompting for a password or importing anything.

Fixes:

1. storage.js saveProfiles: only advance ss_lastModified when at
   least one profile contains real PII (non-empty real value in
   names, emails, usernames, phones, or catchAllEmail). Creating the
   default empty profile structure on first install leaves
   ss_lastModified at 0 so pulls correctly see remote data as newer.

2. sync.js pushToGist: persist ss_last_push_time and
   ss_last_push_source alongside ss_gist_id so the source browser
   (which only pushes) can also show its last activity time.

3. options.js: display both "Pushed: <time>" and "Pulled: <time>"
   in the Gist status area on page load, giving both browsers
   meaningful feedback.

4. service-worker.js: after a successful auto-sync pull, broadcast
   vault:unlocked to all open content-script tabs so substitution
   works immediately without a page reload.

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:53:12 +00:00
Claude 8b6f779a07 Prevent empty-browser auto-sync from clobbering Gist data
On a fresh browser install with auto-sync enabled, performAutoSync
would push because config.lastPush was null (!config.lastPush = true).
With _getAllData now returning lastModified: 0 for browsers with no
saved data, this pushed a payload with lastModified: 0 to the Gist,
overwriting the real data from the source browser. Subsequent pulls
then saw remoteMod (0) <= local (0) and returned "Already up to date"
without ever prompting for a password or importing anything.

Three fixes:

1. performAutoSync: add local.lastModified > 0 guard to the push
   condition so a browser with no saved data never pushes in the
   background (both Gist and URL paths).

2. pushToGist / pushToUrl: return an explicit error if lastModified
   is 0, preventing a manual Push click on a fresh browser from
   clobbering the Gist too.

3. pullFromGist: if the Gist's lastModified is 0 (already clobbered),
   return a clear error message telling the user to push from the
   source browser first, rather than silently returning "up to date".

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:43:52 +00:00
Outis e46d08428e Merge pull request #65 from outis1one/claude/read-repo-yLNcT
Claude/read repo y l nc t
2026-04-01 00:31:16 -04:00
Claude 64f24f28f1 Bump version to 0.9.33
https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:30:39 +00:00
Claude 9f763ba0ec Fix substitution breaking after sync import with at-rest encryption
When at-rest encryption is enabled, injector.js detects encrypted blobs
in storage, passes empty config to the content script, and waits for a
vault:unlocked broadcast from the background. That broadcast was only
ever triggered when the user explicitly entered their password in the
popup. After a Gist/URL sync import (which writes newly-imported data
in encrypted form), no page ever received the decrypted config, so
substitution silently stopped working.

Two fixes:

1. injector.js: when isLocked is true (encrypted blobs detected), send
   vault:request-unlock to the background. If the key is already cached
   (e.g. the user authenticated during the sync pull), the background
   responds immediately with vault:unlocked containing the decrypted
   data. This fixes every new page load after a sync import.

2. service-worker.js: add vault:request-unlock handler that checks
   Storage.isLocked() and, if the key is available, reads decrypted
   mappings/identity/settings and sends vault:unlocked back to the
   requesting tab.

3. options.js: after a successful Gist or URL pull, send vault:unlocked
   to the background so it broadcasts decrypted data to all currently-
   open tabs immediately, without requiring a page reload.

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:27:26 +00:00
Claude 0997f7a8e4 Fix pull silently skipping on fresh browser install; show last pull time
Three issues in the Gist pull flow on a browser with no prior data:

1. _getAllData() returned Date.now() as lastModified when ss_lastModified
   was unset (fresh install). The timestamp check in pullFromGist then
   saw the Gist data as older than local, silently returned imported:false
   ("Already up to date") without importing anything or prompting for
   auth. Fixed by using || 0 so a browser with no data always accepts
   remote data as newer.

2. _applyData now persists ss_last_pull_time and ss_last_pull_source so
   the last successful pull survives page reloads.

3. The Gist section on the options page now shows "Last pulled: <time>"
   alongside the Gist ID on load, so both browsers display their sync
   status rather than showing nothing on first open.

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-04-01 04:11:43 +00:00
Outis 8a066cd357 Merge pull request #64 from outis1one/claude/read-repo-yLNcT
Claude/read repo y l nc t
2026-03-31 17:25:06 -04:00
Claude 6a962e927b Add .version-bump-undo to .gitignore
Local scratch file created by bump-version.sh; no need to track it.

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-03-31 21:21:16 +00:00
Claude 8539c7ba9b Bump version to 0.9.32
https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-03-31 21:20:46 +00:00
Claude 3420299f51 Fix cross-browser GitHub Gist sync when encryption is enabled
Two bugs prevented sync from working between different browsers
sharing the same GitHub token and encryption password:

1. pullFromGist failed immediately with "No Gist ID stored" on any
   browser that had not previously pushed, because ss_gist_id lives
   in browser.storage.local (isolated per browser). Fix: when no
   local Gist ID is found, search the authenticated user's Gists for
   one containing silent-send-sync.json and cache the result.

2. When the pulled data was encrypted with a different salt (each
   browser generates its own random salt on setup), pullFromGist
   returned needsAuth:true but the UI never set
   window.__ssPendingSyncImport, so the auth prompt fell through to
   reverifyWithPassword instead of authenticateForSync, and the pull
   was never retried after the user entered their password. Fix: set
   window.__ssPendingSyncImport before showing the auth prompt for
   both Gist pull and custom-URL pull, matching how sync-code import
   already handled this flow.

https://claude.ai/code/session_01QJnEnLfbXKR5FSCQ3Qfs53
2026-03-31 20:55:12 +00:00
Outis 7a128b9f10 Merge pull request #63 from outis1one/claude/fix-extension-disable-RJffZ
Claude/fix extension disable r jff z
2026-03-30 18:49:55 -04:00
Claude bb5d9d3837 Bump version to 0.9.31
https://claude.ai/code/session_015TEttQgcq5FALLKLb3uEW8
2026-03-30 22:48:36 +00:00
Claude f021e50c08 Fix extension not fully disabling when toggled off
The fetch/XHR interception correctly checked settings.enabled, but
several other features ignored it — highlights, reveal mode, and
PII auto-detect all continued running after disabling. This adds
settings.enabled checks to the MutationObserver, highlightMatches,
auto-detect input/paste listeners, reveal mode, and cleans up
visual artifacts (highlights, warnings) when the extension is
toggled off.

https://claude.ai/code/session_015TEttQgcq5FALLKLb3uEW8
2026-03-30 22:26:58 +00:00
Outis d6707d9cf6 Bump version to 0.9.30 2026-03-30 11:55:20 -04:00
Claude 4968b4cde2 Bump version to 0.9.30 2026-03-30 15:54:48 +00:00
Outis bd9d28cd50 Bump version to 0.9.29 2026-03-30 10:25:08 -04:00