Without -p, dumped keys would be applied to local profile data and
decrypt to garbage; -b all hits the same path because pickFromConfigs
ignores -p when name == "all". Require both.
Consumer side of the cross-host key workflow (pairs with #599).
ApplyDump wires StaticProviders from a dump.json into matching
browsers, so dump --keys f.json -p /copied/data decrypts without
native retrievers.
Promote keyRetrieversSetter to public KeyManager and lift
keychainPasswordSetter from browser_darwin.go into browser.go as
KeychainPasswordReceiver. Engines already implement these methods;
only type-assertion sites switch to the public interface names.
* docs(readme): reflect Safari, Windows ABE, and DuckDuckGo support
* docs(readme): name the ABE build output as hack-browser-data.exe
* docs(readme): address review feedback on ABE browsers and FDA wording
* feat(safari): localstorage extraction
Extracts Safari 17+ localStorage from WebKit's nested layout —
WebsiteDataStore/<uuid>/Origins/<top-hash>/<frame-hash>/LocalStorage/
localstorage.sqlite3 for named profiles, WebsiteData/Default for the
default profile. Parses the binary SecurityOrigin serialization
(length-prefixed scheme+host plus 0x00 default-port or 0x01 <uint16_le>
explicit-port section) and decodes UTF-16 LE ItemTable value BLOBs,
capping oversized values at 2048 bytes to match the Chromium extractor.
Reports the frame origin URL so partitioned third-party storage is
attributed to the iframe origin JavaScript actually sees.
Closes the remaining LocalStorage checkbox in #565.
* docs(safari): add RFC-011 data storage
Documents Safari's profile structure, per-category file layouts, and
storage formats including the Safari 17+ nested WebKit Origins
localStorage layout and binary SecurityOrigin serialization. Defers
Keychain credential extraction to RFC-006 §7 and notes the cross-browser
differences (plaintext cookies, plist bookmarks/downloads, Core Data
epoch timestamps, partitioned storage).
* fix(safari): latin-1 origin decoding, NULL key skip, count fast-path
- Decode originEncASCII via decodeLatin1 so high-byte records preserve
their ISO-8859-1 meaning instead of being interpreted as UTF-8.
Matches the pattern in chromium/extract_storage.go.
- Skip ItemTable rows where key is NULL — SQLite's UNIQUE constraint
permits multiple NULLs, and silently lowering them to empty strings
would collide with legitimate empty-string keys.
- countLocalStorage now walks origin dirs and runs SELECT COUNT(key)
per localstorage.sqlite3 instead of fully decoding every value.
COUNT(key) naturally excludes NULLs, keeping count and extract
symmetric.
Addresses Copilot review feedback on #582.
* fix(safari): round-2 review — WAL replay, stable ordering, error context
- Drop immutable=1 on temp-copy SQLite opens in readLocalStorageFile /
countLocalStorageFile. Session.Acquire copies the -wal / -shm sidecars,
so mode=ro alone lets SQLite replay WAL on the ephemeral copy and
surface entries Safari committed to WAL but hasn't checkpointed yet.
Live-file reads in profiles.go keep immutable=1 as before.
- Order ItemTable query by (key, rowid) for deterministic exports across
runs and SQLite versions.
- Wrap os.ReadFile / os.ReadDir errors with the offending path so
multi-origin debug logs stay scannable.
- RFC-011 §7 rewritten to explain the live-vs-temp split.
- New regression test asserts ORDER BY surfaces rows in key order.
Addresses round-2 Copilot review on #582.
* feat: add CountEntries to skip decryption for list --detail (#549)
* test: add CountEntries and countCategory tests at browser level
* fix: address review feedback on CountRows and countLocalStorage
* test: add CountRows unit tests
* feat(darwin): add interactive terminal password prompt for keychain unlock (#556)
* test: add unit tests for keyretriever and address review feedback
- Add errStorageNotFound sentinel error for precise error matching
- Non-TTY TerminalPasswordRetriever returns nil silently (review #558)
- Add darwin tests: findStorageKey, empty password, non-TTY skip
- Add linux tests: FallbackRetriever peanuts key, DefaultRetriever chain
* fix: add nolint:unused for errStorageNotFound on Windows, clean up error message
errStorageNotFound is only used on darwin/linux; Windows lint flagged it
as unused. Also simplify error format to avoid "storage" duplication.
* fix: add nolint:unused for errStorageNotFound, simplify error message
errStorageNotFound is only referenced on darwin and linux; Windows lint
flags it as unused. Also remove redundant "storage" prefix from the
error format string.
* fix: implement proper Chromium localStorage LevelDB parsing
* feat: add IsMeta field to StorageEntry and keep META entries
* fix: add error logging for decryption and missing data fields
* fix: address PR review for localStorage parsing
* fix: use naïve instead of café in Latin-1 test to avoid typos false positive
* fix: extension enabled detection and sessionStorage decoding
* fix: session storage origin resolution and extension enabled detection
* fix: address PR review comments for storage parsing
Share a single KeyRetriever instance across all profiles of the same
browser, and add sync.Once caching to GcoredumpRetriever and
SecurityCmdRetriever. This avoids repeated keychain password prompts
(or securityd memory dumps) when extracting multiple profiles.
Closes#544