1package sops
2
3import (
4	"bytes"
5	"fmt"
6	"reflect"
7	"testing"
8
9	"github.com/stretchr/testify/assert"
10)
11
12type reverseCipher struct{}
13
14// reverse returns its argument string reversed rune-wise left to right.
15func reverse(s string) string {
16	r := []rune(s)
17	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
18		r[i], r[j] = r[j], r[i]
19	}
20	return string(r)
21}
22
23func (c reverseCipher) Encrypt(value interface{}, key []byte, path string) (string, error) {
24	b, err := ToBytes(value)
25	if err != nil {
26		return "", err
27	}
28	return reverse(string(b)), nil
29}
30func (c reverseCipher) Decrypt(value string, key []byte, path string) (plaintext interface{}, err error) {
31	if value == "error" {
32		return nil, fmt.Errorf("Error")
33	}
34	return reverse(value), nil
35}
36
37func TestUnencryptedSuffix(t *testing.T) {
38	branches := TreeBranches{
39		TreeBranch{
40			TreeItem{
41				Key:   "foo_unencrypted",
42				Value: "bar",
43			},
44			TreeItem{
45				Key: "bar_unencrypted",
46				Value: TreeBranch{
47					TreeItem{
48						Key:   "foo",
49						Value: "bar",
50					},
51				},
52			},
53		},
54	}
55	tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: "_unencrypted"}}
56	expected := TreeBranch{
57		TreeItem{
58			Key:   "foo_unencrypted",
59			Value: "bar",
60		},
61		TreeItem{
62			Key: "bar_unencrypted",
63			Value: TreeBranch{
64				TreeItem{
65					Key:   "foo",
66					Value: "bar",
67				},
68			},
69		},
70	}
71	cipher := reverseCipher{}
72	_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
73	if err != nil {
74		t.Errorf("Encrypting the tree failed: %s", err)
75	}
76	if !reflect.DeepEqual(tree.Branches[0], expected) {
77		t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected)
78	}
79	_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher)
80	if err != nil {
81		t.Errorf("Decrypting the tree failed: %s", err)
82	}
83	if !reflect.DeepEqual(tree.Branches[0], expected) {
84		t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected)
85	}
86}
87
88func TestEncryptedSuffix(t *testing.T) {
89	branches := TreeBranches{
90		TreeBranch{
91			TreeItem{
92				Key:   "foo_encrypted",
93				Value: "bar",
94			},
95			TreeItem{
96				Key: "bar",
97				Value: TreeBranch{
98					TreeItem{
99						Key:   "foo",
100						Value: "bar",
101					},
102				},
103			},
104		},
105	}
106	tree := Tree{Branches: branches, Metadata: Metadata{EncryptedSuffix: "_encrypted"}}
107	expected := TreeBranch{
108		TreeItem{
109			Key:   "foo_encrypted",
110			Value: "rab",
111		},
112		TreeItem{
113			Key: "bar",
114			Value: TreeBranch{
115				TreeItem{
116					Key:   "foo",
117					Value: "bar",
118				},
119			},
120		},
121	}
122	cipher := reverseCipher{}
123	_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
124	if err != nil {
125		t.Errorf("Encrypting the tree failed: %s", err)
126	}
127	if !reflect.DeepEqual(tree.Branches[0], expected) {
128		t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected)
129	}
130	_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher)
131	if err != nil {
132		t.Errorf("Decrypting the tree failed: %s", err)
133	}
134	expected[0].Value = "bar"
135	if !reflect.DeepEqual(tree.Branches[0], expected) {
136		t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected)
137	}
138}
139
140func TestEncryptedRegex(t *testing.T) {
141	branches := TreeBranches{
142		TreeBranch{
143			TreeItem{
144				Key:   "enc:foo",
145				Value: "bar",
146			},
147			TreeItem{
148				Key: "bar",
149				Value: TreeBranch{
150					TreeItem{
151						Key:   "foo",
152						Value: "bar",
153					},
154				},
155			},
156		},
157	}
158	tree := Tree{Branches: branches, Metadata: Metadata{EncryptedRegex: "^enc:"}}
159	expected := TreeBranch{
160		TreeItem{
161			Key:   "enc:foo",
162			Value: "rab",
163		},
164		TreeItem{
165			Key: "bar",
166			Value: TreeBranch{
167				TreeItem{
168					Key:   "foo",
169					Value: "bar",
170				},
171			},
172		},
173	}
174	cipher := reverseCipher{}
175	_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
176	if err != nil {
177		t.Errorf("Encrypting the tree failed: %s", err)
178	}
179	if !reflect.DeepEqual(tree.Branches[0], expected) {
180		t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected)
181	}
182	_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher)
183	if err != nil {
184		t.Errorf("Decrypting the tree failed: %s", err)
185	}
186	expected[0].Value = "bar"
187	if !reflect.DeepEqual(tree.Branches[0], expected) {
188		t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected)
189	}
190}
191
192func TestUnencryptedRegex(t *testing.T) {
193	branches := TreeBranches{
194		TreeBranch{
195			TreeItem{
196				Key:   "dec:foo",
197				Value: "bar",
198			},
199			TreeItem{
200				Key: "dec:bar",
201				Value: TreeBranch{
202					TreeItem{
203						Key:   "foo",
204						Value: "bar",
205					},
206				},
207			},
208		},
209	}
210	tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedRegex: "^dec:"}}
211	expected := TreeBranch{
212		TreeItem{
213			Key:   "dec:foo",
214			Value: "bar",
215		},
216		TreeItem{
217			Key: "dec:bar",
218			Value: TreeBranch{
219				TreeItem{
220					Key:   "foo",
221					Value: "bar",
222				},
223			},
224		},
225	}
226	cipher := reverseCipher{}
227
228	_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher)
229	if err != nil {
230		t.Errorf("Encrypting the tree failed: %s", err)
231	}
232	// expected[1].Value[] = "bar"
233	if !reflect.DeepEqual(tree.Branches[0], expected) {
234		t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected)
235	}
236	_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher)
237	if err != nil {
238		t.Errorf("Decrypting the tree failed: %s", err)
239	}
240	if !reflect.DeepEqual(tree.Branches[0], expected) {
241		t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected)
242	}
243}
244
245type MockCipher struct{}
246
247func (m MockCipher) Encrypt(value interface{}, key []byte, path string) (string, error) {
248	return "a", nil
249}
250
251func (m MockCipher) Decrypt(value string, key []byte, path string) (interface{}, error) {
252	return "a", nil
253}
254
255func TestEncrypt(t *testing.T) {
256	branches := TreeBranches{
257		TreeBranch{
258			TreeItem{
259				Key:   "foo",
260				Value: "bar",
261			},
262			TreeItem{
263				Key: "baz",
264				Value: TreeBranch{
265					TreeItem{
266						Key:   "bar",
267						Value: 5,
268					},
269				},
270			},
271			TreeItem{
272				Key:   "bar",
273				Value: false,
274			},
275			TreeItem{
276				Key:   "foobar",
277				Value: 2.12,
278			},
279			TreeItem{
280				Key:   "barfoo",
281				Value: nil,
282			},
283		},
284		TreeBranch{
285			TreeItem{
286				Key:   "foo2",
287				Value: "bar",
288			},
289		},
290		TreeBranch{
291			TreeItem{
292				Key:   "foo3",
293				Value: "bar",
294			},
295		},
296	}
297	expected := TreeBranches{
298		TreeBranch{
299			TreeItem{
300				Key:   "foo",
301				Value: "a",
302			},
303			TreeItem{
304				Key: "baz",
305				Value: TreeBranch{
306					TreeItem{
307						Key:   "bar",
308						Value: "a",
309					},
310				},
311			},
312			TreeItem{
313				Key:   "bar",
314				Value: "a",
315			},
316			TreeItem{
317				Key:   "foobar",
318				Value: "a",
319			},
320			TreeItem{
321				Key:   "barfoo",
322				Value: nil,
323			},
324		},
325		TreeBranch{
326			TreeItem{
327				Key:   "foo2",
328				Value: "a",
329			},
330		},
331		TreeBranch{
332			TreeItem{
333				Key:   "foo3",
334				Value: "a",
335			},
336		},
337	}
338	tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: DefaultUnencryptedSuffix}}
339	tree.Encrypt(bytes.Repeat([]byte{'f'}, 32), MockCipher{})
340	if !reflect.DeepEqual(tree.Branches, expected) {
341		t.Errorf("%s does not equal expected tree: %s", tree.Branches, expected)
342	}
343}
344
345func TestDecrypt(t *testing.T) {
346	branches := TreeBranches{
347		TreeBranch{
348			TreeItem{
349				Key:   "foo",
350				Value: "bar",
351			},
352			TreeItem{
353				Key: "baz",
354				Value: TreeBranch{
355					TreeItem{
356						Key:   "bar",
357						Value: "5",
358					},
359				},
360			},
361			TreeItem{
362				Key:   "bar",
363				Value: "false",
364			},
365			TreeItem{
366				Key:   "foobar",
367				Value: "2.12",
368			},
369			TreeItem{
370				Key:   "barfoo",
371				Value: nil,
372			},
373		},
374		TreeBranch{
375			TreeItem{
376				Key:   "foo",
377				Value: "bar",
378			},
379			TreeItem{
380				Key: "baz",
381				Value: TreeBranch{
382					TreeItem{
383						Key:   "bar",
384						Value: "6",
385					},
386				},
387			},
388		},
389		TreeBranch{
390			TreeItem{
391				Key:   "foo3",
392				Value: "bar",
393			},
394		},
395	}
396	expected := TreeBranches{
397		TreeBranch{
398			TreeItem{
399				Key:   "foo",
400				Value: "a",
401			},
402			TreeItem{
403				Key: "baz",
404				Value: TreeBranch{
405					TreeItem{
406						Key:   "bar",
407						Value: "a",
408					},
409				},
410			},
411			TreeItem{
412				Key:   "bar",
413				Value: "a",
414			},
415			TreeItem{
416				Key:   "foobar",
417				Value: "a",
418			},
419			TreeItem{
420				Key:   "barfoo",
421				Value: nil,
422			},
423		},
424		TreeBranch{
425			TreeItem{
426				Key:   "foo",
427				Value: "a",
428			},
429			TreeItem{
430				Key: "baz",
431				Value: TreeBranch{
432					TreeItem{
433						Key:   "bar",
434						Value: "a",
435					},
436				},
437			},
438		},
439		TreeBranch{
440			TreeItem{
441				Key:   "foo3",
442				Value: "a",
443			},
444		},
445	}
446	tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: DefaultUnencryptedSuffix}}
447	tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), MockCipher{})
448	if !reflect.DeepEqual(tree.Branches, expected) {
449		t.Errorf("%s does not equal expected tree: %s", tree.Branches[0], expected)
450	}
451}
452
453func TestTruncateTree(t *testing.T) {
454	tree := TreeBranch{
455		TreeItem{
456			Key:   "foo",
457			Value: 2,
458		},
459		TreeItem{
460			Key: "bar",
461			Value: TreeBranch{
462				TreeItem{
463					Key: "foobar",
464					Value: []int{
465						1,
466						2,
467						3,
468						4,
469					},
470				},
471			},
472		},
473	}
474	expected := 3
475	result, err := tree.Truncate([]interface{}{
476		"bar",
477		"foobar",
478		2,
479	})
480	assert.Equal(t, nil, err)
481	assert.Equal(t, expected, result)
482}
483
484func TestEncryptComments(t *testing.T) {
485	tree := Tree{
486		Branches: TreeBranches{
487			TreeBranch{
488				TreeItem{
489					Key:   Comment{"foo"},
490					Value: nil,
491				},
492				TreeItem{
493					Key: "list",
494					Value: []interface{}{
495						"1",
496						Comment{"bar"},
497						"2",
498					},
499				},
500			},
501		},
502		Metadata: Metadata{
503			UnencryptedSuffix: DefaultUnencryptedSuffix,
504		},
505	}
506	tree.Encrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{})
507	assert.Equal(t, "oof", tree.Branches[0][0].Key.(Comment).Value)
508	assert.Equal(t, "rab", tree.Branches[0][1].Value.([]interface{})[1])
509}
510
511func TestDecryptComments(t *testing.T) {
512	tree := Tree{
513		Branches: TreeBranches{
514			TreeBranch{
515				TreeItem{
516					Key:   Comment{"oof"},
517					Value: nil,
518				},
519				TreeItem{
520					Key: "list",
521					Value: []interface{}{
522						"1",
523						Comment{"rab"},
524						"2",
525					},
526				},
527				TreeItem{
528					Key:   "list",
529					Value: nil,
530				},
531			},
532		},
533		Metadata: Metadata{
534			UnencryptedSuffix: DefaultUnencryptedSuffix,
535		},
536	}
537	tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{})
538	assert.Equal(t, "foo", tree.Branches[0][0].Key.(Comment).Value)
539	assert.Equal(t, "bar", tree.Branches[0][1].Value.([]interface{})[1])
540}
541
542func TestDecryptUnencryptedComments(t *testing.T) {
543	tree := Tree{
544		Branches: TreeBranches{
545			TreeBranch{
546				TreeItem{
547					// We use `error` to simulate an error decrypting, the fake cipher will error in this case
548					Key:   Comment{"error"},
549					Value: nil,
550				},
551			},
552		},
553		Metadata: Metadata{},
554	}
555	tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{})
556	assert.Equal(t, "error", tree.Branches[0][0].Key.(Comment).Value)
557}
558
559func TestSetNewKey(t *testing.T) {
560	branch := TreeBranch{
561		TreeItem{
562			Key: "foo",
563			Value: TreeBranch{
564				TreeItem{
565					Key: "bar",
566					Value: TreeBranch{
567						TreeItem{
568							Key:   "baz",
569							Value: "foobar",
570						},
571					},
572				},
573			},
574		},
575	}
576	set := branch.Set([]interface{}{"foo", "bar", "foo"}, "hello")
577	assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[1].Value)
578}
579
580func TestSetArrayDeepNew(t *testing.T) {
581	branch := TreeBranch{
582		TreeItem{
583			Key: "foo",
584			Value: []interface{}{
585				"one",
586				"two",
587			},
588		},
589	}
590	set := branch.Set([]interface{}{"foo", 2, "bar"}, "hello")
591	assert.Equal(t, "hello", set[0].Value.([]interface{})[2].(TreeBranch)[0].Value)
592}
593
594func TestSetNewKeyDeep(t *testing.T) {
595	branch := TreeBranch{
596		TreeItem{
597			Key:   "foo",
598			Value: "bar",
599		},
600	}
601	set := branch.Set([]interface{}{"foo", "bar", "baz"}, "hello")
602	assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[0].Value)
603}
604
605func TestSetNewKeyOnEmptyBranch(t *testing.T) {
606	branch := TreeBranch{}
607	set := branch.Set([]interface{}{"foo", "bar", "baz"}, "hello")
608	assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[0].Value)
609}
610
611func TestSetArray(t *testing.T) {
612	branch := TreeBranch{
613		TreeItem{
614			Key: "foo",
615			Value: []interface{}{
616				"one",
617				"two",
618				"three",
619			},
620		},
621	}
622	set := branch.Set([]interface{}{"foo", 0}, "uno")
623	assert.Equal(t, "uno", set[0].Value.([]interface{})[0])
624}
625
626func TestSetArrayNew(t *testing.T) {
627	branch := TreeBranch{}
628	set := branch.Set([]interface{}{"foo", 0, 0}, "uno")
629	assert.Equal(t, "uno", set[0].Value.([]interface{})[0].([]interface{})[0])
630}
631
632func TestSetExisting(t *testing.T) {
633	branch := TreeBranch{
634		TreeItem{
635			Key:   "foo",
636			Value: "foobar",
637		},
638	}
639	set := branch.Set([]interface{}{"foo"}, "bar")
640	assert.Equal(t, "bar", set[0].Value)
641}
642
643func TestSetArrayLeafNewItem(t *testing.T) {
644	branch := TreeBranch{
645		TreeItem{
646			Key:   "array",
647			Value: []interface{}{},
648		},
649	}
650	set := branch.Set([]interface{}{"array", 2}, "hello")
651	assert.Equal(t, TreeBranch{
652		TreeItem{
653			Key: "array",
654			Value: []interface{}{
655				"hello",
656			},
657		},
658	}, set)
659}
660
661func TestSetArrayNonLeaf(t *testing.T) {
662	branch := TreeBranch{
663		TreeItem{
664			Key: "array",
665			Value: []interface{}{
666				1,
667			},
668		},
669	}
670	set := branch.Set([]interface{}{"array", 0, "hello"}, "hello")
671	assert.Equal(t, TreeBranch{
672		TreeItem{
673			Key: "array",
674			Value: []interface{}{
675				TreeBranch{
676					TreeItem{
677						Key:   "hello",
678						Value: "hello",
679					},
680				},
681			},
682		},
683	}, set)
684}
685
686func TestEmitAsMap(t *testing.T) {
687	expected := map[string]interface{}{
688		"foobar": "barfoo",
689		"number": 42,
690		"foo": map[string]interface{}{
691			"bar": map[string]interface{}{
692				"baz": "foobar",
693			},
694		},
695	}
696	branches := TreeBranches{
697		TreeBranch{
698			TreeItem{
699				Key:   "foobar",
700				Value: "barfoo",
701			},
702			TreeItem{
703				Key:   "number",
704				Value: 42,
705			},
706		},
707		TreeBranch{
708			TreeItem{
709				Key: "foo",
710				Value: TreeBranch{
711					TreeItem{
712						Key: "bar",
713						Value: TreeBranch{
714							TreeItem{
715								Key:   "baz",
716								Value: "foobar",
717							},
718						},
719					},
720				},
721			},
722		},
723	}
724
725	data, err := EmitAsMap(branches)
726
727	if assert.NoError(t, err) {
728		assert.Equal(t, expected, data)
729	}
730}
731