forked from gopasspw/gopass
/
templates.go
159 lines (128 loc) · 4 KB
/
templates.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package action
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/kpitt/gopass/internal/action/exit"
"github.com/kpitt/gopass/internal/editor"
"github.com/kpitt/gopass/internal/out"
"github.com/kpitt/gopass/internal/tpl"
"github.com/kpitt/gopass/internal/tree"
"github.com/kpitt/gopass/pkg/ctxutil"
"github.com/kpitt/gopass/pkg/debug"
"github.com/urfave/cli/v2"
)
const (
templateExample = `{{ .Content }}
# This is an example of the available template operations
# Predefined variables:
# - .Content: The secret payload, usually a generated password
# - .Name: The name of this secret
# - .Path: The path to this secret
# - .Dir: The dir of this secret
#
# Available Template functions:
# - md5sum: e.g. {{ .Content | md5sum }}
# - sha1sum: e.g. {{ .Content | sha1sum }}
# - md5crypt: e.g. {{ .Content | md5crypt }}
# - ssha: e.g. {{ .Content | ssha }}
# - ssha256: e.g. {{ .Content | ssha256 }}
# - ssha512: e.g. {{ .Content | ssha512 }}
# - get "key": e.g. {{ get "path/to/some/other/secret" | md5sum }}
`
)
// TemplatesPrint will pretty-print a tree of templates.
func (s *Action) TemplatesPrint(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
t, err := s.Store.TemplateTree(ctx)
if err != nil {
return exit.Error(exit.List, err, "failed to list templates: %s", err)
}
fmt.Fprintln(stdout, t.Format(tree.INF))
return nil
}
// TemplatePrint will lookup and print a single template.
func (s *Action) TemplatePrint(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
name := c.Args().First()
content, err := s.Store.GetTemplate(ctx, name)
if err != nil {
return exit.Error(exit.IO, err, "failed to retrieve template: %s", err)
}
fmt.Fprintln(stdout, string(content))
return nil
}
// TemplateEdit will load and existing or new template into an
// editor.
func (s *Action) TemplateEdit(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
name := c.Args().First()
var content []byte
if s.Store.HasTemplate(ctx, name) {
var err error
content, err = s.Store.GetTemplate(ctx, name)
if err != nil {
return exit.Error(exit.IO, err, "failed to retrieve template: %s", err)
}
} else {
content = []byte(templateExample)
}
ed := editor.Path(c)
nContent, err := editor.Invoke(ctx, ed, content)
if err != nil {
return exit.Error(exit.Unknown, err, "failed to invoke editor %s: %s", ed, err)
}
// If content is equal, nothing changed, exiting.
if bytes.Equal(content, nContent) {
return nil
}
return s.Store.SetTemplate(ctx, name, nContent)
}
// TemplateRemove will remove a single template.
func (s *Action) TemplateRemove(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
name := c.Args().First()
if name == "" {
return exit.Error(exit.Usage, nil, "usage: %s templates remove [name]", s.Name)
}
if !s.Store.HasTemplate(ctx, name) {
return exit.Error(exit.NotFound, nil, "template %q not found", name)
}
return s.Store.RemoveTemplate(ctx, name)
}
func (s *Action) templatesList(ctx context.Context) []string {
t, err := s.Store.TemplateTree(ctx)
if err != nil {
debug.Log("failed to list templates: %s", err)
return nil
}
return t.List(tree.INF)
}
// TemplatesComplete prints a list of all templates for bash completion.
func (s *Action) TemplatesComplete(c *cli.Context) {
ctx := ctxutil.WithGlobalFlags(c)
for _, v := range s.templatesList(ctx) {
fmt.Fprintln(stdout, v)
}
}
func (s *Action) renderTemplate(ctx context.Context, name string, content []byte) ([]byte, bool) {
tName, tmpl, found := s.Store.LookupTemplate(ctx, name)
if !found {
debug.Log("No template found for %s", name)
return content, false
}
tmplStr := strings.TrimSpace(string(tmpl))
if tmplStr == "" {
debug.Log("Skipping empty template %q, for %s", tName, name)
return content, false
}
// load template if it exists.
nc, err := tpl.Execute(ctx, string(tmpl), name, content, s.Store)
if err != nil {
fmt.Fprintf(stdout, "failed to execute template %q: %s\n", tName, err)
return content, false
}
out.Printf(ctx, "Note: Using template %s", tName)
return nc, true
}