Skip to content

Commit b2fb2ff

Browse files
committed
store: feat encrypted filestore
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
1 parent 5274eb9 commit b2fb2ff

File tree

103 files changed

+18384
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+18384
-0
lines changed

store/filestore/filestore.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package filestore
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/base64"
7+
"encoding/json"
8+
"io"
9+
"os"
10+
"time"
11+
12+
"filippo.io/age"
13+
14+
"github.com/docker/secrets-engine/store"
15+
)
16+
17+
type fileStore struct {
18+
filesystem *os.Root
19+
masterKey string
20+
}
21+
22+
var _ store.Store = &fileStore{}
23+
24+
type keyStore map[string]string
25+
26+
type file struct {
27+
id store.ID
28+
metadata map[string]string
29+
encryptedSecret []byte
30+
}
31+
32+
func getFile(id store.ID, filesystem *os.Root) (*file, error) {
33+
fileName := base64.StdEncoding.EncodeToString([]byte(id.String()))
34+
metadataFileName := "metadata-" + fileName
35+
metadataStore, err := filesystem.Open(metadataFileName)
36+
if err != nil {
37+
return nil, err
38+
}
39+
defer metadataStore.Close()
40+
41+
fileStore, err := filesystem.Open(fileName)
42+
if err != nil {
43+
return nil, err
44+
}
45+
defer fileStore.Close()
46+
47+
var metadata map[string]string
48+
b, err := io.ReadAll(metadataStore)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
if err := json.Unmarshal(b, &metadata); err != nil {
54+
return nil, err
55+
}
56+
57+
encryptedSecret, err := io.ReadAll(fileStore)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
return &file{
63+
metadata: metadata,
64+
encryptedSecret: encryptedSecret,
65+
id: id,
66+
}, nil
67+
}
68+
69+
func saveFile(f file, filesystem *os.Root) error {
70+
fileName := base64.StdEncoding.EncodeToString([]byte(f.id.String()))
71+
metadataFileName := "metadata-" + fileName
72+
metadataStore, err := filesystem.Open(metadataFileName)
73+
if err != nil {
74+
return err
75+
}
76+
defer metadataStore.Close()
77+
metadataStore.SetWriteDeadline(time.Now().Add(time.Second * 60))
78+
79+
fileStore, err := filesystem.Open(fileName)
80+
if err != nil {
81+
return err
82+
}
83+
defer fileStore.Close()
84+
fileStore.SetWriteDeadline(time.Now().Add(time.Second * 60))
85+
86+
enc := json.NewEncoder(metadataStore)
87+
if err := enc.Encode(f.metadata); err != nil {
88+
return err
89+
}
90+
if err := fileStore.Truncate(0); err != nil {
91+
return err
92+
}
93+
if _, err = fileStore.Write(f.encryptedSecret); err != nil {
94+
return err
95+
}
96+
return nil
97+
}
98+
99+
func (f *fileStore) Delete(ctx context.Context, id store.ID) error {
100+
panic("unimplemented")
101+
}
102+
103+
func (f *fileStore) Filter(ctx context.Context, pattern store.Pattern) (map[string]store.Secret, error) {
104+
panic("unimplemented")
105+
}
106+
107+
func (f *fileStore) Get(ctx context.Context, id store.ID) (store.Secret, error) {
108+
panic("unimplemented")
109+
}
110+
111+
func (f *fileStore) GetAllMetadata(ctx context.Context) (map[string]store.Secret, error) {
112+
panic("unimplemented")
113+
}
114+
115+
func (f *fileStore) Save(ctx context.Context, id store.ID, secret store.Secret) error {
116+
var err error
117+
118+
val, err := secret.Marshal()
119+
if err != nil {
120+
return err
121+
}
122+
metadata := secret.Metadata()
123+
124+
recipient, err := age.NewScryptRecipient(f.masterKey)
125+
if err != nil {
126+
return err
127+
}
128+
129+
var encryptedSecret bytes.Buffer
130+
w, err := age.Encrypt(&encryptedSecret, recipient)
131+
if err != nil {
132+
return err
133+
}
134+
if err := w.Close(); err != nil {
135+
return err
136+
}
137+
138+
if _, err := w.Write(val); err != nil {
139+
return err
140+
}
141+
142+
return saveFile(file{
143+
id: id,
144+
encryptedSecret: encryptedSecret.Bytes(),
145+
metadata: metadata,
146+
}, f.filesystem)
147+
}
148+
149+
func NewFileStore(rootDir *os.Root, masterKey string) (store.Store, error) {
150+
return &fileStore{
151+
masterKey: masterKey,
152+
filesystem: rootDir,
153+
}, nil
154+
}

store/filestore/filestore_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package filestore
2+
3+
import "testing"
4+
5+
func TestFilestore(t *testing.T) {
6+
tests := []struct {
7+
desc string
8+
}{
9+
{
10+
desc: "will create a store if there is none",
11+
},
12+
}
13+
for _, tc := range tests {
14+
t.Run(tc.desc, func(t *testing.T) {})
15+
}
16+
}

store/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ go 1.24.3
88
replace github.com/docker/secrets-engine => ../
99

1010
require (
11+
filippo.io/age v1.2.1
1112
github.com/Benehiko/go-keychain/v2 v2.0.0
1213
github.com/danieljoos/wincred v1.2.2
1314
github.com/docker/secrets-engine v0.0.7

store/go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805 h1:u2qwJeEvnypw+OCPUHmoZE3IqwfuN5kgDfo5MLzpNM0=
2+
c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805/go.mod h1:FomMrUJ2Lxt5jCLmZkG3FHa72zUprnhd3v/Z18Snm4w=
3+
filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o=
4+
filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004=
15
github.com/Benehiko/go-keychain/v2 v2.0.0 h1:1savOWp6On9jC+QIBbk8qYZpaqFNF0HwL02aqgRSaro=
26
github.com/Benehiko/go-keychain/v2 v2.0.0/go.mod h1:Qs/Ke0XjDSN07acDqQ89qXyE/mVGmIqB1qpsyu+Th0Q=
37
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=

vendor/filippo.io/age/.gitattributes

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/filippo.io/age/AUTHORS

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/filippo.io/age/LICENSE

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)