Add DB viewer access logging, account deletion, and forced password change

Logs a distinct db_viewer_accessed event (not just the earlier
session_created "requested" event) when an admin's browser actually
completes the hand-off into Adminer. Adds a password-confirmed
account-deletion box to Settings, relying on the existing ON DELETE
CASCADE foreign keys to clean up everything the account owns. Adds an
admin-only "require password change" flag that get_current_user
enforces server-side (403 on everything except /auth/me,
/auth/change-password, /auth/logout) - meant for handing a demo
account to someone with a known sample password.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-05 23:41:21 -04:00
co-authored by Claude Sonnet 5
parent 3d6fe56991
commit 4ee38b6241
23 changed files with 1056 additions and 7 deletions
+14
View File
@@ -29,6 +29,15 @@ from app.models.user import User
from app.repositories.user_repository import UserRepository
from app.services.auth_service import get_or_create_local_user
# Everything an account with must_change_password=True can still reach -
# just enough to discover the flag (/me), fix it (/change-password), and
# bail out (/logout, which doesn't even route through get_current_user but
# is listed for clarity). Every other endpoint 403s until they change it -
# see app.services.auth_service.require_password_change.
_PASSWORD_CHANGE_EXEMPT_PATHS = frozenset(
{"/api/v1/auth/me", "/api/v1/auth/change-password", "/api/v1/auth/logout"}
)
async def get_current_user(
request: Request,
@@ -58,6 +67,11 @@ async def get_current_user(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired access token",
)
if user.must_change_password and request.url.path not in _PASSWORD_CHANGE_EXEMPT_PATHS:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Password change required",
)
return user