mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-06-04 19:48:01 +02:00
100 lines
3.0 KiB
Go
100 lines
3.0 KiB
Go
package browser
|
|
|
|
import (
|
|
"runtime"
|
|
|
|
"github.com/moond4rk/hackbrowserdata/log"
|
|
"github.com/moond4rk/hackbrowserdata/masterkey"
|
|
)
|
|
|
|
// BuildDump exports one Vault per installation (Firefox/Safari, lacking KeyManager, are skipped).
|
|
// Partial results are kept — a Chrome 127+ profile mixes v10+v20, so a v20-only failure must not
|
|
// discard a usable v10 key.
|
|
func BuildDump(browsers []Browser) masterkey.Dump {
|
|
dump := masterkey.NewDump()
|
|
for _, b := range browsers {
|
|
km, ok := b.(KeyManager)
|
|
if !ok {
|
|
continue
|
|
}
|
|
mk, err := km.ExportKeys()
|
|
if err != nil {
|
|
status := "partial"
|
|
if !mk.HasAny() {
|
|
status = "failed"
|
|
}
|
|
log.Warnf("dump-keys: %s %s: %v", b.BrowserName(), status, err)
|
|
}
|
|
if !mk.HasAny() {
|
|
continue
|
|
}
|
|
dump.Vaults = append(dump.Vaults, masterkey.Vault{
|
|
Browser: b.BrowserName(),
|
|
UserDataDir: b.UserDataDir(),
|
|
Profiles: profileNames(b),
|
|
Keys: mk,
|
|
})
|
|
}
|
|
return dump
|
|
}
|
|
|
|
func profileNames(b Browser) []string {
|
|
profiles := b.Profiles()
|
|
names := make([]string, 0, len(profiles))
|
|
for _, p := range profiles {
|
|
names = append(names, p.Name)
|
|
}
|
|
return names
|
|
}
|
|
|
|
// ApplyDump overlays StaticRetrievers from dump onto matching installations (Firefox/Safari skipped).
|
|
// Match is by (BrowserName, UserDataDir); on miss — commonly a cross-host path mismatch (Windows vs
|
|
// POSIX, or a relocated dir via -p) — it falls back to the sole vault for that browser name. No match
|
|
// → warn and leave the platform retrievers in place.
|
|
func ApplyDump(browsers []Browser, dump masterkey.Dump) {
|
|
if dump.Host.OS != "" && dump.Host.OS != runtime.GOOS {
|
|
log.Infof("apply-keys: dump created on %s/%s; current host is %s/%s",
|
|
dump.Host.OS, dump.Host.Arch, runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
vaultIndex := make(map[string]*masterkey.Vault, len(dump.Vaults))
|
|
vaultsByBrowser := make(map[string][]*masterkey.Vault)
|
|
for i := range dump.Vaults {
|
|
v := &dump.Vaults[i]
|
|
vaultIndex[v.Browser+"|"+v.UserDataDir] = v
|
|
vaultsByBrowser[v.Browser] = append(vaultsByBrowser[v.Browser], v)
|
|
}
|
|
for _, b := range browsers {
|
|
km, ok := b.(KeyManager)
|
|
if !ok {
|
|
continue
|
|
}
|
|
v, found := vaultIndex[b.BrowserName()+"|"+b.UserDataDir()]
|
|
if !found {
|
|
if candidates := vaultsByBrowser[b.BrowserName()]; len(candidates) == 1 {
|
|
v = candidates[0]
|
|
log.Infof("apply-keys: %s using sole vault for browser (dump path %q != local %q)",
|
|
b.BrowserName(), v.UserDataDir, b.UserDataDir())
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
log.Warnf("apply-keys: %s no matching vault in dump", b.BrowserName())
|
|
continue
|
|
}
|
|
km.SetRetrievers(masterkey.Retrievers{
|
|
V10: maybeStaticRetriever(v.Keys.V10),
|
|
V11: maybeStaticRetriever(v.Keys.V11),
|
|
V20: maybeStaticRetriever(v.Keys.V20),
|
|
})
|
|
}
|
|
}
|
|
|
|
// maybeStaticRetriever wraps non-empty key bytes as a StaticRetriever; an empty/nil key returns nil
|
|
// to preserve the "tier not applicable" signal NewMasterKeys expects.
|
|
func maybeStaticRetriever(key []byte) masterkey.Retriever {
|
|
if len(key) == 0 {
|
|
return nil
|
|
}
|
|
return masterkey.NewStaticRetriever(key)
|
|
}
|