@@ -14,7 +14,8 @@ import (
1414 "github.com/moond4rk/hackbrowserdata/types"
1515)
1616
17- // Browser is the interface that both chromium.Browser and firefox.Browser implement.
17+ // Browser is the interface implemented by every engine package —
18+ // chromium.Browser, firefox.Browser, and safari.Browser.
1819type Browser interface {
1920 BrowserName () string
2021 ProfileName () string
@@ -27,30 +28,57 @@ type Browser interface {
2728type PickOptions struct {
2829 Name string // browser name filter: "all"|"chrome"|"firefox"|...
2930 ProfilePath string // custom profile directory override
30- KeychainPassword string // macOS keychain password (ignored on other platforms)
31+ KeychainPassword string // macOS only — see browser_darwin.go
3132}
3233
33- // PickBrowsers returns browsers matching the given options.
34- // When Name is "all", all known browsers are tried.
35- // ProfilePath overrides the default user data directory (only when targeting a specific browser).
34+ // PickBrowsers returns browsers that are fully wired up for Extract: the
35+ // key retriever chain and (on macOS) the Keychain password are already
36+ // injected, so the caller can call b.Extract directly. This is the entry
37+ // point for extraction workflows like `dump`.
38+ //
39+ // On macOS this may trigger an interactive prompt for the login password
40+ // when the target set includes a Chromium variant or Safari. Commands that
41+ // only need metadata (name, profile path, per-category counts) should use
42+ // DiscoverBrowsers instead to skip injection — and thereby the prompt.
43+ //
44+ // When Name is "all", all known browsers are tried. ProfilePath overrides
45+ // the default user data directory (only when targeting a specific browser).
3646func PickBrowsers (opts PickOptions ) ([]Browser , error ) {
47+ browsers , err := pickFromConfigs (platformBrowsers (), opts )
48+ if err != nil {
49+ return nil , err
50+ }
51+ inject := newPlatformInjector (opts )
52+ for _ , b := range browsers {
53+ inject (b )
54+ }
55+ return browsers , nil
56+ }
57+
58+ // DiscoverBrowsers returns browsers for metadata-only workflows — listing,
59+ // profile paths, per-category counts. Decryption dependencies are NOT
60+ // injected, so calling b.Extract on the returned browsers will not
61+ // successfully decrypt protected data (passwords, cookies, credit cards).
62+ // CountEntries, BrowserName, ProfileName, and ProfileDir all work
63+ // correctly without injection.
64+ //
65+ // Unlike PickBrowsers, DiscoverBrowsers never prompts for the macOS
66+ // Keychain password, making it the correct choice for `list`-style
67+ // commands that have no use for the credential.
68+ func DiscoverBrowsers (opts PickOptions ) ([]Browser , error ) {
3769 return pickFromConfigs (platformBrowsers (), opts )
3870}
3971
40- // pickFromConfigs is the testable core of PickBrowsers. It iterates over
41- // platform browser configs, discovers installed profiles, and injects a
42- // shared key retriever into Chromium browsers for decryption.
72+ // pickFromConfigs is the testable core of PickBrowsers: it filters the
73+ // platform browser list and discovers installed profiles for each match.
74+ // Dependency injection (key retrievers, keychain credentials) is intentionally
75+ // NOT done here — see PrepareExtract.
4376func pickFromConfigs (configs []types.BrowserConfig , opts PickOptions ) ([]Browser , error ) {
4477 name := strings .ToLower (opts .Name )
4578 if name == "" {
4679 name = "all"
4780 }
4881
49- // Create a single key retriever shared across all Chromium browsers.
50- // On macOS this avoids repeated password prompts; on other platforms
51- // it's harmless (DPAPI reads Local State per-profile, D-Bus is stateless).
52- retriever := keyretriever .DefaultRetriever (opts .KeychainPassword )
53-
5482 configs = resolveGlobs (configs )
5583
5684 var browsers []Browser
@@ -78,21 +106,14 @@ func pickFromConfigs(configs []types.BrowserConfig, opts PickOptions) ([]Browser
78106 continue
79107 }
80108
81- // Inject the shared key retriever into browsers that need it.
82- // Chromium browsers implement retrieverSetter; Firefox does not.
83- for _ , b := range found {
84- if setter , ok := b .(retrieverSetter ); ok {
85- setter .SetRetriever (retriever )
86- }
87- }
88109 browsers = append (browsers , found ... )
89110 }
90111 return browsers , nil
91112}
92113
93- // retrieverSetter is implemented by browsers that need an external key retriever.
94- // This allows pickFromConfigs to inject the shared retriever after construction
95- // without coupling the Browser interface to Chromium-specific concerns .
114+ // retrieverSetter is an optional capability interface. Chromium variants
115+ // implement it to receive a master-key retriever chain; Firefox and Safari
116+ // do not .
96117type retrieverSetter interface {
97118 SetRetriever (keyretriever.KeyRetriever )
98119}
0 commit comments