diff --git a/cmd/hack-browser-data/dumpkeys.go b/cmd/hack-browser-data/dumpkeys.go new file mode 100644 index 0000000..f9041fe --- /dev/null +++ b/cmd/hack-browser-data/dumpkeys.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/moond4rk/hackbrowserdata/browser" + "github.com/moond4rk/hackbrowserdata/log" +) + +func dumpKeysCmd() *cobra.Command { + var ( + browserName string + outputPath string + keychainPw string + ) + + cmd := &cobra.Command{ + Use: "dumpkeys", + Short: "Export Chromium master keys as JSON for cross-host decryption", + Example: ` hack-browser-data dumpkeys -o keys.json + hack-browser-data dumpkeys -b chrome`, + RunE: func(cmd *cobra.Command, args []string) error { + browsers, err := browser.DiscoverBrowsersWithKeys(browser.DiscoverOptions{ + Name: browserName, + KeychainPassword: keychainPw, + }) + if err != nil { + return err + } + + dump := browser.BuildDump(browsers) + log.Infof("Exported keys for %d vault(s)", len(dump.Vaults)) + + if outputPath == "" { + return dump.WriteJSON(os.Stdout) + } + f, err := os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600) + if err != nil { + return fmt.Errorf("create %s: %w", outputPath, err) + } + defer f.Close() + return dump.WriteJSON(f) + }, + } + + cmd.Flags().StringVarP(&browserName, "browser", "b", "all", "target browser: all|"+browser.Names()) + cmd.Flags().StringVarP(&outputPath, "output", "o", "", "output file (default: stdout)") + cmd.Flags().StringVar(&keychainPw, "keychain-pw", "", "macOS keychain password") + + return cmd +} diff --git a/cmd/hack-browser-data/main.go b/cmd/hack-browser-data/main.go index 61a8acf..d8c9c5e 100644 --- a/cmd/hack-browser-data/main.go +++ b/cmd/hack-browser-data/main.go @@ -31,7 +31,7 @@ GitHub: https://github.com/moonD4rk/HackBrowserData`, root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "enable debug logging") dump := dumpCmd() - root.AddCommand(dump, listCmd(), keysCmd(), versionCmd()) + root.AddCommand(dump, dumpKeysCmd(), restoreCmd(), listCmd(), versionCmd()) // Default to dump when no subcommand is given. // Copy dump flags to root so that `hack-browser-data -b chrome` diff --git a/cmd/hack-browser-data/keys.go b/cmd/hack-browser-data/restore.go similarity index 60% rename from cmd/hack-browser-data/keys.go rename to cmd/hack-browser-data/restore.go index 8e346e2..788ca65 100644 --- a/cmd/hack-browser-data/keys.go +++ b/cmd/hack-browser-data/restore.go @@ -13,59 +13,7 @@ import ( "github.com/moond4rk/hackbrowserdata/masterkey" ) -func keysCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "keys", - Short: "Manage cross-host master keys", - } - cmd.AddCommand(keysExportCmd(), keysImportCmd()) - return cmd -} - -func keysExportCmd() *cobra.Command { - var ( - browserName string - outputPath string - keychainPw string - ) - - cmd := &cobra.Command{ - Use: "export", - Short: "Export Chromium master keys as JSON for cross-host decryption", - Example: ` hack-browser-data keys export -o dump.json - hack-browser-data keys export -b chrome`, - RunE: func(cmd *cobra.Command, args []string) error { - browsers, err := browser.DiscoverBrowsersWithKeys(browser.DiscoverOptions{ - Name: browserName, - KeychainPassword: keychainPw, - }) - if err != nil { - return err - } - - dump := browser.BuildDump(browsers) - log.Infof("Exported keys for %d vault(s)", len(dump.Vaults)) - - if outputPath == "" { - return dump.WriteJSON(os.Stdout) - } - f, err := os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600) - if err != nil { - return fmt.Errorf("create %s: %w", outputPath, err) - } - defer f.Close() - return dump.WriteJSON(f) - }, - } - - cmd.Flags().StringVarP(&browserName, "browser", "b", "all", "target browser: all|"+browser.Names()) - cmd.Flags().StringVarP(&outputPath, "output", "o", "", "output file (default: stdout)") - cmd.Flags().StringVar(&keychainPw, "keychain-pw", "", "macOS keychain password") - - return cmd -} - -func keysImportCmd() *cobra.Command { +func restoreCmd() *cobra.Command { var ( keysPath string browserName string @@ -77,11 +25,11 @@ func keysImportCmd() *cobra.Command { ) cmd := &cobra.Command{ - Use: "import", - Short: "Import master keys from JSON and decrypt a copied profile", - Example: ` hack-browser-data keys import -i dump.json -b chrome -p /path/to/copied/User\ Data - hack-browser-data keys import -i dump.json -b edge -p /path -c cookie -f csv - ssh origin "hack-browser-data keys export" | hack-browser-data keys import -i - -b chrome -p /path`, + Use: "restore", + Short: "Decrypt a copied profile using exported master keys", + Example: ` hack-browser-data restore -i keys.json -b chrome -p /path/to/copied/User\ Data + hack-browser-data restore -i keys.json -b edge -p /path -c cookie -f csv + ssh origin "hack-browser-data dumpkeys" | hack-browser-data restore -i - -b chrome -p /path`, RunE: func(cmd *cobra.Command, args []string) error { browsers, err := loadAndApplyKeys(browserName, profilePath, keysPath) if err != nil {