pwstore: pass/gopass + macOS Keychain in-place adapters
Group 2 of the manager wire-up — two CLI ItemUpdaters: pass/gopass: the user's own password-store as a rotation source. Reads line-1=password + key:value metadata via `<bin> show`; updates in place by piping the full body to `<bin> insert -m -f` (off-argv), preserving metadata across the password swap. gopass enumerates via `ls --flat`, pass by walking the store dir; --pass-prefix scopes a subtree. keychain: macOS internet passwords via the `security` CLI. Pure-exec (no build tag) so it unit-tests cross-platform via a fake bin; Available() is false off darwin. Read off-argv (find-internet-password -w); write is delete+add with -w on argv (CLI limitation, documented like 1password). Both MOCK-ONLY (fake-binary unit tests + leak checks); recorded as DATA in BROWSER-ROTATION.md §8. 153 tests green, vet clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ var (
|
||||
flagAllowCSV bool
|
||||
flagExportPath string
|
||||
flagKdbxPath string
|
||||
flagPassPrefix string
|
||||
flagPwLength int
|
||||
flagExcludeAmbig bool
|
||||
flagSymbolSet string
|
||||
@@ -54,7 +55,8 @@ func passwordsCmd() *cobra.Command {
|
||||
"value into the manager ONLY after you confirm the site accepted it. MFA/CAPTCHA are\n" +
|
||||
"always your job; incredigo never bypasses them.\n\n" +
|
||||
"--manager selects the backend:\n" +
|
||||
" in-place (CLI, no plaintext file): bitwarden | 1password | keepassxc\n" +
|
||||
" in-place (CLI, no plaintext file): bitwarden | 1password | keepassxc |\n" +
|
||||
" pass | gopass | keychain(macOS)\n" +
|
||||
" CSV import/export (tmpfs + shred, needs --allow-csv + --export-path):\n" +
|
||||
" chrome | firefox | edge | brave | safari | lastpass | dashlane |\n" +
|
||||
" protonpass | nordpass | roboform | enpass(read-only)\n" +
|
||||
@@ -63,10 +65,11 @@ func passwordsCmd() *cobra.Command {
|
||||
"tmpfs and securely shredded after you confirm re-import).",
|
||||
}
|
||||
pf := c.PersistentFlags()
|
||||
pf.StringVar(&flagPwManager, "manager", "", "backend: bitwarden|1password|keepassxc|chrome|firefox|edge|brave|safari|lastpass|dashlane|protonpass|nordpass|roboform|enpass")
|
||||
pf.StringVar(&flagPwManager, "manager", "", "backend: bitwarden|1password|keepassxc|pass|gopass|keychain|chrome|firefox|edge|brave|safari|lastpass|dashlane|protonpass|nordpass|roboform|enpass")
|
||||
pf.BoolVar(&flagAllowCSV, "allow-csv", false, "allow the flag-gated browser/manager-CSV plaintext path (tmpfs + shred)")
|
||||
pf.StringVar(&flagExportPath, "export-path", "", "CSV managers: the CSV you exported from the browser/manager")
|
||||
pf.StringVar(&flagKdbxPath, "kdbx", "", "keepassxc: path to the .kdbx database")
|
||||
pf.StringVar(&flagPassPrefix, "pass-prefix", "", "pass/gopass: only rotate entries under this subtree (e.g. logins/)")
|
||||
c.AddCommand(pwScanCmd(), pwPlanCmd(), pwGuideCmd(), pwCommitCmd())
|
||||
return c
|
||||
}
|
||||
@@ -109,8 +112,12 @@ func buildManager(v *vault.Vault) (pwstore.Manager, error) {
|
||||
return nil, fmt.Errorf("firefox requires --export-path <csv> (export from about:logins)")
|
||||
}
|
||||
return &pwstore.FirefoxCSV{ExportPath: flagExportPath}, nil
|
||||
case "pass", "gopass":
|
||||
return &pwstore.PassStore{Flavor: strings.ToLower(strings.TrimSpace(flagPwManager)), Prefix: flagPassPrefix}, nil
|
||||
case "keychain":
|
||||
return &pwstore.Keychain{}, nil
|
||||
case "":
|
||||
return nil, fmt.Errorf("--manager is required (bitwarden|1password|keepassxc|chrome|firefox|lastpass|dashlane|protonpass|nordpass|roboform|safari|edge|brave|enpass)")
|
||||
return nil, fmt.Errorf("--manager is required (bitwarden|1password|keepassxc|chrome|firefox|pass|gopass|keychain|lastpass|dashlane|protonpass|nordpass|roboform|safari|edge|brave|enpass)")
|
||||
default:
|
||||
// CSV-based managers (lastpass, dashlane, protonpass, nordpass, roboform, safari,
|
||||
// edge, brave, enpass) all share the generic csvManager + tmpfs/shred staging.
|
||||
|
||||
Reference in New Issue
Block a user