from flask import ( Blueprint, render_template, request, redirect, url_for, flash, session ) from ..models import Users, Sessions from ..constants import InfoboxKind, PermissionLevel from ..auth import digest, verify import secrets import time import re bp = Blueprint("users", __name__, url_prefix = "/users/") def is_logged_in(): return "pyrom_session_key" in session def get_active_user(): if not is_logged_in(): return None sess = Sessions.find({"key": session["pyrom_session_key"]}) if not sess: return None return Users.find({"id": sess.user_id}) def create_session(user_id): return Sessions.create({ "key": secrets.token_hex(16), "user_id": user_id, "expires_at": int(time.time()) + 30 * 24 * 60 * 60, }) def validate_password(password): pattern = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])(?!.*\s).{10,255}$' return bool(re.fullmatch(pattern, password)) def validate_username(username): pattern = r'^[a-zA-Z0-9_-]{3,20}$' return bool(re.fullmatch(pattern, username)) @bp.get("/log_in") def log_in(): return render_template("users/log_in.html") @bp.post("/log_in") def log_in_post(): target_user = Users.find({ "username": request.form['username'] }) if not target_user: flash("Incorrect username or password.", InfoboxKind.ERROR) return redirect(url_for("users.log_in")) if not verify(target_user.password_hash, request.form['password']): flash("Incorrect username or password.", InfoboxKind.ERROR) return redirect(url_for("users.log_in")) session_obj = create_session(target_user.id) session['pyrom_session_key'] = session_obj.key flash("Logged in!", InfoboxKind.INFO) return redirect(url_for("users.log_in")) @bp.get("/sign_up") def sign_up(): return render_template("users/sign_up.html") @bp.post("/sign_up") def sign_up_post(): username = request.form['username'] password = request.form['password'] password_confirm = request.form['password-confirm'] if not validate_username(username): flash("Invalid username.", InfoboxKind.ERROR) return redirect(url_for("users.sign_up")) user_exists = Users.count({"username": username}) > 0 if user_exists: flash(f"Username '{username}' is already taken.", InfoboxKind.ERROR) return redirect(url_for("users.sign_up")) if not validate_password(password): flash("Invalid password.", InfoboxKind.ERROR) return redirect(url_for("users.sign_up")) if password != password_confirm: flash("Passwords do not match.", InfoboxKind.ERROR) return redirect(url_for("users.sign_up")) hashed = digest(password) new_user = Users.create({ "username": username, "password_hash": hashed, "permission": PermissionLevel.GUEST.value, }) session_obj = create_session(new_user.id) session['pyrom_session_key'] = session_obj.key flash("Signed up successfully!", InfoboxKind.INFO) return redirect(url_for("users.sign_up")) @bp.get("/") def page(username): return "stub" @bp.get("//setings") def settings(username): return "stub" @bp.get("//inbox") def inbox(username): return "stub" @bp.get("/list") def user_list(): return "stub"