config: guard against privkey being overwritten in fsrepo setConfig
License: MIT Signed-off-by: Jeromy <why@ipfs.io>
Jeromy committed
Aug 29, 2016 at 14:56 UTC
91dd044d55dcb0b8d12388e2194cb4dac01bafe1
3 files changed
+63
-30
core/commands/config.go
+46
-30
@@ -163,28 +163,12 @@ included in the output of this command.
163
return
164
}
165
166
- idmap, ok := cfg["Identity"].(map[string]interface{})
167
- if !ok {
168
- res.SetError(errors.New("config has no identity"), cmds.ErrNormal)
166
+ err = scrubValue(cfg, []string{config.IdentityTag, config.PrivKeyTag})
167
+ if err != nil {
168
+ res.SetError(err, cmds.ErrNormal)
169
return
170
}
171
172
- privKeyKey := "" // make sure we both find the name of privkey and we delete it
173
- for key, _ := range idmap {
174
- if strings.ToLower(key) == "privkey" {
175
- if privKeyKey != "" {
176
- res.SetError(errors.New("found multiple PrivKey keys"), cmds.ErrNormal)
177
- return
178
- }
179
- privKeyKey = key
180
- }
181
- }
182
- if privKeyKey == "" {
183
- res.SetError(errors.New("haven't found PriveKey key"), cmds.ErrNormal)
184
- }
185
-
186
- delete(idmap, privKeyKey)
187
-
172
output, err := config.HumanOutput(cfg)
173
if err != nil {
174
res.SetError(err, cmds.ErrNormal)
@@ -195,6 +179,47 @@ included in the output of this command.
179
},
180
}
181
182
+func scrubValue(m map[string]interface{}, key []string) error {
183
+ find := func(m map[string]interface{}, k string) (string, interface{}, bool) {
184
+ lckey := strings.ToLower(k)
185
+ for mkey, val := range m {
186
+ lcmkey := strings.ToLower(mkey)
187
+ if lckey == lcmkey {
188
+ return mkey, val, true
189
+ }
190
+ }
191
+ return "", nil, false
192
+ }
193
+
194
+ cur := m
195
+ for _, k := range key[:len(key)-1] {
196
+ foundk, val, ok := find(cur, k)
197
+ if !ok {
198
+ return fmt.Errorf("failed to find specified key")
199
+ }
200
+
201
+ if foundk != k {
202
+ // case mismatch, calling this an error
203
+ return fmt.Errorf("case mismatch in config, expected %q but got %q", k, foundk)
204
+ }
205
+
206
+ mval, mok := val.(map[string]interface{})
207
+ if !mok {
208
+ return fmt.Errorf("%s was not a map", foundk)
209
+ }
210
+
211
+ cur = mval
212
+ }
213
+
214
+ todel, _, ok := find(cur, key[len(key)-1])
215
+ if !ok {
216
+ return fmt.Errorf("%s, not found", strings.Join(key, "."))
217
+ }
218
+
219
+ delete(cur, todel)
220
+ return nil
221
+}
222
+
223
var configEditCmd = &cmds.Command{
224
Helptext: cmds.HelpText{
225
Tagline: "Opens the config file for editing in $EDITOR.",
@@ -265,19 +290,10 @@ func getConfig(r repo.Repo, key string) (*ConfigField, error) {
290
}
291
292
func setConfig(r repo.Repo, key string, value interface{}) (*ConfigField, error) {
268
- keyF, err := getConfig(r, "Identity.PrivKey")
269
- if err != nil {
270
- return nil, errors.New("failed to get PrivKey")
271
- }
272
- privkey := keyF.Value
273
- err = r.SetConfigKey(key, value)
293
+ err := r.SetConfigKey(key, value)
294
if err != nil {
295
return nil, fmt.Errorf("failed to set config value: %s (maybe use --json?)", err)
296
}
277
- err = r.SetConfigKey("Identity.PrivKey", privkey)
278
- if err != nil {
279
- return nil, errors.New("failed to set PrivKey")
280
- }
297
return getConfig(r, key)
298
}
299
@@ -301,7 +317,7 @@ func replaceConfig(r repo.Repo, file io.Reader) error {
317
return errors.New("setting private key with API is not supported")
318
}
319
304
- keyF, err := getConfig(r, "Identity.PrivKey")
320
+ keyF, err := getConfig(r, config.PrivKeySelector)
321
if err != nil {
322
return fmt.Errorf("Failed to get PrivKey")
323
}
repo/config/identity.go
+4
@@ -5,6 +5,10 @@ import (
5
ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto"
6
)
7
8
+const IdentityTag = "Identity"
9
+const PrivKeyTag = "PrivKey"
10
+const PrivKeySelector = IdentityTag + "." + PrivKeyTag
11
+
12
// Identity tracks the configuration of the local node's identity.
13
type Identity struct {
14
PeerID string
repo/fsrepo/fsrepo.go
+13
@@ -482,6 +482,14 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
482
return err
483
}
484
485
+ // Load private key to guard against it being overwritten.
486
+ // NOTE: this is a temporary measure to secure this field until we move
487
+ // keys out of the config file.
488
+ pkval, err := common.MapGetKV(mapconf, config.PrivKeySelector)
489
+ if err != nil {
490
+ return err
491
+ }
492
+
493
// Get the type of the value associated with the key
494
oldValue, err := common.MapGetKV(mapconf, key)
495
ok := true
@@ -523,6 +531,11 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
531
return err
532
}
533
534
+ // replace private key, in case it was overwritten.
535
+ if err := common.MapSetKV(mapconf, "Identity.PrivKey", pkval); err != nil {
536
+ return err
537
+ }
538
+
539
// This step doubles as to validate the map against the struct
540
// before serialization
541
conf, err := config.FromMap(mapconf)