async def forgot_password(self, data: dict, ip: str) -> None: """POST /forgot_password Only for accounts with password. Args: data: {email: "*****@*****.**"} ip: ip from request Returns: None Raises: HTTPException: 400 - validation or timeout. 404 - email not found. """ try: email = UserInForgotPassword(**data).email except ValidationError: raise HTTPException(400, detail=get_error_message( "validation", self._language)) item = await self._repo.get_by_email(email) if item is None: raise HTTPException(404, detail=get_error_message( "email not found", self._language)) if item.get("password") is None: raise HTTPException(406) id = item.get("id") if not await self._repo.is_password_reset_available(id): raise HTTPException(400, detail=get_error_message( "reset before", self._language)) logger.info(f"forgot_password ip={ip} email={email}") token = create_random_string() token_hash = hash_string(token) await self._repo.set_password_reset_token(id, token_hash) # if not self._debug: # TODO email_client = self._create_email_client() await email_client.send_forgot_password_email(email, token) return None
async def password_reset(self, data: dict, token: str) -> None: token_hash = hash_string(token) id = await self._repo.get_id_for_password_reset(token_hash) if id is None: raise HTTPException(404) user_model = self._validate_user_model(UserInSetPassword, data) password_hash = get_password_hash(user_model.password1) await self._repo.set_password(id, password_hash) return None
async def test_password_reset(): token = create_random_string() token_hash = hash_string(token) service = PasswordService() await service._repo.set_password_reset_token(1, token_hash) await service.password_reset( { "password1": "87654321", "password2": "87654321", }, token, ) item = await service._repo.get(1) assert item.get("password") != "12345678"
async def test_confirm_email(): auth_service = AuthService() email = "*****@*****.**" token = create_random_string() token_hash = hash_string(token) await auth_service._repo.request_email_confirmation(email, token_hash) with pytest.raises(HTTPException) as e: await auth_service.confirm_email("wrongtoken") assert e.type is HTTPException assert e.value.args[0] == 403 # TODO: 400 maybe await auth_service.confirm_email(token) item = await auth_service._repo.get_by_email(email) assert item.get("confirmed")
async def confirm_email(self, token: str) -> None: """POST /confirm/{token} Hashes token, looks up hash in db, updates "confirmed" to True for email in a row. Returns: None Raises: HTTPException: 403 - no hash in db. """ token_hash = hash_string(token) if not await self._repo.confirm_email(token_hash): raise HTTPException( 403) # TODO: ??? 400 maybe, change frontend too return None
async def _request_email_confirmation(self, email: str) -> None: token = create_random_string() token_hash = hash_string(token) await self._repo.request_email_confirmation(email, token_hash) email_client = self._create_email_client() await email_client.send_confirmation_email(email, token)