initial pase store definitions
This commit is contained in:
parent
fefe08f6f9
commit
b947535795
10 changed files with 723 additions and 0 deletions
245
store/models.go
Normal file
245
store/models.go
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserStatus string
|
||||
|
||||
const (
|
||||
StatusActive UserStatus = "active"
|
||||
StatusDeactivated UserStatus = "deactivated"
|
||||
StatusLocked UserStatus = "locked"
|
||||
StatusBanned UserStatus = "banned"
|
||||
StatusPendingDeletion UserStatus = "pending_deletion"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID string
|
||||
Email string
|
||||
EmailVerifiedAt NullTime
|
||||
Username string
|
||||
UsernameNormalized string
|
||||
DisplayName string
|
||||
ProfileImageURL string
|
||||
|
||||
Status UserStatus
|
||||
StatusReason string
|
||||
StatusChangedAt NullTime
|
||||
StatusExpiresAt NullTime
|
||||
|
||||
FailedLoginCount int
|
||||
LastFailedLoginAt NullTime
|
||||
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
ID string
|
||||
Name string
|
||||
Description NullString
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
ID string
|
||||
Name string
|
||||
Description NullString
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type RolePermission struct {
|
||||
RoleID string
|
||||
PermissionID string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type PermissionEffect string
|
||||
|
||||
const (
|
||||
PermissionAllow PermissionEffect = "allow"
|
||||
PermissionDeny PermissionEffect = "deny"
|
||||
)
|
||||
|
||||
type UserPermission struct {
|
||||
UserID string
|
||||
PermissionID string
|
||||
Effect PermissionEffect
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
IDHash string
|
||||
UserID string
|
||||
ExpiresAt time.Time
|
||||
LastUsedAt time.Time
|
||||
UserAgent NullString
|
||||
IPAddress NullString
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type TokenPurpose string
|
||||
|
||||
const (
|
||||
TokenPurposeMagicLink TokenPurpose = "magic_link"
|
||||
TokenPurposePasswordReset TokenPurpose = "password_reset"
|
||||
TokenPurposeEmailVerify TokenPurpose = "email_verify"
|
||||
TokenPurposeEmailChange TokenPurpose = "email_change"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
ID string
|
||||
UserID string
|
||||
Purpose TokenPurpose
|
||||
HashedValue string
|
||||
Payload JSONB
|
||||
ExpiresAt time.Time
|
||||
ConsumedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type CredentialType string
|
||||
|
||||
const (
|
||||
CredentialPassword CredentialType = "password"
|
||||
CredentialPasskey CredentialType = "passkey"
|
||||
CredentialTOTP CredentialType = "totp"
|
||||
CredentialOAuth CredentialType = "oauth"
|
||||
)
|
||||
|
||||
type Credential struct {
|
||||
ID string
|
||||
UserID string
|
||||
Type CredentialType
|
||||
|
||||
// Used by passkeys (credential ID) and OAuth (provider account id).
|
||||
// Null for password and TOTP.
|
||||
Identifier NullString
|
||||
|
||||
// Used by OAuth: "google", "github", etc. Null otherwise.
|
||||
Provider NullString
|
||||
|
||||
// The actual secret material. Format depends on type:
|
||||
// password: argon2id hash string
|
||||
// passkey: COSE public key (base64)
|
||||
// totp: encrypted shared secret
|
||||
// oauth: null (tokens go in `data`)
|
||||
Secret NullString
|
||||
|
||||
// Type-specific fields that don't fit elsewhere:
|
||||
// passkey: { sign_count, transports, aaguid, backup_eligible }
|
||||
// totp: { algorithm, digits, period }
|
||||
// oauth: { access_token, refresh_token, expires_at, scope }
|
||||
Data JSONB
|
||||
|
||||
// Human-friendly label, useful for UI ("My iPhone", "YubiKey 5C").
|
||||
// Especially valuable for passkeys where users have multiple.
|
||||
Name NullString
|
||||
|
||||
LastUsedAt time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type PasskeyData struct {
|
||||
SignCount uint32 `json:"sign_count"`
|
||||
Transports []string `json:"transports"`
|
||||
AAGUID string `json:"aaguid"`
|
||||
BackupEligible bool `json:"backup_eligible"`
|
||||
}
|
||||
|
||||
type OAuthData struct {
|
||||
AccessToken string `json:"access_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
type TOTPData struct {
|
||||
Algorithm string `json:"algorithm"`
|
||||
Digits int `json:"digits"`
|
||||
Period int `json:"period"`
|
||||
}
|
||||
|
||||
func (c *Credential) PasskeyData() (*PasskeyData, error) {
|
||||
if c.Type != CredentialPasskey {
|
||||
return nil, fmt.Errorf("pase: credential is %s, not passkey", c.Type)
|
||||
}
|
||||
if len(c.Data) == 0 {
|
||||
return &PasskeyData{}, nil
|
||||
}
|
||||
var d PasskeyData
|
||||
if err := json.Unmarshal(c.Data, &d); err != nil {
|
||||
return nil, fmt.Errorf("pase: decode passkey data: %w", err)
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (c *Credential) SetPasskeyData(d *PasskeyData) error {
|
||||
if c.Type != CredentialPasskey {
|
||||
return fmt.Errorf("pase: credential is %s, not passkey", c.Type)
|
||||
}
|
||||
b, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pase: %w", err)
|
||||
}
|
||||
c.Data = b
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Credential) OAuthData() (*OAuthData, error) {
|
||||
if c.Type != CredentialOAuth {
|
||||
return nil, fmt.Errorf("pase: credential is %s, not oauth", c.Type)
|
||||
}
|
||||
if len(c.Data) == 0 {
|
||||
return &OAuthData{}, nil
|
||||
}
|
||||
var d OAuthData
|
||||
if err := json.Unmarshal(c.Data, &d); err != nil {
|
||||
return nil, fmt.Errorf("pase: decode oauth data: %w", err)
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (c *Credential) SetOAuthData(d *OAuthData) error {
|
||||
if c.Type != CredentialOAuth {
|
||||
return fmt.Errorf("pase: credential is %s, not oauth", c.Type)
|
||||
}
|
||||
b, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pase: %w", err)
|
||||
}
|
||||
c.Data = b
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Credential) TOTPData() (*TOTPData, error) {
|
||||
if c.Type != CredentialTOTP {
|
||||
return nil, fmt.Errorf("pase: credential is %s, not totp", c.Type)
|
||||
}
|
||||
if len(c.Data) == 0 {
|
||||
return &TOTPData{}, nil
|
||||
}
|
||||
var d TOTPData
|
||||
if err := json.Unmarshal(c.Data, &d); err != nil {
|
||||
return nil, fmt.Errorf("pase: decode totp data: %w", err)
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (c *Credential) SetTOTPData(d *TOTPData) error {
|
||||
if c.Type != CredentialTOTP {
|
||||
return fmt.Errorf("pase: credential is %s, not totp", c.Type)
|
||||
}
|
||||
b, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pase: %w", err)
|
||||
}
|
||||
c.Data = b
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue