better password management
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
from flask import render_template, request, flash, redirect, url_for, Blueprint, jsonify
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from models import db, User, Notif
|
||||
from models import db, User, Notif, PasswordSetupToken
|
||||
from functools import wraps
|
||||
from datetime import datetime
|
||||
from utils import log_event, create_notification, get_unread_count
|
||||
import string
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
@@ -215,4 +216,81 @@ def init_routes(auth_bp):
|
||||
flash('Password changed successfully!', 'success')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
return render_template('auth/change_password.html')
|
||||
return render_template('auth/change_password.html')
|
||||
|
||||
@auth_bp.route('/setup-password/<token>', methods=['GET', 'POST'])
|
||||
def setup_password(token):
|
||||
# Find the token
|
||||
setup_token = PasswordSetupToken.query.filter_by(token=token).first()
|
||||
|
||||
if not setup_token or not setup_token.is_valid():
|
||||
flash('Invalid or expired password setup link. Please contact your administrator for a new link.', 'error')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
if request.method == 'POST':
|
||||
password = request.form.get('password')
|
||||
confirm_password = request.form.get('confirm_password')
|
||||
|
||||
if not password or not confirm_password:
|
||||
flash('Please fill in all fields.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
if password != confirm_password:
|
||||
flash('Passwords do not match.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
# Password requirements
|
||||
if len(password) < 8:
|
||||
flash('Password must be at least 8 characters long.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
if not any(c.isupper() for c in password):
|
||||
flash('Password must contain at least one uppercase letter.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
if not any(c.islower() for c in password):
|
||||
flash('Password must contain at least one lowercase letter.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
if not any(c.isdigit() for c in password):
|
||||
flash('Password must contain at least one number.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
if not any(c in string.punctuation for c in password):
|
||||
flash('Password must contain at least one special character.', 'error')
|
||||
return render_template('auth/setup_password.html')
|
||||
|
||||
# Update user's password
|
||||
user = setup_token.user
|
||||
user.set_password(password)
|
||||
|
||||
# Mark token as used
|
||||
setup_token.used = True
|
||||
|
||||
# Create password change notification
|
||||
create_notification(
|
||||
notif_type='password_changed',
|
||||
user_id=user.id,
|
||||
details={
|
||||
'message': 'Your password has been set up successfully.',
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
# Log password setup event
|
||||
log_event(
|
||||
event_type='user_update',
|
||||
details={
|
||||
'user_id': user.id,
|
||||
'user_name': f"{user.username} {user.last_name}",
|
||||
'update_type': 'password_setup',
|
||||
'success': True
|
||||
}
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
flash('Password set up successfully! You can now log in.', 'success')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
return render_template('auth/setup_password.html')
|
||||
Reference in New Issue
Block a user