Skip to content

Commit

Permalink
config: guard against privkey being overwritten in fsrepo setConfig
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Jeromy <why@ipfs.io>
  • Loading branch information
whyrusleeping committed Sep 4, 2016
1 parent 671425e commit 91dd044
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 30 deletions.
76 changes: 46 additions & 30 deletions core/commands/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,28 +163,12 @@ included in the output of this command.
return
}

idmap, ok := cfg["Identity"].(map[string]interface{})
if !ok {
res.SetError(errors.New("config has no identity"), cmds.ErrNormal)
err = scrubValue(cfg, []string{config.IdentityTag, config.PrivKeyTag})
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

privKeyKey := "" // make sure we both find the name of privkey and we delete it
for key, _ := range idmap {
if strings.ToLower(key) == "privkey" {
if privKeyKey != "" {
res.SetError(errors.New("found multiple PrivKey keys"), cmds.ErrNormal)
return
}
privKeyKey = key
}
}
if privKeyKey == "" {
res.SetError(errors.New("haven't found PriveKey key"), cmds.ErrNormal)
}

delete(idmap, privKeyKey)

output, err := config.HumanOutput(cfg)
if err != nil {
res.SetError(err, cmds.ErrNormal)
Expand All @@ -195,6 +179,47 @@ included in the output of this command.
},
}

func scrubValue(m map[string]interface{}, key []string) error {
find := func(m map[string]interface{}, k string) (string, interface{}, bool) {
lckey := strings.ToLower(k)
for mkey, val := range m {
lcmkey := strings.ToLower(mkey)
if lckey == lcmkey {
return mkey, val, true
}
}
return "", nil, false
}

cur := m
for _, k := range key[:len(key)-1] {
foundk, val, ok := find(cur, k)
if !ok {
return fmt.Errorf("failed to find specified key")
}

if foundk != k {
// case mismatch, calling this an error
return fmt.Errorf("case mismatch in config, expected %q but got %q", k, foundk)
}

mval, mok := val.(map[string]interface{})
if !mok {
return fmt.Errorf("%s was not a map", foundk)
}

cur = mval
}

todel, _, ok := find(cur, key[len(key)-1])
if !ok {
return fmt.Errorf("%s, not found", strings.Join(key, "."))
}

delete(cur, todel)
return nil
}

var configEditCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Opens the config file for editing in $EDITOR.",
Expand Down Expand Up @@ -265,19 +290,10 @@ func getConfig(r repo.Repo, key string) (*ConfigField, error) {
}

func setConfig(r repo.Repo, key string, value interface{}) (*ConfigField, error) {
keyF, err := getConfig(r, "Identity.PrivKey")
if err != nil {
return nil, errors.New("failed to get PrivKey")
}
privkey := keyF.Value
err = r.SetConfigKey(key, value)
err := r.SetConfigKey(key, value)
if err != nil {
return nil, fmt.Errorf("failed to set config value: %s (maybe use --json?)", err)
}
err = r.SetConfigKey("Identity.PrivKey", privkey)
if err != nil {
return nil, errors.New("failed to set PrivKey")
}
return getConfig(r, key)
}

Expand All @@ -301,7 +317,7 @@ func replaceConfig(r repo.Repo, file io.Reader) error {
return errors.New("setting private key with API is not supported")
}

keyF, err := getConfig(r, "Identity.PrivKey")
keyF, err := getConfig(r, config.PrivKeySelector)
if err != nil {
return fmt.Errorf("Failed to get PrivKey")
}
Expand Down
4 changes: 4 additions & 0 deletions repo/config/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto"
)

const IdentityTag = "Identity"
const PrivKeyTag = "PrivKey"
const PrivKeySelector = IdentityTag + "." + PrivKeyTag

// Identity tracks the configuration of the local node's identity.
type Identity struct {
PeerID string
Expand Down
13 changes: 13 additions & 0 deletions repo/fsrepo/fsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,14 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
return err
}

// Load private key to guard against it being overwritten.
// NOTE: this is a temporary measure to secure this field until we move
// keys out of the config file.
pkval, err := common.MapGetKV(mapconf, config.PrivKeySelector)
if err != nil {
return err
}

// Get the type of the value associated with the key
oldValue, err := common.MapGetKV(mapconf, key)
ok := true
Expand Down Expand Up @@ -523,6 +531,11 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
return err
}

// replace private key, in case it was overwritten.
if err := common.MapSetKV(mapconf, "Identity.PrivKey", pkval); err != nil {
return err
}

// This step doubles as to validate the map against the struct
// before serialization
conf, err := config.FromMap(mapconf)
Expand Down

0 comments on commit 91dd044

Please sign in to comment.