mirror of
https://github.com/getsops/sops.git
synced 2026-02-05 12:45:21 +01:00
Add dedicated functions for \n and non string encoding
Signed-off-by: Lance Rushing <lance@lancerushing.com>
This commit is contained in:
committed by
Felix Fontein
parent
1161ec17a1
commit
32dbc6be13
@@ -48,7 +48,7 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
}
|
||||
}
|
||||
|
||||
metadata, err := stores.Unflatten(mdMap)
|
||||
metadata, err := stores.UnflattenMetadata(mdMap)
|
||||
if err != nil {
|
||||
return sops.Tree{}, err
|
||||
}
|
||||
@@ -100,7 +100,7 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
// runtime object
|
||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
metadata := stores.MetadataFromInternal(in.Metadata)
|
||||
mdItems, err := stores.Flatten(metadata)
|
||||
mdItems, err := stores.FlattenMetadata(metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ func flattenValue(value interface{}) interface{} {
|
||||
return output
|
||||
}
|
||||
|
||||
// flattenMap flattens a map with potentially nested maps into a flat
|
||||
// Flatten flattens a map with potentially nested maps into a flat
|
||||
// map. Only string keys are allowed on both the top-level map and
|
||||
// child maps.
|
||||
func flattenMap(in map[string]interface{}) map[string]interface{} {
|
||||
func Flatten(in map[string]interface{}) map[string]interface{} {
|
||||
newMap := make(map[string]interface{})
|
||||
for k, v := range in {
|
||||
if flat, ok := flattenValue(v).(map[string]interface{}); ok {
|
||||
@@ -61,7 +61,7 @@ func flattenMap(in map[string]interface{}) map[string]interface{} {
|
||||
return newMap
|
||||
}
|
||||
|
||||
func Flatten(md Metadata) (map[string]interface{}, error) {
|
||||
func FlattenMetadata(md Metadata) (map[string]interface{}, error) {
|
||||
var mdMap map[string]interface{}
|
||||
jsonBytes, err := json.Marshal(md)
|
||||
if err != nil {
|
||||
@@ -72,14 +72,9 @@ func Flatten(md Metadata) (map[string]interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flat := flattenMap(mdMap)
|
||||
macOnlyEncryptedToString(flat)
|
||||
for k, v := range flat {
|
||||
if s, ok := v.(string); ok {
|
||||
flat[k] = strings.Replace(s, "\n", "\\n", -1)
|
||||
}
|
||||
}
|
||||
|
||||
flat := Flatten(mdMap)
|
||||
encodeNonStrings(flat)
|
||||
encodeNewLines(flat)
|
||||
return flat, nil
|
||||
}
|
||||
|
||||
@@ -93,7 +88,7 @@ type listToken struct {
|
||||
position int
|
||||
}
|
||||
|
||||
// tokenize converts a path generated by flattenMap to be used as a key
|
||||
// tokenize converts a path generated by Flatten to be used as a key
|
||||
// in the flattened map, and converts it to a slice of tokens
|
||||
func tokenize(path string) []token {
|
||||
const (
|
||||
@@ -196,8 +191,8 @@ func unflatten(currentNode interface{}, currentToken, nextToken token, value int
|
||||
return nil
|
||||
}
|
||||
|
||||
// unflattenMap unflattens a map flattened by flattenMap
|
||||
func unflattenMap(in map[string]interface{}) map[string]interface{} {
|
||||
// Unflatten unflattens a map flattened by Flatten
|
||||
func Unflatten(in map[string]interface{}) map[string]interface{} {
|
||||
newMap := make(map[string]interface{})
|
||||
for k, v := range in {
|
||||
var current interface{} = newMap
|
||||
@@ -209,16 +204,11 @@ func unflattenMap(in map[string]interface{}) map[string]interface{} {
|
||||
return newMap
|
||||
}
|
||||
|
||||
// Unflatten unflattens a map flattened by Flatten into Metadata
|
||||
func Unflatten(in map[string]interface{}) (Metadata, error) {
|
||||
for k, v := range in {
|
||||
if s, ok := v.(string); ok {
|
||||
in[k] = strings.Replace(s, "\\n", "\n", -1)
|
||||
}
|
||||
}
|
||||
|
||||
m := unflattenMap(in)
|
||||
macOnlyEncryptedToBool(m)
|
||||
// UnflattenMetadata unflattens a map flattened by FlattenMetadata into Metadata
|
||||
func UnflattenMetadata(in map[string]interface{}) (Metadata, error) {
|
||||
decodeNewLines(in)
|
||||
decodeNonStrings(in)
|
||||
m := Unflatten(in)
|
||||
var md Metadata
|
||||
jsonBytes, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
@@ -228,7 +218,24 @@ func Unflatten(in map[string]interface{}) (Metadata, error) {
|
||||
return md, err
|
||||
}
|
||||
|
||||
func macOnlyEncryptedToBool(m map[string]interface{}) {
|
||||
func decodeNewLines(m map[string]interface{}) {
|
||||
for k, v := range m {
|
||||
if s, ok := v.(string); ok {
|
||||
m[k] = strings.Replace(s, "\\n", "\n", -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func encodeNewLines(m map[string]interface{}) {
|
||||
for k, v := range m {
|
||||
if s, ok := v.(string); ok {
|
||||
m[k] = strings.Replace(s, "\n", "\\n", -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decodeNonStrings will look for known keys that are not strings and decode to the appropriate type
|
||||
func decodeNonStrings(m map[string]interface{}) {
|
||||
if v, ok := m["mac_only_encrypted"]; ok {
|
||||
m["mac_only_encrypted"] = false
|
||||
if v == "true" {
|
||||
@@ -237,7 +244,8 @@ func macOnlyEncryptedToBool(m map[string]interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func macOnlyEncryptedToString(m map[string]interface{}) {
|
||||
// encodeNonStrings will look for known keys that are not strings and will encode it to strings
|
||||
func encodeNonStrings(m map[string]interface{}) {
|
||||
if v, found := m["mac_only_encrypted"]; found {
|
||||
if vBool, ok := v.(bool); ok {
|
||||
m["mac_only_encrypted"] = "false"
|
||||
|
||||
@@ -13,9 +13,9 @@ func TestFlat(t *testing.T) {
|
||||
expected := map[string]interface{}{
|
||||
"foo": "bar",
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ func TestMap(t *testing.T) {
|
||||
"foo" + mapSeparator + "bar": 0,
|
||||
"foo" + mapSeparator + "baz": 0,
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
@@ -47,9 +47,9 @@ func TestFlattenMapMoreNesting(t *testing.T) {
|
||||
expected := map[string]interface{}{
|
||||
"foo" + mapSeparator + "bar" + mapSeparator + "baz": 0,
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
@@ -62,9 +62,9 @@ func TestFlattenList(t *testing.T) {
|
||||
expected := map[string]interface{}{
|
||||
"foo" + listSeparator + "0": 0,
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
@@ -79,13 +79,13 @@ func TestFlattenListWithMap(t *testing.T) {
|
||||
expected := map[string]interface{}{
|
||||
"foo" + listSeparator + "0" + mapSeparator + "bar": 0,
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
func TestFlattenMap(t *testing.T) {
|
||||
func TestFlatten(t *testing.T) {
|
||||
input := map[string]interface{}{
|
||||
"foo": "bar",
|
||||
"baz": map[string]interface{}{
|
||||
@@ -106,9 +106,9 @@ func TestFlattenMap(t *testing.T) {
|
||||
"qux" + listSeparator + "1": 1,
|
||||
"qux" + listSeparator + "2": 2,
|
||||
}
|
||||
flattened := flattenMap(input)
|
||||
flattened := Flatten(input)
|
||||
assert.Equal(t, expected, flattened)
|
||||
unflattened := unflattenMap(flattened)
|
||||
unflattened := Unflatten(flattened)
|
||||
assert.Equal(t, input, unflattened)
|
||||
}
|
||||
|
||||
@@ -140,38 +140,7 @@ func TestTokenizeNested(t *testing.T) {
|
||||
assert.Equal(t, expected, tokenized)
|
||||
}
|
||||
|
||||
func TestMacOnlyEncryptedToBool(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac_only_encrypted": "false"}, map[string]interface{}{"mac_only_encrypted": false}},
|
||||
{map[string]interface{}{"mac_only_encrypted": "true"}, map[string]interface{}{"mac_only_encrypted": true}},
|
||||
{map[string]interface{}{"mac_only_encrypted": "something-else"}, map[string]interface{}{"mac_only_encrypted": false}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
macOnlyEncryptedToBool(tt.input)
|
||||
assert.Equal(t, tt.want, tt.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMacOnlyEncryptedToString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac_only_encrypted": false}, map[string]interface{}{"mac_only_encrypted": "false"}},
|
||||
{map[string]interface{}{"mac_only_encrypted": true}, map[string]interface{}{"mac_only_encrypted": "true"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
macOnlyEncryptedToString(tt.input)
|
||||
assert.Equal(t, tt.want, tt.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
func TestFlattenMetadata(t *testing.T) {
|
||||
tests := []struct {
|
||||
input Metadata
|
||||
want map[string]interface{}
|
||||
@@ -183,7 +152,7 @@ func TestFlatten(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got, err := Flatten(tt.input)
|
||||
got, err := FlattenMetadata(tt.input)
|
||||
assert.NoError(t, err)
|
||||
for k, v := range tt.want {
|
||||
assert.Equal(t, v, got[k])
|
||||
@@ -191,7 +160,7 @@ func TestFlatten(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenToUnflatten(t *testing.T) {
|
||||
func TestFlattenMetadataToUnflattenMetadata(t *testing.T) {
|
||||
tests := []struct {
|
||||
input Metadata
|
||||
}{
|
||||
@@ -203,10 +172,75 @@ func TestFlattenToUnflatten(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
flat, err := Flatten(tt.input)
|
||||
flat, err := FlattenMetadata(tt.input)
|
||||
assert.NoError(t, err)
|
||||
md, err := Unflatten(flat)
|
||||
md, err := UnflattenMetadata(flat)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.input, md)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeNewLines(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac": "line1\\nline2"}, map[string]interface{}{"mac": "line1\nline2"}},
|
||||
{map[string]interface{}{"mac": "line1\\n\\n\\nline2\\n\\nline3"}, map[string]interface{}{"mac": "line1\n\n\nline2\n\nline3"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
decodeNewLines(tt.input)
|
||||
for k, v := range tt.want {
|
||||
assert.Equal(t, v, tt.input[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeNewLines(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac": "line1\nline2"}, map[string]interface{}{"mac": "line1\\nline2"}},
|
||||
{map[string]interface{}{"mac": "line1\n\n\nline2\n\nline3"}, map[string]interface{}{"mac": "line1\\n\\n\\nline2\\n\\nline3"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
encodeNewLines(tt.input)
|
||||
for k, v := range tt.want {
|
||||
assert.Equal(t, v, tt.input[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeNonStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac_only_encrypted": "false"}, map[string]interface{}{"mac_only_encrypted": false}},
|
||||
{map[string]interface{}{"mac_only_encrypted": "true"}, map[string]interface{}{"mac_only_encrypted": true}},
|
||||
{map[string]interface{}{"mac_only_encrypted": "something-else"}, map[string]interface{}{"mac_only_encrypted": false}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
decodeNonStrings(tt.input)
|
||||
assert.Equal(t, tt.want, tt.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeNonStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
input map[string]interface{}
|
||||
want map[string]interface{}
|
||||
}{
|
||||
{map[string]interface{}{"mac_only_encrypted": false}, map[string]interface{}{"mac_only_encrypted": "false"}},
|
||||
{map[string]interface{}{"mac_only_encrypted": true}, map[string]interface{}{"mac_only_encrypted": "true"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
encodeNonStrings(tt.input)
|
||||
assert.Equal(t, tt.want, tt.input)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ func (store *Store) iniSectionToMetadata(sopsSection *ini.Section) (stores.Metad
|
||||
for k, v := range sopsSection.KeysHash() {
|
||||
metadataHash[k] = v
|
||||
}
|
||||
return stores.Unflatten(metadataHash)
|
||||
return stores.UnflattenMetadata(metadataHash)
|
||||
}
|
||||
|
||||
// LoadPlainFile loads a plaintext INI file's bytes onto a sops.TreeBranches runtime object
|
||||
@@ -221,7 +221,7 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (store *Store) encodeMetadataToIniBranch(md stores.Metadata) (sops.TreeBranch, error) {
|
||||
flat, err := stores.Flatten(md)
|
||||
flat, err := stores.FlattenMetadata(md)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user