Files
boc/iom/quixzoom-auth-service/models/device.py
T
Bernt 6989a98d75 feat: Passwordless cross-device authentication
- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
2026-07-07 07:11:50 +00:00

101 lines
3.2 KiB
Python

"""
Device model for passwordless authentication
Represents a registered mobile device (app)
"""
from datetime import datetime
from typing import Optional
from enum import Enum
from pydantic import BaseModel, Field
import uuid
class DevicePlatform(str, Enum):
"""Supported device platforms"""
IOS = "ios"
ANDROID = "android"
WEB = "web"
OTHER = "other"
class DeviceStatus(str, Enum):
"""Device status"""
ACTIVE = "active"
REVOKED = "revoked"
SUSPENDED = "suspended"
class Device(BaseModel):
"""Device database model"""
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
user_id: str = Field(..., description="Associated user ID")
device_name: str = Field(..., description="Human-readable device name")
platform: DevicePlatform = Field(..., description="Device platform")
# Device fingerprinting
public_key: str = Field(..., description="Device public key for challenge signing")
device_fingerprint: str = Field(..., description="Unique device fingerprint hash")
# Metadata
push_token: Optional[str] = Field(None, description="Push notification token")
last_ip: Optional[str] = Field(None, description="Last known IP address")
last_user_agent: Optional[str] = Field(None, description="Last user agent")
# Status
status: DeviceStatus = Field(default=DeviceStatus.ACTIVE)
# Timestamps
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
last_used_at: Optional[datetime] = Field(None)
class Config:
json_schema_extra = {
"example": {
"id": "dev_123456789",
"user_id": "user_abc123",
"device_name": "iPhone 15 Pro",
"platform": "ios",
"public_key": "-----BEGIN PUBLIC KEY-----\n...",
"device_fingerprint": "sha256:abc123...",
"status": "active",
"created_at": "2024-01-15T10:30:00Z"
}
}
class DeviceCreate(BaseModel):
"""Request model for device registration"""
user_id: str = Field(..., description="User ID to associate with device")
device_name: str = Field(..., min_length=1, max_length=100)
platform: DevicePlatform
public_key: str = Field(..., min_length=100, description="Device public key")
device_fingerprint: str = Field(..., min_length=32, description="Device fingerprint")
push_token: Optional[str] = Field(None, max_length=500)
class DeviceUpdate(BaseModel):
"""Request model for device update"""
device_name: Optional[str] = Field(None, min_length=1, max_length=100)
push_token: Optional[str] = Field(None, max_length=500)
status: Optional[DeviceStatus] = None
class DeviceResponse(BaseModel):
"""Response model for device operations"""
id: str
user_id: str
device_name: str
platform: DevicePlatform
status: DeviceStatus
created_at: datetime
last_used_at: Optional[datetime] = None
class Config:
from_attributes = True
class DeviceListResponse(BaseModel):
"""Response model for listing devices"""
devices: list[DeviceResponse]
total: int