import json from hashlib import scrypt from os import urandom from hmac import compare_digest import sqlite3 from flask import ( Flask, render_template, request, redirect, url_for, session, g, flash, ) from werkzeug.exceptions import HTTPException SCRYPT_PARAMS = {"n": 16384, "r": 8, "p": 1} HEX_CHARS = set("0123456789ABCDEF") def get_db(): if "db" not in g: g.db = sqlite3.connect("akasha.db", detect_types=sqlite3.PARSE_DECLTYPES) g.db.row_factory = sqlite3.Row return g.db def teardown(e=None): if (db := g.pop("db", None)) is not None: db.close() app = Flask(__name__) with open("./config.json", "r", encoding="utf-8") as file: config = json.load(file) app.config["SECRET_KEY"] = config["fsk"] LIGHT_URL = f"http://192.168.1.10/api/{config['light']}" del config app.teardown_appcontext(teardown) @app.errorhandler(HTTPException) def handle_bad_request(e): if request.endpoint != "static": # TODO: Create an actual error page. if "username" not in session: flash("Guest access is temporarily restricted. Please log in to continue.") return redirect(url_for("login")) flash(f"Error {e.code}: {e.name}") flash("You have been redirected to the main page.") return redirect(url_for("index")) return e @app.route("/") def index(): db = get_db() cur = db.cursor() cur.execute("SELECT * FROM news ORDER BY id DESC LIMIT 1") results = cur.fetchone() return render_template("index.html", news=results) @app.route("/login", methods=["GET", "POST"]) def login(): db = get_db() if request.method == "POST": username = request.form.get("username") password = request.form.get("password") if not username or not password: flash("Error: Empty username or password.") return redirect(url_for("login")) if request.form.get("register") == "1": cur = db.cursor() cur.execute("SELECT 1 FROM users WHERE username=?", (username,)) if cur.fetchone(): flash("Error: User already exists.") return redirect(url_for("login")) salt = urandom(32) hash = scrypt(password.encode("utf-8"), salt=salt, **SCRYPT_PARAMS) cur.execute( "INSERT INTO users (username, hash, salt) VALUES (?, ?, ?)", (username, hash, salt), ) flash("Success: User registered.") db.commit() else: cur = db.cursor() cur.execute("SELECT hash, salt FROM users WHERE username=?", (username,)) results = cur.fetchone() if not results: flash("Error: Invalid username or password.") return redirect(url_for("login")) expected_hash, salt = results actual_hash = scrypt(password.encode("utf-8"), salt=salt, **SCRYPT_PARAMS) if not compare_digest(expected_hash, actual_hash): flash("Error: Invalid username or password.") return redirect(url_for("login")) session["username"] = username flash(f"Success: Logged in as {username}.") return redirect(url_for("index")) return render_template("login.html") @app.route("/logout") def logout(): if "username" in session: del session["username"] flash("Success: You have been logged out.") return redirect(url_for("index")) @app.route("/hyde") def hydematch(): if "username" not in session: flash( "The Drosera Springs Wrestling Database is only available to logged-in users." ) return redirect(url_for("login")) db = get_db() cur = db.cursor() cur.execute("SELECT * FROM matches ORDER BY id DESC") results = cur.fetchall() return render_template("hyde.html", matches=results)