import hashlib import hmac import secrets from utils.config import get_app_settings, save_app_settings def hash_password(password, salt=None): salt = salt or secrets.token_hex(16) digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt.encode("utf-8"), 480000) return f"pbkdf2_sha256${salt}${digest.hex()}" def verify_password(password, stored_hash): if not stored_hash or "$" not in stored_hash: return False algorithm, salt, digest = stored_hash.split("$", 2) if algorithm != "pbkdf2_sha256": return False candidate = hash_password(password, salt=salt) return hmac.compare_digest(candidate, stored_hash) def is_bootstrapped(): return bool(get_app_settings().get("admin_password_hash")) def bootstrap_admin_password(password, username="admin"): settings = get_app_settings(force_reload=True) settings["admin_username"] = username.strip() or "admin" settings["admin_password_hash"] = hash_password(password) return save_app_settings(settings) def update_admin_password(password): settings = get_app_settings(force_reload=True) settings["admin_password_hash"] = hash_password(password) return save_app_settings(settings) def issue_session(request, username): request.session.clear() request.session["user"] = username request.session["csrf_token"] = secrets.token_urlsafe(24) def clear_session(request): request.session.clear() def current_user(request): return request.session.get("user") def csrf_token(request): token = request.session.get("csrf_token") if not token: token = secrets.token_urlsafe(24) request.session["csrf_token"] = token return token def validate_csrf(request, submitted_token): stored_token = request.session.get("csrf_token") return bool(stored_token and submitted_token and hmac.compare_digest(stored_token, submitted_token)) def is_https_request(request): forwarded_proto = request.headers.get("x-forwarded-proto", "") if forwarded_proto: return forwarded_proto.lower() == "https" return request.url.scheme == "https"