This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/crypto/resolver.go
2026-02-24 10:44:12 +00:00

73 lines
1.9 KiB
Go

package crypto
// KeyResolver decrypts API keys using the appropriate tier:
// - global/team → env-derived key
// - personal → user's UEK from cache
type KeyResolver struct {
envKey []byte // derived from ENCRYPTION_KEY
uekCache *UEKCache
}
// NewKeyResolver creates a resolver. envKey may be nil if ENCRYPTION_KEY is
// not set (fresh install with no providers — decryption will fail gracefully).
func NewKeyResolver(envKey []byte, cache *UEKCache) *KeyResolver {
return &KeyResolver{envKey: envKey, uekCache: cache}
}
// Decrypt resolves an API key given its encrypted form, nonce, scope, and
// the requesting user's ID (needed for personal-scope keys).
func (r *KeyResolver) Decrypt(ciphertext, nonce []byte, keyScope, userID string) (string, error) {
if len(ciphertext) == 0 {
return "", nil // No key stored
}
switch keyScope {
case "global", "team":
if r.envKey == nil {
return "", ErrNoEncryptionKey
}
return Decrypt(ciphertext, nonce, r.envKey)
case "personal":
uek, ok := r.uekCache.Load(userID)
if !ok {
return "", ErrVaultLocked
}
return Decrypt(ciphertext, nonce, uek)
default:
// Fallback: try env key (covers pre-migration or unknown scopes)
if r.envKey == nil {
return "", ErrNoEncryptionKey
}
return Decrypt(ciphertext, nonce, r.envKey)
}
}
// EncryptForScope encrypts an API key with the appropriate key for the scope.
func (r *KeyResolver) EncryptForScope(plaintext, keyScope, userID string) ([]byte, []byte, error) {
if plaintext == "" {
return nil, nil, nil
}
switch keyScope {
case "personal":
uek, ok := r.uekCache.Load(userID)
if !ok {
return nil, nil, ErrVaultLocked
}
return Encrypt(plaintext, uek)
default: // global, team
if r.envKey == nil {
return nil, nil, ErrNoEncryptionKey
}
return Encrypt(plaintext, r.envKey)
}
}
// HasEnvKey returns true if the platform encryption key is available.
func (r *KeyResolver) HasEnvKey() bool {
return r.envKey != nil
}