add a way for mods to create a password reset link for users

This commit is contained in:
2025-08-10 19:00:47 +03:00
parent cf2d605077
commit 4c2877403d
6 changed files with 114 additions and 3 deletions

View File

@ -1,9 +1,12 @@
from flask import (
Blueprint, render_template, request, redirect, url_for
)
from .users import login_required, mod_only, get_active_user
from ..models import Users
from .users import login_required, mod_only, get_active_user, admin_only
from ..models import Users, PasswordResetLinks
from ..db import db, DB
import secrets
import time
bp = Blueprint("mod", __name__, url_prefix = "/mod/")
@bp.get("/sort-topics")
@ -31,3 +34,18 @@ def sort_topics_post():
def user_list():
users = Users.select()
return render_template("mod/user-list.html", users = users)
@bp.post("/reset-pass/<user_id>")
@login_required
@mod_only("topics.all_topics")
def create_reset_pass(user_id):
now = int(time.time())
key = secrets.token_urlsafe(20)
reset_link = PasswordResetLinks.create({
'user_id': int(user_id),
'expires_at': now + 24 * 60 * 60,
'key': key,
})
return redirect(url_for('users.reset_link_login', key=key))

View File

@ -4,7 +4,7 @@ from flask import (
from functools import wraps
from ..db import db
from ..lib.babycode import babycode_to_html
from ..models import Users, Sessions, Subscriptions, Avatars
from ..models import Users, Sessions, Subscriptions, Avatars, PasswordResetLinks
from ..constants import InfoboxKind, PermissionLevel
from ..auth import digest, verify
from wand.image import Image
@ -516,3 +516,60 @@ def inbox(username):
})
return render_template("users/inbox.html", new_posts = new_posts, total_unreads_count = total_unreads_count, all_subscriptions = all_subscriptions)
@bp.get('/reset-link/<key>')
def reset_link_login(key):
reset_link = PasswordResetLinks.find({
'key': key
})
if not reset_link:
return redirect(url_for('topics.all_topics'))
if int(time.time()) > int(reset_link.expires_at):
reset_link.delete()
return redirect(url_for('topics.all_topics'))
target_user = Users.find({
'id': reset_link.user_id
})
return render_template('users/reset_link_login.html', username = target_user.username)
@bp.post('/reset-link/<key>')
def reset_link_login_form(key):
reset_link = PasswordResetLinks.find({
'key': key
})
if not reset_link:
return redirect('topics.all_topics')
if int(time.time()) > int(reset_link.expires_at):
reset_link.delete()
return redirect('topics.all_topics')
password = request.form.get('password')
password2 = request.form.get('password2')
if not validate_password(password):
flash("Invalid password.", InfoboxKind.ERROR)
return redirect(url_for('.reset_link_login', key=key))
if password != password2:
flash("Passwords do not match.", InfoboxKind.ERROR)
return redirect(url_for('.reset_link_login', key=key))
target_user = Users.find({
'id': reset_link.user_id
})
reset_link.delete()
hashed = digest(password)
target_user.update({'password_hash': hashed})
session_obj = create_session(target_user.id)
session['pyrom_session_key'] = session_obj.key
flash("Logged in!", InfoboxKind.INFO)
return redirect(url_for('.page', username=target_user.username))