-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtypes.go
203 lines (168 loc) · 5.05 KB
/
types.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package envsecret
import (
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)
// Secret is the interface considered by Process. Custom secret types
// can implement this interface to be populated by Process.
type Secret interface {
// Decode should populate the secret based on the values in the string map returned by
// the secrets provider. For example, PublicKey constructs an *rsa.PublicKey
// from the raw base64 encoded string it looks for in the map.
Decode(map[string]interface{}) error
// ID should return the identifier of the secret to be retrieved.
ID() string
}
// Base type for all Secret implementations exposed by this package.
type Base struct {
id string
}
// NewBase returns a new Base secret with the given identifier.
func NewBase(id string) Base {
return Base{id}
}
// Decode implements envconfig.Decoder and populates id.
func (s *Base) Decode(value string) error { s.id = value; return nil }
// ID returns the secret's identifier in the secret store being used,
// e.g. an ARN if using AWS Secrets Manager or a Vault secret path.
func (s *Base) ID() string { return s.id }
// String is a general purpose secret and holds a single string value.
type String struct {
Base
Value string
}
// NewString builds a new String type secret with the given id.
func NewString(id string) String {
return String{Base: Base{id: id}}
}
// Decode implements Secret and populates Key with the secret string.
func (s *String) Decode(secrets map[string]interface{}) error {
if s.Value = find(secrets, "value"); s.Value == "" {
return errors.New("finding secret in map")
}
return nil
}
// Map contains a map of secret strings, possibly filtered by an allowList.
type Map struct {
Base
Values map[string]interface{}
}
// NewMap builds a new Map type secret with the given id.
func NewMap(id string) Map {
return Map{Base: Base{id: id}}
}
// Decode implements Secret and populates Values with the secret map.
func (m *Map) Decode(secrets map[string]interface{}) error {
m.Values = secrets
return nil
}
// Login contains a username and password.
type Login struct {
Base
Username string
Password string
}
// NewLogin builds a new DatabaseLogin type secret with the given id.
func NewLogin(id string) Login {
return Login{Base: Base{id: id}}
}
// Decode implements Secret and populates the database credentials and host information.
func (l *Login) Decode(secrets map[string]interface{}) error {
var (
username, foundUsername = secrets["username"]
password, foundPassword = secrets["password"]
)
if !foundUsername || !foundPassword {
return errors.New("finding username or password in map")
}
l.Username, l.Password = str(username), str(password)
return nil
}
// PublicKey contains an RSA public key.
type PublicKey struct {
Base
Key *rsa.PublicKey
}
// NewPublicKey builds a new PublicKey type secret with the given id.
func NewPublicKey(id string) PublicKey {
return PublicKey{Base: Base{id: id}}
}
// Decode implements Secret and populates Key with the constructed public key.
func (k *PublicKey) Decode(secrets map[string]interface{}) error {
value := find(secrets, "public_key")
if value == "" {
return errors.New("finding secret in map")
}
bytes, err := base64.StdEncoding.DecodeString(value)
if err != nil {
return err
}
var block *pem.Block
if block, _ = pem.Decode(bytes); block == nil {
return errors.New("decoding pem")
}
var (
parsed interface{}
ok bool
)
if parsed, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
return err
} else if k.Key, ok = parsed.(*rsa.PublicKey); !ok {
return errors.New("parsing public key")
}
return nil
}
// PrivateKey contains a secret RSA private key.
type PrivateKey struct {
Base
Key *rsa.PrivateKey
}
// NewPrivateKey builds a new PrivateKey type secret with the given id.
func NewPrivateKey(id string) PrivateKey {
return PrivateKey{Base: Base{id: id}}
}
// Decode implements Secret and populates Key with the constructed private key.
func (k *PrivateKey) Decode(secrets map[string]interface{}) error {
value := find(secrets, "private_key")
if value == "" {
return errors.New("finding secret in map")
}
bytes, err := base64.StdEncoding.DecodeString(value)
if err != nil {
return err
}
var block *pem.Block
if block, _ = pem.Decode(bytes); block == nil {
return errors.New("decoding pem")
}
var parsed interface{}
if parsed, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
if parsed, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return err
}
}
var ok bool
if k.Key, ok = parsed.(*rsa.PrivateKey); !ok {
return errors.New("parsing private key")
}
return nil
}
// find a secret value in a map - if there is only one option, return it, else return
// the value of the given key (which may be an empty string if no corresponding value exists)
func find(secrets map[string]interface{}, key string) string {
if len(secrets) == 1 {
for _, v := range secrets {
return str(v)
}
} else if v, found := secrets[key]; found {
return str(v)
}
return ""
}
func str(x interface{}) string {
return fmt.Sprintf("%v", x)
}