Commit Graph
20 Commits
Author SHA1 Message Date
Claude 2719e1be44 revert: restore entire src/ from pre-doc-scanner commit (e4b44a7)
Going back to a known-good baseline. This version had:
- Working reveal mode with CSS Highlight API
- Working substitution (fetch + XHR hooks)
- Smart patterns (names, emails, phones, usernames)
- Encryption/sync (password, TOTP, WebAuthn)
- Multiple identity profiles
- Activity log
- Secret scanner
- Auto-detect PII warnings
- Pre-send PII detection

Kept current manifests (UUID, data_collection_permissions, version).
No renames applied — uses original naming (secretScanning, PPI, etc).
Will re-apply renames and new features from this working base.

https://claude.ai/code/session_01KF4i7Ra7zCEDskxDBaNtcT
2026-03-29 18:45:10 +00:00
Outis b95dcc6a40 Merge pull request #27 from outis1one/claude/read-repo-wA3y1
fix: reveal mode broken + missing await + select rendering — v2.0.10
2026-03-27 08:45:43 -04:00
Claude 85fbc6c4d0 fix: reveal mode broken + missing await + select rendering — v2.0.10
Bug 1 - Reveal mode not working (all browsers):
sessionSubstitutions stored "ademo demo" (full name) as key, but
buildRevealPairs looked up "ademo" and "demo" individually. No match,
no reveal pairs, reveal did nothing. Fixed by also storing individual
words from multi-word replacements so both "ademo demo" AND "ademo"
AND "demo" are in the map.

Bug 2 - Missing await on _handleDecryptedMeta (sync.js):
Two call sites returned the Promise instead of the resolved value.
Downstream code checking decResult.data got undefined. Added await.

Bug 3 - Profile selector broken by safeHTML (popup.js):
DOMParser.parseFromString wraps content in <html><body> which
mangles <option> elements when moved to a <select>. Replaced with
new Option() DOM API which creates proper option elements.

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-27 12:41:47 +00:00
Outis 80571934d0 Merge pull request #26 from outis1one/claude/read-repo-wA3y1
Claude/read repo w a3y1
2026-03-27 08:23:18 -04:00
Claude 97e37e65ac fix: cross-browser sync import corrupting local encryption + v2.0.9
Root cause: when importing an encrypted sync code from another device,
_decryptFromSync was replacing the local encryption config (salt) with
the source device's salt. This caused:
1. Local key cache derived from wrong salt
2. Local data (encrypted with local salt) became unreadable
3. _applyData tried to write with the wrong key

Fixed with a complete refactor of cross-device decryption:
- authenticateForSync() derives a TEMPORARY key using the source salt
- Temporary key stored separately as 'tempSyncKey' in IndexedDB
- Local encryption config and cached key are NEVER modified
- After decryption, _applyData writes via _writeSecure using the
  LOCAL key (which uses the local salt)
- _handleDecryptedMeta extracted for code reuse

Also:
- Options.js auth handler detects pending sync import and routes to
  authenticateForSync instead of regular authenticate
- After auth success, automatically retries the import
- README updated: imported passwords are protected (dots in UI,
  vault password to reveal, AES-256 encrypted at rest)
- Bumped to v2.0.9

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-27 05:23:50 +00:00
Outis 9a4b26eb61 Merge pull request #24 from outis1one/claude/read-repo-wA3y1
fix: cross-browser sync decryption + WebAuthn on extension pages
2026-03-27 00:39:03 -04:00
Claude d1bc43d02d fix: cross-browser sync decryption + WebAuthn on extension pages
Sync code import between browsers was failing with "Wrong key or
corrupted data" because each browser derives a different AES key
from the same password (different salt). The decrypt function was
using the local device's salt instead of the source device's salt
embedded in the sync envelope.

Fixed _decryptFromSync to always use the sync envelope's salt for
decryption. If the cached key's salt doesn't match, forces re-auth
so the password is re-entered and a new key is derived with the
correct salt.

Also fixed WebAuthn "device can't be used" error on extension pages.
chrome-extension:// and moz-extension:// origins are not valid for
WebAuthn. isWebAuthnAvailable() now returns false on extension pages.

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-27 04:38:25 +00:00
Outis 483cfff70b Merge pull request #21 from outis1one/claude/read-repo-YMu21
security: require encryption for all sync channels, reduce activity l…
2026-03-27 00:27:10 -04:00
Claude a3904843ba security: require encryption for all sync channels, reduce activity log to 100
Sync operations (browser sync, Gist, custom URL, sync code) now refuse to
operate without encryption enabled. Disabling encryption also turns off all
active sync channels. Activity log cap reduced from 200 to 100 entries for
both storage and display.

https://claude.ai/code/session_01KF4i7Ra7zCEDskxDBaNtcT
2026-03-27 04:17:50 +00:00
Claude 0870c050cb fix: sync code not transferring identity when encryption enabled
_getAllData() was reading raw storage which contains encrypted blobs
when at-rest encryption is enabled. The sync code export would send
{ _ssLocalEncrypted: true, data: <blob> } instead of actual identity
data. The importing browser couldn't use these blobs.

Fixed _getAllData() to use Storage._readSecure() which decrypts
transparently. Fixed _applyData() to use Storage._writeSecure()
so imported data gets encrypted on the receiving end.

Also: hide the Auto-Sync Folder section entirely in browsers that
don't support File System Access API (Firefox, Brave, Safari)
instead of showing a broken-looking error message.

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-27 03:57:53 +00:00
Claude 70c7b759c6 feat: auto-sync, version history, merge, org policy, tamper guard
New modules:
- version-history.js: IndexedDB snapshot storage with pruning/rollback
- merge.js: three-way field-level merge for sync conflict resolution
- org-policy.js: team/org policy enforcement, compliance checking,
  invite codes, required mappings that can't be disabled
- tamper-guard.js: admin password to protect disable/clear/export
  actions, org policy can prevent disabling

Auto background sync:
- Gist/URL sync via chrome.alarms (MV3-safe, survives SW restarts)
- Configurable interval (5/15/30 min), push on local changes
- performAutoSync() orchestrates pull-then-conditional-push

Multi-device dashboard:
- Device auto-registration with UUID + browser/platform detection
- Device list embedded in sync data for cross-device visibility
- getDeviceInfo(), setDeviceName(), getDevices(), removeDevice()

Manifest changes:
- Added "alarms" permission for background polling

Service worker:
- Alarm listeners for auto-sync and org policy polling (hourly)
- Tamper guard message handlers
- Alarms set up on install and startup

WIP: Options UI integration pending for all new features.

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 19:39:28 +00:00
Claude a22ba549a2 feat: at-rest encryption for all sensitive data + vault unlock flow
All sensitive data (identity, mappings, activity log) is now AES-256
encrypted in browser.storage.local when sync encryption is enabled.
TOTP secret is also encrypted at rest using the derived key.

Vault unlock flow:
- On browser restart, extension detects locked state (encrypted data,
  no cached CryptoKey) and shows LOCK badge in red
- Popup shows a full-screen unlock prompt with password field,
  optional TOTP, and biometric button
- After unlock, background decrypts and broadcasts data to all tabs
- Content scripts start with empty config when locked; receive
  decrypted config via vault:unlocked message after unlock
- Injector skips encrypted blobs in storage change events

Storage module changes:
- _readSecure / _writeSecure transparently encrypt/decrypt
- encryptExistingData() migrates plaintext → encrypted on setup
- decryptAllData() restores plaintext when encryption is disabled
- isLocked() checks for encrypted data + missing key

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 19:03:54 +00:00
Claude 39e609a14e feat: cross-device encryption bootstrap via sync payload
Encrypted sync data now embeds the encryption config so new devices
can self-bootstrap from just the sync data + the password:

Outer envelope (plaintext):
  - salt + verificationBlob — needed to derive key on new device

Inner payload (encrypted):
  - TOTP secret, authMethod, ttlDays, webauthn flag

Flow on new device:
1. Pull encrypted sync data from any channel
2. _decryptFromSync detects no local config, bootstraps from _encConfig
3. User enters password → key derived → payload decrypted
4. Full config (including TOTP secret) restored from inner _encMeta
5. Device is now fully configured — WebAuthn can be registered locally

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 18:44:42 +00:00
Claude 51a25a208b feat: TOTP as standalone re-auth method alongside WebAuthn/password
Re-verification (TTL expired, key still cached) now accepts any ONE of:
- WebAuthn (biometric/PIN)
- TOTP code alone (no password needed)
- Password alone (no TOTP needed)

First-device setup still requires password (+ TOTP if configured) since
the password is needed to derive the encryption key.

Added reverifyWithTOTP() and reverifyWithPassword() to sync.js.
Auth prompt UI adapts: first-device shows password+TOTP fields,
re-verify shows all three methods as alternatives.

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 18:42:05 +00:00
Claude 7fd70e0891 fix: WebAuthn as primary re-auth, key persists indefinitely
- CryptoKey now persists in IndexedDB forever — never auto-deleted
- TTL controls when re-verification is needed, not key lifetime
- WebAuthn is the primary re-auth method (not a post-expiry fallback)
- Password only needed once per device (first-time setup)
- Added needsReverification() and markVerified() to crypto.js
- Auth prompt adapts message: first-device vs re-verify vs decrypt
- Biometric button hidden on first-device setup (no credential yet)

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 18:23:17 +00:00
Claude 8198620b8a feat: encrypted sync with password/TOTP/WebAuthn + smart reveal
Sync encryption:
- AES-256-GCM encryption for all sync channels (browser sync, gist,
  custom URL, folder sync, sync codes)
- Password with optional TOTP (RFC 6238) second factor
- Configurable auth TTL: session, 30/90/180/365 days, or never
- CryptoKey cached in IndexedDB — auth only needed when cache expires
  AND new data exists (lastModified check runs before auth prompt)
- WebAuthn (biometric/PIN) as low-friction re-authentication gate
- Full options UI for setup, password change, and inline auth prompt

Smart reveal:
- Track which substitute values were actually sent outbound per session
- Reveal mode only replaces values that were genuinely substituted,
  preventing false positives (e.g. AI using the word "user" won't be
  replaced with a real username that maps to "user")

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
2026-03-26 18:08:21 +00:00
Claude cbe5b8584d feat: GitHub Gist and custom HTTP URL cloud sync
GitHub Gist sync:
- pushToGist(token): pushes all settings to a private Gist; creates a
  new Gist on first use and stores the Gist ID in local storage so
  subsequent pushes update the same Gist.
- pullFromGist(token): fetches the Gist, compares lastModified, applies
  if newer (raw_url used to avoid API truncation).
- No desktop client needed; works across any browser/OS with a GitHub PAT.
- Options page shows a token field + Push/Pull buttons; Gist ID shown
  once linked.

Custom URL sync:
- pushToUrl({ url, method, headers }): HTTP PUT to any endpoint.
- pullFromUrl({ url, headers }): HTTP GET, applies if newer.
- Works with Nextcloud/ownCloud WebDAV, self-hosted servers, cloud
  functions, or any static-file host that allows PUT.
- Options page shows URL + optional JSON headers field + Push/Pull.

Both methods write ss_sync_notification on apply, triggering the purple
'SYN' badge and desktop notification added in the previous commit.

https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
2026-03-26 14:44:18 +00:00
Claude 1e475196d6 feat: sync notification badge + clarify cloud storage support
Notification system:
- When sync applies data (file folder, browser account, or sync code),
  ss_sync_notification is written to local storage with the source.
- Service worker catches it via storage.onChanged, shows a purple 'SYN'
  badge on the extension icon that persists until Options is opened, and
  fires a desktop notification ('Settings updated via sync folder — open
  Options to review').
- Clicking the desktop notification opens the Options page directly.
- On service worker wake, SYN badge is restored if the notification was
  not yet dismissed.
- Opening Options clears ss_sync_notification, resets the badge, and
  sends a sync:notification-seen message to the service worker.
- Added 'notifications' permission to both manifests.

Cloud storage clarity:
- Options page now explicitly lists that the folder sync works with any
  cloud storage that has a desktop sync client: Dropbox, OneDrive, Google
  Drive, iCloud Drive, Box, pCloud, Nextcloud, Synology Drive, etc.

https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
2026-03-26 14:42:18 +00:00
Claude f05375c2ec fix: PPI + button replaces text immediately; add auto-sync folder
PPI + button fix:
- After adding a mapping, the real PPI value is now immediately replaced
  with the fake value in the input/contenteditable element via the new
  replaceInInput() helper (handles both <textarea>/<input> and
  contenteditable divs by walking text nodes).
- Triggers a re-scan 150ms later so the pre-send warning updates or
  dismisses itself if no more PPI remains.

Auto-sync folder (File System Access API):
- User picks a folder once per browser via "Choose Sync Folder".
  Any settings/mappings/identity change writes silent-send-sync.json
  to that folder automatically (via api.storage.onChanged listener).
- On options page open and every time the page regains focus, the file
  is read back; if its lastModified is newer than local data, settings
  are imported immediately and the UI refreshes.
- File handle is stored in IndexedDB (ss_sync_handles) so it persists
  across browser sessions without repeated permission prompts.
- Pick the SAME folder in each browser (or a synced cloud folder for
  cross-computer sync) — fully automatic after that, no copy-paste.
- sync.js gains saveSyncDirHandle / loadSyncDirHandle / clearSyncDirHandle
  helpers backed by IndexedDB.

https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
2026-03-26 14:32:53 +00:00
Claude 84f6e675db fix: date false-positive, partial-word highlights, cross-browser sync
Bug fixes:
- Date (possible DOB) pattern now requires context words (born, birthday,
  dob, etc.) before firing — prevents spurious warnings on page-load API
  calls that happen to contain ISO dates in conversation history.
- Highlight regex now uses word boundaries (\b) so short substitute values
  (e.g. "aud") no longer match inside unrelated words like "Claude".
- Both TreeWalkers in content.js now skip the extension's own UI elements
  (.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge) to
  prevent the highlight API from marking text in the extension's banners.

Settings sync:
- New src/lib/sync.js: exportSyncCode / importSyncCode (base64 JSON) for
  manual copy-paste across any browser combination. Newest lastModified
  timestamp wins; force flag available to override.
- browser.storage.sync support: when "Browser account sync" is enabled the
  extension automatically pushes/pulls via Firefox Sync or Chrome account,
  chunked to stay within per-item quota limits.
- storage.js now writes ss_lastModified on every save so conflict resolution
  has an accurate timestamp.
- service-worker.js listens for both local and sync storage changes to keep
  all copies in sync.
- New "Sync Between Browsers" section in options.html with Generate/Copy/
  Import Sync Code UI and the browser sync toggle.

https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
2026-03-26 14:13:22 +00:00