7a17e3babd
Subsonic auth (t=md5(password+salt), legacy p=) needs a recoverable secret, but login passwords are stored as a one-way argon2 hash. Add a separate, per-user app-password: high-entropy, random, and encrypted at rest with a Fernet key derived from SUBSONIC_SECRET_KEY (never stored in the DB). - SubsonicPasswordCipher + generate_subsonic_password in core.security - users.subsonic_password_enc column (+ Alembic migration), repo + port methods - SubsonicAuthService: verify (t+s / p / p=enc:) and rotate/reveal lifecycle - self-service GET/POST /users/me/subsonic-password + admin rotate endpoint - domain SubsonicCredentials + SubsonicCipher port; deps wiring Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
"""User entity.
|
|
|
|
Admin is a single ``is_superuser`` flag — no role system in Phase 1 (kept
|
|
deliberately minimal; granular permissions are deferred, see plan §3.5).
|
|
``User`` is the outward-facing entity and never carries the password hash;
|
|
the hash lives on :class:`Credentials`, used only inside the auth service.
|
|
"""
|
|
|
|
import datetime as dt
|
|
import uuid
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class User:
|
|
"""A person with access to the instance. The password hash is intentionally
|
|
absent — see :class:`Credentials`."""
|
|
|
|
id: uuid.UUID
|
|
username: str
|
|
is_superuser: bool
|
|
is_active: bool
|
|
created_at: dt.datetime
|
|
updated_at: dt.datetime
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Credentials:
|
|
"""A user paired with their stored password hash. Stays inside the
|
|
application layer — never serialized to clients."""
|
|
|
|
user: User
|
|
password_hash: str
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SubsonicCredentials:
|
|
"""A user paired with their *encrypted* Subsonic app-password.
|
|
|
|
``password_enc`` is ``None`` until the user generates one. Stays inside the
|
|
application layer; the plaintext is only recovered for auth verification."""
|
|
|
|
user: User
|
|
password_enc: str | None
|