Commit Graph

491 Commits

Author SHA1 Message Date
Roger 439ff52b02 fix(windows): silent default dump on double-click (#591) v1.0.0 2026-04-27 14:47:59 +08:00
Roger 5c0b1ad5cf ci(release): integrate Windows ABE payload into goreleaser (#590) 2026-04-26 22:53:42 +08:00
Roger 15680c1512 refactor(keyretriever): reduce duplicate master-key WARN logs (#589) 2026-04-25 22:00:33 +08:00
Roger 50c4ea84cb fix(time): correct export data timestamp conversions (#586) 2026-04-23 20:39:56 +08:00
Roger 0c6c781567 feat(yandex): password and credit card decryption (#585) 2026-04-23 17:00:09 +08:00
Roger 7e64d50891 docs(readme): reflect Safari, Windows ABE support (#584)
* 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
2026-04-22 02:47:56 +08:00
Roger 5cad2d1538 feat(safari): extract installed extensions (#583) 2026-04-22 02:30:19 +08:00
Roger 7a5db25b4f feat(safari): localstorage extraction (#582)
* 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.
2026-04-21 20:47:11 +08:00
Roger d75738b90f feat(safari): multi-profile support (#581)
* feat(safari): multi-profile support
2026-04-21 15:50:36 +08:00
Roger 7b9a973c9c fix: per-tier master-key retrievers for mixed-cipher profiles (#579)
* fix: per-tier master-key retrievers for mixed-cipher profiles
2026-04-20 17:33:38 +08:00
Roger e50c623db0 fix: retrieve correct ABE master key when browser is running (#577)
* fix(windows): retrieve correct ABE master key when browser is running
2026-04-19 20:07:51 +08:00
Roger ae1ec66ccb refactor(windows): split Windows code into winapi (#575) 2026-04-19 18:12:37 +08:00
Roger 76e2615db2 refactor(windows): clean up Chrome ABE module (#574)
* refactor(abe): remove --abe-key flag and its global state
* refactor(abe): rework scratch protocol and Go/C structure
2026-04-19 15:20:51 +08:00
slimwang c3d30b9e8a feat(windows): Chrome App-Bound Encryption implementation (#573)
* build(abe): add zig-cc payload build system + C reflective loader
* feat(abe): add reflective injector and Go ABE key-retriever primitives
* feat(abe): wire ABERetriever into DefaultRetriever chain + --abe-key CLI
* feat(abe): route Chromium v20 ciphertext through AES-GCM with ABE key
2026-04-18 23:25:59 +08:00
Roger eb58ebbbf4 fix: support Linux v11 cipher prefix for Chromium decryption (#571) 2026-04-13 22:12:40 +08:00
Roger 370c5882c4 feat: add Safari password extraction from macOS Keychain (#568) 2026-04-13 21:34:40 +08:00
Roger d105a1f488 feat: add Safari bookmark and download extraction from plist (#567)
* feat: add Safari bookmark and download extraction from plist files
* test: add nested folder test for bookmark tree traversal
Part of #565
2026-04-12 01:50:54 +08:00
Roger 7bf1759dd9 feat: add Safari cookie extraction from BinaryCookies format (#566)
* feat: add Safari cookie extraction from BinaryCookies format
* fix: use expiry presence instead of current time for HasExpire
2026-04-12 01:16:59 +08:00
Roger 509cdc2468 feat: add Safari browser support with history extraction (#564)
* feat: add Safari browser support with history extraction
* fix: use correlated subquery to ensure title matches latest visit
2026-04-11 23:47:53 +08:00
hackbrowserdata-bot[bot] 26817b44d5 chore: update contributors list [skip ci] 2026-04-10 16:08:12 +00:00
Roger 454834c06c feat: support MSIX/UWP browsers on Windows (Arc, DuckDuckGo) (#563)
* chore: remove redundant separator comments in browser_test.go
2026-04-11 00:07:58 +08:00
Roger b3bbc0dadf feat: add CountEntries to skip decryption for list --detail (#562)
* 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
2026-04-07 22:28:39 +08:00
Roger 5f42d4fe5f refactor: redesign logging system for CLI-friendly output (#561)
* refactor: redesign logging system for CLI-friendly output
* refactor: remove ANSI color support from logger
* fix: address PR review feedback
2026-04-07 16:50:01 +08:00
Roger a0b4412bf2 fix: share key retriever across all browsers to avoid repeated prompts (#560)
* fix: share key retriever across all browsers to avoid repeated password prompts
2026-04-06 21:57:52 +08:00
Roger ccc8643d86 feat: add interactive terminal password prompt for keychain unlock (#558)
* 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.
2026-04-06 01:27:13 +08:00
Roger 4c3dd9704f chore: add Go version lint check, modernize issue templates (#557)
- Add go.mod version check in lint workflow (fails if go directive != 1.20)
- Add golang.org/x/sys to dependabot ignore list (newer versions require Go 1.21+)
- Fix golang.org/x/text ignore comment
- Migrate issue templates from markdown to YAML forms:
- Update PR template (dev → main, add go.mod checklist item)
- Update .gitignore for YAML issue templates
2026-04-06 00:33:25 +08:00
Roger d8032ac824 docs: rewrite readme, rfcs, and contributing (#555)
* docs: rewrite README, RFCs, and CONTRIBUTING
* docs: fix Linux storage labels in RFC-006 (Opera/Vivaldi swapped)
2026-04-06 00:16:47 +08:00
hackbrowserdata-bot[bot] 2ee7d0ac79 chore: update contributors list [skip ci] 2026-04-05 13:43:24 +00:00
dependabot[bot] a1d4fddddf chore(deps): bump codecov/codecov-action from 5 to 6 (#553)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 21:43:10 +08:00
hackbrowserdata-bot[bot] 08c0fb4069 chore: update contributors list [skip ci] 2026-04-05 13:19:01 +00:00
Roger 6902243895 chore: update CI/CD workflows, Homebrew and new contributors (#552) 2026-04-05 21:18:49 +08:00
github-actions[bot] 15cc1816c1 chore: update contributors [skip ci] 2026-04-05 09:05:35 +00:00
Roger 410bffe643 refactor: naming cleanup and crypto package improvements (#551)
* refactor: naming cleanup across all packages
2026-04-05 16:51:56 +08:00
Roger 4af2ded428 feat: cli migrate to cobra with subcommands (#550)
* feat: migrate CLI to cobra with dump/list/version subcommands (#546)
* fix: remove residual duckduckgo references and add README/LICENSE to release archives
* fix: address PR review feedback from Copilot
2026-04-05 14:25:51 +08:00
Roger 068b82178f fix: improve extract parsing with proper decoding and error handling (#543)
* 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
2026-04-04 18:52:54 +08:00
Roger a58d432688 fix: cache keychain retriever across browser profiles on macOS (#545)
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
2026-04-04 18:36:49 +08:00
Roger 92053b85b0 chore: update golangci-lint config and fix lint issues (#542)
* chore: update golangci-lint config and fix lint issues
2026-04-04 16:26:07 +08:00
Roger e35907de6f refactor: remove dead code and rename V2 files (#541)
* refactor: remove V1 dead code and rename V2 files

- Delete extractor/ package (V1 Extractor interface and registry)
- Delete browserdata/ package (V1 orchestrator, outputter, 9 sub-packages)
- Delete V1 browser implementations (chromium.go, chromium_{platform}.go, firefox.go)
- Delete types/types.go (V1 DataType enum) and utils/byteutil/
- Remove gocsv and go-sqlmock dependencies, demote x/text to indirect
- Upgrade keychainbreaker v0.1.0 → v0.2.5
- Rename chromium_new.go → chromium.go, firefox_new.go → firefox.go

* refactor: remove unused V1 utility functions

Remove functions no longer called by V2 code:
- fileutil: IsDirExists, CopyDir, BrowserName, ReadFile, CopyFile,
  Filename, ParentDir, ParentBaseDir, BaseDir
- typeutil: Keys, IntToBool
2026-04-04 15:51:54 +08:00
Roger 0ace27ce9a feat: wire V2 architecture into CLI entry point (#540)
* feat: wire V2 architecture into CLI entry point
* fix: warn and exit early when no browsers found
2026-04-04 14:11:08 +08:00
Roger 00ad0e0bd4 feat: add output package with Formatter interface (#537)
* docs: add RFC-004 for CLI (cobra) and output design
* feat: add output package with Formatter interface and BrowserData.Each
* fix: golangci config array syntax + add output package tests
* refactor: encapsulated Output as Writer, collect-then-write pattern
* refactor: unified row type with reflection-based CSV/JSON output
* fix: ProfileName empty guard, writeFile close error check, sync RFC-004
2026-04-04 01:41:02 +08:00
Roger 1a3aea553e feat: add Firefox Browser with new v2 architecture (#536)
* feat: add Firefox Browser implementation with new v2 architecture

Add Firefox NewBrowsers + Extract pipeline following the Chromium v2
pattern. Firefox-specific differences handled:
- Profile discovery: random directory names (e.g. abc123.default-release)
- Master key: NSS/ASN1PBE from key4.db (platform-agnostic, no DPAPI/Keychain)
- Key validation: reuse logins.json from acquireFiles tempPaths
- Extract: only Password needs masterKey; Cookie is plaintext
- No CreditCard or SessionStorage support

Files:
- firefox_new.go: Browser struct, NewBrowsers, Extract, getMasterKey,
  extractCategory, deriveKeys, validateKeyWithLogins, profile discovery
- masterkey.go: extracted shared NSS logic (processMasterKey, queryMetaData,
  queryNssPrivateCandidates, parseLoginCipherPairs, canDecryptAnyLoginCipherPair)
- firefox_new_test.go: table-driven tests with shared fixtures
- source.go: remove dataSource wrapper, use []sourcePath directly
- firefox.go: remove functions moved to masterkey.go

* fix: address Copilot review feedback on Firefox v2

- Fix stale comment referencing removed readLoginCipherPairs
- Rename finallyKey to derivedKey for clarity in processMasterKey
- Add sqlite driver import to masterkey.go for self-containedness

* refactor: rewrite Firefox masterkey and improve naming

Masterkey rewrite:
- Replace raw SQL functions with structured key4DB type (globalSalt,
  passwordCheck, privateKeys) for clear data modeling
- Split processMasterKey into verifyPasswordCheck + decryptPrivateKey
- Add nssKeyTypeTag constant for the magic bytes
- Rename finallyKey to derivedKey
- Add sqlite driver import for self-containedness
- Return error (not fallback) when logins validation explicitly fails

Naming cleanup:
- loginPair → encryptedLogin (clarify these are encrypted blobs)
- parseLoginPairs → sampleEncryptedLogins (clarify sampling purpose)
- canDecryptLogin → tryDecryptLogins (accurate verb, plural alignment)
- Expand abbreviated variables: p→login, uPBE→userPBE, pPBE→pwdPBE

Password extraction:
- Keep entries when decryptPBE fails (URL preserved, user/pwd empty)
- Align with Chromium behavior where decrypt failure doesn't skip records

Old code cleanup:
- firefox.go GetMasterKey now delegates to retrieveMasterKey
- Remove functions moved to masterkey.go

* docs: add RFC-003 for crypto package naming cleanup

Track accumulated naming and structural issues in crypto/asn1pbe.go
and cross-browser shared code for a future dedicated refactoring pass.

* refactor: move masterkey tests to masterkey_test.go

- Rename firefox_test.go to masterkey_test.go since all tests in
  this file test masterkey.go functions (readKey4DB, sampleEncryptedLogins)
- Fix TestReadKey4DB to check nssPrivate rows as a set instead of
  assuming SQLite insertion order
- Future deletion of firefox.go won't accidentally remove masterkey tests
2026-04-04 01:41:02 +08:00
Roger 1b8bb1df3d feat: add Chromium Browser with new v2 architecture (#530)
* feat: add Chromium Browser implementation with new architecture
* refactor: replace Walk with ReadDir+Stat for profile discovery
* refactor: remove queries override, use extractors for Yandex passwords
* refactor: remove dataSource wrapper, use []sourcePath directly
* fix: address Copilot review feedback on chromium_new.go
* fix: always call key retriever regardless of Local State existence
2026-04-04 01:41:02 +08:00
Roger 1ec2781131 feat: add Firefox extract methods and complete data model fields (#527)
* feat: add Firefox extract methods and complete data model fields

Firefox extract methods:
- extractPasswords: JSON + ASN1PBE decryption via decryptPBE helper
- extractCookies: SQLite, plaintext (no encryption), journalOff
- extractHistories: SQLite, visit count ASC sort (matches old behavior)
- extractDownloads: SQLite, moz_annos JOIN with JSON content parsing
- extractBookmarks: SQLite, moz_bookmarks JOIN moz_places
- extractExtensions: JSON, filter by location=app-profile
- extractLocalStorage: SQLite webappsstore2, reversed originKey parsing

Complete data model fields (union of Chromium and Firefox):
- CookieEntry: add HasExpire, IsPersistent
- DownloadEntry: add MimeType
- CreditCardEntry: add NickName, Address
- ExtensionEntry: add HomepageURL, Enabled

Update Chromium extractors to populate new fields:
- extract_cookie.go: fill HasExpire, IsPersistent
- extract_download.go: SELECT and fill mime_type
- extract_creditcard.go: SELECT nickname, billing_address_id
- extract_extension.go: fill HomepageURL, Enabled (state==1)

Tests:
- Full test coverage for all 7 Firefox extract functions
- Password test uses known ASN1PBE test vectors from crypto package
- Table-driven tests for parseOriginKey
- Updated Chromium tests for new fields

* fix: add COALESCE for nullable bookmark title in Firefox query

Firefox moz_bookmarks.title can be NULL (PR #500 fixed this in old code).
Add COALESCE to handle NULL gracefully in SQL instead of relying on
driver-specific NULL→string conversion behavior.

* fix: enable journalOff for all Firefox SQLite extractors and populate cookie flags

- Set journalOff=true for extract_history, extract_download, extract_bookmark
  (Firefox databases require PRAGMA journal_mode=off to avoid lock errors)
- Populate HasExpire and IsPersistent for Firefox cookies (derived from expiry>0)
- Add test assertions for HasExpire/IsPersistent in both Chromium and Firefox
2026-04-04 01:41:02 +08:00
Roger 2c4e871e59 fix: strip host_key prefix from Chrome 130+ cookie values (#526)
* 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
2026-04-04 01:41:01 +08:00
Roger b3dd4ed6e4 feat: add Chromium extract methods and source mapping (#521)
* 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.
2026-04-04 01:41:01 +08:00
Roger 9fb5165fcb feat: add crypto/keyretriever with keychainbreaker integration (#518)
* feat: add crypto/keyretriever package for Chromium master key retrieval

* feat: complete keyretriever with gcoredump, chainbreaker, and tests

* refactor: replace internal chainbreaker with keychainbreaker v0.1.0

Replace the incomplete internal chainbreaker implementation (~1400 lines
of duplicated code) with the external keychainbreaker package, which
provides a complete, well-tested keychain parsing library.

Changes:
- Add github.com/moond4rk/keychainbreaker v0.1.0 dependency
- Update gcoredump_darwin.go to use keychainbreaker API (Open/Unlock/GenericPasswords)
- Add KeychainPasswordRetriever for password-based keychain unlocking
  with sync.Once caching across multiple browser queries
- Unify DefaultRetriever(keychainPassword string) signature across all platforms
- Delete utils/chainbreaker/ (696 lines + test + testdata)
- Delete crypto/keyretriever/chainbreaker_darwin.go (696 lines duplicate)
- Delete browser/exploit/gcoredump/ (duplicate of keyretriever version)
- Update chromium_darwin.go to use keyretriever.DecryptKeychain
- Clean up .golangci.yml lint exceptions and .gitignore entries
- Use errors.Is() instead of == for context.DeadlineExceeded check

* refactor: improve gcoredump exploit code quality and add comments
* fix: address Copilot review feedback on keyretriever
2026-04-04 01:41:01 +08:00
Roger 12436217ae feat: add filemanager session and crypto version detection (#516)
* feat: add filemanager session and crypto version detection

* refactor: move copy logic into filemanager, remove fileutil dependency

* fix: apply review suggestions for filemanager

* feat: add Windows locked file tests, fix readFileContent with ReadFile+FileMapping fallback

* fix: remove self-PID skip in findFileHandle to fix Windows CI test

* fix: seek to file start before reading duplicated handle

* fix: use full path matching in findFileHandle to avoid cross-app handle collision

* test: enhance Windows copyLocked tests with write-then-read, large file, and normal copy scenarios

* fix: check all errors in Windows tests, use bytes.Equal for large file comparison

* fix: use stable path suffix matching to handle Windows short path names in CI
2026-04-04 01:41:01 +08:00
Roger e86e3e62d6 feat: add browserdata/datautil helpers (#513)
* feat: add browserdata/datautil helpers (QuerySQLite, QueryRows, DecryptChromiumValue)

Phase 2 of architecture refactoring (RFC-002 Section 3):

- datautil/sqlite.go: QuerySQLite() — shared SQLite open/query/scan helper
  with optional journal_mode=off for Firefox databases
- datautil/query.go: QueryRows[T]() — generic helper (Go 1.20) that wraps
  QuerySQLite and collects results into a typed slice
- datautil/decrypt.go: DecryptChromiumValue() — unified Chromium decryption
  (DPAPI first, then AES-GCM/CBC fallback)
- datautil/sqlite_test.go: tests for all helpers

* refactor: move DecryptChromiumValue from datautil to browser/chromium

- Remove browserdata/datautil/decrypt.go (Chromium-specific, not a generic util)
- Will be added as browser/chromium/decrypt.go (unexported decryptValue)
  in the chromium extract methods PR
- Update RFCs to reflect the change
- Remove decrypt test from datautil tests

* refactor: move datautil to utils/sqliteutil for consistency

- Rename browserdata/datautil/ → utils/sqliteutil/
- Aligns with existing utils/ convention (fileutil, typeutil, byteutil)
- QuerySQLite/QueryRows are generic SQLite helpers, not browserdata-specific
- Update package name from datautil to sqliteutil
- Update both RFCs to reflect new location

* fix: apply review suggestions for sqliteutil

- QuerySQLite: validate dbPath exists before sql.Open to prevent
  silently creating empty databases
- Tests: check db.Close() errors with require.NoError
2026-04-04 01:41:01 +08:00
Roger b680d43caa feat: add types.Category, data models, and browserdata.Data (#512)
* feat: add new types.Category, data models, and browserdata.Data

Phase 1 of architecture refactoring (RFC-001/RFC-002):

- types/category.go: Category enum (9 values) replacing DataType (22 values)
  with String(), IsSensitive(), AllCategories, NonSensitiveCategories()
- types/models.go: browser-agnostic data models (LoginEntry, CookieEntry,
  BookmarkEntry, HistoryEntry, DownloadEntry, CreditCardEntry, StorageEntry,
  ExtensionEntry) — no encrypted fields, no browser prefixes
- types/category_test.go: tests for Category methods
- browserdata/browser_data.go: new Data struct with typed slices,
  coexists with old BrowserData during migration

* docs: replace Coveralls badge with Codecov in README

* fix: apply review suggestions (is_http_only tag, json tags on Data)
2026-04-04 01:41:00 +08:00
chleynx c493804ede fix: correctly parse Chromium localStorage LevelDB entries (#539) 2026-04-04 01:01:55 +08:00