From 89d53d31fcb23e4792924d12b43b37374b25b140 Mon Sep 17 00:00:00 2001 From: JustIceO7 Date: Thu, 6 Feb 2025 02:09:33 +0000 Subject: [PATCH] UPDATE: Started implementing the email for reset password --- web_server/blueprints/email.py | 51 ++++++++++++++++++++++++++-------- web_server/blueprints/user.py | 14 ++++++---- web_server/utils/user_utils.py | 11 ++++++-- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/web_server/blueprints/email.py b/web_server/blueprints/email.py index b588f7c..67d75bb 100644 --- a/web_server/blueprints/email.py +++ b/web_server/blueprints/email.py @@ -4,10 +4,13 @@ from email.mime.text import MIMEText from os import getenv from random import randrange from dotenv import load_dotenv +from utils.user_utils import generate_token +from secrets import token_hex + load_dotenv() -def send_email(email) -> None: +def send_email(email, func) -> None: """ Send a verification email to the user. """ @@ -20,15 +23,8 @@ def send_email(email) -> None: # Setup up the receiver details login_code = randrange(100000, 1000000) - body = f""" - - - -

Thank you for choosing Gander

-

Your Gander login code is: {login_code}

- - - """ + body = func() + print(body, flush=True) msg = MIMEText(body, "html") msg["Subject"] = "Reset Gander Login" msg["From"] = SMTP_EMAIL @@ -43,7 +39,38 @@ def send_email(email) -> None: smtp.send_message(msg) except TimeoutError: - print("Server timed out") + print("Server timed out", flush=True) except Exception as e: - print("Error: ", e) \ No newline at end of file + print("Error: ", e, flush=True) + +def forgot_password_body(email): + token = generate_token(email, token_hex(32)) + url = getenv("VITE_API_URL") + + full_url = url + "/reset_password/" + token + content = f""" + + + + Password Reset + + + +
+

Gander

+

Password Reset Request

+

Click the button below to reset your password. This link is valid for 1 hour.

+ Reset Password +
+ + + """ + + return content \ No newline at end of file diff --git a/web_server/blueprints/user.py b/web_server/blueprints/user.py index c51c1d2..6508b57 100644 --- a/web_server/blueprints/user.py +++ b/web_server/blueprints/user.py @@ -1,6 +1,7 @@ -from flask import Blueprint, jsonify, session, abort +from flask import Blueprint, jsonify, session, abort, abort from utils.user_utils import * from blueprints.utils import login_required +from blueprints.email import send_email, forgot_password_body user_bp = Blueprint("user", __name__) @@ -89,14 +90,15 @@ def get_login_status(): username = session.get("username") return jsonify({'status': username is not None, 'username': username}) -@user_bp.route('/user/forgot_password/', methods=['POST']) +@user_bp.route('/user/forgot_password/', methods=['GET','POST']) def user_forgot_password(email): """ Will send link to email to reset password by looking at the user_id within session to see whos password should be reset Creates a super random number to be used a the link to reset password I guess a random number generator seeded with a secret """ + send_email(email, lambda: forgot_password_body(email)) + return email - return @user_bp.route('/user/reset_password//') def user_reset_password(token, new_password): @@ -107,7 +109,7 @@ def user_reset_password(token, new_password): if email: response = reset_password(new_password, email) if response: - return "Success" + return 200 else: - return "Failure" - return "Failure" \ No newline at end of file + abort(500) + return abort(500) \ No newline at end of file diff --git a/web_server/utils/user_utils.py b/web_server/utils/user_utils.py index bb1c4f0..d454023 100644 --- a/web_server/utils/user_utils.py +++ b/web_server/utils/user_utils.py @@ -124,11 +124,18 @@ def subscription_expiration(user_id: int, subscribed_id: int) -> int: return 0 -def verify_token(token: str) -> Optional[str]: +def generate_token(email, salt_value) -> str: + """ + Creates a token for password reset + """ + token = serializer.dumps(email, salt=salt_value) + return token + +def verify_token(token: str, salt_value) -> Optional[str]: """ Given a token verifies token and decodes the token into an email """ - email = serializer.loads(token, salt='1', max_age=3600) + email = serializer.loads(token, salt=salt_value, max_age=3600) return email if email else False def reset_password(new_password: str, email: str) -> bool: