package secrets
import (
"context"
"errors"
"regexp"
"time"
"github.com/bluesky-social/indigo/atproto/syntax"
)
type RepoIdentifier string
type Secret[T any] struct {
Key string
Value T
Repo RepoIdentifier
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(ctx context.Context, secret UnlockedSecret) error
RemoveSecret(ctx context.Context, secret Secret[any]) error
RemoveAllSecrets(ctx context.Context, repo RepoIdentifier) error
GetSecretsLocked(ctx context.Context, repo RepoIdentifier) ([]LockedSecret, error)
GetSecretsUnlocked(ctx context.Context, repo RepoIdentifier) ([]UnlockedSecret, error)
}
// stopper interface for managers that need cleanup
type Stopper interface {
Stop()
}
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{},
&OpenBaoManager{},
}
)
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
}