125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
|
|
AccountProvider = Literal["aws", "cloudflare"]
|
|
|
|
|
|
class AccountCreate(BaseModel):
|
|
provider: AccountProvider
|
|
name: str = Field(min_length=1, max_length=80)
|
|
use_default_aws_credentials: bool = False
|
|
aws_access_key_id: str | None = Field(default=None, max_length=128)
|
|
aws_secret_access_key: str | None = Field(default=None, max_length=256)
|
|
aws_session_token: str | None = Field(default=None, max_length=4096)
|
|
cloudflare_api_token: str | None = Field(default=None, max_length=2048)
|
|
|
|
@field_validator("name")
|
|
@classmethod
|
|
def normalize_name(cls, value: str) -> str:
|
|
normalized = value.strip()
|
|
if not normalized:
|
|
raise ValueError("账号名称不能为空")
|
|
return normalized
|
|
|
|
@field_validator(
|
|
"aws_access_key_id",
|
|
"aws_secret_access_key",
|
|
"aws_session_token",
|
|
"cloudflare_api_token",
|
|
mode="before",
|
|
)
|
|
@classmethod
|
|
def normalize_secret(cls, value: object) -> object:
|
|
if value is None:
|
|
return None
|
|
normalized = str(value).strip()
|
|
return normalized or None
|
|
|
|
@model_validator(mode="after")
|
|
def validate_provider_credentials(self) -> AccountCreate:
|
|
if self.provider == "aws":
|
|
if self.cloudflare_api_token:
|
|
raise ValueError("AWS 账号不能包含 Cloudflare API Token")
|
|
if self.use_default_aws_credentials:
|
|
if self.aws_access_key_id or self.aws_secret_access_key or self.aws_session_token:
|
|
raise ValueError("使用 AWS 默认凭据链时不能同时填写 API 密钥")
|
|
elif not (self.aws_access_key_id and self.aws_secret_access_key):
|
|
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
|
|
else:
|
|
if self.use_default_aws_credentials or any(
|
|
(self.aws_access_key_id, self.aws_secret_access_key, self.aws_session_token)
|
|
):
|
|
raise ValueError("Cloudflare 账号不能包含 AWS 凭据")
|
|
if not self.cloudflare_api_token:
|
|
raise ValueError("Cloudflare API Token 不能为空")
|
|
return self
|
|
|
|
|
|
class AccountUpdate(BaseModel):
|
|
config_version: int = Field(ge=1)
|
|
name: str | None = Field(default=None, min_length=1, max_length=80)
|
|
use_default_aws_credentials: bool | None = None
|
|
aws_access_key_id: str | None = Field(default=None, max_length=128)
|
|
aws_secret_access_key: str | None = Field(default=None, max_length=256)
|
|
aws_session_token: str | None = Field(default=None, max_length=4096)
|
|
cloudflare_api_token: str | None = Field(default=None, max_length=2048)
|
|
|
|
@field_validator("name")
|
|
@classmethod
|
|
def normalize_name(cls, value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
normalized = value.strip()
|
|
if not normalized:
|
|
raise ValueError("账号名称不能为空")
|
|
return normalized
|
|
|
|
@field_validator(
|
|
"aws_access_key_id",
|
|
"aws_secret_access_key",
|
|
"aws_session_token",
|
|
"cloudflare_api_token",
|
|
mode="before",
|
|
)
|
|
@classmethod
|
|
def normalize_secret(cls, value: object) -> object:
|
|
if value is None:
|
|
return None
|
|
normalized = str(value).strip()
|
|
return normalized or None
|
|
|
|
@model_validator(mode="after")
|
|
def validate_update(self) -> AccountUpdate:
|
|
fields = self.model_fields_set
|
|
access_fields = {"aws_access_key_id", "aws_secret_access_key"}
|
|
supplied_access_fields = fields & access_fields
|
|
if supplied_access_fields and supplied_access_fields != access_fields:
|
|
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
|
|
if bool(self.aws_access_key_id) != bool(self.aws_secret_access_key):
|
|
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
|
|
if not fields - {"config_version"}:
|
|
raise ValueError("请至少修改一项账号配置")
|
|
return self
|
|
|
|
|
|
class AccountSecretFlags(BaseModel):
|
|
aws_access_key_id: bool = False
|
|
aws_secret_access_key: bool = False
|
|
aws_session_token: bool = False
|
|
cloudflare_api_token: bool = False
|
|
|
|
|
|
class AccountView(BaseModel):
|
|
id: str
|
|
provider: AccountProvider
|
|
name: str
|
|
use_default_aws_credentials: bool | None
|
|
config_version: int
|
|
secrets_configured: AccountSecretFlags
|
|
created_at: str
|
|
updated_at: str
|
|
archived_at: str | None
|