1package leaf
2
3import (
4	"context"
5	"os"
6	"path/filepath"
7	"sort"
8	"strings"
9	"testing"
10
11	"github.com/gopasspw/gopass/internal/backend"
12	"github.com/gopasspw/gopass/pkg/gopass/secrets"
13
14	_ "github.com/gopasspw/gopass/internal/backend/crypto"
15	"github.com/gopasspw/gopass/internal/backend/crypto/plain"
16	_ "github.com/gopasspw/gopass/internal/backend/storage"
17
18	"github.com/stretchr/testify/assert"
19	"github.com/stretchr/testify/require"
20)
21
22func createSubStore(dir string) (*Store, error) {
23	sd := filepath.Join(dir, "sub")
24	_, _, err := createStore(sd, nil, nil)
25	if err != nil {
26		return nil, err
27	}
28
29	if err := os.Setenv("GOPASS_CONFIG", filepath.Join(dir, ".gopass.yml")); err != nil {
30		return nil, err
31	}
32	if err := os.Setenv("GOPASS_HOMEDIR", dir); err != nil {
33		return nil, err
34	}
35	if err := os.Unsetenv("PAGER"); err != nil {
36		return nil, err
37	}
38	if err := os.Setenv("CHECKPOINT_DISABLE", "true"); err != nil {
39		return nil, err
40	}
41	if err := os.Setenv("GOPASS_NO_NOTIFY", "true"); err != nil {
42		return nil, err
43	}
44	if err := os.Setenv("GOPASS_DISABLE_ENCRYPTION", "true"); err != nil {
45		return nil, err
46	}
47
48	gpgDir := filepath.Join(dir, ".gnupg")
49	if err := os.Setenv("GNUPGHOME", gpgDir); err != nil {
50		return nil, err
51	}
52
53	ctx := context.Background()
54	ctx = backend.WithCryptoBackendString(ctx, "plain")
55	ctx = backend.WithStorageBackendString(ctx, "fs")
56	return New(
57		ctx,
58		"",
59		sd,
60	)
61}
62
63func createStore(dir string, recipients, entries []string) ([]string, []string, error) {
64	if recipients == nil {
65		recipients = []string{
66			"0xDEADBEEF",
67			"0xFEEDBEEF",
68		}
69	}
70	if entries == nil {
71		entries = []string{
72			"foo/bar/baz",
73			"baz/ing/a",
74		}
75	}
76	sort.Strings(entries)
77	for _, file := range entries {
78		filename := filepath.Join(dir, file+"."+plain.Ext)
79		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
80			return recipients, entries, err
81		}
82		if err := os.WriteFile(filename, []byte{}, 0644); err != nil {
83			return recipients, entries, err
84		}
85	}
86	err := os.WriteFile(filepath.Join(dir, plain.IDFile), []byte(strings.Join(recipients, "\n")), 0600)
87	return recipients, entries, err
88}
89
90func TestStore(t *testing.T) {
91	tempdir, err := os.MkdirTemp("", "gopass-")
92	require.NoError(t, err)
93	defer func() {
94		_ = os.RemoveAll(tempdir)
95	}()
96
97	s, err := createSubStore(tempdir)
98	require.NoError(t, err)
99
100	if !s.Equals(s) {
101		t.Errorf("Should be equal to myself")
102	}
103}
104
105func TestIdFile(t *testing.T) {
106	ctx := context.Background()
107
108	tempdir, err := os.MkdirTemp("", "gopass-")
109	require.NoError(t, err)
110	defer func() {
111		_ = os.RemoveAll(tempdir)
112	}()
113
114	s, err := createSubStore(tempdir)
115	require.NoError(t, err)
116
117	// test sub-id
118	secName := "a"
119	for i := 0; i < 99; i++ {
120		secName += "/a"
121	}
122	sec := &secrets.Plain{}
123	sec.Set("foo", "bar")
124	sec.WriteString("bar")
125	require.NoError(t, s.Set(ctx, secName, sec))
126	require.NoError(t, os.WriteFile(filepath.Join(tempdir, "sub", "a", plain.IDFile), []byte("foobar"), 0600))
127	assert.Equal(t, filepath.Join("a", plain.IDFile), s.idFile(ctx, secName))
128	assert.True(t, s.Exists(ctx, secName))
129
130	// test abort condition
131	secName = "a"
132	for i := 0; i < 100; i++ {
133		secName += "/a"
134	}
135	require.NoError(t, s.Set(ctx, secName, sec))
136	require.NoError(t, os.WriteFile(filepath.Join(tempdir, "sub", "a", ".gpg-id"), []byte("foobar"), 0600))
137	assert.Equal(t, plain.IDFile, s.idFile(ctx, secName))
138}
139
140func TestNew(t *testing.T) {
141	ctx := context.Background()
142
143	tempdir, err := os.MkdirTemp("", "gopass-")
144	require.NoError(t, err)
145	defer func() {
146		_ = os.RemoveAll(tempdir)
147	}()
148
149	for _, tc := range []struct {
150		dsc string
151		dir string
152		ctx context.Context
153		ok  bool
154	}{
155		{
156			dsc: "Invalid Storage",
157			ctx: backend.WithStorageBackend(ctx, -1),
158			// ok:  false, // TODO clarify
159			ok: true,
160		},
161		{
162			dsc: "GitFS Storage",
163			dir: tempdir,
164			ctx: backend.WithCryptoBackend(backend.WithStorageBackend(ctx, backend.GitFS), backend.Plain),
165			ok:  true,
166		},
167		{
168			dsc: "FS Storage",
169			dir: tempdir,
170			ctx: backend.WithCryptoBackend(backend.WithStorageBackend(ctx, backend.FS), backend.Plain),
171			ok:  true,
172		},
173		{
174			dsc: "GPG Crypto",
175			dir: tempdir,
176			ctx: backend.WithCryptoBackend(ctx, backend.GPGCLI),
177			ok:  true,
178		},
179		{
180			dsc: "Plain Crypto",
181			dir: tempdir,
182			ctx: backend.WithCryptoBackend(ctx, backend.Plain),
183			ok:  true,
184		},
185		{
186			dsc: "Invalid Crypto",
187			dir: tempdir,
188			ctx: backend.WithCryptoBackend(ctx, -1),
189			// ok:  false, // TODO clarify
190			ok: true,
191		},
192	} {
193		s, err := New(tc.ctx, "", tempdir)
194		if tc.ok {
195			assert.NoError(t, err, tc.dsc)
196			assert.NotNil(t, s, tc.dsc)
197		} else {
198			assert.Error(t, err, tc.dsc)
199		}
200	}
201}
202