* fix: strip SHA256(host_key) prefix from Chrome 130+ cookie values
Chrome 130 (Cookie DB schema v24) prepends SHA256(domain) to cookie
values before encryption to prevent cross-domain replay attacks.
After decryption, this 32-byte hash must be verified and stripped.
Changes:
- Add stripCookieHash() that verifies SHA256(host_key) and strips
the prefix only when it matches (auto-compatible with older Chrome)
- Fix edge case: cookies with empty values (exactly 32 bytes = hash only)
- Add decrypt_test.go with v10 round-trip encryption/decryption test
- Add stripCookieHash test cases for v24+, older Chrome, empty values,
short values, and host mismatch scenarios
Closes#524
* fix: strip SHA256(host_key) prefix from Chrome 130+ cookie values
Chrome 130 (Cookie DB schema v24) prepends SHA256(domain) to cookie
values before encryption to prevent cross-domain replay attacks.
After decryption, this 32-byte hash must be verified and stripped.
Changes:
- Add stripCookieHash() that verifies SHA256(host_key) and strips
the prefix only when it matches (auto-compatible with older Chrome)
- Fix edge case: cookies with empty values (exactly 32 bytes = hash only)
- Add table-driven decrypt tests for v10/v20/DPAPI per platform
- Add Windows-specific DPAPI round-trip test using CryptProtectData
- Add shared testAESKey constant in testutil_test.go
- Add stripCookieHash tests for v24+, older Chrome, empty values,
short values, and host mismatch scenarios
- Extend lint CI to run on ubuntu, windows, and macos
Closes#524
* fix: remove DPAPI test from darwin/linux (returns nil on Linux)
DecryptWithDPAPI returns nil error on Linux (silent no-op) but error
on macOS, causing the test to fail on Ubuntu CI. DPAPI round-trip
testing is properly covered in decrypt_windows_test.go.
* fix: resolve Windows CI lint errors exposed by multi-platform lint
- Add _ = before windows.CloseHandle calls to satisfy errcheck
- Add build tag to params.go (only used on macOS/Linux, not Windows)
* fix: add .gitattributes to force LF and refactor cookie tests
- Add .gitattributes with `* text=auto eol=lf` to prevent CRLF
conversion on Windows CI causing gofumpt false positives
- Add .gitattributes to .gitignore whitelist
- Refactor stripCookieHash tests into table-driven style
* fix: address Copilot review on decrypt tests
- Assert error on wrong key instead of ignoring it (AES-CBC returns
padding error, not silent empty result)
- Guard empty plaintext in encryptWithDPAPI to prevent nil pointer panic
- Convert uint32 to int for make/copy slice bounds in Windows test
* fix: assert specific error message in wrong key decrypt test
* feat: add Chromium extract methods, source mapping, and tests
Implement per-category data extraction for Chromium browsers as typed
standalone functions, preparing for Phase 8 wiring into the new
Chromium struct.
New files:
- source.go: dataSource struct, chromiumSources/yandexSources maps,
yandexQueryOverrides for Yandex action_url variant
- decrypt.go: decryptValue() wrapping platform-specific decryption
- extract_password.go: SQLite + decrypt → []LoginEntry
- extract_cookie.go: SQLite + decrypt → []CookieEntry
- extract_creditcard.go: SQLite + decrypt → []CreditCardEntry
- extract_history.go: SQLite → []HistoryEntry
- extract_download.go: SQLite → []DownloadEntry
- extract_bookmark.go: JSON recursive → []BookmarkEntry
- extract_extension.go: JSON → []ExtensionEntry
- extract_storage.go: LevelDB → []StorageEntry (local + session)
- firefox/source.go: firefoxSources map
Tests use real Chrome table schemas for SQLite fixtures, with INSERT
helpers to keep test data readable and self-documenting.
Ref #520
* fix: remove LevelDB invalid path test (Windows compatibility)
leveldb.OpenFile creates the directory on Windows instead of returning
an error, causing TestExtractLocalStorage_InvalidPath to fail in CI.
This test was verifying LevelDB behavior, not our extraction logic.
* refactor: remove unused query parameter from extract functions
Only extractPasswords needs the query override (Yandex action_url).
The other 7 SQLite extract functions always use their default query,
so remove the unnecessary query parameter from their signatures.
* refactor: use DetectVersion in decryptValue instead of blind fallback
Replace try-then-fallback pattern with explicit version detection using
crypto.DetectVersion. Routes v10 to DecryptWithChromium, DPAPI to
DecryptWithDPAPI, and adds a TODO placeholder for v20 App-Bound
Encryption.
* chore: relax gocognit and gocritic linters for test files
* revert: restore strict gocognit and gocritic linters for test files
* fix: address review feedback on extract methods
- Store DetectVersion result in local variable to avoid duplicate call
- Scan credit card expiration_month/year as int then convert to string
(matches INTEGER column type in real Chrome schema)
- Add os.Stat check before leveldb.OpenFile to prevent creating empty
directories for non-existent paths
- Rename TestExtractExtensions_InvalidJSON to
TestExtractExtensions_MissingSettingsPath (JSON is valid, path is missing)
* fix: revert creditcard scan to string type for NULL safety
modernc.org/sqlite handles INTEGER→string conversion automatically.
Scanning into string is safer for nullable columns — NULL becomes ""
instead of "0" which would be an invalid month/year.