feat(domain): add authentication types and token structures
Add core domain types for registry authentication: - AuthType enum (password, token) - Token and TokenClaims structures for JWT handling - SecretsBackend enum (pass, sops, unsafe) - Authentication error types (ErrInvalidToken, ErrRevokedToken, etc.)
- commit
- d69187a1c284c40a23a38193aa64da71afe46dfe
- author
- brice · · 2026-01-12 17:54 UTC
- committer
- brice · · 2026-01-12 19:05 UTC
- parent
- 00198fe
- signature
- unsigned
2 files · +61 -0
A internal/domain/auth.go +54 -0
| @@ -0,0 +1,54 @@ | |||
| 1 | + | // Package domain contains pure business types without external dependencies. | |
| 2 | + | package domain | |
| 3 | + | ||
| 4 | + | import "time" | |
| 5 | + | ||
| 6 | + | // AuthType represents the type of authentication configured for the registry. | |
| 7 | + | type AuthType string | |
| 8 | + | ||
| 9 | + | const ( | |
| 10 | + | // AuthTypePassword uses bcrypt-hashed password authentication. | |
| 11 | + | AuthTypePassword AuthType = "password" | |
| 12 | + | // AuthTypeToken uses JWT token-based authentication. | |
| 13 | + | AuthTypeToken AuthType = "token" | |
| 14 | + | ) | |
| 15 | + | ||
| 16 | + | // Token represents a generated authentication token stored in the secrets backend. | |
| 17 | + | type Token struct { | |
| 18 | + | ID string | |
| 19 | + | Subject string | |
| 20 | + | Scopes []string | |
| 21 | + | IssuedAt time.Time | |
| 22 | + | ExpiresAt time.Time // Zero value means never expires | |
| 23 | + | Revoked bool | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | // TokenClaims represents the JWT claims for a token. | |
| 27 | + | type TokenClaims struct { | |
| 28 | + | ID string `json:"jti"` | |
| 29 | + | Subject string `json:"sub"` | |
| 30 | + | Scopes []string `json:"scopes"` | |
| 31 | + | IssuedAt int64 `json:"iat"` | |
| 32 | + | ExpiresAt int64 `json:"exp,omitempty"` // 0 means never expires | |
| 33 | + | Issuer string `json:"iss"` | |
| 34 | + | } | |
| 35 | + | ||
| 36 | + | // IsExpired checks if the token has expired. | |
| 37 | + | func (t *Token) IsExpired() bool { | |
| 38 | + | if t.ExpiresAt.IsZero() { | |
| 39 | + | return false // Never expires | |
| 40 | + | } | |
| 41 | + | return time.Now().After(t.ExpiresAt) | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // SecretsBackend represents the type of secrets storage backend. | |
| 45 | + | type SecretsBackend string | |
| 46 | + | ||
| 47 | + | const ( | |
| 48 | + | // SecretsBackendPass uses the pass password manager. | |
| 49 | + | SecretsBackendPass SecretsBackend = "pass" | |
| 50 | + | // SecretsBackendSops uses SOPS for encrypted secrets. | |
| 51 | + | SecretsBackendSops SecretsBackend = "sops" | |
| 52 | + | // SecretsBackendUnsafe stores secrets in plain text (development only). | |
| 53 | + | SecretsBackendUnsafe SecretsBackend = "unsafe" | |
| 54 | + | ) | |
| @@ -0,0 +1,54 @@ | |||||
| 1 | + | // Package domain contains pure business types without external dependencies. | |||
| 2 | + | package domain | |||
| 3 | + | ||||
| 4 | + | import "time" | |||
| 5 | + | ||||
| 6 | + | // AuthType represents the type of authentication configured for the registry. | |||
| 7 | + | type AuthType string | |||
| 8 | + | ||||
| 9 | + | const ( | |||
| 10 | + | // AuthTypePassword uses bcrypt-hashed password authentication. | |||
| 11 | + | AuthTypePassword AuthType = "password" | |||
| 12 | + | // AuthTypeToken uses JWT token-based authentication. | |||
| 13 | + | AuthTypeToken AuthType = "token" | |||
| 14 | + | ) | |||
| 15 | + | ||||
| 16 | + | // Token represents a generated authentication token stored in the secrets backend. | |||
| 17 | + | type Token struct { | |||
| 18 | + | ID string | |||
| 19 | + | Subject string | |||
| 20 | + | Scopes []string | |||
| 21 | + | IssuedAt time.Time | |||
| 22 | + | ExpiresAt time.Time // Zero value means never expires | |||
| 23 | + | Revoked bool | |||
| 24 | + | } | |||
| 25 | + | ||||
| 26 | + | // TokenClaims represents the JWT claims for a token. | |||
| 27 | + | type TokenClaims struct { | |||
| 28 | + | ID string `json:"jti"` | |||
| 29 | + | Subject string `json:"sub"` | |||
| 30 | + | Scopes []string `json:"scopes"` | |||
| 31 | + | IssuedAt int64 `json:"iat"` | |||
| 32 | + | ExpiresAt int64 `json:"exp,omitempty"` // 0 means never expires | |||
| 33 | + | Issuer string `json:"iss"` | |||
| 34 | + | } | |||
| 35 | + | ||||
| 36 | + | // IsExpired checks if the token has expired. | |||
| 37 | + | func (t *Token) IsExpired() bool { | |||
| 38 | + | if t.ExpiresAt.IsZero() { | |||
| 39 | + | return false // Never expires | |||
| 40 | + | } | |||
| 41 | + | return time.Now().After(t.ExpiresAt) | |||
| 42 | + | } | |||
| 43 | + | ||||
| 44 | + | // SecretsBackend represents the type of secrets storage backend. | |||
| 45 | + | type SecretsBackend string | |||
| 46 | + | ||||
| 47 | + | const ( | |||
| 48 | + | // SecretsBackendPass uses the pass password manager. | |||
| 49 | + | SecretsBackendPass SecretsBackend = "pass" | |||
| 50 | + | // SecretsBackendSops uses SOPS for encrypted secrets. | |||
| 51 | + | SecretsBackendSops SecretsBackend = "sops" | |||
| 52 | + | // SecretsBackendUnsafe stores secrets in plain text (development only). | |||
| 53 | + | SecretsBackendUnsafe SecretsBackend = "unsafe" | |||
| 54 | + | ) | |||
M internal/domain/errors.go +7 -0
| @@ -47,4 +47,11 @@ var ( | |||
| 47 | 47 | ErrEnvFileNotFound = errors.New("environment file not found") | |
| 48 | 48 | ErrSecretNotFound = errors.New("secret not found") | |
| 49 | 49 | ErrProviderNotFound = errors.New("secret provider not found") | |
| 50 | + | ||
| 51 | + | // Authentication errors | |
| 52 | + | ErrInvalidToken = errors.New("invalid token") | |
| 53 | + | ErrExpiredToken = errors.New("token has expired") | |
| 54 | + | ErrRevokedToken = errors.New("token has been revoked") | |
| 55 | + | ErrInvalidCredentials = errors.New("invalid credentials") | |
| 56 | + | ErrTokenNotFound = errors.New("token not found") | |
| 50 | 57 | ) | |
| @@ -47,4 +47,11 @@ var ( | |||||
| 47 | ErrEnvFileNotFound = errors.New("environment file not found") | 47 | ErrEnvFileNotFound = errors.New("environment file not found") | ||
| 48 | ErrSecretNotFound = errors.New("secret not found") | 48 | ErrSecretNotFound = errors.New("secret not found") | ||
| 49 | ErrProviderNotFound = errors.New("secret provider not found") | 49 | ErrProviderNotFound = errors.New("secret provider not found") | ||
| 50 | + | ||||
| 51 | + | // Authentication errors | |||
| 52 | + | ErrInvalidToken = errors.New("invalid token") | |||
| 53 | + | ErrExpiredToken = errors.New("token has expired") | |||
| 54 | + | ErrRevokedToken = errors.New("token has been revoked") | |||
| 55 | + | ErrInvalidCredentials = errors.New("invalid credentials") | |||
| 56 | + | ErrTokenNotFound = errors.New("token not found") | |||
| 50 | ) | 57 | ) | ||