74 lines
2.3 KiB
Python
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")
|