diff --git a/app/controllers/login.py b/app/controllers/login.py index 457e17e..265918f 100644 --- a/app/controllers/login.py +++ b/app/controllers/login.py @@ -5,7 +5,7 @@ from urllib.parse import urlparse from flask import Blueprint, render_template, request, redirect, flash, session -from app.models.user import user_by_name +from app.models.user import user_by_name, user_by_mail from app.models.errors import ErrNoResult from app.services.passhash import match_string from app.services.limiter import limit @@ -66,9 +66,21 @@ def login_post(): # Track login attempts attempts = session.get('login_attempt', 0) + # Try email lookup first, then username (email takes precedence) + user = None try: - user = user_by_name(name) + try: + user = user_by_mail(name) + except ErrNoResult: + user = user_by_name(name) + except ErrNoResult: + pass # Neither found, user stays None + except Exception as e: + print(f"Login error: {e}") + flash('There was an error. Please try again later.', FLASH_ERROR) + return render_template('login/login.html') + if user: # Check password if match_string(user['password'], password): # Login successful @@ -76,7 +88,7 @@ def login_post(): session['email'] = user['email'] session['name'] = user['name'] flash('Login successful!', FLASH_SUCCESS) - + # Retrieve and clear the redirect from session # Only allow relative URLs to prevent redirecting to external sites redirect_url = session.pop('login_redirect', '/') @@ -87,16 +99,11 @@ def login_post(): attempts += 1 session['login_attempt'] = attempts flash(f'Password is incorrect - Attempt: {attempts}', FLASH_WARNING) - - except ErrNoResult: + else: attempts += 1 session['login_attempt'] = attempts flash(f'Password is incorrect - Attempt: {attempts}', FLASH_WARNING) - except Exception as e: - print(f"Login error: {e}") - flash('There was an error. Please try again later.', FLASH_ERROR) - return render_template('login/login.html') diff --git a/app/controllers/password_reset.py b/app/controllers/password_reset.py index 34d1270..e445f21 100644 --- a/app/controllers/password_reset.py +++ b/app/controllers/password_reset.py @@ -113,8 +113,10 @@ def reset_password_get(token): """Display the reset password form.""" try: # Validate token exists and is not expired - get_reset_token(token) - return render_template('password_reset/reset.html', token=token) + token_doc = get_reset_token(token) + # Look up user to get username + user = user_by_mail(token_doc['email']) + return render_template('password_reset/reset.html', token=token, username=user['name']) except ErrNoResult: flash('This password reset link is invalid or has expired.', FLASH_ERROR) return redirect('/forgot-password') @@ -131,46 +133,50 @@ def reset_password_post(token): new_password = request.form.get('new_password', '') new_password_verify = request.form.get('new_password_verify', '') + # Validate token and get user first (so we can show username in error messages) + try: + token_doc = get_reset_token(token) + email = token_doc['email'] + user = user_by_mail(email) + username = user['name'] + except ErrNoResult: + flash('This password reset link is invalid or has expired.', FLASH_ERROR) + return redirect('/forgot-password') + except Exception as e: + print(f"Error validating reset token: {e}") + flash('An error occurred. Please try again.', FLASH_ERROR) + return redirect('/forgot-password') + # Validate passwords if not new_password or not new_password_verify: flash('Please fill in all password fields', FLASH_ERROR) - return render_template('password_reset/reset.html', token=token) + return render_template('password_reset/reset.html', token=token, username=username) if new_password != new_password_verify: flash('Passwords do not match', FLASH_ERROR) - return render_template('password_reset/reset.html', token=token) + return render_template('password_reset/reset.html', token=token, username=username) if len(new_password) < 8: flash('Password must be at least 8 characters long', FLASH_ERROR) - return render_template('password_reset/reset.html', token=token) + return render_template('password_reset/reset.html', token=token, username=username) try: - # Validate token and get associated email - token_doc = get_reset_token(token) - email = token_doc['email'] - - # Find user by email - user = user_by_mail(email) - # Hash new password hashed_password = hash_string(new_password) # Update user's password - update_user_password(user['name'], hashed_password) + update_user_password(username, hashed_password) # Delete the used token delete_reset_token(token) # Notify moderation channel - notify_password_reset_complete(user['name'], email) + notify_password_reset_complete(username, email) - flash('Your password has been reset successfully. You can now log in.', FLASH_SUCCESS) + flash(f'Password reset successfully for {username}. You can now log in.', FLASH_SUCCESS) return redirect('/login') - except ErrNoResult: - flash('This password reset link is invalid or has expired.', FLASH_ERROR) - return redirect('/forgot-password') except Exception as e: print(f"Error resetting password: {e}") flash('An error occurred while resetting your password. Please try again.', FLASH_ERROR) - return render_template('password_reset/reset.html', token=token) + return render_template('password_reset/reset.html', token=token, username=username) diff --git a/app/controllers/register.py b/app/controllers/register.py index 66a4159..7e99617 100644 --- a/app/controllers/register.py +++ b/app/controllers/register.py @@ -77,7 +77,7 @@ def register_post(): flash('An error occurred on the server. Please try again later.', FLASH_ERROR) return redirect('/register') - # Check if email already exists + # Check if email already exists as an email try: user_by_mail(email) flash(f'Account already exists for: {email}', FLASH_ERROR) @@ -89,22 +89,49 @@ def register_post(): flash('An error occurred on the server. Please try again later.', FLASH_ERROR) return render_template('register/register.html', name=name, email=email) - # Check if username already exists + # Check if username already exists as a username try: user_by_name(name) flash(f'Account already exists for: {name}', FLASH_ERROR) return render_template('register/register.html', name=name, email=email) except ErrNoResult: - # Username not taken, create account - try: - user_create(name, email, hashed_password) - flash(f'Account created successfully for: {name}', FLASH_SUCCESS) - return redirect('/login') - except Exception as e: - print(f"User creation error: {e}") - flash('An error occurred on the server. Please try again later.', FLASH_ERROR) + pass # Username not taken, continue except Exception as e: print(f"Database error: {e}") flash('An error occurred on the server. Please try again later.', FLASH_ERROR) + return render_template('register/register.html', name=name, email=email) + + # Cross-check: username must not match an existing user's email + try: + user_by_mail(name) + flash('This username is not available', FLASH_ERROR) + return render_template('register/register.html', name=name, email=email) + except ErrNoResult: + pass # No conflict, continue + except Exception as e: + print(f"Database error: {e}") + flash('An error occurred on the server. Please try again later.', FLASH_ERROR) + return render_template('register/register.html', name=name, email=email) + + # Cross-check: email must not match an existing user's username + try: + user_by_name(email) + flash('This email is not available', FLASH_ERROR) + return render_template('register/register.html', name=name, email=email) + except ErrNoResult: + pass # No conflict, continue + except Exception as e: + print(f"Database error: {e}") + flash('An error occurred on the server. Please try again later.', FLASH_ERROR) + return render_template('register/register.html', name=name, email=email) + + # All checks passed, create account + try: + user_create(name, email, hashed_password) + flash(f'Account created successfully for: {name}', FLASH_SUCCESS) + return redirect('/login') + except Exception as e: + print(f"User creation error: {e}") + flash('An error occurred on the server. Please try again later.', FLASH_ERROR) return render_template('register/register.html', name=name, email=email) diff --git a/templates/login/login.html b/templates/login/login.html index 9f3829a..4b70a89 100644 --- a/templates/login/login.html +++ b/templates/login/login.html @@ -11,10 +11,10 @@
Resetting password for: {{ username }}
Enter your new password below.