diff --git a/src/opencmo/web/app.py b/src/opencmo/web/app.py index c3ba757..86f4c4d 100644 --- a/src/opencmo/web/app.py +++ b/src/opencmo/web/app.py @@ -1529,11 +1529,7 @@ async def api_v1_auth_verify_email(payload: _AuthVerifyEmailRequest, request: Re return JSONResponse({"ok": False, "error": "user_not_found"}, status_code=404) if await storage.is_user_verified(payload.user_id): - # Idempotent: already verified -> just sign them in. - account = await storage.get_user_account(payload.user_id) - if account is None or account["status"] != "active": - return JSONResponse({"ok": False, "error": "account_unavailable"}, status_code=403) - return await _json_with_session(request, user, account) + return JSONResponse({"ok": False, "error": "already_verified"}, status_code=400) result = await storage.consume_verification_code(payload.user_id, payload.code, purpose="signup") if not result.get("ok"): diff --git a/tests/test_email_verification.py b/tests/test_email_verification.py index 73e761e..38a5432 100644 --- a/tests/test_email_verification.py +++ b/tests/test_email_verification.py @@ -205,6 +205,31 @@ def test_verified_user_login_succeeds(verification_db): assert login.json()["authenticated"] is True +def test_verify_email_already_verified_requires_login_flow(verification_db): + with TestClient(app) as client: + signup = _signup(client, "already@example.test") + user_id = signup["user_id"] + code = _last_code_for("already@example.test") + + first = client.post( + "/api/v1/auth/verify-email", + json={"user_id": user_id, "code": code}, + ) + assert first.status_code == 200, first.text + assert first.json()["authenticated"] is True + + client.post("/api/v1/auth/logout") + client.cookies.clear() + + second = client.post( + "/api/v1/auth/verify-email", + json={"user_id": user_id, "code": "000000"}, + ) + assert second.status_code == 400, second.text + assert second.json()["error"] == "already_verified" + assert "opencmo_session" not in client.cookies + + def test_existing_legacy_users_remain_verified_after_backfill(tmp_path, monkeypatch): """A user created before this feature should keep working — backfill runs once at ensure_db() startup."""