diff --git a/.gitignore b/.gitignore index 75f20af..1149575 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ database.db -uploads -__pycache__ \ No newline at end of file +uploads \ No newline at end of file diff --git a/README.md b/README.md index d484197..d13ed3e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ burgercat: burger social media -now back again! - ### self hosting: -this guide assumes you have git, python3, and redis installed on your server +this guide assumes you have git and python3 installed ``` git clone https://codeberg.org/burger-software/burgercat @@ -12,7 +10,9 @@ python init_db python main ``` +### zero downtime restarts: +- launch new burgercat server +- close previous server + ### contribution guidelines: -- please check that your PR does not break anything -- unless absolutely nessecary, avoid adding dependecies -- for consistency, use quotation marks, not apostrophes when possible \ No newline at end of file +- please check that your PR does not break anything \ No newline at end of file diff --git a/config.ini b/config.ini index 596f2a9..b4471fb 100644 --- a/config.ini +++ b/config.ini @@ -3,4 +3,4 @@ PORT = 8080 SECRET_KEY = placeholder UPLOAD_FOLDER = uploads PASSWORD_REQUIREMENT = 12 -UPLOAD_LIMIT = 12 \ No newline at end of file +UPLOAD_LIMIT = 4 diff --git a/hashpass.py b/hashpass.py deleted file mode 100644 index d64f4fe..0000000 --- a/hashpass.py +++ /dev/null @@ -1,4 +0,0 @@ -from werkzeug.security import generate_password_hash, check_password_hash - -passwordthing = input("insert pass: ") -print(generate_password_hash(passwordthing)) \ No newline at end of file diff --git a/main b/main index 15521d5..57a5084 100644 --- a/main +++ b/main @@ -7,16 +7,15 @@ import json import secrets import datetime import socket -import threading import subprocess -import asyncio -from hypercorn.config import Config -from hypercorn.asyncio import serve from itertools import groupby +from waitress import serve from werkzeug.utils import secure_filename from werkzeug.security import generate_password_hash, check_password_hash -from quart import Quart, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request, jsonify, websocket -from apscheduler.schedulers.background import BackgroundScheduler +from werkzeug.middleware.proxy_fix import ProxyFix +from flask import Flask, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request +from flask_limiter import Limiter +from flask_limiter.util import get_remote_address # read config file config = configparser.ConfigParser() @@ -28,10 +27,20 @@ UPLOAD_FOLDER = config["config"]["UPLOAD_FOLDER"] UPLOAD_LIMIT = config["config"]["UPLOAD_LIMIT"] PASSWORD_REQUIREMENT = config["config"]["PASSWORD_REQUIREMENT"] -app = Quart(__name__) +app = Flask(__name__) app.config["SECRET_KEY"] = SECRET_KEY app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000 +app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1) + +limiter = Limiter( + get_remote_address, + app = app, + default_limits = ["3 per second"], + storage_uri = "memory://", + strategy = "fixed-window" +) + if SECRET_KEY == "placeholder": print("[WARNING] Secret key is not set") @@ -121,14 +130,15 @@ def get_session(id): full_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode().strip() short_hash = subprocess.check_output(["git", "rev-parse", "--short=8", "HEAD"]).decode().strip() -ALLOWED_EXTENSIONS = {"png", "apng", "jpg", "jpeg", "gif", "svg", "webp", "jxl"} +ALLOWED_EXTENSIONS = {"png", "apng", "jpg", "jpeg", "gif", "svg", "webp"} def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + @app.route("/", methods=("GET", "POST")) -async def main(): +def main(): usersession = request.cookies.get("session_DO_NOT_SHARE") conn = get_db_connection() posts = conn.execute("SELECT * FROM posts ORDER BY created DESC;").fetchall() @@ -137,24 +147,24 @@ async def main(): if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return await render_template("main.html", userdata=user, posts=posts, full_hash=full_hash, short_hash=short_hash) + return render_template("main.html", userdata=user, posts=posts, full_hash=full_hash, short_hash=short_hash) else: - return await render_template("main.html", posts=posts, full_hash=full_hash, short_hash=short_hash) + return render_template("main.html", posts=posts, full_hash=full_hash, short_hash=short_hash) @app.route("/chat", methods=("GET", "POST")) -async def chat(): +def chat(): usersession = request.cookies.get("session_DO_NOT_SHARE") if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return await render_template("chat.html", userdata=user) + return render_template("chat.html", userdata=user) else: - return await render_template("chat.html") + return render_template("chat.html") @app.route("/api/chat/listrooms") -async def chatlistrooms(): +def chatlistrooms(): conn = get_db_connection() - rooms = conn.execute("SELECT * FROM chatrooms ORDER BY id ASC;").fetchall() + rooms = conn.execute("SELECT * FROM chatrooms ORDER BY roomname ASC;").fetchall() conn.close() template = [] @@ -169,8 +179,9 @@ async def chatlistrooms(): return(template), 200 @app.route("/api/chat/getmessages/") -async def chatget(roomid): - messages = get_messages(roomid, 150) +@limiter.exempt +def chatget(roomid): + messages = get_messages(roomid, 40) template = [] @@ -192,16 +203,21 @@ async def chatget(roomid): return(template), 200 +burgerMessageUpdate = True +burgerMessageCache = "" @app.route("/api/chat/send/", methods=("GET", "POST")) -async def chatsend(roomid): +def chatsend(roomid): usersession = request.cookies.get("session_DO_NOT_SHARE") if usersession: if request.method == "POST": - data = await request.get_json() + data = request.get_json() content = data["content"] + print(content) + print(roomid) + userCookie = get_session(usersession) user = get_user(userCookie["id"]) @@ -210,26 +226,22 @@ async def chatsend(roomid): "error": "banned" }, 403 - chatMessageContent = { - "content": content, - "creator": user["username"], - "roomid": roomid, - "created": str(time.time()) - } - - #message_queue.append({"message": chatMessageContent}) - conn = get_db_connection() conn.execute("INSERT INTO chatmessages (content, chatroom_id, creator, created) VALUES (?, ?, ?, ?)", (content, roomid, userCookie["id"], str(time.time()))) conn.commit() conn.close() + global burgerMessageCache + global burgerMessageUpdate + burgerMessageUpdate = True + burgerMessageCache = user["username"] + ": " + content + return "success", 200 @app.route("/@", methods=("GET", "POST")) -async def user(pageusername): +def user(pageusername): usersession = request.cookies.get("session_DO_NOT_SHARE") checkusername = check_username_taken(pageusername) @@ -239,20 +251,20 @@ async def user(pageusername): if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return await render_template("user.html", userdata=user, createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) + return render_template("user.html", userdata=user, createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) else: - return await render_template("user.html", createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) + return render_template("user.html", createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) else: return """""", 404 @app.route("/api/page/", methods=("GET", "POST")) -async def apipageuser(userid): +def apipageuser(userid): pageuser = get_user(userid) addhtml = """ - """ + """ if not pageuser == "error": return addhtml + pageuser["htmldescription"] @@ -260,7 +272,7 @@ async def apipageuser(userid): return """""", 404 @app.route("/@/edit", methods=("GET", "POST")) -async def edituser(pageusername): +def edituser(pageusername): usersession = request.cookies.get("session_DO_NOT_SHARE") checkusername = check_username_taken(pageusername) @@ -272,9 +284,7 @@ async def edituser(pageusername): user = get_user(userCookie["id"]) if pageuser["username"] == user["username"]: if request.method == "POST": - requestData = await request.form - - code = requestData["code"].replace("Content-Security-Policy", "").replace("