forked from 99designs/keyring
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyring.go
136 lines (118 loc) · 3.82 KB
/
keyring.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
// Package keyring provides a uniform API over a range of desktop credential storage engines
//
// See project homepage at https://github.com/99designs/keyring for more background
package keyring
import (
"errors"
"log"
"time"
)
// A BackendType is an identifier for a credential storage service
type BackendType string
// All currently supported secure storage backends
const (
InvalidBackend BackendType = ""
SecretServiceBackend BackendType = "secret-service"
KeychainBackend BackendType = "keychain"
KeyCtlBackend BackendType = "keyctl"
KWalletBackend BackendType = "kwallet"
WinCredBackend BackendType = "wincred"
FileBackend BackendType = "file"
PassBackend BackendType = "pass"
)
// This order makes sure the OS-specific backends
// are picked over the more generic backends.
var backendOrder = []BackendType{
// Windows
WinCredBackend,
// MacOS
KeychainBackend,
// Linux
SecretServiceBackend,
KWalletBackend,
KeyCtlBackend,
// General
PassBackend,
FileBackend,
}
var supportedBackends = map[BackendType]opener{}
// AvailableBackends provides a slice of all available backend keys on the current OS
func AvailableBackends() []BackendType {
b := []BackendType{}
for _, k := range backendOrder {
_, ok := supportedBackends[k]
if ok {
b = append(b, k)
}
}
return b
}
type opener func(cfg Config) (Keyring, error)
// Open will open a specific keyring backend
func Open(cfg Config) (Keyring, error) {
if cfg.AllowedBackends == nil {
cfg.AllowedBackends = AvailableBackends()
}
debugf("Considering backends: %v", cfg.AllowedBackends)
for _, backend := range cfg.AllowedBackends {
if opener, ok := supportedBackends[backend]; ok {
openBackend, err := opener(cfg)
if err != nil {
debugf("Failed backend %s: %s", backend, err)
continue
}
return openBackend, nil
}
}
return nil, ErrNoAvailImpl
}
// Item is a thing stored on the keyring
type Item struct {
Key string
Data []byte
Label string
Description string
// Backend specific config
KeychainNotTrustApplication bool
KeychainNotSynchronizable bool
}
// Metadata is information about a thing stored on the keyring; retrieving
// metadata must not require authentication. The embedded Item should be
// filled in with an empty Data field.
// It's allowed for Item to be a nil pointer, indicating that all we
// have is the timestamps.
type Metadata struct {
*Item
ModificationTime time.Time
}
// Keyring provides the uniform interface over the underlying backends
type Keyring interface {
// Returns an Item matching the key or ErrKeyNotFound
Get(key string) (Item, error)
// Returns the non-secret parts of an Item
GetMetadata(key string) (Metadata, error)
// Stores an Item on the keyring
Set(item Item) error
// Removes the item with matching key
Remove(key string) error
// Provides a slice of all keys stored on the keyring
Keys() ([]string, error)
}
// ErrNoAvailImpl is returned by Open when a backend cannot be found
var ErrNoAvailImpl = errors.New("Specified keyring backend not available")
// ErrKeyNotFound is returned by Keyring Get when the item is not on the keyring
var ErrKeyNotFound = errors.New("The specified item could not be found in the keyring")
// ErrMetadataNeedsCredentials is returned when Metadata is called against a
// backend which requires credentials even to see metadata.
var ErrMetadataNeedsCredentials = errors.New("The keyring backend requires credentials for metadata access")
// ErrMetadataNotSupported is returned when Metadata is not available for the backend.
var ErrMetadataNotSupported = errors.New("The keyring backend does not support metadata access")
var (
// Debug specifies whether to print debugging output
Debug bool
)
func debugf(pattern string, args ...interface{}) {
if Debug {
log.Printf("[keyring] "+pattern, args...)
}
}