def verify(enc_email: str, secret: str, app_id: str) -> Optional[str]: email = config.FERNET.decrypt(unquote(enc_email).encode("utf-8")).decode("utf-8") secret_hash = MAGIC_STORE.get(f"{app_id}:magic:{email}") if PWD_CONTEXT.verify(secret, secret_hash): MAGIC_STORE.expire(f"{app_id}:magic:{email}", datetime.timedelta(seconds=1)) return email return None
async def generate_refresh_token(email: str, client_app: ClientApp) -> str: if not client_app.get_refresh_key( ) or not client_app.refresh_token_expire_hours: raise TokenCreationError("Refresh is not enabled") uid = str(uuid.uuid4()) payload = { "iss": f"{config.ISSUER}/app/{client_app.app_id}", "sub": email, "uid": uid, } token = jwt.generate_jwt( payload, client_app.get_refresh_key(), "ES256", datetime.timedelta(hours=client_app.refresh_token_expire_hours), ) token_hash = PWD_CONTEXT.hash(token) expires = datetime.datetime.now() + datetime.timedelta( hours=client_app.refresh_token_expire_hours) await RefreshToken( app_id=client_app.app_id, email=email, hash=token_hash, expires=expires, uid=uid, ).insert() return token
def generate(email: str, app_id: str) -> str: code = "".join(secrets.choice(string.digits) for _ in range(config.OTP_LENGTH)) code_hash = PWD_CONTEXT.hash(code) OTP_STORE.set(f"{app_id}:otp:{email}", code_hash) OTP_STORE.expire( f"{app_id}:otp:{email}", datetime.timedelta(minutes=config.OTP_LIFETIME) ) return code
async def verify_refresh_token(token: str, client_app: ClientApp) -> str: _, claims = _check_token(token, client_app.get_refresh_key(), client_app.app_id) found_rt = await _find_refresh_token(claims, client_app) if found_rt.expires <= datetime.datetime.now(): await found_rt.delete() raise TokenVerificationError("Expired Token. Please log in again.") if PWD_CONTEXT.verify(token, found_rt.hash): return generate(claims["sub"], client_app) raise TokenVerificationError("Could not find matching refresh token")
def generate(email: str, app_id: str) -> str: url_secret = secrets.token_urlsafe() secret_hash = PWD_CONTEXT.hash(url_secret) MAGIC_STORE.set(f"{app_id}:magic:{email}", secret_hash) MAGIC_STORE.expire( f"{app_id}:magic:{email}", datetime.timedelta(minutes=config.MAGIC_LIFETIME) ) enc_email = config.FERNET.encrypt(email.encode("utf-8")) return ( f"{config.HOST}/magic/confirm/{app_id}?secret={url_secret}" f"&id={quote_plus(enc_email)}" )
def verify_dp_code(user: User, delete_id: str, code: str) -> bool: """ Verify a deletion protection code against the hash stored in redis. :param user: the user requesting the code :param delete_id: the app_id of the app to delete or "account" if they are deleting their account. :param code: :return: True if the code is valid, false otherwise """ code_hash = DP_CODE_STORE.get(f"{user.email}:{delete_id}") if PWD_CONTEXT.verify(code, code_hash): DP_CODE_STORE.expire(f"{user.email}:{delete_id}", datetime.timedelta(seconds=1)) return True return False
def generate_dp_code(user: User, delete_id: str) -> str: """ Generate a verification code for deletion protection and store it in redis. :param user: the user requesting the code :param delete_id: the app_id of the app to delete or "account" if they are deleting their account :return: the verification code """ code = "".join( secrets.choice(string.digits) for _ in range(config.OTP_LENGTH)) code_hash = PWD_CONTEXT.hash(code) DP_CODE_STORE.set(f"{user.email}:{delete_id}", code_hash) DP_CODE_STORE.expire(f"{user.email}:{delete_id}", datetime.timedelta(minutes=config.OTP_LIFETIME)) return code
def verify(email: str, code: str, app_id: str) -> bool: code_hash = OTP_STORE.get(f"{app_id}:otp:{email}") if PWD_CONTEXT.verify(code, code_hash): OTP_STORE.expire(f"{app_id}:otp:{email}", datetime.timedelta(seconds=1)) return True return False