PySimpleSocial/src/endpoints/password.py

74 lines
2.3 KiB
Python

from datetime import timedelta
from datetime import timezone, datetime
from fastapi.exceptions import HTTPException
from fastapi import APIRouter as FastAPI, Depends, Request
from config import (
LIMITER,
EMAIL_VERIFICATION_EXPIRATION,
UNVERIFIED_MANAGER,
)
from responses import (
Response as APIResponse,
UnprocessableEntity,
BadRequest,
NotFound,
)
from orm.users import User, UserModel
from orm.email_verification import EmailVerification, EmailVerificationType
router = FastAPI()
@router.get(
"/user/resetPassword/{verification_id}",
tags=["Users"],
status_code=200,
responses={
200: {"model": APIResponse},
400: {"model": BadRequest},
422: {"model": UnprocessableEntity},
404: {"model": NotFound},
},
)
@LIMITER.limit("3/second")
async def reset_password(
request: Request,
verification_id: str,
user: UserModel = Depends(UNVERIFIED_MANAGER),
):
"""
Modifies a user's password. Endpoint is limited
to 3 hits per second
"""
if not (
verification := await EmailVerification.select(*EmailVerification.all_columns())
.where(EmailVerification.id == verification_id)
.first()
):
raise HTTPException(status_code=404, detail="Request ID is invalid")
elif not verification["pending"]:
raise HTTPException(status_code=400, detail="This link has already been used")
elif datetime.now().astimezone(timezone.utc) - verification[
"creation_date"
].astimezone(timezone.utc) > timedelta(seconds=EMAIL_VERIFICATION_EXPIRATION):
raise HTTPException(
status_code=400,
detail="Verification window has expired. Try again",
)
else:
# Note how we don't update based on the verification ID:
# this way, multiple pending email verification requests
# are all cleared at once
await EmailVerification.update({EmailVerification.pending: False}).where(
EmailVerification.user == user.public_id
and EmailVerification.kind == EmailVerificationType.PASSWORD_RESET
)
await User.update({User.password_hash: verification["data"]}).where(
User.public_id == user.public_id
)
return APIResponse(status_code=200, msg="Password updated")