[split-required] [guardrail-change] Enforce 500 LOC budget across all services
Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook) and split all 44 files exceeding 500 LOC into domain-focused modules: - consent-service (Go): models, handlers, services, database splits - backend-core (Python): security_api, rbac_api, pdf_service, auth splits - admin-core (TypeScript): 5 page.tsx + sidebar extractions - pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits - voice-service (Python): enhanced_task_orchestrator split Result: 0 violations, 36 exempted (pipeline, tests, pure-data files). Go build verified clean. No behavior changes — pure structural splits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
195
consent-service/internal/models/user.go
Normal file
195
consent-service/internal/models/user.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// User represents a user with full authentication support
|
||||
type User struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
ExternalID *string `json:"external_id,omitempty" db:"external_id"`
|
||||
Email string `json:"email" db:"email"`
|
||||
PasswordHash *string `json:"-" db:"password_hash"` // Never exposed in JSON
|
||||
Name *string `json:"name,omitempty" db:"name"`
|
||||
Role string `json:"role" db:"role"` // 'user', 'admin', 'super_admin', 'data_protection_officer'
|
||||
EmailVerified bool `json:"email_verified" db:"email_verified"`
|
||||
EmailVerifiedAt *time.Time `json:"email_verified_at,omitempty" db:"email_verified_at"`
|
||||
AccountStatus string `json:"account_status" db:"account_status"` // 'active', 'suspended', 'locked'
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty" db:"last_login_at"`
|
||||
FailedLoginAttempts int `json:"failed_login_attempts" db:"failed_login_attempts"`
|
||||
LockedUntil *time.Time `json:"locked_until,omitempty" db:"locked_until"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// EmailVerificationToken for email verification
|
||||
type EmailVerificationToken struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Token string `json:"token" db:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
||||
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// PasswordResetToken for password reset
|
||||
type PasswordResetToken struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Token string `json:"token" db:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
||||
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
||||
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// UserSession for session management
|
||||
type UserSession struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
TokenHash string `json:"-" db:"token_hash"`
|
||||
DeviceInfo *string `json:"device_info,omitempty" db:"device_info"`
|
||||
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
||||
UserAgent *string `json:"user_agent,omitempty" db:"user_agent"`
|
||||
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
||||
RevokedAt *time.Time `json:"revoked_at,omitempty" db:"revoked_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
LastActivityAt time.Time `json:"last_activity_at" db:"last_activity_at"`
|
||||
}
|
||||
|
||||
// RegisterRequest for user registration
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required,min=8"`
|
||||
Name *string `json:"name"`
|
||||
}
|
||||
|
||||
// LoginRequest for user login
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
// LoginResponse after successful login
|
||||
type LoginResponse struct {
|
||||
User User `json:"user"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn int `json:"expires_in"` // seconds
|
||||
}
|
||||
|
||||
// RefreshTokenRequest for token refresh
|
||||
type RefreshTokenRequest struct {
|
||||
RefreshToken string `json:"refresh_token" binding:"required"`
|
||||
}
|
||||
|
||||
// VerifyEmailRequest for email verification
|
||||
type VerifyEmailRequest struct {
|
||||
Token string `json:"token" binding:"required"`
|
||||
}
|
||||
|
||||
// ForgotPasswordRequest for password reset request
|
||||
type ForgotPasswordRequest struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
}
|
||||
|
||||
// ResetPasswordRequest for password reset
|
||||
type ResetPasswordRequest struct {
|
||||
Token string `json:"token" binding:"required"`
|
||||
NewPassword string `json:"new_password" binding:"required,min=8"`
|
||||
}
|
||||
|
||||
// ChangePasswordRequest for changing password
|
||||
type ChangePasswordRequest struct {
|
||||
CurrentPassword string `json:"current_password" binding:"required"`
|
||||
NewPassword string `json:"new_password" binding:"required,min=8"`
|
||||
}
|
||||
|
||||
// UpdateProfileRequest for profile updates
|
||||
type UpdateProfileRequest struct {
|
||||
Name *string `json:"name"`
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Two-Factor Authentication (2FA/TOTP)
|
||||
// ========================================
|
||||
|
||||
// UserTOTP stores 2FA TOTP configuration for a user
|
||||
type UserTOTP struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
Secret string `json:"-" db:"secret"` // Encrypted TOTP secret
|
||||
Verified bool `json:"verified" db:"verified"` // Has 2FA been verified/activated
|
||||
RecoveryCodes []string `json:"-" db:"recovery_codes"` // Encrypted backup codes
|
||||
EnabledAt *time.Time `json:"enabled_at,omitempty" db:"enabled_at"`
|
||||
LastUsedAt *time.Time `json:"last_used_at,omitempty" db:"last_used_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// TwoFactorChallenge represents a pending 2FA challenge during login
|
||||
type TwoFactorChallenge struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
||||
ChallengeID string `json:"challenge_id" db:"challenge_id"` // Temporary token
|
||||
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
||||
UserAgent *string `json:"user_agent,omitempty" db:"user_agent"`
|
||||
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
||||
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
}
|
||||
|
||||
// Setup2FAResponse when initiating 2FA setup
|
||||
type Setup2FAResponse struct {
|
||||
Secret string `json:"secret"` // Base32 encoded secret for manual entry
|
||||
QRCodeDataURL string `json:"qr_code"` // Data URL for QR code image
|
||||
RecoveryCodes []string `json:"recovery_codes"` // One-time backup codes
|
||||
}
|
||||
|
||||
// Verify2FARequest for verifying 2FA setup or login
|
||||
type Verify2FARequest struct {
|
||||
Code string `json:"code" binding:"required"` // 6-digit TOTP code
|
||||
ChallengeID string `json:"challenge_id,omitempty"` // For login flow
|
||||
}
|
||||
|
||||
// TwoFactorLoginResponse when 2FA is required during login
|
||||
type TwoFactorLoginResponse struct {
|
||||
RequiresTwoFactor bool `json:"requires_two_factor"`
|
||||
ChallengeID string `json:"challenge_id"` // Use this to complete 2FA
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Complete2FALoginRequest to complete login with 2FA
|
||||
type Complete2FALoginRequest struct {
|
||||
ChallengeID string `json:"challenge_id" binding:"required"`
|
||||
Code string `json:"code" binding:"required"` // 6-digit TOTP or recovery code
|
||||
}
|
||||
|
||||
// Disable2FARequest for disabling 2FA
|
||||
type Disable2FARequest struct {
|
||||
Password string `json:"password" binding:"required"` // Require password confirmation
|
||||
Code string `json:"code" binding:"required"` // Current TOTP code
|
||||
}
|
||||
|
||||
// RecoveryCodeUseRequest for using a recovery code
|
||||
type RecoveryCodeUseRequest struct {
|
||||
ChallengeID string `json:"challenge_id" binding:"required"`
|
||||
RecoveryCode string `json:"recovery_code" binding:"required"`
|
||||
}
|
||||
|
||||
// TwoFactorStatusResponse for checking 2FA status
|
||||
type TwoFactorStatusResponse struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Verified bool `json:"verified"`
|
||||
EnabledAt *time.Time `json:"enabled_at,omitempty"`
|
||||
RecoveryCodesCount int `json:"recovery_codes_count"`
|
||||
}
|
||||
|
||||
// Verify2FAChallengeRequest for verifying a 2FA challenge during login
|
||||
type Verify2FAChallengeRequest struct {
|
||||
ChallengeID string `json:"challenge_id" binding:"required"`
|
||||
Code string `json:"code,omitempty"` // 6-digit TOTP code
|
||||
RecoveryCode string `json:"recovery_code,omitempty"` // Alternative: recovery code
|
||||
}
|
||||
Reference in New Issue
Block a user