diff --git a/action/show.go b/action/show.go index 190254937b..e84b94fe0b 100644 --- a/action/show.go +++ b/action/show.go @@ -1,12 +1,12 @@ package action import ( - "bytes" "fmt" "github.com/atotto/clipboard" "github.com/fatih/color" "github.com/justwatchcom/gopass/qrcon" + "github.com/smallfish/simpleyaml" "github.com/urfave/cli" ) @@ -16,6 +16,7 @@ func (s *Action) Show(c *cli.Context) error { clip := c.Bool("clip") force := c.Bool("force") qr := c.Bool("qr") + key := c.String("key") if name == "" { return fmt.Errorf("provide a secret name") @@ -25,12 +26,42 @@ func (s *Action) Show(c *cli.Context) error { return s.List(c) } - if clip || qr { - content, err := s.Store.First(name) + content, err := s.Store.Get(name) + if err != nil { + return err + } + + // load metadata if we want to parse the YAML (key is given) or we only want to display safe content (=metadata) and no clip/qr flag is given + if key != "" || (s.Store.SafeContent && !force && !(clip || qr)) { + content, err = s.Store.Metadata(name) if err != nil { return err } + } else if clip || qr { + content, err = s.Store.First(name) + if err != nil { + return err + } + } + if key != "" { + yaml, err := simpleyaml.NewYaml(content) + if err != nil { + return fmt.Errorf("failed to load secret as yaml") + } else { + value, err := yaml.Get(key).String() + if err != nil { + keys, err := yaml.GetMapKeys() + if err == nil { + return fmt.Errorf("%s not available. Available keys are: %s\n", key, keys) + } + } else { + content = []byte(value) + } + } + } + + if clip || qr { if qr { qr, err := qrcon.QRCode(string(content)) if err != nil { @@ -42,19 +73,6 @@ func (s *Action) Show(c *cli.Context) error { return s.copyToClipboard(name, content) } - content, err := s.Store.Get(name) - if err != nil { - return err - } - - if s.Store.SafeContent && !force { - lines := bytes.SplitN(content, []byte("\n"), 2) - if len(lines) < 2 || len(bytes.TrimSpace(lines[1])) == 0 { - return fmt.Errorf("no safe content to display, you can force display with show -f") - } - content = lines[1] - } - color.Yellow(string(content)) return nil diff --git a/main.go b/main.go index 38605932ac..c9f70d15eb 100644 --- a/main.go +++ b/main.go @@ -416,6 +416,10 @@ func main() { Name: "force, f", Usage: "Display the password even if safecontent is enabled", }, + cli.StringFlag{ + Name: "key, k", + Usage: "Load secret metadata as YAML and display a single key", + }, }, }, { diff --git a/password/root_store.go b/password/root_store.go index a75d7503a9..0aa9b03e38 100644 --- a/password/root_store.go +++ b/password/root_store.go @@ -325,6 +325,19 @@ func (r *RootStore) First(name string) ([]byte, error) { return bytes.TrimSpace(lines[0]), nil } +// Metadata returns the content of a single entry except of the first line (the password) +func (r *RootStore) Metadata(name string) ([]byte, error) { + content, err := r.Get(name) + if err != nil { + return nil, err + } + lines := bytes.SplitN(content, []byte("\n"), 2) + if len(lines) < 2 || len(bytes.TrimSpace(lines[1])) == 0 { + return nil, fmt.Errorf("no metadata found") + } + return lines[1], nil +} + // Exists checks the existence of a single entry func (r *RootStore) Exists(name string) (bool, error) { store := r.getStore(name)