diff --git a/app.py b/app.py deleted file mode 100644 index 6f13c93..0000000 --- a/app.py +++ /dev/null @@ -1,3 +0,0 @@ -from flask import Flask -app = Flask(__name__) - diff --git a/auth.py b/auth.py deleted file mode 100644 index 228b921..0000000 --- a/auth.py +++ /dev/null @@ -1,215 +0,0 @@ -from flask import render_template, request, make_response, redirect -import database, re, bcrypt, secrets, time -import user_controller - -from app import app - -def get_session(request): - sessionid = request.cookies.get('session') - - if not sessionid: - return False - - sessionid = str(sessionid) - sessioninfo = database.fetch("""SELECT uid, created_at, expires, description - FROM session - WHERE value=?;""", - [sessionid]) - - if len(sessioninfo) == 0: - return False - - if len(sessioninfo) > 1: - # there is a problem - return False - - return sessioninfo[0] + (sessionid,) - -def check_pw(uid, password): - userquery = database.fetch("SELECT uid, password FROM user WHERE username=?", [username]) - - # STOP TIMING ATTACKS - time.sleep(secrets.randbelow(100)/50) - - if len(userquery) == 0: - return render_template("auth/login.html", - response=f"Der Nutzername >{username} oder das Passwort ist falsch.", - username=username) - - uidquery = userquery[0][0] - passquery = userquery[0][1] - - passform = str(request.form['pass']) - passform = passform.encode("utf8") - passcorrect = bcrypt.checkpw(passform, passquery) - - if not passcorrect: - return render_template("auth/login.html", - response=f"Der Nutzername {username} oder das >Passwort ist falsch.", - username=username) - - -@app.route("/auth/headerbar") -def headerbar(): - sessioninfo = get_session(request) - - if not sessioninfo: - return render_template("auth/headerbar.html", loggedin=False) - - return render_template("auth/headerbar.html", loggedin=True) - -@app.route("/auth/sessioninfo", methods=['GET']) -def sessioninfo(): - time.sleep(secrets.randbelow(100)/50) # Rate limiting - - sessioninfo = get_session(request) - - if not sessioninfo: - return "Invalid session" - - (uid, created_at, expires, description) = sessioninfo - # uid = sessioninfo[0][0] - # created_at = sessioninfo[0][1] - # expires = sessioninfo[0][2] - # description = sessioninfo[0][3] - return render_template("/auth/sessioninfo.html", - sessionid=sessionid, - uid=uid, - created_at=created_at, - expires=expires, - description=description) - -@app.route("/auth/logout", methods=['GET']) -def logout(): - sessioninfo = get_session(request) - - response = redirect("/") - response.set_cookie('session', value='', expires=0) - - if not sessioninfo: - return response - - database.execute("DELETE FROM session WHERE value = ?", [sessioninfo[4]]) - - return response - -@app.route("/auth/login", methods=['GET', 'POST']) -def login(): - sessioninfo = get_session(request) - - if sessioninfo: - uid = sessioninfo[0] - username = database.fetch("SELECT username FROM user WHERE uid = ?", [uid]) - username = username[0][0] - return render_template("auth/loginsuccess.html", username=username) - - - if request.method == 'GET': - return render_template("auth/login.html", - response="", - username="") - - username = _sanitizeUsername(request.form['user']) - if len(username) < 3: - return render_template("auth/login.html", - response=f"Der Nutzername {username} ist zu kurz.", - username=username) - - userquery = database.fetch("SELECT uid, password FROM user WHERE username=?", [username]) - - # STOP TIMING ATTACKS - time.sleep(secrets.randbelow(100)/50) - - if len(userquery) == 0: - return render_template("auth/login.html", - response=f"Der Nutzername >{username} oder das Passwort ist falsch.", - username=username) - - uidquery = userquery[0][0] - passquery = userquery[0][1] - - passform = str(request.form['pass']) - passform = passform.encode("utf8") - passcorrect = bcrypt.checkpw(passform, passquery) - - if not passcorrect: - return render_template("auth/login.html", - response=f"Der Nutzername {username} oder das >Passwort ist falsch.", - username=username) - - now = int(time.time()) - - timeout = int(request.form['timeout']) - timeout = now + timeout - - session = secrets.randbelow(999999999) - session = str(session) + str(now) - - database.execute("DELETE FROM session WHERE expires < ?", [str(now)]) - database.execute("""INSERT INTO session - (uid, created_at, expires, description, value) - VALUES (?, ?, ?, ?, ?);""", - (uidquery, int(time.time()), timeout, "", session) - ) - - response = make_response("") - response.set_cookie('session', value=session, expires=timeout) - return response - -@app.route("/auth/newuser", methods=['GET', 'POST']) -def newuser(): - if request.method == 'GET': - return render_template("auth/register.html", - responses=[], - username="") - - success = True - responses = [] - - username = _sanitizeUsername(request.form['user']) - if len(username) < 3: - success = False - responses.append(f"Der Nutzername {username} ist zu kurz.") - - if user_controller.id_from_username(username) != 0: - success = False - responses.append(f"Der Nutzername {username} wird bereits verwendet.") - - pass1 = str(request.form['pass1']) - pass2 = str(request.form['pass2']) - if pass1 != pass2: - success = False - responses.append("Passwort und Passwortbestätigung sind ungleich.") - - if len(pass1) < 10: - success = False - responses.append("Das Passwort ist kürzer als 10 Zeichen.") - - if not success: - return render_template("auth/register.html", - responses=responses, - username=username) - - user_controller.new(username, pass1) - - return render_template("auth/registersuccess.html", username=username) - -def _sanitizeUsername(username): - username = str(username) - username = username.strip() - username = username[:32] - - # Remove all non-word characters (everything except numbers and letters) - username = re.sub(r"[^._\w\s-]", '', username) - - # Replace all runs of whitespace with a single dash - username = re.sub(r"\s+", '_', username) - - return username - -def _verifyEmail(email): - pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' - if re.match(pattern, email): - return True - else: - return False diff --git a/database.py b/database.py deleted file mode 100644 index 43bf972..0000000 --- a/database.py +++ /dev/null @@ -1,25 +0,0 @@ -import sqlite3 - -def execute(query, data): - connection = sqlite3.connect("kver.db") - cursor = connection.cursor() - - cursor.execute(query, data) - - connection.commit() - connection.close() - -def fetch(query, data, many=True): - connection = sqlite3.connect("kver.db") - cursor = connection.cursor() - - result = cursor.execute(query, data) - - if many: - result = result.fetchall() - else: - result = result.fetchone() - - connection.close() - - return result diff --git a/entry.py b/entry.py deleted file mode 100644 index 43252f6..0000000 --- a/entry.py +++ /dev/null @@ -1,150 +0,0 @@ -from flask import render_template, request -from PIL import Image -# import database, re, bcrypt, secrets, time -import secrets, time, os, database -from auth import get_session -from app import app - - -@app.route("/entry//interactions/", methods=['GET']) -def interactions(pid, mode): - # session = get_session(request) - - # empty = (mode!='left' and mode!='right') - # selected = 'none' - - # if session and not empty: - # uid = session[0] - # previous = database.fetch("SELECT mode FROM vote WHERE uid=? AND pid=?", [uid, pid]) - # if len(previous) == 0: - # selected=mode - # database.execute("INSERT INTO vote (uid, pid, mode) VALUES (?,?,?)", [uid, pid, mode]) - # else: - - # previous = previous[0][0] - # previous = 'none' - - # if previous < 1: - # elif previous[0][0]==mode: - # database.execute("DELETE FROM vote WHERE uid=? AND pid=?", [uid, pid]) - # else: - # database.execute("UPDATE vote SET mode=? WHERE uid=? AND pid=?", [mode, uid, pid]) - - # left = database.fetch("SELECT COUNT(id) FROM vote WHERE pid=? and mode='left';", [pid])[0][0] - # right = database.fetch("SELECT COUNT(id) FROM vote WHERE pid=? and mode='right';", [pid])[0][0] - - # return render_template("entry/interactions.html", pid=pid, stats=f"{left} {right} {mode}") - return "--" - -@app.route("/entry/feed/", methods=['GET']) -def feed(page): - page = int(page, 0) - page = max(0,page) - page = min(100,page) - - count = 20 - offset = page*count - - posts = database.fetch("SELECT * FROM entry ORDER BY created_at DESC LIMIT ? OFFSET ?", [count, offset]) - - if len(posts) <= 0: - return """
-

YOU REACHED THE END!

-
""" - - posts_with_usernames = [] - for post in posts: - username = database.fetch("SELECT username FROM user WHERE uid = ?", [post[2]]) - posts_with_usernames.append(post + username[0]) - - return render_template("entry/feed.html", posts=posts_with_usernames, page=page) - -@app.route("/entry/create", methods=['GET', 'POST']) -def newentry(): - session = get_session(request) - - if not session: - return "Melde dich an, um einen Beitrag zu erstellen!" - - uid = session[0] - - if request.method == 'GET': - return render_template('entry/create.html') - - content = str(request.form["content"]) - content = content.strip() - content = content[:1000] - - fileattached = False - if 'file' in request.files: - file = request.files['file'] - fileattached=True - - if fileattached: - fileattached = _storeimage(file) - - if not fileattached and content == '': - return render_template('entry/create.html', responses=["Leerer Beitrag!"]) - - if not fileattached: - fileattached = "none" - - pid = secrets.randbelow(999999999999) - now = int(time.time()) - database.execute("""INSERT INTO entry - (pid, uid, created_at, content, filepath) - VALUES (?, ?, ?, ?, ?)""", - (pid, uid, now, content, fileattached)) - - return render_template('entry/create.html', responses=[content, str(fileattached)]) - -def _storeimage(file): - maxsize = 1024 - tmpfile = secrets.randbelow(999999) - tmppath = f"tmp/{tmpfile}" - - import resizegif - - try: - file.save(tmppath) - - i = Image.open(tmppath) - if i.format == 'GIF': - filetype = 'gif' - else: - i = i.convert("RGB") - filetype = 'jpg' - - newpath = f"static/media/{int(time.time())}-{tmpfile}.{filetype}" - - (width, height) = i.size; - aspect = width/height - - if width < maxsize and height < maxsize: - if filetype == 'gif': - resizegif.resize_gif(i, newpath, (width, height)) - else: - i.save(newpath) - - os.remove(tmppath) - return newpath - - if width > height: - width = maxsize - height = maxsize/aspect - else: - height = maxsize - width = aspect*maxsize - - if filetype == 'gif': - resizegif.resize_gif(i, newpath, (width, height)) - else: - i.thumbnail((width, height), Image.Resampling.LANCZOS) - i.save(newpath) - - os.remove(tmppath) - return newpath - except Exception as e: - print(e) - os.remove(tmppath) - return False diff --git a/main.py b/main.py deleted file mode 100644 index 4c25f72..0000000 --- a/main.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -from flask import Flask, request, render_template -from datetime import datetime - -from werkzeug.exceptions import HTTPException - -from app import app -app.config['UPLOAD_FOLDER'] = "uploads/" - -@app.errorhandler(400) -def handle_bad_request(e): - print(f"400 BAD REQUEST: {e}") - return '400
BAD REQUEST' - -@app.template_filter('timestamp') -def timestamp_filter(value): - try: - dt = datetime.fromtimestamp(value) - return dt.strftime("%d.%m.%Y %H:%M") - except: - return value - -import html, re - -@app.template_filter('content') -def content_filter(value): - value = value.strip() - value = html.escape(value) - # Regulärer Ausdruck, um URLs zu finden - url_pattern = re.compile( - r'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:;%_\+.~#?&//=]*)' - ) - - # Ersetze jede gefundene URL durch einen -Tag - def replace_url(match): - url = match.group(0) - if not url.startswith(('http://', 'https://')): - url = 'http://' + url - return f'{match.group(0)}' - - value = url_pattern.sub(replace_url, value) - value = value.replace('\n', '
') - - return value - -import auth -import entry -import user - -@app.route("/") -def template(): - return render_template("index.html", name="Hmmm") - -if __name__ == "__main__": - app.run(debug=True) diff --git a/resizegif.py b/resizegif.py deleted file mode 100644 index 327f383..0000000 --- a/resizegif.py +++ /dev/null @@ -1,44 +0,0 @@ -# Source - https://stackoverflow.com/a -# Posted by brvoisin -# Retrieved 2025-12-13, License - CC BY-SA 4.0 - -""" -# Resize an animated GIF -Inspired from https://gist.github.com/skywodd/8b68bd9c7af048afcedcea3fb1807966 -Useful links: - * https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#saving - * https://stackoverflow.com/a/69850807 -Example: - ``` - python resize_gif.py input.gif output.gif 400,300 - ``` -""" - -import sys - -from PIL import Image -from PIL import ImageSequence - - -def resize_gif(input_image, output_path, max_size): - frames = list(_thumbnail_frames(input_image, max_size)) - output_image = frames[0] - output_image.save( - output_path, - save_all=True, - append_images=frames[1:], - disposal=input_image.disposal_method, - **input_image.info, - ) - - -def _thumbnail_frames(image, max_size): - for frame in ImageSequence.Iterator(image): - new_frame = frame.copy() - new_frame.thumbnail(max_size, Image.Resampling.LANCZOS) - yield new_frame - - -if __name__ == "__main__": - max_size = [int(px) for px in sys.argv[3].split(",")] # "150,100" -> (150, 100) - resize_gif(sys.argv[1], sys.argv[2], max_size) diff --git a/sendmail.py b/sendmail.py deleted file mode 100644 index 0a27766..0000000 --- a/sendmail.py +++ /dev/null @@ -1,41 +0,0 @@ -import smtplib, ssl, database, time - -def send(subject, message, recipient, type): - hour_ago = int(time.time()) - 3600 - count = database.fetch("SELECT COUNT(*) FROM email WHERE time > ?", [hour_ago]) - if count[0][0] > 5: - return False - - database.execute("INSERT INTO email (recipient, time, type) VALUES (?, ?, ?)", [ - recipient, - int(time.time()), - type - ]) - - smtp_server = "webspace29.do.de" - port = 587 # For starttls - sender_email = "system@bnd.wtf" - password = "" - message = f"""From: system@bnd.wtf\nSubject: {subject} - - {message}""" - - # Create a secure SSL context - context = ssl.create_default_context() - - # Try to log in to server and send email - try: - server = smtplib.SMTP(smtp_server,port) - server.ehlo() # Can be omitted - server.starttls(context=context) # Secure the connection - server.ehlo() # Can be omitted - server.login(sender_email, password) - server.sendmail(sender_email, recipient, message) - # TODO: Send email here - except Exception as e: - # Print any error messages to stdout - print(e) - finally: - server.quit() - - return True diff --git a/templates/auth/headerbar.html b/templates/auth/headerbar.html deleted file mode 100644 index 8845727..0000000 --- a/templates/auth/headerbar.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- {% if loggedin %} - - - {% else %} - - - {% endif %} -
- -
diff --git a/templates/auth/login.html b/templates/auth/login.html deleted file mode 100644 index 58e1fc1..0000000 --- a/templates/auth/login.html +++ /dev/null @@ -1,17 +0,0 @@ -

Einloggen

-
-
-
- - - -
- {{response}} -
-
diff --git a/templates/auth/loginsuccess.html b/templates/auth/loginsuccess.html deleted file mode 100644 index 31e25d4..0000000 --- a/templates/auth/loginsuccess.html +++ /dev/null @@ -1,3 +0,0 @@ -

Willkommen, {{username}}!

- - diff --git a/templates/auth/register.html b/templates/auth/register.html deleted file mode 100644 index 02ae410..0000000 --- a/templates/auth/register.html +++ /dev/null @@ -1,15 +0,0 @@ -

Neuen Account registrieren

-
-
-
-
- - - -
-{% for r in responses %} -{{ r }}
-{% endfor %} -
-
- diff --git a/templates/auth/registersuccess.html b/templates/auth/registersuccess.html deleted file mode 100644 index b5a0c9c..0000000 --- a/templates/auth/registersuccess.html +++ /dev/null @@ -1,4 +0,0 @@ -

Willkommen im Kontrollverlust!

-

Du kannst dich nun als {{username}} -!

- diff --git a/templates/auth/sessioninfo.html b/templates/auth/sessioninfo.html deleted file mode 100644 index 4ea03ff..0000000 --- a/templates/auth/sessioninfo.html +++ /dev/null @@ -1,5 +0,0 @@ -Sessionid: {{ sessionid }}
-UID: {{ uid }}
-Created: {{ created_at | timestamp }}
-Expires: {{ expires | timestamp }}
-Description: {{ description }}
diff --git a/templates/baseof.html b/templates/baseof.html deleted file mode 100644 index eb08f33..0000000 --- a/templates/baseof.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - {% block title %}{% endblock %} - - - - - - - - - - -
-

Achtung!

-

Kontrollverlust

-
-

Dieses Forum richtet sich ausschließlich an erwachsene Besucher:innen.

- -

- Die Inhalte könnten explizite Sprache, anstößige Themen, gewalthaltige Äußerungen, sowie pornografische Darstellungen in Text-, Zeichnungs- oder angedeuteter Form enthalten. -

-

- Fotografische Nacktheit, reale Gewalt, Gore oder NSFL-Inhalte sind verboten – dennoch können Diskussionen und Beiträge für sensible Personen belastend sein. -

-

- Wenn du mit solchen Inhalten nicht konfrontiert werden möchtest, verlasse die Seite jetzt. Durch das Fortsetzen erklärst du dich damit einverstanden, dass du die Inhalte auf eigene Verantwortung nutzt. -

-
- - -
-
- -
-
-

Kontrollverlust

-
- Verbuggte scheise hier. Komm hack mich doch, trau dich! -
- -
-
- -
- {% block content %}{% endblock %} -
- - diff --git a/templates/database.html b/templates/database.html deleted file mode 100644 index 8057342..0000000 --- a/templates/database.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Database - - - -{% for tablename in tables %} - {{ tablename[0] }}
-{% endfor %} - - diff --git a/templates/database_table.html b/templates/database_table.html deleted file mode 100644 index 873a446..0000000 --- a/templates/database_table.html +++ /dev/null @@ -1,9 +0,0 @@ - - {% for row in data %} - - {% for column in row %} - - {% endfor %} - - {% endfor %} -
{{ column }}
diff --git a/templates/entry/create.html b/templates/entry/create.html deleted file mode 100644 index dc59b69..0000000 --- a/templates/entry/create.html +++ /dev/null @@ -1,11 +0,0 @@ -
- - - - -
-{% for r in responses %} -{{ r }}
-{% endfor %} -
-
diff --git a/templates/entry/feed.html b/templates/entry/feed.html deleted file mode 100644 index 93e6e59..0000000 --- a/templates/entry/feed.html +++ /dev/null @@ -1,31 +0,0 @@ -{% for p in posts %} - -
-
{{ p[6] }} - {{ p[3] | timestamp }}
- {% if p[4] != '' %} -
-

{{ p[4] | content | safe}}

-
- {% endif %} - {% if p[5] != 'none' %} - - {% endif %} -
-
-
- -{% endfor %} - -
-

Loading more...

-
diff --git a/templates/entry/interactions.html b/templates/entry/interactions.html deleted file mode 100644 index cdc927a..0000000 --- a/templates/entry/interactions.html +++ /dev/null @@ -1,3 +0,0 @@ - -{{stats}} - diff --git a/templates/header.html b/templates/header.html deleted file mode 100644 index 46a3c69..0000000 --- a/templates/header.html +++ /dev/null @@ -1,6 +0,0 @@ - - -
-
- -
diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 51e6c90..0000000 --- a/templates/index.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "baseof.html" %} - -{% block title %}Kontrollverlust{% endblock %} - -{% block content %} - -
- -
- -
- -
- -
- -{% endblock %} diff --git a/templates/upload.html b/templates/upload.html deleted file mode 100644 index c0d0722..0000000 --- a/templates/upload.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - My new Site! - - - -

Upload new File

- {{ state }} -
- - -
- - {% for id in imagedata %} - {{ id }} - {% endfor %} - - diff --git a/templates/user/delete.html b/templates/user/delete.html deleted file mode 100644 index 08db4a2..0000000 --- a/templates/user/delete.html +++ /dev/null @@ -1,13 +0,0 @@ -
-

Account dauerhaft löschen

-
-
- - -
- {% for r in responses %} - {{ r }}
- {% endfor %} -
-
-
diff --git a/templates/user/userinfo.html b/templates/user/userinfo.html deleted file mode 100644 index 554baa9..0000000 --- a/templates/user/userinfo.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "baseof.html" %} -{% block content %} - -Username: {{ username }}
-ID: {{ uid }}
-Profil erstellt: {{ created_at | timestamp }}
- -
- -{% endblock %} diff --git a/user.py b/user.py deleted file mode 100644 index 2e5c2d7..0000000 --- a/user.py +++ /dev/null @@ -1,27 +0,0 @@ -from flask import render_template, request, make_response, redirect -import database, re, bcrypt, secrets, time -from auth import get_session - -from app import app - -@app.route("/u/") -def userpage(username): - return "Page of " + username - -@app.route("/user/info") -def userinfo(): - sessioninfo = get_session(request) - - if not sessioninfo: - return "Melde dich an, um Einstellungen zu ändern!" - - uid = sessioninfo[0] - - userdata = database.fetch("SELECT created_at, last_login, username FROM user WHERE uid=?", [uid])[0] - - return render_template("user/userinfo.html", username=userdata[2], uid=uid, created_at=userdata[0]) - - -@app.route("/user/delete") -def userdelete(): - return render_template("user/delete.html") diff --git a/user_controller.py b/user_controller.py deleted file mode 100644 index 82db12b..0000000 --- a/user_controller.py +++ /dev/null @@ -1,63 +0,0 @@ -import database, re, bcrypt, secrets, time - -def new(username, password): - uid = secrets.randbelow(99999999) - created_at = int(time.time()) - - passsalt = bcrypt.gensalt() - passhash = bcrypt.hashpw(password.encode("utf8"), passsalt) - - database.execute("""INSERT INTO user - (uid, created_at, username, password) VALUES - (?, ?, ?, ?)""", - (uid, created_at, username, passhash)) - - return - -def from_uid(): - pass - -def id_from_username(username): - query = database.fetch("SELECT id FROM user WHERE username=?", [username], False) - if query: - return query[0] - else: - return 0 - -def id_from_session(session): - sessioninfo = database.fetch("""SELECT uid, expires - FROM session - WHERE value=?;""", - [sessionid], False) - - if not sessioninfo: - return 0 - - # if int(sessioninfo[2] > int(time.time())): - # return 0 # session expired - - - pass - -def exists(): - # count from database - pass - -def authenticate(password): - # verify password with stored hash - pass - -def get_info() -> dict: - pass - -def set_username(newname): - # update username - pass - -def set_password(newpass): - # update password - pass - -def delete(): - # delete database entry - pass