1package secrets
2
3import (
4 "context"
5 "errors"
6 "regexp"
7 "time"
8
9 "github.com/bluesky-social/indigo/atproto/syntax"
10)
11
12type DidSlashRepo string
13
14type Secret[T any] struct {
15 Key string
16 Value T
17 Repo DidSlashRepo
18 CreatedAt time.Time
19 CreatedBy syntax.DID
20}
21
22// the secret is not present
23type LockedSecret = Secret[struct{}]
24
25// the secret is present in plaintext, never expose this publicly,
26// only use in the workflow engine
27type UnlockedSecret = Secret[string]
28
29type Manager interface {
30 AddSecret(ctx context.Context, secret UnlockedSecret) error
31 RemoveSecret(ctx context.Context, secret Secret[any]) error
32 GetSecretsLocked(ctx context.Context, repo DidSlashRepo) ([]LockedSecret, error)
33 GetSecretsUnlocked(ctx context.Context, repo DidSlashRepo) ([]UnlockedSecret, error)
34}
35
36// stopper interface for managers that need cleanup
37type Stopper interface {
38 Stop()
39}
40
41var ErrKeyAlreadyPresent = errors.New("key already present")
42var ErrInvalidKeyIdent = errors.New("key is not a valid identifier")
43var ErrKeyNotFound = errors.New("key not found")
44
45// ensure that we are satisfying the interface
46var (
47 _ = []Manager{
48 &SqliteManager{},
49 &OpenBaoManager{},
50 }
51)
52
53var (
54 // bash identifier syntax
55 keyIdent = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
56)
57
58func isValidKey(key string) bool {
59 if key == "" {
60 return false
61 }
62 return keyIdent.MatchString(key)
63}
64
65func ValidateKey(key string) error {
66 if !isValidKey(key) {
67 return ErrInvalidKeyIdent
68 }
69 return nil
70}