diff --git a/spindle/secrets/manager.go b/spindle/secrets/manager.go new file mode 100644 --- /dev/null +++ b/spindle/secrets/manager.go @@ -0,0 +1,63 @@ +package secrets + +import ( + "errors" + "regexp" + "time" + + "github.com/bluesky-social/indigo/atproto/syntax" +) + +type DidSlashRepo string + +type Secret[T any] struct { + Key string + Value T + Repo DidSlashRepo + CreatedAt time.Time + CreatedBy syntax.DID +} + +// the secret is not present +type LockedSecret = Secret[struct{}] + +// the secret is present in plaintext, never expose this publicly, +// only use in the workflow engine +type UnlockedSecret = Secret[string] + +type Manager interface { + AddSecret(secret UnlockedSecret) error + RemoveSecret(secret Secret[any]) error + GetSecretsLocked(repo DidSlashRepo) ([]LockedSecret, error) + GetSecretsUnlocked(repo DidSlashRepo) ([]UnlockedSecret, error) +} + +var ErrKeyAlreadyPresent = errors.New("key already present") +var ErrInvalidKeyIdent = errors.New("key is not a valid identifier") +var ErrKeyNotFound = errors.New("key not found") + +// ensure that we are satisfying the interface +var ( + _ = []Manager{ + &SqliteManager{}, + } +) + +var ( + // bash identifier syntax + keyIdent = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`) +) + +func isValidKey(key string) bool { + if key == "" { + return false + } + return keyIdent.MatchString(key) +} + +func ValidateKey(key string) error { + if !isValidKey(key) { + return ErrInvalidKeyIdent + } + return nil +}