Files

82 lines
2.4 KiB
Python

from __future__ import annotations
import re
from datetime import datetime
from typing import Annotated, Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, StringConstraints, model_validator
Checksum = Annotated[str, StringConstraints(pattern=r"^sha256:[0-9a-f]{64}$")]
class StrictModel(BaseModel):
model_config = ConfigDict(extra="forbid", strict=True)
class Attachment(StrictModel):
attachment_id: UUID
quarantine_object_key: Annotated[str, StringConstraints(min_length=1, max_length=1024)]
quarantine_version_id: Annotated[str, StringConstraints(min_length=1, max_length=512)]
quarantine_etag: Annotated[str, StringConstraints(min_length=1, max_length=512)]
mime_type: Annotated[str, StringConstraints(min_length=1, max_length=127)]
size_bytes: int = Field(ge=1, le=5_242_880)
checksum: Checksum
@model_validator(mode="after")
def canonical_key(self) -> Attachment:
uuid = r"[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"
pattern = rf"^quarantine/users/{uuid}/dialogs/{uuid}/{uuid}$"
if not self.quarantine_object_key.isascii() or not re.fullmatch(
pattern, self.quarantine_object_key
):
raise ValueError("quarantine_object_key is not canonical")
return self
class TextCheck(StrictModel):
message_id: UUID
content_kind: Literal["text"]
text: Annotated[str, StringConstraints(min_length=1, max_length=10_000)]
attachment: None = None
class FileCheck(StrictModel):
message_id: UUID
content_kind: Literal["file"]
text: Literal[""]
attachment: Attachment
CheckRequest = Annotated[TextCheck | FileCheck, Field(discriminator="content_kind")]
class Verdict(StrictModel):
verdict: Literal["allow", "deny"]
processing_mode: Literal["standard", "mock"]
config_version: int
rule_id: str
rules_version: str
reason_code: Literal["message_blocked"] | None = None
class Pending(StrictModel):
verdict: Literal["pending"] = "pending"
processing_mode: Literal["standard"] = "standard"
config_version: int
task_id: UUID
poll_after_ms: int = 2000
expires_at: datetime
rules_version: str
class ErrorBody(StrictModel):
code: str
message: str
request_id: str
details: dict[str, object] = Field(default_factory=dict)
class ErrorEnvelope(StrictModel):
error: ErrorBody