async def authenticate( self, credentials: OAuth2PasswordRequestForm ) -> Optional[UD]: """ Authenticate and return a user following an phone and a password. Will automatically upgrade password hash if necessary. """ user = await self.get_by_phone(credentials.username) if user is None: # Run the hasher to mitigate timing attack # Inspired from Django: https://code.djangoproject.com/ticket/20760 password.get_password_hash(credentials.password) return None verified, updated_password_hash = password.verify_and_update_password( credentials.password, user.hashed_password ) if not verified: return None # Update password hash to a more robust one if needed if updated_password_hash is not None: user.hashed_password = updated_password_hash await self.update(user) return user
async def test_queries(sqlalchemy_user_db: SQLAlchemyUserDatabase[UserDB]): user = UserDB( email="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await sqlalchemy_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.email == user.email # Update user_db.is_superuser = True await sqlalchemy_user_db.update(user_db) # Get by id id_user = await sqlalchemy_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by email email_user = await sqlalchemy_user_db.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id # Exception when inserting existing email with pytest.raises(sqlite3.IntegrityError): await sqlalchemy_user_db.create(user) # Exception when inserting non-nullable fields with pytest.raises(sqlite3.IntegrityError): wrong_user = UserDB(hashed_password="******") await sqlalchemy_user_db.create(wrong_user) # Unknown user unknown_user = await sqlalchemy_user_db.get_by_email("*****@*****.**") assert unknown_user is None # Delete user await sqlalchemy_user_db.delete(user) deleted_user = await sqlalchemy_user_db.get(user.id) assert deleted_user is None # Exception when creating/updating a OAuth user user_oauth = UserDBOAuth( email="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) with pytest.raises(NotSetOAuthAccountTableError): await sqlalchemy_user_db.create(user_oauth) with pytest.raises(NotSetOAuthAccountTableError): await sqlalchemy_user_db.update(user_oauth) # Exception when trying to get by OAuth account with pytest.raises(NotSetOAuthAccountTableError): await sqlalchemy_user_db.get_by_oauth_account("foo", "bar")
async def edit_user_profile( user_update: UserUpdate, user: User = Depends(fastapi_users.get_current_active_user) ): # Email and Password field not provided in JSON argument if user_update.email is None and user_update.password is None: raise HTTPException(status_code=400, detail="An email or password is needed.") # Email field provided current_email = user.email if user_update.email is not None: new_email = user_update.email user_in_db = mongo_db_users_reg.find_json({"email": new_email}) if user_in_db is None: mongo_db_users_reg.collection.update_one( {"email": user.email}, {"$set": {"email": new_email}} ) current_email = new_email else: raise HTTPException( status_code=400, detail="Email is already used.") # password field provided if user_update.password is not None: new_password = user_update.password hashed_password = get_password_hash(new_password) mongo_db_users_reg.collection.update_one( {"email": current_email}, {"$set": {"hashed_password": hashed_password}} ) return {"Message": "Success", "Email": current_email}
async def reset_password(token: str = Body(...), password: str = Body(...)): try: data = jwt.decode( token, reset_password_token_secret, audience=reset_password_token_audience, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await user_db.get(user_id) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user.hashed_password = get_password_hash(password) await user_db.update(user) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )
async def create( self, user: models.UC, safe: bool = False, request: Optional[Request] = None ) -> models.UD: """ Create a user in database. Triggers the on_after_register handler on success. :param user: The UserCreate model to create. :param safe: If True, sensitive values like is_superuser or is_verified will be ignored during the creation, defaults to False. :param request: Optional FastAPI request that triggered the operation, defaults to None. :raises UserAlreadyExists: A user already exists with the same e-mail. :return: A new user. """ await self.validate_password(user.password, user) existing_user = await self.user_db.get_by_email(user.email) if existing_user is not None: raise UserAlreadyExists() hashed_password = get_password_hash(user.password) user_dict = ( user.create_update_dict() if safe else user.create_update_dict_superuser() ) db_user = self.user_db_model(**user_dict, hashed_password=hashed_password) created_user = await self.user_db.create(db_user) await self.on_after_register(created_user, request) return created_user
async def test_queries_oauth( ormar_user_db_oauth: OrmarUserDatabase[UserDBOAuth], oauth_account1, oauth_account2, oauth_account3, ): user = UserDBOAuth( email="*****@*****.**", hashed_password=get_password_hash("guinevere"), oauth_accounts=[oauth_account1, oauth_account2], ) # Create user_db = await ormar_user_db_oauth.create(user) assert user_db.id is not None assert hasattr(user_db, "oauth_accounts") assert len(user_db.oauth_accounts) == 2 # Update user_db.oauth_accounts[0].access_token = "NEW_TOKEN" await ormar_user_db_oauth.update(user_db) # Get by id id_user = await ormar_user_db_oauth.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.oauth_accounts[0].access_token == "NEW_TOKEN" # Add new oauth id_user.oauth_accounts.append(oauth_account3) await ormar_user_db_oauth.update(id_user) id_user_updated = await ormar_user_db_oauth.get(user.id) assert len(id_user_updated.oauth_accounts) == 3 # Remove oauth2 and update id_user.oauth_accounts = [ oauth for oauth in id_user.oauth_accounts if oauth.id != oauth_account2.id ] await ormar_user_db_oauth.update(id_user) id_user_updated = await ormar_user_db_oauth.get(user.id) assert len(id_user_updated.oauth_accounts) == 2 # Get by email email_user = await ormar_user_db_oauth.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id assert len(email_user.oauth_accounts) == 2 # Get by OAuth account oauth_user = await ormar_user_db_oauth.get_by_oauth_account( oauth_account1.oauth_name, oauth_account1.account_id) assert oauth_user is not None assert oauth_user.id == user.id # Unknown OAuth account unknown_oauth_user = await ormar_user_db_oauth.get_by_oauth_account( "foo", "bar") assert unknown_oauth_user is None
async def _update_user(user: models.BaseUserDB, update_dict: Dict[str, Any]): for field in update_dict: if field == "password": hashed_password = get_password_hash(update_dict[field]) user.hashed_password = hashed_password else: setattr(user, field, update_dict[field]) return await user_db.update(user)
async def test_queries(ormar_user_db: OrmarUserDatabase[UserDB]): user = UserDB( email="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await ormar_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.email == user.email # Update user_db.is_superuser = True await ormar_user_db.update(user_db) # Exception when updating a user with a not existing id id_backup = user_db.id user_db.id = uuid.uuid4() with pytest.raises(NoMatch): await ormar_user_db.update(user_db) user_db.id = id_backup # Get by id id_user = await ormar_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by email email_user = await ormar_user_db.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id # Get by uppercased email email_user = await ormar_user_db.get_by_email("*****@*****.**") assert email_user is not None assert email_user.id == user_db.id # Exception when inserting existing email with pytest.raises(IntegrityError): await ormar_user_db.create(user) # Exception when inserting non-nullable fields with pytest.raises(ValueError): wrong_user = UserDB(hashed_password="******") await ormar_user_db.create(wrong_user) # Unknown user unknown_user = await ormar_user_db.get_by_email("*****@*****.**") assert unknown_user is None # Delete user await ormar_user_db.delete(user) deleted_user = await ormar_user_db.get(user.id) assert deleted_user is None
class UserFactory(factory.alchemy.SQLAlchemyModelFactory): class Meta: model = models.User id = factory.LazyAttribute(lambda _: uuid4()) email = factory.Faker('email') hashed_password = factory.LazyAttribute(lambda obj: get_password_hash('test')) is_active = True is_verified = True is_superuser = False
async def _update_user( user: models.UserDB, update_dict: typing.Dict[str, typing.Any] # type: ignore ): for field in update_dict: if field == "password": hashed_password = get_password_hash(update_dict[field]) user.hashed_password = hashed_password else: setattr(user, field, update_dict[field]) return await user_db.update(user)
async def _update_user(user: models.BaseUserDB, update_dict: Dict[str, Any], request: Request): for field in update_dict: if field == "password": hashed_password = get_password_hash(update_dict[field]) user.hashed_password = hashed_password else: setattr(user, field, update_dict[field]) updated_user = await user_db.update(user) if after_update: await run_handler(after_update, updated_user, update_dict, request) return updated_user
async def reset_password( request: Request, token: str = Body(...), password: str = Body(...) ): try: data = jwt.decode( token, reset_password_token_secret, audience=RESET_PASSWORD_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM], ) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) try: user_uiid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await user_db.get(user_uiid) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) if validate_password: try: await validate_password(password, user) except InvalidPasswordException as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail={ "code": ErrorCode.RESET_PASSWORD_INVALID_PASSWORD, "reason": e.reason, }, ) user.hashed_password = get_password_hash(password) await user_db.update(user) if after_reset_password: await run_handler(after_reset_password, user, request) except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )
async def _update_user( user: UserDB, update_dict: Dict[str, Any], request: Request ): #TODO: implement changing roles for field in update_dict: if field == "password": hashed_password = get_password_hash(update_dict[field]) user.hashed_password = hashed_password else: setattr(user, field, update_dict[field]) updated_user = await user_db.update(user) return updated_user
async def update_user(user_id: UUID4, update_dict: Dict[str, Any]) -> UserDB: user = await get_or_404(user_id) user = dict(user) for field in update_dict: if field == "password" and update_dict[field]: hashed_password = get_password_hash(update_dict[field]) user["hashed_password"] = hashed_password elif update_dict[field] is not None: user[field] = update_dict[field] updated_user = await user_db.update(UserDB(**user)) return updated_user
async def create_user(user: models.BaseUserCreate, safe: bool = False) -> models.BaseUserDB: existing_user = await user_db.get_by_email(user.email) if existing_user is not None: raise UserAlreadyExists() hashed_password = get_password_hash(user.password) user_dict = (user.create_update_dict() if safe else user.create_update_dict_superuser()) db_user = user_db_model(**user_dict, hashed_password=hashed_password) return await user_db.create(db_user)
async def test_queries(tortoise_user_db: TortoiseUserDatabase[UserDB]): user = UserDB( id="111", email="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await tortoise_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.email == user.email # Update user_db.is_superuser = True await tortoise_user_db.update(user_db) # Get by id id_user = await tortoise_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by email email_user = await tortoise_user_db.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id # List users = await tortoise_user_db.list() assert len(users) == 1 first_user = users[0] assert first_user.id == user_db.id # Exception when inserting existing email with pytest.raises(IntegrityError): await tortoise_user_db.create(user) # Exception when inserting non-nullable fields with pytest.raises(ValueError): wrong_user = UserDB(id="222", hashed_password="******") await tortoise_user_db.create(wrong_user) # Unknown user unknown_user = await tortoise_user_db.get_by_email("*****@*****.**") assert unknown_user is None # Delete user await tortoise_user_db.delete(user) deleted_user = await tortoise_user_db.get(user.id) assert deleted_user is None
async def test_email_query( mongodb_user_db: MongoDBUserDatabase[UserDB], email: str, query: str, found: bool ): user = UserDB(email=email, hashed_password=get_password_hash("guinevere"),) await mongodb_user_db.create(user) email_user = await mongodb_user_db.get_by_email(query) if found: assert email_user is not None assert email_user.id == user.id else: assert email_user is None
async def test_queries_custom_fields(ormar_user_db: OrmarUserDatabase[UserDB]): """It should output custom fields in query result.""" user = UserDB( email="*****@*****.**", hashed_password=get_password_hash("guinevere"), first_name="Lancelot", ) await ormar_user_db.create(user) id_user = await ormar_user_db.get(user.id) assert id_user is not None assert id_user.id == user.id assert id_user.first_name == user.first_name
async def test_queries_oauth( tortoise_user_db_oauth: TortoiseUserDatabase[UserDBOAuth], oauth_account1, oauth_account2, ): user = UserDBOAuth( id="111", email="*****@*****.**", hashed_password=get_password_hash("guinevere"), oauth_accounts=[oauth_account1, oauth_account2], ) # Create user_db = await tortoise_user_db_oauth.create(user) assert user_db.id is not None assert hasattr(user_db, "oauth_accounts") assert len(user_db.oauth_accounts) == 2 # Update user_db.oauth_accounts[0].access_token = "NEW_TOKEN" await tortoise_user_db_oauth.update(user_db) # Get by id id_user = await tortoise_user_db_oauth.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.oauth_accounts[0].access_token == "NEW_TOKEN" # Get by email email_user = await tortoise_user_db_oauth.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id assert len(email_user.oauth_accounts) == 2 # List users = await tortoise_user_db_oauth.list() assert len(users) == 1 first_user = users[0] assert first_user.id == user_db.id assert len(first_user.oauth_accounts) == 2 # Get by OAuth account oauth_user = await tortoise_user_db_oauth.get_by_oauth_account( oauth_account1.oauth_name, oauth_account1.account_id) assert oauth_user is not None assert oauth_user.id == user.id # Unknown OAuth account unknown_oauth_user = await tortoise_user_db_oauth.get_by_oauth_account( "foo", "bar") assert unknown_oauth_user is None
async def oauth_callback( self, oauth_account: models.BaseOAuthAccount, request: Optional[Request] = None ) -> models.UD: """ Handle the callback after a successful OAuth authentication. If the user already exists with this OAuth account, the token is updated. If a user with the same e-mail already exists, the OAuth account is linked to it. If the user does not exist, it is created and the on_after_register handler is triggered. :param oauth_account: The new OAuth account to create. :param request: Optional FastAPI request that triggered the operation, defaults to None :return: A user. """ try: user = await self.get_by_oauth_account( oauth_account.oauth_name, oauth_account.account_id ) except UserNotExists: try: # Link account user = await self.get_by_email(oauth_account.account_email) user.oauth_accounts.append(oauth_account) # type: ignore await self.user_db.update(user) except UserNotExists: # Create account password = generate_password() user = self.user_db_model( email=oauth_account.account_email, hashed_password=get_password_hash(password), oauth_accounts=[oauth_account], ) await self.user_db.create(user) await self.on_after_register(user, request) else: # Update oauth updated_oauth_accounts = [] for existing_oauth_account in user.oauth_accounts: # type: ignore if existing_oauth_account.account_id == oauth_account.account_id: updated_oauth_accounts.append(oauth_account) else: updated_oauth_accounts.append(existing_oauth_account) user.oauth_accounts = updated_oauth_accounts # type: ignore await self.user_db.update(user) return user
async def test_queries(tortoise_user_db: TortoiseUserDatabase[UserDB]): user = UserDB( phone="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await tortoise_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.phone == user.phone # Update user_db.is_superuser = True await tortoise_user_db.update(user_db) # Get by id id_user = await tortoise_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by phone phone_user = await tortoise_user_db.get_by_phone(str(user.phone)) assert phone_user is not None assert phone_user.id == user_db.id # Get by uppercased phone phone_user = await tortoise_user_db.get_by_phone("*****@*****.**") assert phone_user is not None assert phone_user.id == user_db.id # Exception when inserting existing phone with pytest.raises(IntegrityError): await tortoise_user_db.create(user) # Exception when inserting non-nullable fields with pytest.raises(ValueError): wrong_user = UserDB(hashed_password="******") await tortoise_user_db.create(wrong_user) # Unknown user unknown_user = await tortoise_user_db.get_by_phone("*****@*****.**") assert unknown_user is None # Delete user await tortoise_user_db.delete(user) deleted_user = await tortoise_user_db.get(user.id) assert deleted_user is None
async def test_phone_query(mongodb_user_db: MongoDBUserDatabase[UserDB], phone: str, query: str, found: bool): user = UserDB( phone=phone, hashed_password=get_password_hash("guinevere"), ) await mongodb_user_db.create(user) phone_user = await mongodb_user_db.get_by_phone(query) if found: assert phone_user is not None assert phone_user.id == user.id else: assert phone_user is None
async def _update(self, user: models.UD, update_dict: Dict[str, Any]) -> models.UD: for field, value in update_dict.items(): if field == "email" and value != user.email: try: await self.get_by_email(value) raise UserAlreadyExists() except UserNotExists: user.email = value user.is_verified = False elif field == "password": await self.validate_password(value, user) hashed_password = get_password_hash(value) user.hashed_password = hashed_password else: setattr(user, field, value) return await self.user_db.update(user)
async def test_queries(mongodb_user_db: MongoDBUserDatabase[UserDB]): user = UserDB( id="111", email="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await mongodb_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.email == user.email # Update user_db.is_superuser = True await mongodb_user_db.update(user_db) # Get by id id_user = await mongodb_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by email email_user = await mongodb_user_db.get_by_email(str(user.email)) assert email_user is not None assert email_user.id == user_db.id # List users = await mongodb_user_db.list() assert len(users) == 1 first_user = users[0] assert first_user.id == user_db.id # Exception when inserting existing email with pytest.raises(pymongo.errors.DuplicateKeyError): await mongodb_user_db.create(user) # Unknown user unknown_user = await mongodb_user_db.get_by_email("*****@*****.**") assert unknown_user is None # Delete user await mongodb_user_db.delete(user) deleted_user = await mongodb_user_db.get(user.id) assert deleted_user is None
async def register(user: models.UserCreate): # type: ignore existing_user = await user_db.get_by_email(user.email) if existing_user is not None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.REGISTER_USER_ALREADY_EXISTS, ) hashed_password = get_password_hash(user.password) db_user = models.UserDB(**user.create_update_dict(), hashed_password=hashed_password) created_user = await user_db.create(db_user) await router.run_handlers(Event.ON_AFTER_REGISTER, created_user) return created_user
async def test_queries(mongodb_user_db: MongoDBUserDatabase[UserDB]): user = UserDB( phone="*****@*****.**", hashed_password=get_password_hash("guinevere"), ) # Create user_db = await mongodb_user_db.create(user) assert user_db.id is not None assert user_db.is_active is True assert user_db.is_superuser is False assert user_db.phone == user.phone # Update user_db.is_superuser = True await mongodb_user_db.update(user_db) # Get by id id_user = await mongodb_user_db.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.is_superuser is True # Get by phone phone_user = await mongodb_user_db.get_by_phone(str(user.phone)) assert phone_user is not None assert phone_user.id == user_db.id # Get by uppercased phone phone_user = await mongodb_user_db.get_by_phone("*****@*****.**") assert phone_user is not None assert phone_user.id == user_db.id # Exception when inserting existing phone with pytest.raises(pymongo.errors.DuplicateKeyError): await mongodb_user_db.create(user) # Unknown user unknown_user = await mongodb_user_db.get_by_phone("*****@*****.**") assert unknown_user is None # Delete user await mongodb_user_db.delete(user) deleted_user = await mongodb_user_db.get(user.id) assert deleted_user is None
async def create_register_user(*, email=Form(...), password=Form(...)): user_in_db = await UserModel.filter(email=email) if user_in_db: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.REGISTER_USER_ALREADY_EXISTS, ) hashed_password = get_password_hash(password) created_user = await UserModel.create( id=str(uuid.uuid4()), email=email, hashed_password=hashed_password, is_active=True, is_superuser=False, ) return created_user
async def test_queries_oauth( sqlalchemy_user_db_oauth: SQLAlchemyUserDatabase[UserDBOAuth], oauth_account1, oauth_account2, ): user = UserDBOAuth( phone="*****@*****.**", hashed_password=get_password_hash("guinevere"), oauth_accounts=[oauth_account1, oauth_account2], ) # Create user_db = await sqlalchemy_user_db_oauth.create(user) assert user_db.id is not None assert hasattr(user_db, "oauth_accounts") assert len(user_db.oauth_accounts) == 2 # Update user_db.oauth_accounts[0].access_token = "NEW_TOKEN" await sqlalchemy_user_db_oauth.update(user_db) # Get by id id_user = await sqlalchemy_user_db_oauth.get(user.id) assert id_user is not None assert id_user.id == user_db.id assert id_user.oauth_accounts[0].access_token == "NEW_TOKEN" # Get by phone phone_user = await sqlalchemy_user_db_oauth.get_by_phone(str(user.phone)) assert phone_user is not None assert phone_user.id == user_db.id assert len(phone_user.oauth_accounts) == 2 # Get by OAuth account oauth_user = await sqlalchemy_user_db_oauth.get_by_oauth_account( oauth_account1.oauth_name, oauth_account1.account_id) assert oauth_user is not None assert oauth_user.id == user.id # Unknown OAuth account unknown_oauth_user = await sqlalchemy_user_db_oauth.get_by_oauth_account( "foo", "bar") assert unknown_oauth_user is None
async def register(request: Request, user: user_create_model): # type: ignore user = cast(models.BaseUserCreate, user) # Prevent mypy complain existing_user = await user_db.get_by_email(user.email) if existing_user is not None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.REGISTER_USER_ALREADY_EXISTS, ) hashed_password = get_password_hash(user.password) db_user = user_db_model(**user.create_update_dict(), hashed_password=hashed_password) created_user = await user_db.create(db_user) await router.run_handlers(Event.ON_AFTER_REGISTER, created_user, request) return created_user
async def reset_password(_: Response, formdata: ResetPasswordVM): token = formdata.token password = formdata.password try: data = jwt.decode(token, s.SECRET_KEY_EMAIL, audience=RESET_PASSWORD_TOKEN_AUDIENCE, algorithms=[JWT_ALGORITHM]) user_id = data.get("user_id") if user_id is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) try: user_uuid = UUID4(user_id) except ValueError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user = await userdb.get(user_uuid) if user is None or not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, ) user.hashed_password = get_password_hash(password) # Use UserDB in order to remove the extra attributes generated by UserDBComplete user = UserDB(**user.dict()) await userdb.update(user) return True except jwt.PyJWTError: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.RESET_PASSWORD_BAD_TOKEN, )