forked from gopasspw/gopass
-
Notifications
You must be signed in to change notification settings - Fork 0
/
edit.go
77 lines (66 loc) · 2.16 KB
/
edit.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package action
import (
"bytes"
"context"
"fmt"
"github.com/justwatchcom/gopass/pkg/audit"
"github.com/justwatchcom/gopass/pkg/editor"
"github.com/justwatchcom/gopass/pkg/out"
"github.com/justwatchcom/gopass/pkg/pwgen"
"github.com/justwatchcom/gopass/pkg/store/secret"
"github.com/justwatchcom/gopass/pkg/store/sub"
"github.com/justwatchcom/gopass/pkg/tpl"
"github.com/urfave/cli"
)
// Edit the content of a password file
func (s *Action) Edit(ctx context.Context, c *cli.Context) error {
name := c.Args().First()
if name == "" {
return ExitError(ctx, ExitUsage, nil, "Usage: %s edit secret", s.Name)
}
ed := editor.Path(c)
// get existing content or generate new one from a template
var content []byte
var changed bool
if s.Store.Exists(ctx, name) {
sec, err := s.Store.Get(ctx, name)
if err != nil {
return ExitError(ctx, ExitDecrypt, err, "failed to decrypt %s: %s", name, err)
}
content, err = sec.Bytes()
if err != nil {
return ExitError(ctx, ExitDecrypt, err, "failed to decode %s: %s", name, err)
}
} else if tmpl, found := s.Store.LookupTemplate(ctx, name); found {
changed = true
// load template if it exists
content = []byte(pwgen.GeneratePassword(defaultLength, false))
if nc, err := tpl.Execute(ctx, string(tmpl), name, content, s.Store); err == nil {
content = nc
} else {
fmt.Fprintf(stdout, "failed to execute template: %s\n", err)
}
}
// invoke the editor to let the user edit the content
nContent, err := editor.Invoke(ctx, ed, content)
if err != nil {
return ExitError(ctx, ExitUnknown, err, "failed to invoke editor: %s", err)
}
// If content is equal, nothing changed, exiting
if bytes.Equal(content, nContent) && !changed {
return nil
}
nSec, err := secret.Parse(nContent)
if err != nil {
out.Red(ctx, "WARNING: Invalid YAML: %s", err)
}
// if the secret has a password, we check it's strength
if pw := nSec.Password(); pw != "" {
audit.Single(ctx, pw)
}
// write result (back) to store
if err := s.Store.Set(sub.WithReason(ctx, fmt.Sprintf("Edited with %s", ed)), name, nSec); err != nil {
return ExitError(ctx, ExitEncrypt, err, "failed to encrypt secret %s: %s", name, err)
}
return nil
}