diff --git a/go.mod b/go.mod index 02dc894192..4c077e7c18 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/urfave/cli/v2 v2.2.0 github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b // indirect golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae - golang.org/x/net v0.0.0-20201021035429-f5854403a974 + golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect golang.org/x/sys v0.0.0-20201024232916-9f70ab9862d5 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect diff --git a/internal/action/clone.go b/internal/action/clone.go index 48ad062034..41d0ac052e 100644 --- a/internal/action/clone.go +++ b/internal/action/clone.go @@ -53,7 +53,7 @@ func (s *Action) clone(ctx context.Context, repo, mount, path string) error { if path == "" { path = config.PwStoreDir(mount) } - inited, err := s.Store.Initialized(ctxutil.WithGitInit(ctx, false)) + inited, err := s.Store.IsInitialized(ctxutil.WithGitInit(ctx, false)) if err != nil { return ExitError(ExitUnknown, err, "Failed to initialized stores: %s", err) } @@ -113,7 +113,7 @@ func (s *Action) cloneAddMount(ctx context.Context, mount, path string) error { return nil } - inited, err := s.Store.Initialized(ctx) + inited, err := s.Store.IsInitialized(ctx) if err != nil { return ExitError(ExitUnknown, err, "Failed to initialize store: %s", err) } diff --git a/internal/action/commands.go b/internal/action/commands.go index 7448b897df..5d8aac95ad 100644 --- a/internal/action/commands.go +++ b/internal/action/commands.go @@ -36,11 +36,11 @@ func (s *Action) GetCommands() []*cli.Command { }, { Name: "audit", - Usage: "Scan for weak passwords", + Usage: "Decrypt all secrets and scan for weak or shard passwords", Description: "" + "This command decrypts all secrets and checks for common flaws and (optionally) " + "against a list of previously leaked passwords.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Audit, Flags: []cli.Flag{ &cli.IntFlag{ @@ -59,13 +59,13 @@ func (s *Action) GetCommands() []*cli.Command { "It can either be used to retrieve the decoded content of a secret " + "similar to 'cat file' or vice versa to encode the content from STDIN " + "to a secret.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Cat, BashComplete: s.Complete, }, { Name: "clone", - Usage: "Clone a store from git", + Usage: "Clone a store from a git repository", Description: "" + "This command clones an existing password store from a git remote to " + "a local password store. Can be either used to initialize a new root store " + @@ -88,7 +88,7 @@ func (s *Action) GetCommands() []*cli.Command { }, { Name: "config", - Usage: "Edit configuration", + Usage: "Configuration editor", Description: "" + "This command allows for easy printing and editing of the configuration. " + "Without argument, the entire config is printed. " + @@ -105,10 +105,10 @@ func (s *Action) GetCommands() []*cli.Command { }, { Name: "convert", - Usage: "Convert a store", + Usage: "Convert a store to different backends", Description: "Convert a store to a different set of backends", Action: s.Convert, - Before: s.Initialized, + Before: s.IsInitialized, Hidden: true, Flags: []cli.Flag{ &cli.StringFlag{ @@ -144,7 +144,7 @@ func (s *Action) GetCommands() []*cli.Command { "automatically copy recursively. In that case, the source directory is re-created " + "at the destination if no trailing slash is found, otherwise the contents are " + "flattened (similar to rsync).", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Copy, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -157,12 +157,12 @@ func (s *Action) GetCommands() []*cli.Command { }, { Name: "delete", - Usage: "Remove secrets", + Usage: "Remove one or many secrets from the store", Description: "" + "This command removes secrets. It can work recursively on folders. " + "Recursing across stores is purposefully not supported.", Aliases: []string{"remove", "rm"}, - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Delete, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -187,7 +187,7 @@ func (s *Action) GetCommands() []*cli.Command { "for storing your secret while the editor is accessing it. Please make " + "sure your editor doesn't leak sensitive data to other locations while " + "editing.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Edit, Aliases: []string{"set"}, BashComplete: s.Complete, @@ -208,7 +208,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "env", Usage: "Run a subprocess with a pre-populated environment", Description: "This command runs a sub process with the environment populated from the keys of a secret.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Env, BashComplete: s.Complete, Hidden: true, @@ -220,7 +220,7 @@ func (s *Action) GetCommands() []*cli.Command { "This command will first attempt a simple pattern match on the name of the " + "secret. If there is an exact match it will be shown directly; if there are " + "multiple matches, a selection will be shown.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.FindNoFuzzy, Aliases: []string{"search"}, BashComplete: s.Complete, @@ -243,7 +243,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "Check the integrity of the given sub-store or all stores if none are specified. " + "Will automatically fix all issues found.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Fsck, BashComplete: s.MountsComplete, Flags: []cli.Flag{ @@ -262,7 +262,7 @@ func (s *Action) GetCommands() []*cli.Command { "a secret and writes the result to a file. Either source or destination " + "must be a file and the other one a secret. If you want the source to " + "be securely removed after copying, use 'gopass binary move'", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.BinaryCopy, BashComplete: s.Complete, Hidden: true, @@ -285,7 +285,7 @@ func (s *Action) GetCommands() []*cli.Command { "from disk or from the store after it has been copied successfully " + "and validated. If you don't want the source to be removed use " + "'gopass binary copy'", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.BinaryMove, BashComplete: s.Complete, Hidden: true, @@ -306,7 +306,7 @@ func (s *Action) GetCommands() []*cli.Command { "Optionally put it on the clipboard and clear clipboard after 45 seconds. " + "Prompt before overwriting existing password unless forced. " + "It will replace only the first line of an existing file with a new password.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Generate, BashComplete: s.CompleteGenerate, Flags: []cli.Flag{ @@ -371,7 +371,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "init", Usage: "Init git repo", Description: "Create and initialize a new git repo in the store", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSInit, Flags: []cli.Flag{ &cli.StringFlag{ @@ -403,13 +403,13 @@ func (s *Action) GetCommands() []*cli.Command { Name: "remote", Usage: "Manage git remotes", Description: "These subcommands can be used to manage git remotes", - Before: s.Initialized, + Before: s.IsInitialized, Subcommands: []*cli.Command{ { Name: "add", Usage: "Add git remote", Description: "Add a new git remote", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSAddRemote, Flags: []cli.Flag{ &cli.StringFlag{ @@ -422,7 +422,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "remove", Usage: "Remove git remote", Description: "Remove a git remote", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSRemoveRemote, Flags: []cli.Flag{ &cli.StringFlag{ @@ -437,7 +437,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "push", Usage: "Push to remote", Description: "Push to a git remote", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSPush, Flags: []cli.Flag{ &cli.StringFlag{ @@ -450,7 +450,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "pull", Usage: "Pull from remote", Description: "Pull from a git remote", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSPull, Flags: []cli.Flag{ &cli.StringFlag{ @@ -463,7 +463,7 @@ func (s *Action) GetCommands() []*cli.Command { Name: "status", Usage: "RCS status", Description: "Show the RCS status", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RCSStatus, Flags: []cli.Flag{ &cli.StringFlag{ @@ -480,7 +480,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "This command decrypts all secrets and performs a pattern matching on the " + "content.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Grep, Hidden: true, Flags: []cli.Flag{ @@ -497,7 +497,7 @@ func (s *Action) GetCommands() []*cli.Command { Aliases: []string{"hist"}, Description: "" + "Display the change history for a secret", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.History, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -544,7 +544,7 @@ func (s *Action) GetCommands() []*cli.Command { "Insert a new secret. Optionally, echo the secret back to the console during entry. " + "Or, optionally, the entry may be multiline. " + "Prompt before overwriting existing secret unless forced.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Insert, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -577,7 +577,7 @@ func (s *Action) GetCommands() []*cli.Command { "This command will list all existing secrets. Provide a folder prefix to list " + "only certain subfolders of the store.", Aliases: []string{"ls"}, - Before: s.Initialized, + Before: s.IsInitialized, Action: s.List, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -612,7 +612,7 @@ func (s *Action) GetCommands() []*cli.Command { "across different sub-stores. If the source is a directory, the source directory " + "is re-created at the destination if no trailing slash is found, otherwise the " + "contents are flattened (similar to rsync).", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Move, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -629,7 +629,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "This command displays all mounted password stores. It offers several " + "subcommands to create or remove mounts.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.MountsPrint, Subcommands: []*cli.Command{ { @@ -639,7 +639,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "This command allows for mounting an existing or new password store " + "at any path in an existing root store.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.MountAdd, }, { @@ -649,7 +649,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "This command allows to unmount an mounted password store. This will " + "only updated the configuration and not delete the password store.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.MountRemove, BashComplete: s.MountsComplete, }, @@ -662,7 +662,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "Tries to parse an OTP URL (otpauth://). URL can be TOTP or HOTP. " + "The URL can be provided on its own line or on a key value line with a key named 'totp'.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.OTP, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -689,7 +689,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "This command displays all existing recipients for all mounted stores. " + "The subcommands allow adding or removing recipients.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RecipientsPrint, Subcommands: []*cli.Command{ { @@ -702,7 +702,7 @@ func (s *Action) GetCommands() []*cli.Command { "After adding the recipient to the list it will re-encrypt the whole " + "affected store to make sure the recipient has access to all existing " + "secrets.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RecipientsAdd, Flags: []cli.Flag{ &cli.StringFlag{ @@ -728,7 +728,7 @@ func (s *Action) GetCommands() []*cli.Command { "be able to decrypt old revisions of the password store and any local " + "copies they might have. The only way to reliably remove a recipient is to " + "rotate all existing secrets.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.RecipientsRemove, BashComplete: s.RecipientsComplete, Flags: []cli.Flag{ @@ -751,8 +751,7 @@ func (s *Action) GetCommands() []*cli.Command { "This command is automatically invoked if gopass is started without any " + "existing password store. This command exists so users can be provided with " + "simple one-command setup instructions.", - Hidden: true, - Action: s.InitOnboarding, + Action: s.Setup, Flags: []cli.Flag{ &cli.StringFlag{ Name: "remote", @@ -790,7 +789,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "Show an existing secret and optionally put its first line on the clipboard. " + "If put on the clipboard, it will be cleared after 45 seconds.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Show, BashComplete: s.Complete, Flags: []cli.Flag{ @@ -837,7 +836,7 @@ func (s *Action) GetCommands() []*cli.Command { "over the decoded data. This is useful to verify the integrity of an " + "inserted secret.", Aliases: []string{"sha", "sha256"}, - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Sum, BashComplete: s.Complete, }, @@ -847,7 +846,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "Sync all local stores with their git remotes, if any, and check " + "any possibly affected gpg keys.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.Sync, Flags: []cli.Flag{ &cli.StringFlag{ @@ -863,7 +862,7 @@ func (s *Action) GetCommands() []*cli.Command { Description: "" + "List existing templates in the password store and allow for editing " + "and creating them.", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.TemplatesPrint, Subcommands: []*cli.Command{ { @@ -871,7 +870,7 @@ func (s *Action) GetCommands() []*cli.Command { Usage: "Show a secret template.", Description: "Display an existing template", Aliases: []string{"cat"}, - Before: s.Initialized, + Before: s.IsInitialized, Action: s.TemplatePrint, BashComplete: s.TemplatesComplete, }, @@ -880,7 +879,7 @@ func (s *Action) GetCommands() []*cli.Command { Usage: "Edit secret templates.", Description: "Edit an existing or new template", Aliases: []string{"create", "new"}, - Before: s.Initialized, + Before: s.IsInitialized, Action: s.TemplateEdit, BashComplete: s.TemplatesComplete, }, @@ -889,7 +888,7 @@ func (s *Action) GetCommands() []*cli.Command { Aliases: []string{"rm"}, Usage: "Remove secret templates.", Description: "Remove an existing template", - Before: s.Initialized, + Before: s.IsInitialized, Action: s.TemplateRemove, BashComplete: s.TemplatesComplete, }, diff --git a/internal/action/completion.go b/internal/action/completion.go index 5561ebab6f..d64b6732d1 100644 --- a/internal/action/completion.go +++ b/internal/action/completion.go @@ -30,7 +30,7 @@ func bashEscape(s string) string { // Complete prints a list of all password names to os.Stdout func (s *Action) Complete(c *cli.Context) { ctx := ctxutil.WithGlobalFlags(c) - _, err := s.Store.Initialized(ctx) // important to make sure the structs are not nil + _, err := s.Store.IsInitialized(ctx) // important to make sure the structs are not nil if err != nil { out.Error(ctx, "Store not initialized: %s", err) return diff --git a/internal/action/create/commands.go b/internal/action/create/commands.go index 22fc575315..e6c4ae36fc 100644 --- a/internal/action/create/commands.go +++ b/internal/action/create/commands.go @@ -5,7 +5,7 @@ import ( ) type initializer interface { - Initialized(*cli.Context) error + IsInitialized(*cli.Context) error } // GetCommands returns the CLI commands exported for the create commands @@ -17,7 +17,7 @@ func GetCommands(i initializer, store storer) []*cli.Command { Usage: "Easy creation of new secrets", Description: "" + "This command starts a wizard to aid in creation of new secrets.", - Before: i.Initialized, + Before: i.IsInitialized, Action: func(c *cli.Context) error { return Create(c, store) }, diff --git a/internal/action/delete.go b/internal/action/delete.go index 19544665bf..6ce0143d62 100644 --- a/internal/action/delete.go +++ b/internal/action/delete.go @@ -33,7 +33,7 @@ func (s *Action) Delete(c *cli.Context) error { if recursive { recStr = "recursively " } - if (s.Store.Exists(ctx, name) || s.Store.IsDir(ctx, name)) && key == "" && !termio.AskForConfirmation(ctx, fmt.Sprintf("Are you sure you would like to %sdelete %s?", recStr, name)) { + if (s.Store.Exists(ctx, name) || s.Store.IsDir(ctx, name)) && key == "" && !termio.AskForConfirmation(ctx, fmt.Sprintf("โ˜  Are you sure you would like to %sdelete %s?", recStr, name)) { return nil } } @@ -63,7 +63,7 @@ func (s *Action) deleteKeyFromYAML(ctx context.Context, name, key string) error return ExitError(ExitIO, err, "Can not delete key '%s' from '%s': %s", key, name, err) } sec.Del(key) - if err := s.Store.Set(ctxutil.WithCommitMessage(ctx, "Updated Key in YAML"), name, sec); err != nil { + if err := s.Store.Set(ctxutil.WithCommitMessage(ctx, "Updated Key"), name, sec); err != nil { return ExitError(ExitIO, err, "Can not delete key '%s' from '%s': %s", key, name, err) } return nil diff --git a/internal/action/edit.go b/internal/action/edit.go index 3a6a2ac994..db4d9c40ab 100644 --- a/internal/action/edit.go +++ b/internal/action/edit.go @@ -30,7 +30,7 @@ func (s *Action) Edit(c *cli.Context) error { func (s *Action) edit(ctx context.Context, c *cli.Context, name string) error { ed := editor.Path(c) if err := editor.Check(ctx, ed); err != nil { - out.Red(ctx, "Failed to check editor config: %s", err) + out.Red(ctx, "โŒ Failed to check editor config: %s", err) } // get existing content or generate new one from a template @@ -76,7 +76,7 @@ func (s *Action) editGetContent(ctx context.Context, name string, create bool) ( return nil } if err := s.find(ctxutil.WithFuzzySearch(ctx, false), nil, name, cb); err == nil { - cont, err := termio.AskForBool(ctx, fmt.Sprintf("No secret at '%s'. Found possible match in '%s'. Edit existing entry?", name, newName), true) + cont, err := termio.AskForBool(ctx, fmt.Sprintf("Secret does not exist %q. Found possible match in %q. Edit existing entry?", name, newName), true) if err != nil { return "", nil, false, err } @@ -97,7 +97,7 @@ func (s *Action) editGetContent(ctx context.Context, name string, create bool) ( } if !create { - out.Yellow(ctx, "Entry %s not found. Creating new secret ...", name) + out.Yellow(ctx, "โš  Entry %s not found. Creating new secret ...", name) } // load template if it exists diff --git a/internal/action/generate.go b/internal/action/generate.go index 5c44d6b65d..58e8c46b2e 100644 --- a/internal/action/generate.go +++ b/internal/action/generate.go @@ -337,7 +337,7 @@ func (s *Action) CompleteGenerate(c *cli.Context) { } needle := c.Args().Get(0) - _, err := s.Store.Initialized(ctx) // important to make sure the structs are not nil + _, err := s.Store.IsInitialized(ctx) // important to make sure the structs are not nil if err != nil { out.Error(ctx, "Store not initialized: %s", err) return diff --git a/internal/action/init.go b/internal/action/init.go index ccec2e1cee..836422ac56 100644 --- a/internal/action/init.go +++ b/internal/action/init.go @@ -2,31 +2,34 @@ package action import ( "context" - "fmt" - "io/ioutil" "github.com/gopasspw/gopass/internal/backend" - "github.com/gopasspw/gopass/internal/backend/crypto/gpg" "github.com/gopasspw/gopass/internal/config" "github.com/gopasspw/gopass/internal/cui" "github.com/gopasspw/gopass/internal/out" - "github.com/gopasspw/gopass/internal/store/root" "github.com/gopasspw/gopass/pkg/ctxutil" "github.com/gopasspw/gopass/pkg/debug" "github.com/gopasspw/gopass/pkg/fsutil" - "github.com/gopasspw/gopass/pkg/pwgen/xkcdgen" "github.com/gopasspw/gopass/pkg/termio" "github.com/urfave/cli/v2" - "github.com/fatih/color" "github.com/pkg/errors" ) -// Initialized returns an error if the store is not properly +const logo = ` + __ _ _ _ _ _ ___ ___ + /'_ '\ /'_'\ ( '_'\ /'_' )/',__)/',__) +( (_) |( (_) )| (_) )( (_| |\__, \\__, \ +'\__ |'\___/'| ,__/''\__,_)(____/(____/ +( )_) | | | + \___/' (_) +` + +// IsInitialized returns an error if the store is not properly // prepared. -func (s *Action) Initialized(c *cli.Context) error { +func (s *Action) IsInitialized(c *cli.Context) error { ctx := ctxutil.WithGlobalFlags(c) - inited, err := s.Store.Initialized(ctx) + inited, err := s.Store.IsInitialized(ctx) if err != nil { return ExitError(ExitUnknown, err, "Failed to initialize store: %s", err) } @@ -39,15 +42,16 @@ func (s *Action) Initialized(c *cli.Context) error { if !ctxutil.IsInteractive(ctx) { return ExitError(ExitNotInitialized, nil, "password-store is not initialized. Try '%s init'", s.Name) } - ok, err := termio.AskForBool(ctx, "It seems you are new to gopass. Do you want to run the onboarding wizard?", true) - if err != nil || !ok { - return ExitError(ExitNotInitialized, err, "can run onboarding wizard") - } - c.Context = ctx - if err := s.InitOnboarding(c); err != nil { - return ExitError(ExitUnknown, err, "failed to run onboarding wizard: %s", err) - } - return nil + out.Print(ctx, logo) + out.Print(ctx, "๐ŸŒŸ Welcome to gopass!") + out.Print(ctx, "โš  No existing configuration found.") + out.Print(ctx, "โ˜ Please run 'gopass setup'") + + return ExitError(ExitNotInitialized, err, "not initialized") +} + +func welcomeToGopass(ctx context.Context) { + } // Init a new password store with a first gpg id @@ -57,8 +61,7 @@ func (s *Action) Init(c *cli.Context) error { alias := c.String("store") ctx = initParseContext(ctx, c) - ctx = out.WithPrefix(ctx, "[init] ") - out.Cyan(ctx, "Initializing a new password store ...") + out.Print(ctx, "๐Ÿญ Initializing a new password store ...") if name := termio.DetectName(c.Context, c); name != "" { ctx = ctxutil.WithUsername(ctx, name) @@ -66,12 +69,12 @@ func (s *Action) Init(c *cli.Context) error { if email := termio.DetectEmail(c.Context, c); email != "" { ctx = ctxutil.WithEmail(ctx, email) } - inited, err := s.Store.Initialized(ctx) + inited, err := s.Store.IsInitialized(ctx) if err != nil { return ExitError(ExitUnknown, err, "Failed to initialized store: %s", err) } if inited { - out.Error(ctx, "WARNING: Store is already initialized") + out.Error(ctx, "โŒ Store is already initialized!") } if err := s.init(ctx, alias, path, c.Args().Slice()...); err != nil { @@ -112,13 +115,14 @@ func (s *Action) init(ctx context.Context, alias, path string, keys ...string) e debug.Log("action.init(%s, %s, %+v)", alias, path, keys) debug.Log("Checking private keys ...") + out.Print(ctx, "๐Ÿ”‘ Searching for usable private Keys ...") crypto := s.getCryptoFor(ctx, alias) // private key selection doesn't matter for plain. save one question. if crypto.Name() == "plain" { keys, _ = crypto.ListIdentities(ctx) } if len(keys) < 1 { - nk, err := cui.AskForPrivateKey(ctx, crypto, color.CyanString("Please select a private key for encrypting secrets:")) + nk, err := cui.AskForPrivateKey(ctx, crypto, "๐ŸŽฎ Please select a private key for encrypting secrets:") if err != nil { return errors.Wrapf(err, "failed to read user input") } @@ -142,20 +146,21 @@ func (s *Action) init(ctx context.Context, alias, path string, keys ...string) e debug.Log("Initializing RCS (%s) ...", bn) if err := s.rcsInit(ctx, alias, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)); err != nil { debug.Log("Stacktrace: %+v\n", err) - out.Error(ctx, "Failed to init RCS (%s): %s", bn, err) + out.Error(ctx, "โŒ Failed to init Version Control (%s): %s", bn, err) } } else { debug.Log("not initializing RCS backend ...") } - out.Green(ctx, "Password store %s initialized for:", path) - s.printRecipients(ctx, alias) - // write config + debug.Log("Writing configuration to %q", s.cfg.ConfigPath) if err := s.cfg.Save(); err != nil { return ExitError(ExitConfig, err, "failed to write config: %s", err) } + out.Print(ctx, "๐Ÿ Password store %s initialized for:", path) + s.printRecipients(ctx, alias) + return nil } @@ -166,275 +171,10 @@ func (s *Action) printRecipients(ctx context.Context, alias string) { if kl, err := crypto.FindRecipients(ctx, recipient); err == nil && len(kl) > 0 { r = crypto.FormatKey(ctx, kl[0], "") } - out.Yellow(ctx, " "+r) + out.Print(ctx, "๐Ÿ“ฉ "+r) } } func (s *Action) getCryptoFor(ctx context.Context, name string) backend.Crypto { return s.Store.Crypto(ctx, name) } - -// InitOnboarding will invoke the onboarding / setup wizard -func (s *Action) InitOnboarding(c *cli.Context) error { - ctx := ctxutil.WithGlobalFlags(c) - remote := c.String("remote") - team := c.String("alias") - create := c.Bool("create") - - ctx = initParseContext(ctx, c) - ctx = out.WithPrefix(ctx, "[init] ") - out.Cyan(ctx, "Initializing a new password store ...") - - if name := termio.DetectName(c.Context, c); name != "" { - ctx = ctxutil.WithUsername(ctx, name) - } - if email := termio.DetectEmail(c.Context, c); email != "" { - ctx = ctxutil.WithEmail(ctx, email) - } - // need to re-initialize the root store or it's already initialized - // and won't properly set up crypto according to our context. - s.Store = root.New(s.cfg) - inited, err := s.Store.Initialized(ctx) - if err != nil { - return ExitError(ExitUnknown, err, "Failed to initialized store: %s", err) - } - if inited { - out.Error(ctx, "WARNING: Store is already initialized") - return nil - } - - debug.Log("Starting Onboarding Wizard - remote: %s - team: %s - create: %t - name: %s - email: %s", remote, team, create, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)) - - crypto := s.getCryptoFor(ctx, team) - if crypto == nil { - return fmt.Errorf("can not continue without crypto") - } - debug.Log("Crypto Backend initialized as: %s", crypto.Name()) - - // check for existing GPG keypairs (private/secret keys). We need at least - // one useable key pair. If none exists try to create one - if !s.initHasUseablePrivateKeys(ctx, crypto) { - out.Yellow(ctx, "No useable crypto keys. Generating new key pair") - ctx := out.AddPrefix(ctx, "[crypto] ") - out.Print(ctx, "Key generation may take up to a few minutes") - if err := s.initGenerateIdentity(ctx, crypto, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)); err != nil { - return errors.Wrapf(err, "failed to create new private key") - } - } - - debug.Log("Has useable private keys") - - // if a git remote and a team name are given attempt unattended team setup - if remote != "" && team != "" { - if create { - return s.initCreateTeam(ctx, team, remote) - } - return s.initJoinTeam(ctx, team, remote) - } - - // no flags given, run interactively - choices := []string{ - "Local store", - "Create a Team", - "Join an existing Team", - } - act, sel := cui.GetSelection(ctx, "Select action", choices) - switch act { - case "default": - fallthrough - case "show": - switch sel { - case 0: - return s.initLocal(ctx) - case 1: - return s.initCreateTeam(ctx, "", "") - case 2: - return s.initJoinTeam(ctx, "", "") - } - default: - return fmt.Errorf("user aborted") - } - return nil -} - -func (s *Action) initGenerateIdentity(ctx context.Context, crypto backend.Crypto, name, email string) error { - out.Green(ctx, "Creating key pair ...") - out.Yellow(ctx, "WARNING: We are about to generate some GPG keys.") - out.Print(ctx, `However, the GPG program can sometimes lock up, displaying the following: -"We need to generate a lot of random bytes." -If this happens, please see the following tips: -https://github.com/gopasspw/gopass/blob/master/docs/entropy.md`) - name, err := termio.AskForString(ctx, "What is your name?", name) - if err != nil { - return err - } - - email, err = termio.AskForString(ctx, "What is your email?", email) - if err != nil { - return err - } - - if want, err := termio.AskForBool(ctx, "Continue?", true); err != nil || !want { - return errors.Wrapf(err, "User aborted") - } - passphrase := xkcdgen.Random() - if err := crypto.GenerateIdentity(ctx, name, email, passphrase); err != nil { - return errors.Wrapf(err, "failed to create new private key in batch mode") - } - out.Green(ctx, "-> OK") - out.Print(ctx, color.MagentaString("Passphrase: ")+color.HiGreenString(passphrase)) - - kl, err := crypto.ListIdentities(gpg.WithUseCache(ctx, false)) - if err != nil { - return errors.Wrapf(err, "failed to list private keys") - } - if len(kl) > 1 { - out.Cyan(ctx, "WARNING: More than one private key detected. Make sure to communicate the right one") - return nil - } - if len(kl) < 1 { - debug.Log("Private Keys: %+v", kl) - return errors.New("failed to create a useable key pair") - } - - if want, err := termio.AskForBool(ctx, "Do you want to export your public key?", false); err == nil && want { - key := kl[0] - fn := key + ".pub.key" - pk, err := crypto.ExportPublicKey(ctx, key) - if err != nil { - return errors.Wrapf(err, "failed to export public key") - } - _ = ioutil.WriteFile(fn, pk, 06444) - out.Cyan(ctx, "Public key exported to '%s'", fn) - } - out.Green(ctx, "Done") - return nil -} - -func (s *Action) initHasUseablePrivateKeys(ctx context.Context, crypto backend.Crypto) bool { - kl, err := crypto.ListIdentities(gpg.WithAlwaysTrust(ctx, false)) - if err != nil { - return false - } - return len(kl) > 0 -} - -func (s *Action) initSetupGitRemote(ctx context.Context, team, remote string) error { - var err error - remote, err = termio.AskForString(ctx, "Please enter the git remote for your shared store", remote) - if err != nil { - return errors.Wrapf(err, "failed to read user input") - } - { - ctx := ctxutil.WithHidden(ctx, true) - if err := s.Store.RCSAddRemote(ctx, team, "origin", remote); err != nil { - return errors.Wrapf(err, "failed to add git remote") - } - // initial pull, in case the remote is non-empty - if err := s.Store.RCSPull(ctx, team, "origin", "master"); err != nil { - debug.Log("Initial git pull failed: %s", err) - } - if err := s.Store.RCSPush(ctx, team, "origin", "master"); err != nil { - return errors.Wrapf(err, "failed to push to git remote") - } - } - return nil -} - -// initLocal will initialize a local store, useful for local-only setups or as -// part of team setups to create the root store -func (s *Action) initLocal(ctx context.Context) error { - ctx = out.AddPrefix(ctx, "[local] ") - - path := "" - if s.Store != nil { - path = s.Store.Path() - } - - out.Print(ctx, "Initializing your local store ...") - if err := s.init(ctxutil.WithHidden(ctx, true), "", path); err != nil { - return errors.Wrapf(err, "failed to init local store") - } - out.Green(ctx, " -> OK") - - out.Print(ctx, "Configuring your local store ...") - - if want, err := termio.AskForBool(ctx, out.Prefix(ctx)+"Do you want to add a git remote?", false); err == nil && want { - out.Print(ctx, "Configuring the git remote ...") - if err := s.initSetupGitRemote(ctx, "", ""); err != nil { - return errors.Wrapf(err, "failed to setup git remote") - } - } - - // save config - if err := s.cfg.Save(); err != nil { - return errors.Wrapf(err, "failed to save config") - } - - out.Green(ctx, " -> OK") - return nil -} - -// initCreateTeam will create a local root store and a shared team store -func (s *Action) initCreateTeam(ctx context.Context, team, remote string) error { - var err error - - out.Print(ctx, "Creating a new team ...") - if err := s.initLocal(ctx); err != nil { - return errors.Wrapf(err, "failed to create local store") - } - - // name of the new team - team, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the name of your team (may contain slashes)", team) - if err != nil { - return errors.Wrapf(err, "failed to read user input") - } - ctx = out.AddPrefix(ctx, "["+team+"] ") - - out.Print(ctx, "Initializing your shared store ...") - if err := s.init(ctxutil.WithHidden(ctx, true), team, ""); err != nil { - return errors.Wrapf(err, "failed to init shared store") - } - out.Green(ctx, " -> OK") - - out.Print(ctx, "Configuring the git remote ...") - if err := s.initSetupGitRemote(ctx, team, remote); err != nil { - return errors.Wrapf(err, "failed to setup git remote") - } - out.Green(ctx, " -> OK") - out.Green(ctx, "Created Team '%s'", team) - return nil -} - -// initJoinTeam will create a local root store and clone and existing store to -// a mount -func (s *Action) initJoinTeam(ctx context.Context, team, remote string) error { - var err error - - out.Print(ctx, "Joining existing team ...") - if err := s.initLocal(ctx); err != nil { - return errors.Wrapf(err, "failed to create local store") - } - - // name of the existing team - team, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the name of your team (may contain slashes)", team) - if err != nil { - return err - } - ctx = out.AddPrefix(ctx, "["+team+"]") - - out.Print(ctx, "Configuring git remote ...") - remote, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the git remote for your shared store", remote) - if err != nil { - return err - } - - out.Print(ctx, "Cloning from the git remote ...") - if err := s.clone(ctxutil.WithHidden(ctx, true), remote, team, ""); err != nil { - return errors.Wrapf(err, "failed to clone repo") - } - out.Green(ctx, " -> OK") - out.Green(ctx, "Joined Team '%s'", team) - out.Yellow(ctx, "Note: You still need to request access to decrypt any secret!") - return nil -} diff --git a/internal/action/repl.go b/internal/action/repl.go index def7e350f1..325d6e9e9a 100644 --- a/internal/action/repl.go +++ b/internal/action/repl.go @@ -114,6 +114,11 @@ func (s *Action) REPL(c *cli.Context) error { } out.Red(c.Context, "Error: %s", err) } + + out.Print(c.Context, logo) + out.Print(c.Context, "๐ŸŒŸ Welcome to gopass!") + out.Print(c.Context, "โš  This is the built-in shell. Type 'help' for a list of commands.") + rl, err := readline.New("gopass> ") if err != nil { return err diff --git a/internal/action/setup.go b/internal/action/setup.go new file mode 100644 index 0000000000..13de16170e --- /dev/null +++ b/internal/action/setup.go @@ -0,0 +1,287 @@ +package action + +import ( + "context" + "fmt" + "io/ioutil" + + "github.com/fatih/color" + "github.com/gopasspw/gopass/internal/backend" + "github.com/gopasspw/gopass/internal/backend/crypto/gpg" + "github.com/gopasspw/gopass/internal/out" + "github.com/gopasspw/gopass/internal/store/root" + "github.com/gopasspw/gopass/pkg/ctxutil" + "github.com/gopasspw/gopass/pkg/debug" + "github.com/gopasspw/gopass/pkg/pwgen/xkcdgen" + "github.com/gopasspw/gopass/pkg/termio" + "github.com/pkg/errors" + "github.com/urfave/cli/v2" +) + +// Setup will invoke the onboarding / setup wizard +func (s *Action) Setup(c *cli.Context) error { + ctx := ctxutil.WithGlobalFlags(c) + remote := c.String("remote") + team := c.String("alias") + create := c.Bool("create") + + ctx = initParseContext(ctx, c) + + out.Print(ctx, logo) + out.Print(ctx, "๐ŸŒŸ Welcome to gopass!") + out.Print(ctx, "๐ŸŒŸ Initializing a new password store ...") + + if name := termio.DetectName(c.Context, c); name != "" { + ctx = ctxutil.WithUsername(ctx, name) + } + if email := termio.DetectEmail(c.Context, c); email != "" { + ctx = ctxutil.WithEmail(ctx, email) + } + // need to re-initialize the root store or it's already initialized + // and won't properly set up crypto according to our context. + s.Store = root.New(s.cfg) + inited, err := s.Store.IsInitialized(ctx) + if err != nil { + return ExitError(ExitUnknown, err, "Failed to initialized store: %s", err) + } + if inited { + out.Error(ctx, "โš  Store is already initialized. Aborting.") + return nil + } + + debug.Log("Starting Onboarding Wizard - remote: %s - team: %s - create: %t - name: %s - email: %s", remote, team, create, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)) + + crypto := s.getCryptoFor(ctx, team) + if crypto == nil { + return fmt.Errorf("can not continue without crypto") + } + debug.Log("Crypto Backend initialized as: %s", crypto.Name()) + + // check for existing GPG keypairs (private/secret keys). We need at least + // one useable key pair. If none exists try to create one + if !s.initHasUseablePrivateKeys(ctx, crypto) { + out.Print(ctx, "๐Ÿ” No useable cryptographic keys. Generating new key pair") + out.Print(ctx, "๐Ÿ•ฐ Key generation may take up to a few minutes") + if err := s.initGenerateIdentity(ctx, crypto, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)); err != nil { + return errors.Wrapf(err, "failed to create new private key") + } + out.Print(ctx, "๐Ÿ” Cryptographic keys validated") + } + + debug.Log("Has useable private keys") + + // if a git remote and a team name are given attempt unattended team setup + if remote != "" && team != "" { + if create { + return s.initCreateTeam(ctx, team, remote) + } + return s.initJoinTeam(ctx, team, remote) + } + + // assume local setup by default, remotes can be added easily later + return s.initLocal(ctx) +} + +func (s *Action) initGenerateIdentity(ctx context.Context, crypto backend.Crypto, name, email string) error { + out.Green(ctx, "๐Ÿงช Creating cryptographic key pair (%s) ...", crypto.Name()) + + out.Print(ctx, "๐ŸŽฉ Gathering information for the key pair ...") + name, err := termio.AskForString(ctx, "๐Ÿšถ What is your name?", name) + if err != nil { + return err + } + + email, err = termio.AskForString(ctx, "๐Ÿ“ง What is your email?", email) + if err != nil { + return err + } + + passphrase := xkcdgen.Random() + pwGenerated := true + if bv, err := termio.AskForBool(ctx, "โš  Do you want to enter a passphrase? (otherwise we generate one for you)", false); err != nil && bv { + pwGenerated = false + sv, err := termio.AskForPassword(ctx, "โœ Please enter your passphrase") + if err != nil { + return errors.Wrapf(err, "Failed to read passphrase") + } + passphrase = sv + } + + out.Yellow(ctx, "โณ This can take a long time. If you get impatient see https://github.com/gopasspw/gopass/blob/master/docs/entropy.md") + if want, err := termio.AskForBool(ctx, "Continue?", true); err != nil || !want { + return errors.Wrapf(err, "User aborted") + } + + if err := crypto.GenerateIdentity(ctx, name, email, passphrase); err != nil { + return errors.Wrapf(err, "failed to create new private key in batch mode") + } + + out.Print(ctx, "โœ… Key pair generated") + + if pwGenerated { + out.Print(ctx, color.MagentaString("Passphrase: ")+color.HiGreenString(passphrase)) + } + + // avoid the gpg cache or we won't find the newly created key + kl, err := crypto.ListIdentities(gpg.WithUseCache(ctx, false)) + if err != nil { + return errors.Wrapf(err, "failed to list private keys") + } + if len(kl) > 1 { + out.Print(ctx, "โš  More than one private key detected. Make sure to use the correct one!") + return nil + } + if len(kl) < 1 { + debug.Log("Private Keys: %+v", kl) + return errors.New("failed to create a usable key pair") + } + + // we can export the generated key to the current directory for convenience + if err := s.initExportPublicKey(ctx, crypto, kl[0]); err != nil { + return err + } + out.Green(ctx, "โœ… Key pair validated") + return nil +} + +func (s *Action) initExportPublicKey(ctx context.Context, crypto backend.Crypto, key string) error { + fn := key + ".pub.key" + want, err := termio.AskForBool(ctx, fmt.Sprintf("Do you want to export your public key to %q?", fn), false) + if err != nil { + return err + } + if !want { + return nil + } + pk, err := crypto.ExportPublicKey(ctx, key) + if err != nil { + return errors.Wrapf(err, "failed to export public key") + } + if err := ioutil.WriteFile(fn, pk, 06444); err != nil { + out.Error(ctx, "โŒ Failed to export public key %q: %q", fn, err) + return err + } + out.Print(ctx, "โœด Public key exported to '%s'", fn) + return nil +} + +func (s *Action) initHasUseablePrivateKeys(ctx context.Context, crypto backend.Crypto) bool { + kl, err := crypto.ListIdentities(gpg.WithAlwaysTrust(ctx, false)) + if err != nil { + return false + } + return len(kl) > 0 +} + +func (s *Action) initSetupGitRemote(ctx context.Context, team, remote string) error { + var err error + remote, err = termio.AskForString(ctx, "Please enter the git remote for your shared store", remote) + if err != nil { + return errors.Wrapf(err, "failed to read user input") + } + { + ctx := ctxutil.WithHidden(ctx, true) + if err := s.Store.RCSAddRemote(ctx, team, "origin", remote); err != nil { + return errors.Wrapf(err, "failed to add git remote") + } + // initial pull, in case the remote is non-empty + if err := s.Store.RCSPull(ctx, team, "origin", "master"); err != nil { + debug.Log("Initial git pull failed: %s", err) + } + if err := s.Store.RCSPush(ctx, team, "origin", "master"); err != nil { + return errors.Wrapf(err, "failed to push to git remote") + } + } + return nil +} + +// initLocal will initialize a local store, useful for local-only setups or as +// part of team setups to create the root store +func (s *Action) initLocal(ctx context.Context) error { + path := "" + if s.Store != nil { + path = s.Store.Path() + } + + out.Print(ctx, "๐ŸŒŸ Configuring your password store ...") + if err := s.init(ctxutil.WithHidden(ctx, true), "", path); err != nil { + return errors.Wrapf(err, "failed to init local store") + } + + if want, err := termio.AskForBool(ctx, "โ“ Do you want to add a git remote?", false); err == nil && want { + out.Print(ctx, "Configuring the git remote ...") + if err := s.initSetupGitRemote(ctx, "", ""); err != nil { + return errors.Wrapf(err, "failed to setup git remote") + } + } + + // save config + if err := s.cfg.Save(); err != nil { + return errors.Wrapf(err, "failed to save config") + } + + out.Green(ctx, "โœ… Configured") + return nil +} + +// initCreateTeam will create a local root store and a shared team store +func (s *Action) initCreateTeam(ctx context.Context, team, remote string) error { + var err error + + out.Print(ctx, "Creating a new team ...") + if err := s.initLocal(ctx); err != nil { + return errors.Wrapf(err, "failed to create local store") + } + + // name of the new team + team, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the name of your team (may contain slashes)", team) + if err != nil { + return errors.Wrapf(err, "failed to read user input") + } + ctx = out.AddPrefix(ctx, "["+team+"] ") + + out.Print(ctx, "Initializing your shared store ...") + if err := s.init(ctxutil.WithHidden(ctx, true), team, ""); err != nil { + return errors.Wrapf(err, "failed to init shared store") + } + out.Print(ctx, "โœ… Done. Initialized the store.") + + out.Print(ctx, "Configuring the git remote ...") + if err := s.initSetupGitRemote(ctx, team, remote); err != nil { + return errors.Wrapf(err, "failed to setup git remote") + } + out.Print(ctx, "โœ… Done. Created Team %q", team) + return nil +} + +// initJoinTeam will create a local root store and clone and existing store to +// a mount +func (s *Action) initJoinTeam(ctx context.Context, team, remote string) error { + var err error + + out.Print(ctx, "Joining existing team ...") + if err := s.initLocal(ctx); err != nil { + return errors.Wrapf(err, "failed to create local store") + } + + // name of the existing team + team, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the name of your team (may contain slashes)", team) + if err != nil { + return err + } + ctx = out.AddPrefix(ctx, "["+team+"]") + + out.Print(ctx, "Configuring git remote ...") + remote, err = termio.AskForString(ctx, out.Prefix(ctx)+"Please enter the git remote for your shared store", remote) + if err != nil { + return err + } + + out.Print(ctx, "Cloning from the git remote ...") + if err := s.clone(ctxutil.WithHidden(ctx, true), remote, team, ""); err != nil { + return errors.Wrapf(err, "failed to clone repo") + } + out.Print(ctx, "โœ… Done. Joined Team %q", team) + out.Print(ctx, "โš  You still need to request access to decrypt secrets!") + return nil +} diff --git a/internal/action/show.go b/internal/action/show.go index a3b3610798..edfdd548da 100644 --- a/internal/action/show.go +++ b/internal/action/show.go @@ -174,7 +174,7 @@ func (s *Action) showGetContent(ctx context.Context, sec gopass.Secret) (string, debug.Log("got(found: %t) key %s: %s", found, key, val) return val, val, nil } else if HasKey(ctx) { - out.Warning(ctx, "parsing is disabled but a key was provided.") + out.Warning(ctx, "โš  Parsing is disabled but a key was provided.") debug.Log("attempting to parse key %s with parsing disabled", GetKey(ctx)) } diff --git a/internal/action/sync.go b/internal/action/sync.go index 5c5d960ddf..ef33f3f68e 100644 --- a/internal/action/sync.go +++ b/internal/action/sync.go @@ -23,7 +23,7 @@ func (s *Action) Sync(c *cli.Context) error { } func (s *Action) sync(ctx context.Context, store string) error { - out.Green(ctx, "Sync starting ...") + out.Print(ctx, "๐Ÿšฅ Syncing with all remotes ...") numEntries := 0 if l, err := s.Store.Tree(ctx); err == nil { @@ -48,9 +48,11 @@ func (s *Action) sync(ctx context.Context, store string) error { numMPs++ _ = s.syncMount(ctx, mp) } - out.Green(ctx, "All done") + out.Green(ctx, "โœ… All done") - // calculate number of changes entries + // Calculate number of changed entries. + // This is a rough estimate as additions and deletions + // might cancel each other out. if l, err := s.Store.Tree(ctx); err == nil { numEntries = len(l.List(tree.INF)) - numEntries } diff --git a/internal/action/version.go b/internal/action/version.go index a1de14e88e..6b6a86b8c0 100644 --- a/internal/action/version.go +++ b/internal/action/version.go @@ -24,7 +24,7 @@ func (s *Action) Version(c *cli.Context) error { version := make(chan string, 1) go s.checkVersion(ctx, version) - _ = s.Initialized(c) + _ = s.IsInitialized(c) cli.VersionPrinter(c) diff --git a/internal/out/print.go b/internal/out/print.go index 7e26ca0819..2c306bd6c8 100644 --- a/internal/out/print.go +++ b/internal/out/print.go @@ -109,5 +109,5 @@ func Warning(ctx context.Context, format string, args ...interface{}) { if ctxutil.IsHidden(ctx) { return } - fmt.Fprint(Stderr, color.YellowString(Prefix(ctx)+"WARNING: "+format+newline(ctx), args...)) + fmt.Fprint(Stderr, color.YellowString(Prefix(ctx)+"โš  "+format+newline(ctx), args...)) } diff --git a/internal/store/leaf/init.go b/internal/store/leaf/init.go index c387f33e65..c73c00f77e 100644 --- a/internal/store/leaf/init.go +++ b/internal/store/leaf/init.go @@ -10,7 +10,7 @@ import ( ) // Initialized returns true if the store is properly initialized -func (s *Store) Initialized(ctx context.Context) bool { +func (s *Store) IsInitialized(ctx context.Context) bool { if s == nil || s.storage == nil { return false } @@ -19,7 +19,7 @@ func (s *Store) Initialized(ctx context.Context) bool { // Init tries to initialize a new password store location matching the object func (s *Store) Init(ctx context.Context, path string, ids ...string) error { - if s.Initialized(ctx) { + if s.IsInitialized(ctx) { return errors.Errorf(`Found already initialized store at %s. You can add secondary stores with gopass init --path --store `, path) } diff --git a/internal/store/leaf/recipients.go b/internal/store/leaf/recipients.go index 44c74e6b46..4687941b7e 100644 --- a/internal/store/leaf/recipients.go +++ b/internal/store/leaf/recipients.go @@ -272,7 +272,7 @@ func (s *Store) saveRecipients(ctx context.Context, rs []string, msg string) err if errors.Cause(err) == store.ErrGitNoRemote { msg := "Warning: git has no remote. Ignoring auto-push option\n" + "Run: gopass git remote add origin ..." - out.Yellow(ctx, msg) + debug.Log(msg) return nil } return errors.Wrapf(err, "failed to push changes to git") diff --git a/internal/store/leaf/reencrypt.go b/internal/store/leaf/reencrypt.go index 94a9fa44cf..e1946091c5 100644 --- a/internal/store/leaf/reencrypt.go +++ b/internal/store/leaf/reencrypt.go @@ -122,13 +122,13 @@ func (s *Store) reencryptGitPush(ctx context.Context) error { if errors.Cause(err) == store.ErrGitNotInit { msg := "Warning: git is not initialized for this.storage. Ignoring auto-push option\n" + "Run: gopass git init" - out.Error(ctx, msg) + debug.Log(msg) return nil } if errors.Cause(err) == store.ErrGitNoRemote { msg := "Warning: git has no remote. Ignoring auto-push option\n" + "Run: gopass git remote add origin ..." - out.Yellow(ctx, msg) + debug.Log(msg) return nil } return errors.Wrapf(err, "failed to push change to git remote") diff --git a/internal/store/leaf/write.go b/internal/store/leaf/write.go index 97b1b202b9..41ecc9b06a 100644 --- a/internal/store/leaf/write.go +++ b/internal/store/leaf/write.go @@ -91,7 +91,7 @@ func (s *Store) gitCommitAndPush(ctx context.Context, name string) error { if errors.Cause(err) == store.ErrGitNoRemote { msg := "Warning: git has no remote. Ignoring auto-push option\n" + "Run: gopass git remote add origin ..." - out.Yellow(ctx, msg) + debug.Log(msg) return nil } return errors.Wrapf(err, "failed to push to git remote") diff --git a/internal/store/root/init.go b/internal/store/root/init.go index 525294e64e..37f8bf3d47 100644 --- a/internal/store/root/init.go +++ b/internal/store/root/init.go @@ -12,15 +12,15 @@ import ( "github.com/pkg/errors" ) -// Initialized checks on disk if .gpg-id was generated and thus returns true. -func (r *Store) Initialized(ctx context.Context) (bool, error) { +// IsInitialized checks on disk if .gpg-id was generated and thus returns true. +func (r *Store) IsInitialized(ctx context.Context) (bool, error) { if r.store == nil { debug.Log("initializing store and possible sub-stores") if err := r.initialize(ctx); err != nil { return false, errors.Wrapf(err, "failed to initialized stores: %s", err) } } - return r.store.Initialized(ctx), nil + return r.store.IsInitialized(ctx), nil } // Init tries to initialize a new password store location matching the object @@ -36,7 +36,7 @@ func (r *Store) Init(ctx context.Context, alias, path string, ids ...string) err if err != nil { return errors.Wrapf(err, "failed to instantiate new sub store: %s", err) } - if !r.store.Initialized(ctx) && alias == "" { + if !r.store.IsInitialized(ctx) && alias == "" { r.store = sub } diff --git a/internal/store/root/init_test.go b/internal/store/root/init_test.go index 9e9ad762f2..df443cbf0a 100644 --- a/internal/store/root/init_test.go +++ b/internal/store/root/init_test.go @@ -26,12 +26,12 @@ func TestInit(t *testing.T) { cfg.Path = u.StoreDir("rs") rs := New(cfg) - inited, err := rs.Initialized(ctx) + inited, err := rs.IsInitialized(ctx) assert.NoError(t, err) assert.False(t, inited) assert.NoError(t, rs.Init(ctx, "", u.StoreDir("rs"), "0xDEADBEEF")) - inited, err = rs.Initialized(ctx) + inited, err = rs.IsInitialized(ctx) require.NoError(t, err) assert.True(t, inited) assert.NoError(t, rs.Init(ctx, "rs2", u.StoreDir("rs2"), "0xDEADBEEF")) diff --git a/internal/store/root/mount.go b/internal/store/root/mount.go index 1407c09495..34385da843 100644 --- a/internal/store/root/mount.go +++ b/internal/store/root/mount.go @@ -62,7 +62,7 @@ func (r *Store) initSub(ctx context.Context, alias, path string, keys []string) return nil, errors.Wrapf(err, "failed to initialize store '%s' at '%s': %s", alias, path, err) } - if s.Initialized(ctx) { + if s.IsInitialized(ctx) { return s, nil } diff --git a/internal/store/root/move.go b/internal/store/root/move.go index 695ddddbed..bcb424dcd4 100644 --- a/internal/store/root/move.go +++ b/internal/store/root/move.go @@ -6,7 +6,6 @@ import ( "path" "strings" - "github.com/gopasspw/gopass/internal/out" "github.com/gopasspw/gopass/internal/store" "github.com/gopasspw/gopass/internal/store/leaf" "github.com/gopasspw/gopass/pkg/ctxutil" @@ -65,13 +64,13 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { if errors.Cause(err) == store.ErrGitNotInit { msg := "Warning: git is not initialized for this.storage. Ignoring auto-push option\n" + "Run: gopass git init" - out.Error(ctx, msg) + debug.Log(msg) return nil } if errors.Cause(err) == store.ErrGitNoRemote { msg := "Warning: git has no remote. Ignoring auto-push option\n" + "Run: gopass git remote add origin ..." - out.Yellow(ctx, msg) + debug.Log(msg) return nil } return errors.Wrapf(err, "failed to push change to git remote") @@ -81,13 +80,13 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error { if errors.Cause(err) == store.ErrGitNotInit { msg := "Warning: git is not initialized for this.storage. Ignoring auto-push option\n" + "Run: gopass git init" - out.Error(ctx, msg) + debug.Log(msg) return nil } if errors.Cause(err) == store.ErrGitNoRemote { msg := "Warning: git has no remote. Ignoring auto-push option\n" + "Run: gopass git remote add origin ..." - out.Yellow(ctx, msg) + debug.Log(msg) return nil } return errors.Wrapf(err, "failed to push change to git remote") diff --git a/internal/store/root/store_test.go b/internal/store/root/store_test.go index 627925ab26..25ba98eb4e 100644 --- a/internal/store/root/store_test.go +++ b/internal/store/root/store_test.go @@ -130,7 +130,7 @@ func createRootStore(ctx context.Context, u *gptest.Unit) (*Store, error) { Path: u.StoreDir(""), }, ) - if _, err := s.Initialized(ctx); err != nil { + if _, err := s.IsInitialized(ctx); err != nil { return nil, err } return s, nil diff --git a/main.go b/main.go index 3e2b4e4aef..67fcec915e 100644 --- a/main.go +++ b/main.go @@ -155,7 +155,7 @@ func setupApp(ctx context.Context, sv semver.Version) (context.Context, *cli.App }, } app.Action = func(c *cli.Context) error { - if err := action.Initialized(c); err != nil { + if err := action.IsInitialized(c); err != nil { return err }