better password management
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
|
||||
from flask_login import login_required, current_user
|
||||
from models import db, User, Notif
|
||||
from models import db, User, Notif, PasswordSetupToken
|
||||
from forms import UserForm
|
||||
from flask import abort
|
||||
from sqlalchemy import or_
|
||||
@@ -9,7 +9,9 @@ from utils import log_event, create_notification, get_unread_count
|
||||
import json
|
||||
import os
|
||||
from werkzeug.utils import secure_filename
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import secrets
|
||||
import string
|
||||
|
||||
contacts_bp = Blueprint('contacts', __name__, url_prefix='/contacts')
|
||||
|
||||
@@ -113,6 +115,10 @@ def new_contact():
|
||||
file.save(file_path)
|
||||
profile_picture = filename
|
||||
|
||||
# Generate a random password
|
||||
alphabet = string.ascii_letters + string.digits + string.punctuation
|
||||
random_password = ''.join(secrets.choice(alphabet) for _ in range(32))
|
||||
|
||||
# Create new user account
|
||||
user = User(
|
||||
username=form.first_name.data,
|
||||
@@ -126,10 +132,20 @@ def new_contact():
|
||||
is_admin=form.is_admin.data,
|
||||
profile_picture=profile_picture
|
||||
)
|
||||
user.set_password('changeme') # Set default password
|
||||
user.set_password(random_password) # Set random password
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
# Create password setup token
|
||||
token = secrets.token_urlsafe(32)
|
||||
setup_token = PasswordSetupToken(
|
||||
user_id=user.id,
|
||||
token=token,
|
||||
expires_at=datetime.utcnow() + timedelta(hours=24)
|
||||
)
|
||||
db.session.add(setup_token)
|
||||
db.session.commit()
|
||||
|
||||
# Create notification for the new user
|
||||
create_notification(
|
||||
notif_type='account_created',
|
||||
@@ -140,7 +156,8 @@ def new_contact():
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'created_by': f"{current_user.username} {current_user.last_name}",
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'setup_link': url_for('auth.setup_password', token=token, _external=True)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -159,7 +176,7 @@ def new_contact():
|
||||
)
|
||||
db.session.commit()
|
||||
|
||||
flash('User created successfully! They will need to change their password on first login.', 'success')
|
||||
flash('User created successfully! They will receive an email with a link to set up their password.', 'success')
|
||||
return redirect(url_for('contacts.contacts_list'))
|
||||
return render_template('contacts/form.html', form=form, title='New User', total_admins=total_admins)
|
||||
|
||||
@@ -446,4 +463,54 @@ def toggle_active(id):
|
||||
db.session.commit()
|
||||
|
||||
flash(f'User marked as {"active" if user.is_active else "inactive"}!', 'success')
|
||||
return redirect(url_for('contacts.contacts_list'))
|
||||
|
||||
@contacts_bp.route('/<int:id>/resend-setup', methods=['POST'])
|
||||
@login_required
|
||||
@require_password_change
|
||||
def resend_setup_link(id):
|
||||
result = admin_required()
|
||||
if result: return result
|
||||
|
||||
user = User.query.get_or_404(id)
|
||||
|
||||
# Create new password setup token
|
||||
token = secrets.token_urlsafe(32)
|
||||
setup_token = PasswordSetupToken(
|
||||
user_id=user.id,
|
||||
token=token,
|
||||
expires_at=datetime.utcnow() + timedelta(hours=24)
|
||||
)
|
||||
db.session.add(setup_token)
|
||||
|
||||
# Create notification for the user
|
||||
create_notification(
|
||||
notif_type='account_created',
|
||||
user_id=user.id,
|
||||
sender_id=current_user.id,
|
||||
details={
|
||||
'message': 'A new password setup link has been sent to you.',
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'created_by': f"{current_user.username} {current_user.last_name}",
|
||||
'timestamp': datetime.utcnow().isoformat(),
|
||||
'setup_link': url_for('auth.setup_password', token=token, _external=True)
|
||||
}
|
||||
)
|
||||
|
||||
# Log the event
|
||||
log_event(
|
||||
event_type='user_update',
|
||||
details={
|
||||
'user_id': user.id,
|
||||
'user_name': f"{user.username} {user.last_name}",
|
||||
'updated_by': current_user.id,
|
||||
'updated_by_name': f"{current_user.username} {current_user.last_name}",
|
||||
'update_type': 'password_setup_link_resend'
|
||||
}
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
flash('Password setup link has been resent to the user.', 'success')
|
||||
return redirect(url_for('contacts.contacts_list'))
|
||||
Reference in New Issue
Block a user