Files
nessi f925009977 chore: initial project setup with backend, frontend, Android app, and CI/CD
Add complete NexaMFA push MFA system with:
- FastAPI backend with PostgreSQL, Redis, OIDC provider, and Prometheus metrics
- React TypeScript admin console
- Android Kotlin/Jetpack Compose app with biometric authentication
- Docker Compose deployment configuration
- Gitea CI workflow for backend, frontend, and Android builds
- Environment configuration template with security settings
- Documentation for security model, deployment
2026-06-28 09:37:51 +02:00

107 lines
2.3 KiB
Python

from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import BaseModel, Field
class UserOut(BaseModel):
id: UUID
username: str
display_name: str | None = None
email: str | None = None
created_at: datetime
model_config = {"from_attributes": True}
class DeviceOut(BaseModel):
id: UUID
user_id: UUID
name: str
platform: str
public_key_alg: str
is_revoked: bool
revoked_at: datetime | None = None
last_seen_at: datetime | None = None
created_at: datetime
model_config = {"from_attributes": True}
class EnrollmentStartRequest(BaseModel):
username: str = Field(min_length=1, max_length=255)
display_name: str | None = None
email: str | None = None
class EnrollmentStartResponse(BaseModel):
enrollment_id: UUID
qr_payload: dict[str, Any]
qr_png_base64: str
expires_at: datetime
class EnrollmentFinishRequest(BaseModel):
enrollment_token: str
device_name: str = Field(min_length=1, max_length=255)
public_key_pem: str
public_key_alg: str = "ES256"
fcm_token: str | None = None
app_version: str | None = None
attestation: dict[str, Any] | None = None
class EnrollmentFinishResponse(BaseModel):
device_id: UUID
user_id: UUID
class ChallengeCreateRequest(BaseModel):
username: str
relying_party: str
requester_ip: str
location: str | None = None
ttl_seconds: int | None = Field(default=None, ge=10, le=300)
oidc_state: str | None = None
class ChallengeOut(BaseModel):
id: UUID
user_id: UUID
device_id: UUID | None
status: str
relying_party: str
requester_ip: str
location: str | None
payload: dict[str, Any]
issued_at: datetime
expires_at: datetime
responded_at: datetime | None
model_config = {"from_attributes": True}
class ChallengeApprovalRequest(BaseModel):
device_id: UUID
signature: str
payload: dict[str, Any]
class DenyRequest(BaseModel):
device_id: UUID | None = None
reason: str | None = Field(default=None, max_length=255)
class AuditOut(BaseModel):
id: UUID
actor: str | None
action: str
target_type: str | None
target_id: str | None
ip_address: str | None
metadata_json: dict[str, Any] | None
created_at: datetime
model_config = {"from_attributes": True}