fix(security): add username validation, constant-time login, default credential rejection, and tooling
This commit is contained in:
@@ -7,6 +7,27 @@ from datetime import datetime
|
||||
from pydantic import BaseModel, ConfigDict, EmailStr, field_validator
|
||||
|
||||
|
||||
# ── Username policy ─────────────────────────────────────────────────
|
||||
|
||||
_USERNAME_RE = re.compile(r"^[a-zA-Z0-9_-]{3,50}$")
|
||||
_RESERVED_USERNAMES = frozenset({
|
||||
"admin", "root", "system", "api", "null", "undefined",
|
||||
"administrator", "superuser", "aegis",
|
||||
})
|
||||
|
||||
|
||||
def _validate_username(username: str) -> str:
|
||||
"""Validate username format and reject reserved names."""
|
||||
if not _USERNAME_RE.match(username):
|
||||
raise ValueError(
|
||||
"Username must be 3-50 characters, containing only "
|
||||
"letters, digits, underscores, and hyphens"
|
||||
)
|
||||
if username.lower() in _RESERVED_USERNAMES:
|
||||
raise ValueError(f"Username '{username}' is reserved")
|
||||
return username
|
||||
|
||||
|
||||
# ── Password policy ─────────────────────────────────────────────────
|
||||
|
||||
_MIN_PASSWORD_LENGTH = 12
|
||||
@@ -56,6 +77,11 @@ class UserCreate(BaseModel):
|
||||
password: str
|
||||
role: str = "viewer"
|
||||
|
||||
@field_validator("username")
|
||||
@classmethod
|
||||
def username_format(cls, v: str) -> str:
|
||||
return _validate_username(v)
|
||||
|
||||
@field_validator("password")
|
||||
@classmethod
|
||||
def password_strength(cls, v: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user