-
-
Notifications
You must be signed in to change notification settings - Fork 478
/
askpass.go
100 lines (85 loc) · 2.05 KB
/
askpass.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
package age
import (
"context"
"fmt"
"time"
"github.com/gopasspw/gopass/internal/cache"
"github.com/gopasspw/gopass/internal/out"
"github.com/gopasspw/gopass/pkg/debug"
"github.com/gopasspw/pinentry"
"github.com/gopasspw/gopass/pkg/pinentry/cli"
)
type piner interface {
Close()
Confirm() bool
Set(string, string) error
GetPin() ([]byte, error)
}
type cacher interface {
Get(string) (string, bool)
Set(string, string)
Remove(string)
Purge()
}
type askPass struct {
testing bool
cache cacher
pinentry func() (piner, error)
}
var (
// DefaultAskPass is the default password cache
DefaultAskPass = newAskPass()
)
func newAskPass() *askPass {
return &askPass{
cache: cache.NewInMemTTL(time.Hour, 24*time.Hour),
pinentry: func() (piner, error) {
p, err := pinentry.New()
if err == nil {
return p, nil
}
debug.Log("Pinentry not found: %q", err)
return cli.New()
},
}
}
func (a *askPass) Ping(_ context.Context) error {
return nil
}
func (a *askPass) Passphrase(key string, reason string, repeat bool) (string, error) {
if value, found := a.cache.Get(key); found || a.testing {
debug.Log("Read value for %s from cache", key)
return value, nil
}
debug.Log("Value for %s not found in cache", key)
// TODO we shouldn't print here like this ...
out.Printf(context.TODO(), "🔑 Please enter your passphrase to unlock the age keyring")
pi, err := a.pinentry()
if err != nil {
return "", fmt.Errorf("pinentry Error: %s", err)
}
defer pi.Close()
_ = pi.Set("title", "gopass")
_ = pi.Set("desc", "Need your passphrase "+reason)
_ = pi.Set("prompt", "Please enter your passphrase:")
_ = pi.Set("ok", "OK")
if repeat {
_ = pi.Set("REPEAT", "Confirm")
}
pw, err := pi.GetPin()
if err != nil {
return "", fmt.Errorf("pinentry Error: %s", err)
}
pass := string(pw)
debug.Log("Updated value for %s in cache", key)
a.cache.Set(key, pass)
return pass, nil
}
func (a *askPass) Remove(key string) {
a.cache.Remove(key)
}
// Lock flushes the password cache
func (a *Age) Lock() {
a.askPass.cache.Purge()
a.krCache = nil
}