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
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
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}
|
||||
Reference in New Issue
Block a user