async def generate_password_reset_token(self, request): self._check_server_key(request=request) request_body: CreatePasswordResetTokenRequest = convert_request( CreatePasswordResetTokenRequest, await request.json()) user: User = await self.user_repository.find_user_by_id( request_body.user_id) if not user: return json_response(reason=f"user not found", status=404) if user.type != UserType.EMAIL: return json_response(reason=f"only email user can reset password", status=400) user_claim: ResetPasswordClaim = deserialize.deserialize( ResetPasswordClaim, { "id": str(user.id), "type": int(user.type), "exp": time.time() + self.ACCESS_TOKEN_EXPIRE_TIME, }, ) token = user_claim.to_jwt(self.jwt_secret) return json_response(result=token)
async def create_third_party_user_token(self, request): request_body: CreateThirdPartyUserTokenRequest = convert_request( CreateThirdPartyUserTokenRequest, await request.json()) try: get_third_party_user = self.third_party_user_method[ request_body.user_type] except KeyError: return json_response(reason='invalid user type', status=400) try: third_party_user: ThirdPartyUser = await get_third_party_user( request_body.third_party_token) except ThirdPartyTokenVerifyError: return json_response(reason='invalid third party token', status=400) user: User = await find_user_by_third_party_user_id( third_party_user_id=third_party_user.id, user_type=request_body.user_type, ) if user is None: return json_response(reason='user not found', status=404) refresh_token = await self._create_refresh_token(user) access_token = self._create_access_token(user) return json_response(result={ 'access_token': access_token, 'refresh_token': refresh_token, })
async def search_users(self, request): self._check_server_key(request=request) available_order_bys = { "id", "-id", "email", "-email", "created_at", "-created_at", "modified_at", "-modified_at", } request_body: SearchUserRequest = convert_request( SearchUserRequest, await request.json()) total, users = await self.user_repository.search_users( emails=request_body.emails, created_at_range=request_body.created_at_range, modified_at_range=request_body.modified_at_range, extra_text=request_body.extras, start=request_body.start, size=request_body.size, order_bys=list( available_order_bys.intersection(request_body.order_bys)), status=request_body.status, types=request_body.types, ) return json_response( result={ "total": total, "users": [user_model_to_dict(user) for user in users], })
async def update_email_user_password(self, request): user_info: UserClaim = get_bearer_token(self.jwt_secret, request) request_body: UpdateUserPasswordRequest = convert_request( UpdateUserPasswordRequest, await request.json()) user: User = await self.user_repository.find_user_by_id(user_info.id) if not user: return json_response(reason=f"user not found", status=404) if user.type != UserType.EMAIL: return json_response(reason=f"only email user can update password", status=404) if not is_valid_password(request_body.new_password): return json_response(reason="password policy is not satisfied", status=400) if not bcrypt.checkpw(request_body.original_password.encode(), user.hashed_password.encode()): return json_response(reason="Invalid password", status=403) hashed_password = bcrypt.hashpw(request_body.new_password.encode(), bcrypt.gensalt()).decode() affected_rows = await self.user_repository.update_user( user_id=user_info.id, hashed_password=hashed_password, ) return json_response(result=affected_rows > 0)
async def update_myself(self, request): user_info: UserClaim = get_bearer_token(self.jwt_secret, request) request_body: UpdateUserRequest = convert_request( UpdateUserRequest, await request.json()) if not is_valid_email(request_body.email): return json_response( reason=f"{request_body.email} is invalid email format", status=400) user: User = await self.user_repository.find_user_by_id(user_info.id) if not user: return json_response(reason=f"user not found", status=404) verified_status = {} if user.email != request_body.email: verified_status["is_email_verified"] = False affected_rows = await self.user_repository.update_user( user_id=user_info.id, email=request_body.email, extra=request_body.extra, **verified_status, ) await self._send_user_update_event( original=user, delta={ "email": request_body.email, "extra": request_body.extra, "is_email_verified": False, }, ) return json_response(result=affected_rows > 0)
async def create_third_party_user(self, request): request_body: CreateThirdPartyUserRequest = convert_request( CreateThirdPartyUserRequest, await request.json()) try: get_third_party_user = self.third_party_user_method[ request_body.user_type] except KeyError: return json_response(reason="invalid user type", status=400) try: third_party_user: ThirdPartyUser = await get_third_party_user( request_body.third_party_token) except ThirdPartyTokenVerifyError: return json_response(reason="invalid third party token", status=400) user: User = await self.user_repository.find_user_by_third_party_user_id( third_party_user_id=third_party_user.id, user_type=request_body.user_type, ) if user: return json_response( reason=f"account[{third_party_user.id}] already exists", status=409) user = await self.user_repository.create_user( user_type=third_party_user.type, email=third_party_user.email, third_party_user_id=third_party_user.id, extra=request_body.extra, ) await self._send_user_creation_event(user) return json_response(result=user_model_to_dict(user))
async def create_email_user(self, request): request_body: CreateEmailUserRequest = convert_request( CreateEmailUserRequest, await request.json()) user = await find_user_by_account(request_body.account) if user: return json_response( reason=f'account[{request_body.account}] already exists', status=409) if not is_valid_account(request_body.account): return json_response( reason=f'{request_body.account} is invalid account format', status=400) if not is_valid_email(request_body.email): return json_response( reason=f'{request_body.email} is invalid email format', status=400) if not is_valid_password(request_body.password): return json_response(reason='password policy is not satisfied', status=400) hashed_password = bcrypt.hashpw(request_body.password.encode(), bcrypt.gensalt()).decode() user = await create_user( user_type=UserType.EMAIL, account=request_body.account, hashed_password=hashed_password, email=request_body.email, extra=request_body.extra, ) return json_response(result=user_model_to_dict(user))
async def generate_email_verifying_token(self, request): self._check_server_key(request=request) request_body: CreateEmailVerifyingTokenRequest = convert_request( CreateEmailVerifyingTokenRequest, await request.json()) user: User = await find_user_by_id(request_body.user_id) token = self._create_access_token(user) return json_response(result=token)
async def put(self, request): request_body: RefreshTokenRequest = convert_request( RefreshTokenRequest, await request.json()) user_id = await self.get_user_id_by_refresh_token( request_body.refresh_token) if user_id is None: return json_response(reason='token not found', status=404) user = await find_user_by_id(to_string(user_id)) if not user: return json_response(reason=f'user not found', status=404) access_token = self._create_access_token(user) return json_response(result={'access_token': access_token})
async def verify_myself(self, request): request_param: VerifyEmailRequest = convert_request( VerifyEmailRequest, dict(request.rel_url.query)) user_info: VerifyUserEmailClaim = VerifyUserEmailClaim.from_jwt( request_param.temp_token, self.jwt_secret) user: User = await find_user_by_id(user_info.id) if not user: return json_response(reason=f'user not found', status=404) await update_user( user_id=user_info.id, is_email_verified=True, ) return json_response(result=True)
async def create_email_user_token(self, request): request_body: CreateEmailUserTokenRequest = convert_request( CreateEmailUserTokenRequest, await request.json()) user: User = await find_user_by_account(request_body.account) if user is None: return json_response(reason='user not found', status=404) if not bcrypt.checkpw(request_body.password.encode(), user.hashed_password.encode()): return json_response(reason='Invalid password', status=403) refresh_token = await self._create_refresh_token(user) access_token = self._create_access_token(user) return json_response(result={ 'access_token': access_token, 'refresh_token': refresh_token, })
async def generate_email_verifying_token(self, request): self._check_server_key(request=request) request_body: CreateEmailVerifyingTokenRequest = convert_request( CreateEmailVerifyingTokenRequest, await request.json()) user: User = await self.user_repository.find_user_by_id( request_body.user_id) if not user: return json_response(reason=f"user not found", status=404) user_claim: VerifyUserEmailClaim = deserialize.deserialize( VerifyUserEmailClaim, { "id": str(user.id), "type": int(user.type), "exp": time.time() + self.ACCESS_TOKEN_EXPIRE_TIME, }, ) token = user_claim.to_jwt(self.jwt_secret) return json_response(result=token)
async def verify_myself(self, request): request_body: VerifyEmailRequest = convert_request( VerifyEmailRequest, await request.json()) user_info: VerifyUserEmailClaim = VerifyUserEmailClaim.from_jwt( request_body.temp_token, self.jwt_secret) user: User = await self.user_repository.find_user_by_id(user_info.id) if not user: return json_response(reason=f"user not found", status=404) await self.user_repository.update_user( user_id=user_info.id, is_email_verified=True, ) await self._send_user_update_event( original=user, delta={ "is_email_verified": True, }, ) return json_response(result=True)
async def reset_email_user_password(self, request): request_body: ResetPasswordRequest = convert_request( ResetPasswordRequest, await request.json()) user_info: ResetPasswordClaim = ResetPasswordClaim.from_jwt( request_body.temp_token, self.jwt_secret) if user_info.type != UserType.EMAIL: return json_response(reason=f"only email user can reset password", status=400) if not is_valid_password(request_body.new_password): return json_response(reason="password policy is not satisfied", status=400) hashed_password = bcrypt.hashpw(request_body.new_password.encode(), bcrypt.gensalt()).decode() affected_rows = await self.user_repository.update_user( user_id=user_info.id, hashed_password=hashed_password, ) return json_response(result=affected_rows > 0)
async def update_myself(self, request): user_info: UserClaim = get_bearer_token(self.jwt_secret, request) request_body: UpdateUserRequest = convert_request( UpdateUserRequest, await request.json()) if not is_valid_email(request_body.email): return json_response( reason=f'{request_body.email} is invalid email format', status=400) user: User = await find_user_by_id(user_info.id) if not user: return json_response(reason=f'user not found', status=404) verified_status = {} if user.email != request_body.email: verified_status['is_email_verified'] = False affected_rows = await update_user( user_id=user_info.id, email=request_body.email, extra=request_body.extra, **verified_status, ) return json_response(result=affected_rows > 0)