@@ -3,6 +3,7 @@ package chromium
33import (
44 "os"
55 "path/filepath"
6+ "sync"
67 "time"
78
89 "github.com/moond4rk/hackbrowserdata/crypto/keyretriever"
@@ -51,17 +52,7 @@ func NewBrowsers(cfg types.BrowserConfig) ([]*Browser, error) {
5152 return browsers , nil
5253}
5354
54- // SetKeyRetrievers wires the per-tier master-key retrievers used by Extract. Each slot
55- // (V10 / V11 / V20) is populated only on platforms where that cipher tier is used:
56- //
57- // - Windows: V10 (DPAPI) + V20 (ABE). V11 nil — Chromium does not emit v11 prefix on Windows.
58- // - Linux: V10 ("peanuts" kV10Key) + V11 (D-Bus Secret Service kV11Key). V20 nil.
59- // - macOS: V10 (Keychain chain). V11 and V20 nil.
60- //
61- // Slots are independent — a failure or absence in one tier does not affect others. A single
62- // Chromium profile can carry mixed cipher-prefix ciphertexts (the motivation for issue #578), so
63- // every configured retriever runs at extract time and decryptValue picks the matching key per
64- // ciphertext.
55+ // SetKeyRetrievers wires the per-tier master-key retrievers (V10/V11/V20) used by Extract; unused tiers stay nil.
6556func (b * Browser ) SetKeyRetrievers (r keyretriever.Retrievers ) {
6657 b .retrievers = r
6758}
@@ -178,12 +169,11 @@ func (b *Browser) acquireFiles(session *filemanager.Session, categories []types.
178169 return tempPaths
179170}
180171
181- // getMasterKeys retrieves the Chromium master keys for every configured tier. Chrome mixes
182- // cipher tiers on the same profile — v20 for new cookies alongside v10 passwords on Windows; v10
183- // (peanuts) alongside v11 (keyring) on Linux after session-mode changes — so every retriever in
184- // b.retrievers runs independently and keyretriever.NewMasterKeys assembles the results. Any tier
185- // key may be nil if its retriever failed or is not configured for this platform; decryptValue
186- // treats a missing tier key as "that tier cannot decrypt" so partial success is still reported.
172+ // warnedMasterKeyFailure dedupes "master key retrieval" WARN per installation (BrowserName + UserDataDir);
173+ // profiles share one Safe Storage entry, but glob-expanded configs may yield multiple installations of the same browser.
174+ var warnedMasterKeyFailure sync.Map
175+
176+ // getMasterKeys retrieves master keys for all configured cipher tiers.
187177func (b * Browser ) getMasterKeys (session * filemanager.Session ) keyretriever.MasterKeys {
188178 label := b .BrowserName () + "/" + b .ProfileName ()
189179
@@ -207,7 +197,12 @@ func (b *Browser) getMasterKeys(session *filemanager.Session) keyretriever.Maste
207197
208198 keys , err := keyretriever .NewMasterKeys (b .retrievers , b .cfg .Storage , localStateDst )
209199 if err != nil {
210- log .Warnf ("%s: master key retrieval: %v" , label , err )
200+ installKey := b .BrowserName () + "|" + b .cfg .UserDataDir
201+ if _ , already := warnedMasterKeyFailure .LoadOrStore (installKey , struct {}{}); ! already {
202+ log .Warnf ("%s: master key retrieval: %v" , b .BrowserName (), err )
203+ } else {
204+ log .Debugf ("%s: master key retrieval: %v" , label , err )
205+ }
211206 }
212207 return keys
213208}
0 commit comments