docs: cross-host decryption guide and comment cleanup (#614)

* docs(readme): document cross-host decryption workflow

* docs: drop RFC citations and what-comments
This commit is contained in:
Roger
2026-06-13 21:17:00 +08:00
committed by GitHub
parent dc610d3c63
commit 2860bb82f9
31 changed files with 176 additions and 103 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ func extractCreditCards(masterKeys masterkey.MasterKeys, path string) ([]types.C
return cards, nil
}
// extractYandexCreditCards reads the records table (not Chromium's credit_cards). AAD = guid. See RFC-012 §4.
// extractYandexCreditCards reads the records table (not Chromium's credit_cards). AAD = guid.
func extractYandexCreditCards(masterKeys masterkey.MasterKeys, path string) ([]types.CreditCardEntry, error) {
dataKey, err := loadYandexDataKey(path, masterKeys.V10)
if err != nil {
+1 -1
View File
@@ -51,7 +51,7 @@ func extractPasswordsWithQuery(masterKeys masterkey.MasterKeys, path, query stri
return logins, nil
}
// extractYandexPasswords walks Ya Passman Data; protocol in RFC-012 §4.
// extractYandexPasswords walks Ya Passman Data.
// Note: URL column is origin_url — it's what the per-row AAD is computed over (not action_url).
func extractYandexPasswords(masterKeys masterkey.MasterKeys, path string) ([]types.LoginEntry, error) {
dataKey, err := loadYandexDataKey(path, masterKeys.V10)
+2 -2
View File
@@ -73,10 +73,10 @@ func yandexCardAAD(guid string, keyID []byte) []byte {
return out
}
// errYandexMasterPasswordSet: caller warns + skips; RSA-OAEP unseal is deferred (RFC-012 §6).
// errYandexMasterPasswordSet: caller warns + skips; RSA-OAEP unseal is deferred.
var errYandexMasterPasswordSet = errors.New("yandex: profile protected by master password, skipping")
// loadYandexDataKey honors the master-password gate and returns the per-DB data key. See RFC-012 §4.2.
// loadYandexDataKey honors the master-password gate and returns the per-DB data key.
func loadYandexDataKey(dbPath string, masterKey []byte) ([]byte, error) {
if len(masterKey) == 0 {
return nil, fmt.Errorf("yandex: master key not available")
-2
View File
@@ -50,13 +50,11 @@ func readKey4DB(path string) (*key4DB, error) {
var record key4DB
// Read metaData table
const metaQuery = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
if err := db.QueryRow(metaQuery).Scan(&record.globalSalt, &record.passwordCheck); err != nil {
return nil, fmt.Errorf("query metaData: %w", err)
}
// Read nssPrivate table
const nssQuery = `SELECT a11, a102 FROM nssPrivate`
rows, err := db.Query(nssQuery)
if err != nil {
-4
View File
@@ -55,7 +55,6 @@ func (p *profile) extract(categories []types.Category) *types.BrowserData {
return data
}
// count counts entries per category without decryption.
func (p *profile) count(categories []types.Category) map[types.Category]int {
session, err := filemanager.NewSession()
if err != nil {
@@ -76,7 +75,6 @@ func (p *profile) count(categories []types.Category) map[types.Category]int {
return counts
}
// acquireFiles copies source files to the session temp directory.
func (p *profile) acquireFiles(session *filemanager.Session, categories []types.Category) map[types.Category]string {
tempPaths := make(map[types.Category]string)
for _, cat := range categories {
@@ -114,7 +112,6 @@ func (p *profile) getMasterKey(session *filemanager.Session, tempPaths map[types
return retrieveMasterKey(key4Dst, loginsPath)
}
// extractCategory calls the appropriate extract function for a category.
func (p *profile) extractCategory(data *types.BrowserData, cat types.Category, masterKey []byte, path string) {
var err error
switch cat {
@@ -140,7 +137,6 @@ func (p *profile) extractCategory(data *types.BrowserData, cat types.Category, m
}
}
// countCategory calls the appropriate count function for a category.
func (p *profile) countCategory(cat types.Category, path string) int {
var count int
var err error
+2 -2
View File
@@ -72,7 +72,7 @@ func TestDiscoverSafariProfiles_OrphanUUIDWithoutDBEntry(t *testing.T) {
// Profile directory with a History.db exists on disk but is absent from
// SafariTabs.db. When the DB is readable and doesn't mention it, we trust
// the DB — the orphan stays hidden because production filters profiles
// with no resolvable data in NewBrowsers anyway. Here we assert discovery
// with no resolvable data in NewBrowser anyway. Here we assert discovery
// returns only what the DB declares.
const dbUUID = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"
const orphanUUID = "11111111-2222-3333-4444-555555555555"
@@ -182,7 +182,7 @@ func TestDiscoverSafariProfiles_DefaultProfileSentinelIgnored(t *testing.T) {
func TestDiscoverSafariProfiles_EmptyProfileDirectoryFiltersOutInNewBrowsers(t *testing.T) {
// Matches the real 4E2D8DD0 orphan on the author's Mac: a profile dir
// listed in neither SafariTabs.db nor containing any extractable data.
// Discovery without the DB surfaces it; NewBrowsers then drops it when
// Discovery without the DB surfaces it; NewBrowser then drops it when
// resolveSourcePaths yields zero matches.
const uuid = "4E2D8DD0-A7D2-4684-939A-898B7675C700"
library := t.TempDir()
+3 -4
View File
@@ -107,10 +107,9 @@ func resolveSourcePaths(sources map[types.Category][]sourcePath) map[types.Categ
// Offset from the Core Data epoch (2001-01-01 UTC) to the Unix epoch.
const coreDataEpochOffset = 978307200
// maxCoreDataSeconds is the largest CFAbsoluteTime that still lands inside
// time.Time.MarshalJSON's [1, 9999] year window. Also bounds the float
// int64 conversion below; Go's spec makes out-of-range conversions return
// an implementation-dependent int64, which could silently corrupt results.
// maxCoreDataSeconds guards against CFAbsoluteTime values that would exceed
// time.Time.MarshalJSON's year-9999 ceiling, and bounds the float→int64
// conversion below (Go spec: out-of-range result is implementation-dependent).
const maxCoreDataSeconds = 252423993600
// coredataTimestamp converts Core Data seconds (CFAbsoluteTime) to UTC.
+1 -1
View File
@@ -76,7 +76,7 @@ func TestNewBrowsers(t *testing.T) {
}
// ---------------------------------------------------------------------------
// NewBrowsers — multi-profile (macOS 14+ named profiles)
// NewBrowser — multi-profile (macOS 14+ named profiles)
// ---------------------------------------------------------------------------
func TestNewBrowsers_MultiProfile(t *testing.T) {