From a97312b2e4a853b9ba911eabb14b7bb334bd94dd Mon Sep 17 00:00:00 2001 From: ffqq Date: Thu, 13 Jul 2023 16:34:49 +0000 Subject: [PATCH 1/8] fix: xss vulnerability in chat.js --- static/js/chat.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/js/chat.js b/static/js/chat.js index 1c7194e..1df74dd 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -21,10 +21,10 @@ async function updateMessages(id) { const { creator, content, id, created } = message; // Check if the message content contains any links that are not image links and hide image links - const linkRegex = /(https?:\/\/[^\s]+(?$1"); + const hideRegex = /(https?:\/\/(?:cdn\.discordapp\.com|media\.discordapp\.net|media\.tenor\.com|i\.imgur\.com)\/.+?\.(?:png|apng|webp|svg|jpg|jpeg|gif))(?=$|\s)/gi; + let messageContent = content.replace(hideRegex, ""); - messageParagraph.innerHTML = `${creator.username}: ${messageContent}`; + messageParagraph.innerText = `${creator.username}: ${messageContent}`; messageParagraph.classList.add("messageParagraph"); messageParagraph.id = `messageParagraph${id}`; messageParagraph.appendChild(timeParagraph); -- 2.39.2 From 7c5f7efc91a2bd5c2ecb1e1dd5e212e703e6b5f4 Mon Sep 17 00:00:00 2001 From: maaa Date: Fri, 14 Jul 2023 02:29:58 +0200 Subject: [PATCH 2/8] server side events --- .gitignore | 3 +- README.md | 2 +- config.ini | 1 + main | 32 ++++++------ requirements.txt | 6 ++- static/css/style.css | 2 +- static/js/chat.js | 116 +++++++++++++++++++++---------------------- 7 files changed, 83 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 1149575..75f20af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ database.db -uploads \ No newline at end of file +uploads +__pycache__ \ No newline at end of file diff --git a/README.md b/README.md index 206be24..2f7fee2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ burgercat: burger social media ### self hosting: -this guide assumes you have git and python3 installed +this guide assumes you have git, python3, and redis installed on your server ``` git clone https://codeberg.org/burger-software/burgercat diff --git a/config.ini b/config.ini index b4471fb..ff3fe97 100644 --- a/config.ini +++ b/config.ini @@ -4,3 +4,4 @@ SECRET_KEY = placeholder UPLOAD_FOLDER = uploads PASSWORD_REQUIREMENT = 12 UPLOAD_LIMIT = 4 +REDIS_URL = redis://localhost \ No newline at end of file diff --git a/main b/main index 57a5084..bd57b71 100644 --- a/main +++ b/main @@ -7,6 +7,7 @@ import json import secrets import datetime import socket +import threading import subprocess from itertools import groupby from waitress import serve @@ -16,6 +17,8 @@ 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 +from flask_sse import sse +from apscheduler.schedulers.background import BackgroundScheduler # read config file config = configparser.ConfigParser() @@ -26,10 +29,13 @@ SECRET_KEY = config["config"]["SECRET_KEY"] UPLOAD_FOLDER = config["config"]["UPLOAD_FOLDER"] UPLOAD_LIMIT = config["config"]["UPLOAD_LIMIT"] PASSWORD_REQUIREMENT = config["config"]["PASSWORD_REQUIREMENT"] +REDIS_URL = config["config"]["REDIS_URL"] app = Flask(__name__) app.config["SECRET_KEY"] = SECRET_KEY +app.config["REDIS_URL"] = REDIS_URL app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000 +app.register_blueprint(sse, url_prefix="/stream") app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1) @@ -164,7 +170,7 @@ def chat(): @app.route("/api/chat/listrooms") def chatlistrooms(): conn = get_db_connection() - rooms = conn.execute("SELECT * FROM chatrooms ORDER BY roomname ASC;").fetchall() + rooms = conn.execute("SELECT * FROM chatrooms ORDER BY id ASC;").fetchall() conn.close() template = [] @@ -181,7 +187,7 @@ def chatlistrooms(): @app.route("/api/chat/getmessages/") @limiter.exempt def chatget(roomid): - messages = get_messages(roomid, 40) + messages = get_messages(roomid, 150) template = [] @@ -203,9 +209,6 @@ def chatget(roomid): return(template), 200 -burgerMessageUpdate = True -burgerMessageCache = "" - @app.route("/api/chat/send/", methods=("GET", "POST")) def chatsend(roomid): usersession = request.cookies.get("session_DO_NOT_SHARE") @@ -215,9 +218,6 @@ def chatsend(roomid): data = request.get_json() content = data["content"] - print(content) - print(roomid) - userCookie = get_session(usersession) user = get_user(userCookie["id"]) @@ -226,17 +226,21 @@ def chatsend(roomid): "error": "banned" }, 403 + chatMessageContent = { + "content": content, + "creator": user["username"], + "roomid": roomid, + "created": str(time.time()) + } + + sse.publish({"message": chatMessageContent}, type="publish") + 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 @@ -699,6 +703,6 @@ if __name__ == "__main__": sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) sock.bind(('', int(PORT))) - serve(app, sockets=[sock]) + serve(app, sockets=[sock], threads=9999) print("[INFO] Server stopped") diff --git a/requirements.txt b/requirements.txt index 79aec11..ccd3104 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -flask +Flask Flask-Limiter werkzeug waitress -requests \ No newline at end of file +requests +Flask-SSE +APScheduler \ No newline at end of file diff --git a/static/css/style.css b/static/css/style.css index 7ac1133..3999647 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -246,7 +246,7 @@ body { right: 0; overflow-y: auto; display: flex; - flex-direction: column-reverse; + flex-direction: column; } .messageDiv p { diff --git a/static/js/chat.js b/static/js/chat.js index 1c7194e..eed3f97 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -5,67 +5,56 @@ let statusMessage = document.getElementById("statusMessage") let channelID = 0 -// create a cache to store the images (delete this once you add SSE) -const imageCache = {}; +function addMessage(content, created, creator, roomid) { + const messageParagraph = document.createElement("p"); + const timeParagraph = document.createElement("p"); + + const hideRegex = /(https?:\/\/(?:cdn\.discordapp\.com|media\.discordapp\.net|media\.tenor\.com|i\.imgur\.com)\/.+?\.(?:png|apng|webp|svg|jpg|jpeg|gif))(?=$|\s)/gi; + let messageContent = content.replace(hideRegex, ""); + + messageParagraph.innerText = `${creator}: ${messageContent}`; + messageParagraph.classList.add("messageParagraph"); + messageParagraph.id = "messageParagraph"; + messageParagraph.appendChild(timeParagraph); + + const time = new Intl.DateTimeFormat("en-GB", { hour: "numeric", minute: "numeric" }).format(Number(created.split(".")[0]) * 1000 + 20265); + + messageParagraph.innerHTML = `${time} ${messageParagraph.innerHTML}`; + messageDiv.append(messageParagraph); + + const imgLinks = content?.match(/(https?:\/\/(?:cdn\.discordapp\.com|media\.discordapp\.net|media\.tenor\.com|i\.imgur\.com|burger\.ctaposter\.xyz)\/.+?\.(?:png|apng|webp|svg|jpg|jpeg|gif))(?=$|\s)/gi) || []; + + for (const link of imgLinks) { + const img = new Image(); + img.src = link; + img.className = "messageImage"; + img.onload = () => { + const maxWidth = 400; + const maxHeight = 400; + let { width, height } = img; + if (width > maxWidth || height > maxHeight) { + const ratio = Math.min(maxWidth / width, maxHeight / height); + width *= ratio; + height *= ratio; + } + img.width = width; + img.height = height; + messageParagraph.appendChild(img); + }; + } + messageDiv.scrollTop = messageDiv.scrollHeight - messageDiv.clientHeight; +} async function updateMessages(id) { - try { const response = await fetch(`/api/chat/getmessages/${id}`); const messages = await response.json(); statusMessage.innerText = ""; document.querySelectorAll(".messageParagraph").forEach((el) => el.remove()); - for (const message of messages) { - const messageParagraph = document.createElement("p"); - const timeParagraph = document.createElement("p"); - const { creator, content, id, created } = message; - - // Check if the message content contains any links that are not image links and hide image links - const linkRegex = /(https?:\/\/[^\s]+(?$1"); - - messageParagraph.innerHTML = `${creator.username}: ${messageContent}`; - messageParagraph.classList.add("messageParagraph"); - messageParagraph.id = `messageParagraph${id}`; - messageParagraph.appendChild(timeParagraph); - - const time = new Intl.DateTimeFormat("en-GB", { hour: "numeric", minute: "numeric" }).format(Number(created.split(".")[0]) * 1000 + 20265); - - messageParagraph.innerHTML = `${time} ${messageParagraph.innerHTML}`; - messageDiv.append(messageParagraph); - - const imgLinks = content?.match(/(https?:\/\/(?:cdn\.discordapp\.com|media\.discordapp\.net|media\.tenor\.com|i\.imgur\.com|burger\.ctaposter\.xyz)\/.+?\.(?:png|apng|webp|svg|jpg|jpeg|gif))(?=$|\s)/gi) || []; - - for (const link of imgLinks) { - // delete the code below once you add sse - if (imageCache[link]) { - messageParagraph.appendChild(imageCache[link].cloneNode(true)); - } else { - // delete the code above once you add sse - const img = new Image(); - img.src = link; - img.className = "messageImage"; - img.onload = () => { - const maxWidth = 400; - const maxHeight = 400; - let { width, height } = img; - if (width > maxWidth || height > maxHeight) { - const ratio = Math.min(maxWidth / width, maxHeight / height); - width *= ratio; - height *= ratio; - } - img.width = width; - img.height = height; - // delete the line below once you add sse - imageCache[link] = img.cloneNode(true); - messageParagraph.appendChild(img); - }; - } - } + for (const message of messages.reverse()) { + const { creator, content, roomid, created } = message; + addMessage(content, created, creator["username"], roomid) } - } catch { - statusMessage.innerText = "Not connected"; - } } function selectChannel(id) { @@ -138,20 +127,27 @@ messageBox.addEventListener("keyup", function onEvent(event) { if (!messageBox.value == "") { if (messageBox.value.length < 140) { sendMessage(messageBox.value, channelID) - updateMessages(channelID) messageBox.value = "" } } } }) -function update() { - updateMessages(channelID) - - setTimeout(update, 1500); -} +let messageStream = new EventSource("/stream") window.addEventListener("load", function () { updateRooms() - update() + updateMessages(channelID) + + messageStream.addEventListener("publish", function (event) { + results = JSON.parse(event.data) + + if (Number(results["message"]["roomid"]) == channelID) { + addMessage(results["message"]["content"], results["message"]["created"], results["message"]["creator"], results["message"]["roomid"]) + } + }) +}) + +window.addEventListener("beforeunload", function () { + messageStream.close() }) \ No newline at end of file -- 2.39.2 From 07bbfd9530a20f02868d9ef74e4ce789a669b26c Mon Sep 17 00:00:00 2001 From: maaa Date: Wed, 19 Jul 2023 20:16:13 +0200 Subject: [PATCH 3/8] shutdown --- static/css/style.css | 2 +- static/shutdown.html | 23 +++++++++++++++++++++++ templates/main.html | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 static/shutdown.html diff --git a/static/css/style.css b/static/css/style.css index 3999647..4382dff 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -291,7 +291,7 @@ body { } .warning { - width: 100%; + width: calc(100% - 20px); background-color: #f1b739; color: black; padding: 10px; diff --git a/static/shutdown.html b/static/shutdown.html new file mode 100644 index 0000000..6b607c4 --- /dev/null +++ b/static/shutdown.html @@ -0,0 +1,23 @@ + + + + + burgercat + + + + + + + +
+

burgercat is permanently shutting down on July 21th.

+
+
+

After 19 days of service, burgercat is permanently shutting down on July 21th 2023. 😔

+ After July 21th, you will no longer be able to access burgercat. Please back up anything you want to keep before July 21th.

+

The Codeberg repository will be archived. Third-party instances will not be affected.

+

Thank you for using burgercat, and thank @ffqq, @carsand101, @Mollomm1, and @TestingPlant, @Anonymous for contributing to the project.

+
+ + \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index 2a3932f..8b58fe5 100644 --- a/templates/main.html +++ b/templates/main.html @@ -36,6 +36,7 @@

Your account has been banned. Reason: "{{ userdata.banned }}". Log out

{% endif %} {% endif %} +

⚠️ burgercat will permanently shut down on July 21th. ⚠️ Read more

{% for post in posts %}

{{ getUser(post["creator"])["username"] }}

-- 2.39.2 From faa4dddc53221ec0192a1387eae84f68dc92bc3e Mon Sep 17 00:00:00 2001 From: maaa Date: Wed, 19 Jul 2023 20:21:25 +0200 Subject: [PATCH 4/8] a --- static/shutdown.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/shutdown.html b/static/shutdown.html index 6b607c4..3e42fbc 100644 --- a/static/shutdown.html +++ b/static/shutdown.html @@ -17,7 +17,7 @@

After 19 days of service, burgercat is permanently shutting down on July 21th 2023. 😔

After July 21th, you will no longer be able to access burgercat. Please back up anything you want to keep before July 21th.

The Codeberg repository will be archived. Third-party instances will not be affected.

-

Thank you for using burgercat, and thank @ffqq, @carsand101, @Mollomm1, and @TestingPlant, @Anonymous for contributing to the project.

+

Thank you for using burgercat, and thank @ffqq, @carsand101, @Mollomm1, @TestingPlant, and @Anonymous for contributing to the project.

\ No newline at end of file -- 2.39.2 From 8ca281b1d3045907e9257bf4146e4638ff407400 Mon Sep 17 00:00:00 2001 From: maaa Date: Wed, 19 Jul 2023 20:31:40 +0200 Subject: [PATCH 5/8] add sewn --- static/shutdown.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/shutdown.html b/static/shutdown.html index 3e42fbc..a9b7ee5 100644 --- a/static/shutdown.html +++ b/static/shutdown.html @@ -17,7 +17,7 @@

After 19 days of service, burgercat is permanently shutting down on July 21th 2023. 😔

After July 21th, you will no longer be able to access burgercat. Please back up anything you want to keep before July 21th.

The Codeberg repository will be archived. Third-party instances will not be affected.

-

Thank you for using burgercat, and thank @ffqq, @carsand101, @Mollomm1, @TestingPlant, and @Anonymous for contributing to the project.

+

Thank you for using burgercat, and thank @ffqq, @carsand101, @Mollomm1, @TestingPlant, @sewn, and @Anonymous for contributing to the project.

\ No newline at end of file -- 2.39.2 From e6359db97db87d8edf8aea07de2ec69d532f1e80 Mon Sep 17 00:00:00 2001 From: maaa Date: Mon, 29 Apr 2024 22:36:42 +0200 Subject: [PATCH 6/8] we are so back --- README.md | 6 +- config.ini | 3 +- hashpass.py | 4 + main | 210 +++++++++++++++++++--------------------- requirements.txt | 9 +- static/css/style.css | 27 +++++- static/css/xp.css | 137 -------------------------- static/js/chat.js | 49 +++------- static/shutdown.html | 23 ----- templates/apidocs.html | 9 +- templates/main.html | 9 +- templates/post.html | 24 ++--- templates/settings.html | 9 +- 13 files changed, 173 insertions(+), 346 deletions(-) create mode 100644 hashpass.py delete mode 100644 static/css/xp.css delete mode 100644 static/shutdown.html diff --git a/README.md b/README.md index 2f7fee2..d484197 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ burgercat: burger social media +now back again! + ### self hosting: this guide assumes you have git, python3, and redis installed on your server @@ -10,10 +12,6 @@ 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 diff --git a/config.ini b/config.ini index ff3fe97..596f2a9 100644 --- a/config.ini +++ b/config.ini @@ -3,5 +3,4 @@ PORT = 8080 SECRET_KEY = placeholder UPLOAD_FOLDER = uploads PASSWORD_REQUIREMENT = 12 -UPLOAD_LIMIT = 4 -REDIS_URL = redis://localhost \ No newline at end of file +UPLOAD_LIMIT = 12 \ No newline at end of file diff --git a/hashpass.py b/hashpass.py new file mode 100644 index 0000000..d64f4fe --- /dev/null +++ b/hashpass.py @@ -0,0 +1,4 @@ +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 bd57b71..9ec863f 100644 --- a/main +++ b/main @@ -9,15 +9,13 @@ 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 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 -from flask_sse import sse +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 # read config file @@ -29,23 +27,10 @@ SECRET_KEY = config["config"]["SECRET_KEY"] UPLOAD_FOLDER = config["config"]["UPLOAD_FOLDER"] UPLOAD_LIMIT = config["config"]["UPLOAD_LIMIT"] PASSWORD_REQUIREMENT = config["config"]["PASSWORD_REQUIREMENT"] -REDIS_URL = config["config"]["REDIS_URL"] -app = Flask(__name__) +app = Quart(__name__) app.config["SECRET_KEY"] = SECRET_KEY -app.config["REDIS_URL"] = REDIS_URL app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000 -app.register_blueprint(sse, url_prefix="/stream") - -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") @@ -136,15 +121,14 @@ 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"} +ALLOWED_EXTENSIONS = {"png", "apng", "jpg", "jpeg", "gif", "svg", "webp", "jxl"} def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS - @app.route("/", methods=("GET", "POST")) -def main(): +async 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() @@ -153,22 +137,22 @@ def main(): if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return render_template("main.html", userdata=user, posts=posts, full_hash=full_hash, short_hash=short_hash) + return await render_template("main.html", userdata=user, posts=posts, full_hash=full_hash, short_hash=short_hash) else: - return render_template("main.html", posts=posts, full_hash=full_hash, short_hash=short_hash) + return await render_template("main.html", posts=posts, full_hash=full_hash, short_hash=short_hash) @app.route("/chat", methods=("GET", "POST")) -def chat(): +async def chat(): usersession = request.cookies.get("session_DO_NOT_SHARE") if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return render_template("chat.html", userdata=user) + return await render_template("chat.html", userdata=user) else: - return render_template("chat.html") + return await render_template("chat.html") @app.route("/api/chat/listrooms") -def chatlistrooms(): +async def chatlistrooms(): conn = get_db_connection() rooms = conn.execute("SELECT * FROM chatrooms ORDER BY id ASC;").fetchall() conn.close() @@ -185,8 +169,7 @@ def chatlistrooms(): return(template), 200 @app.route("/api/chat/getmessages/") -@limiter.exempt -def chatget(roomid): +async def chatget(roomid): messages = get_messages(roomid, 150) template = [] @@ -209,13 +192,14 @@ def chatget(roomid): return(template), 200 + @app.route("/api/chat/send/", methods=("GET", "POST")) -def chatsend(roomid): +async def chatsend(roomid): usersession = request.cookies.get("session_DO_NOT_SHARE") if usersession: if request.method == "POST": - data = request.get_json() + data = await request.get_json() content = data["content"] userCookie = get_session(usersession) @@ -233,7 +217,7 @@ def chatsend(roomid): "created": str(time.time()) } - sse.publish({"message": chatMessageContent}, type="publish") + #message_queue.append({"message": chatMessageContent}) conn = get_db_connection() conn.execute("INSERT INTO chatmessages (content, chatroom_id, creator, created) VALUES (?, ?, ?, ?)", @@ -245,7 +229,7 @@ def chatsend(roomid): @app.route("/@", methods=("GET", "POST")) -def user(pageusername): +async def user(pageusername): usersession = request.cookies.get("session_DO_NOT_SHARE") checkusername = check_username_taken(pageusername) @@ -255,20 +239,20 @@ def user(pageusername): if usersession: userCookie = get_session(usersession) user = get_user(userCookie["id"]) - return render_template("user.html", userdata=user, createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) + return await render_template("user.html", userdata=user, createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) else: - return render_template("user.html", createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser) + return await 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")) -def apipageuser(userid): +async def apipageuser(userid): pageuser = get_user(userid) addhtml = """ - """ + """ if not pageuser == "error": return addhtml + pageuser["htmldescription"] @@ -276,7 +260,7 @@ def apipageuser(userid): return """""", 404 @app.route("/@/edit", methods=("GET", "POST")) -def edituser(pageusername): +async def edituser(pageusername): usersession = request.cookies.get("session_DO_NOT_SHARE") checkusername = check_username_taken(pageusername) @@ -288,7 +272,9 @@ def edituser(pageusername): user = get_user(userCookie["id"]) if pageuser["username"] == user["username"]: if request.method == "POST": - code = request.form["code"].replace("Content-Security-Policy", "").replace("