"""Models for the API.""" import secrets from typing import Annotated, Literal, Self, Union from pydantic import ( AfterValidator, BaseModel, ConfigDict, Field, IPvAnyAddress, IPvAnyNetwork, model_validator, ) from sshecret.crypto import validate_public_key def public_key_validator(value: str) -> str: """Public key validator.""" if validate_public_key(value): return value raise ValueError("Error: Public key must be a valid RSA public key.") class SecretListView(BaseModel): """Model containing a list of all available secrets.""" name: str clients: list[str] = Field(default_factory=list) # Clients that have access to it. class SecretView(BaseModel): """Model containing a secret, including its clear-text value.""" name: str secret: str clients: list[str] = Field(default_factory=list) # Clients that have access to it. class UpdateKeyModel(BaseModel): """Model for updating client public key.""" public_key: Annotated[str, AfterValidator(public_key_validator)] class UpdateKeyResponse(BaseModel): """Response model after updating the public key.""" public_key: str updated_secrets: list[str] = Field(default_factory=list) detail: str | None = None class UpdatePoliciesRequest(BaseModel): """Update policy request.""" sources: list[IPvAnyAddress | IPvAnyNetwork] class ClientCreate(BaseModel): """Model to create a client.""" name: str public_key: Annotated[str, AfterValidator(public_key_validator)] sources: list[IPvAnyAddress | IPvAnyNetwork] = Field(default_factory=list) class AutoGenerateOpts(BaseModel): """Option to auto-generate a password.""" auto_generate: Literal[True] length: int = 32 class SecretUpdate(BaseModel): """Model to update a secret.""" value: str | AutoGenerateOpts = Field( description="Secret as string value or auto-generated with optional length", examples=["MySecretString", {"auto_generate": True, "length": 32}] ) def get_secret(self) -> str: """Get secret. This returns the specified one, or generates one according to auto-generation. """ if isinstance(self.value, str): return self.value secret = secrets.token_urlsafe(self.value.length) return secret class SecretCreate(SecretUpdate): """Model to create a secret.""" name: str clients: list[str] | None = Field(default=None, description="Assign the secret to a list of clients.") model_config: ConfigDict = ConfigDict( json_schema_extra={ "examples": [ { "name": "MySecret", "clients": ["client-1", "client-2"], "value": { "auto_generate": True, "length": 32 } }, { "name": "MySecret", "value": "mysecretstring", } ] } )