fix: reject empty credential fields with 400 instead of 500

Add an explicit non-empty check before encrypting user-submitted
email/password fields in the create and update user routes, so a
request that bypasses the HTML `required` attribute gets a clean
400 instead of an unhandled ValueError from CredentialCipher.encrypt
propagating as a 500. Applies to all four credential fields on
create, and to the two email fields on update (the password-blank-
means-keep-existing behavior on update is unchanged).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Bastian Wagner
2026-08-15 09:50:05 +02:00
parent b39842fe2c
commit d2ac079870
2 changed files with 128 additions and 6 deletions

View File

@@ -24,6 +24,14 @@ def _cipher(request: Request) -> CredentialCipher:
return CredentialCipher(request.app.state.settings.credential_encryption_key)
def _require_non_empty(value: str, field_name: str) -> None:
if not value.strip():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"{field_name} must not be empty",
)
@router.get("/login", response_class=HTMLResponse)
def login_page(request: Request):
return templates.TemplateResponse(request, "login.html", {"csrf_token": ensure_csrf_token(request)})
@@ -81,14 +89,18 @@ def create_user(
request: Request,
csrf_token: str = Form(...),
name: str = Form(...),
mywhoosh_email: str = Form(...),
mywhoosh_password: str = Form(...),
garmin_email: str = Form(...),
garmin_password: str = Form(...),
mywhoosh_email: str = Form(""),
mywhoosh_password: str = Form(""),
garmin_email: str = Form(""),
garmin_password: str = Form(""),
enabled: str | None = Form(None),
):
require_admin(request)
validate_csrf(request, csrf_token)
_require_non_empty(mywhoosh_email, "mywhoosh_email")
_require_non_empty(mywhoosh_password, "mywhoosh_password")
_require_non_empty(garmin_email, "garmin_email")
_require_non_empty(garmin_password, "garmin_password")
form = UserFormData(
name=name,
mywhoosh_email=mywhoosh_email,
@@ -152,14 +164,16 @@ def update_user(
user_id: int,
csrf_token: str = Form(...),
name: str = Form(...),
mywhoosh_email: str = Form(...),
mywhoosh_email: str = Form(""),
mywhoosh_password: str = Form(""),
garmin_email: str = Form(...),
garmin_email: str = Form(""),
garmin_password: str = Form(""),
enabled: str | None = Form(None),
):
require_admin(request)
validate_csrf(request, csrf_token)
_require_non_empty(mywhoosh_email, "mywhoosh_email")
_require_non_empty(garmin_email, "garmin_email")
form = UserFormData(
name=name,
mywhoosh_email=mywhoosh_email,