From 9111f645b71d797d0152b6902e8b821be94f2258 Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Thu, 3 Feb 2022 19:05:01 -0800 Subject: [PATCH] fix: require passreset's target user is unsuspended Signed-off-by: Kevin Morris --- aurweb/routers/accounts.py | 23 ++++++++++++----------- test/test_accounts_routes.py | 12 ++++++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 33ca9ed7..d296a9b9 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -43,18 +43,19 @@ async def passreset_post(request: Request, context = await make_variable_context(request, "Password Reset") # The user parameter being required, we can match against - user = db.query(models.User, or_(models.User.Username == user, - models.User.Email == user)).first() - if not user: + criteria = or_(models.User.Username == user, models.User.Email == user) + db_user = db.query(models.User, + and_(criteria, models.User.Suspended == 0)).first() + if db_user is None: context["errors"] = ["Invalid e-mail."] return render_template(request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND) - db.refresh(user) + db.refresh(db_user) if resetkey: context["resetkey"] = resetkey - if not user.ResetKey or resetkey != user.ResetKey: + if not db_user.ResetKey or resetkey != db_user.ResetKey: context["errors"] = ["Invalid e-mail."] return render_template(request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND) @@ -83,10 +84,10 @@ async def passreset_post(request: Request, # We got to this point; everything matched up. Update the password # and remove the ResetKey. with db.begin(): - user.ResetKey = str() - if user.session: - db.delete(user.session) - user.update_password(password) + db_user.ResetKey = str() + if db_user.session: + db.delete(db_user.session) + db_user.update_password(password) # Render ?step=complete. return RedirectResponse(url="/passreset?step=complete", @@ -95,9 +96,9 @@ async def passreset_post(request: Request, # If we got here, we continue with issuing a resetkey for the user. resetkey = generate_resetkey() with db.begin(): - user.ResetKey = resetkey + db_user.ResetKey = resetkey - ResetKeyNotification(user.ID).send() + ResetKeyNotification(db_user.ID).send() # Render ?step=confirm. return RedirectResponse(url="/passreset?step=confirm", diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 30531ac7..92b33730 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -152,6 +152,18 @@ def test_post_passreset_user(client: TestClient, user: User): assert response.headers.get("location") == "/passreset?step=confirm" +def test_post_passreset_user_suspended(client: TestClient, user: User): + with db.begin(): + user.Suspended = True + + with client as request: + response = request.post("/passreset", data={"user": TEST_USERNAME}) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + errors = get_errors(response.text) + expected = "Invalid e-mail." + assert errors[0].text.strip() == expected + + def test_post_passreset_resetkey(client: TestClient, user: User): with db.begin(): user.session = Session(UsersID=user.ID, SessionID="blah",