diff --git a/kms/keysource.go b/kms/keysource.go index 779be89e8..968833ca1 100644 --- a/kms/keysource.go +++ b/kms/keysource.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "regexp" - "sort" "strings" "time" @@ -162,8 +161,8 @@ func (key MasterKey) createSession() (*session.Session, error) { } // ToMap converts the MasterKey to a map for serialization purposes -func (key MasterKey) ToMap() map[string]string { - out := make(map[string]string) +func (key MasterKey) ToMap() map[string]interface{} { + out := make(map[string]interface{}) out["arn"] = key.Arn if key.Role != "" { out["role"] = key.Role @@ -171,28 +170,47 @@ func (key MasterKey) ToMap() map[string]string { out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339) out["enc"] = key.EncryptedKey if key.EncryptionContext != nil { - var outContexts []string + outcontext := make(map[string]string) for k, v := range key.EncryptionContext { - outContexts = append(outContexts, k+":"+*v) + outcontext[k] = *v } - sort.Strings(outContexts) - out["context"] = strings.Join(outContexts, ",") + out["context"] = outcontext } return out } -// ParseKMSContext takes a comma-separated list of KMS context key:value pairs and returns a map -func ParseKMSContext(in string) map[string]*string { - if in == "" { - return nil - } +// ParseKMSContext takes either a KMS context map or a comma-separated list of KMS context key:value pairs and returns a map +func ParseKMSContext(in interface{}) map[string]*string { out := make(map[string]*string) - for _, kv := range strings.Split(in, ",") { - kv := strings.Split(kv, ":") - if len(kv) != 2 { + + switch in := in.(type) { + case map[string]interface{}: + if len(in) == 0 { return nil } - out[kv[0]] = &kv[1] + for k, v := range in { + var v = v.(string) + out[k] = &v + } + case map[interface{}]interface{}: + if len(in) == 0 { + return nil + } + for k, v := range in { + var v = v.(string) + out[k.(string)] = &v + } + case string: + if in == "" { + return nil + } + for _, kv := range strings.Split(in, ",") { + kv := strings.Split(kv, ":") + if len(kv) != 2 { + return nil + } + out[kv[0]] = &kv[1] + } } return out } diff --git a/kms/keysource_test.go b/kms/keysource_test.go index dbdd9bd86..6065f9c26 100644 --- a/kms/keysource_test.go +++ b/kms/keysource_test.go @@ -73,6 +73,27 @@ func TestKMSKeySourceFromString(t *testing.T) { func TestParseEncryptionContext(t *testing.T) { value1 := "value1" value2 := "value2" + // map from YAML + var yamlmap = map[interface{}]interface{}{ + "key1": value1, + "key2": value2, + } + assert.Equal(t, ParseKMSContext(yamlmap), map[string]*string{ + "key1": &value1, + "key2": &value2, + }) + assert.Nil(t, ParseKMSContext(map[interface{}]interface{}{})) + // map from JSON + var jsonmap = map[string]interface{}{ + "key1": value1, + "key2": value2, + } + assert.Equal(t, ParseKMSContext(jsonmap), map[string]*string{ + "key1": &value1, + "key2": &value2, + }) + assert.Nil(t, ParseKMSContext(map[string]interface{}{})) + // sops 2.0.x formatted encryption context as a comma-separated list of key:value pairs assert.Equal(t, ParseKMSContext("key1:value1,key2:value2"), map[string]*string{ "key1": &value1, "key2": &value2, @@ -87,7 +108,6 @@ func TestParseEncryptionContext(t *testing.T) { func TestKeyToMap(t *testing.T) { value1 := "value1" value2 := "value2" - value3 := "value3" key := MasterKey{ CreationDate: time.Date(2016, time.October, 31, 10, 0, 0, 0, time.UTC), Arn: "foo", @@ -96,14 +116,16 @@ func TestKeyToMap(t *testing.T) { EncryptionContext: map[string]*string{ "key1": &value1, "key2": &value2, - "AAA_this_key_should_be_first": &value3, }, } - assert.Equal(t, map[string]string{ + assert.Equal(t, map[string]interface{}{ "arn": "foo", "role": "bar", "enc": "this is encrypted", "created_at": "2016-10-31T10:00:00Z", - "context": "AAA_this_key_should_be_first:value3,key1:value1,key2:value2", + "context": map[string]string{ + "key1": value1, + "key2": value2, + }, }, key.ToMap()) } diff --git a/pgp/keysource.go b/pgp/keysource.go index b52d7ddb2..434fbf146 100644 --- a/pgp/keysource.go +++ b/pgp/keysource.go @@ -201,8 +201,8 @@ func (key *MasterKey) passphrasePrompt(keys []openpgp.Key, symmetric bool) ([]by } // ToMap converts the MasterKey into a map for serialization purposes -func (key MasterKey) ToMap() map[string]string { - out := make(map[string]string) +func (key MasterKey) ToMap() map[string]interface{} { + out := make(map[string]interface{}) out["fp"] = key.Fingerprint out["created_at"] = key.CreationDate.UTC().Format(time.RFC3339) out["enc"] = key.EncryptedKey diff --git a/sops.go b/sops.go index def9c20d5..d3530c0e2 100644 --- a/sops.go +++ b/sops.go @@ -303,7 +303,7 @@ type MasterKey interface { Decrypt() ([]byte, error) NeedsRotation() bool ToString() string - ToMap() map[string]string + ToMap() map[string]interface{} } // Store provides a way to load and save the sops tree along with metadata @@ -426,7 +426,7 @@ func (m *Metadata) ToMap() map[string]interface{} { out["mac"] = m.MessageAuthenticationCode out["version"] = m.Version for _, ks := range m.KeySources { - var keys []map[string]string + var keys []map[string]interface{} for _, k := range ks.Keys { keys = append(keys, k.ToMap()) } @@ -550,7 +550,7 @@ func mapKMSEntriesToKeySource(in []interface{}) (KeySource, error) { return keysource, fmt.Errorf("Could not parse creation date: %s", err) } if _, ok := entry["context"]; ok { - key.EncryptionContext = kms.ParseKMSContext(entry["context"].(string)) + key.EncryptionContext = kms.ParseKMSContext(entry["context"]) } key.CreationDate = creationDate keysource.Keys = append(keysource.Keys, key)