From cabae556772201b37e47a4f3de0c65e2e3a3c9ca Mon Sep 17 00:00:00 2001 From: april Date: Fri, 5 Jan 2024 17:03:56 -0600 Subject: [PATCH] Implement password updating --- api/routes/auth.py | 2 +- api/routes/users.py | 30 +++++++++++++++++++++++++----- api/schemas/user.py | 16 ++++++++++------ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/api/routes/auth.py b/api/routes/auth.py index 523ea18..4128448 100644 --- a/api/routes/auth.py +++ b/api/routes/auth.py @@ -50,7 +50,7 @@ async def logout(user_token: (UserDisplaySchema, TokenSchema) = Depends(get_curr user, token = user_token # Blacklist token - blacklisted = tokens.blacklist_token(token) + blacklisted = await tokens.blacklist_token(token) if not blacklisted: logger.debug("Failed to add token to blacklist") diff --git a/api/routes/users.py b/api/routes/users.py index 51e722f..03077a8 100644 --- a/api/routes/users.py +++ b/api/routes/users.py @@ -3,9 +3,9 @@ from fastapi import APIRouter, HTTPException, Depends from pydantic import ValidationError from app.deps import get_current_user, admin_required -from database import users as db -from schemas.user import AuthLevel, UserCreateSchema, UserDisplaySchema, UserUpdateSchema -from routes.utils import get_hashed_password +from database import users as db, users +from schemas.user import AuthLevel, UserCreateSchema, UserDisplaySchema, UserUpdateSchema, PasswordUpdateSchema +from routes.utils import get_hashed_password, verify_password router = APIRouter() @@ -101,13 +101,33 @@ async def get_user_profile(user_id: str) -> UserDisplaySchema: async def update_profile(body: UserUpdateSchema, user: UserDisplaySchema = Depends(get_current_user)) -> UserDisplaySchema: """ - Update the profile of the currently logged-in user + Update the profile of the currently logged-in user. Cannot update password this way :param body: New information to insert :param user: Currently logged-in user + :return: Updated user profile + """ + return await db.edit_profile(user.id, username=body.username, auth_level=body.level) + + +@router.put('/me/password', summary="Update the password of the currently logged-in user", status_code=200) +async def update_password(body: PasswordUpdateSchema, user: UserDisplaySchema = Depends(get_current_user)): + """ + Update the password of the currently logged-in user. Requires password confirmation + + :param body: Password confirmation and new password + :param user: Currently logged-in user :return: None """ - return await db.edit_profile(user.id, body.username, body.password, body.level) + # Get current user's password + user = await users.get_user_system_info(username=user.username) + + # Verify password confirmation + if not verify_password(body.current_password, user.password): + raise HTTPException(403, "Invalid password") + + # Update the user's password + await db.edit_profile(user.id, password=body.new_password) @router.put('/{user_id}', summary="Update profile of the given user", status_code=200, diff --git a/api/schemas/user.py b/api/schemas/user.py index dd197cf..8d38f8e 100644 --- a/api/schemas/user.py +++ b/api/schemas/user.py @@ -66,7 +66,6 @@ class UserCreateSchema(UserBaseSchema): class UserUpdateSchema(BaseModel): username: Optional[str] = None - password: Optional[str] = None level: Optional[AuthLevel] = AuthLevel.USER @field_validator("username") @@ -74,11 +73,6 @@ class UserUpdateSchema(BaseModel): def _valid_username(cls, value): validate_username(value) - @field_validator("password") - @classmethod - def _valid_password(cls, value): - validate_password(value) - class UserDisplaySchema(UserBaseSchema): id: str @@ -89,6 +83,16 @@ class UserSystemSchema(UserDisplaySchema): password: str +class PasswordUpdateSchema(BaseModel): + current_password: str + new_password: str + + @field_validator("new_password") + @classmethod + def _valid_password(cls, value): + validate_password(value) + + class TokenSchema(BaseModel): access_token: str refresh_token: str