73 lines
1.9 KiB
Go
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
|
|
}
|