From 26164170117de849e7b33d65099f94847cb01825 Mon Sep 17 00:00:00 2001 From: i-am-called-glitchy Date: Tue, 3 Jun 2025 12:51:30 +0000 Subject: [PATCH] fuck you i aint commiting with actual messages --- app.py | 38 ++++++++++++++++++++++++++++++++------ static/note.js | 20 ++++++++++++++++---- templates/note.html | 1 + 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/app.py b/app.py index 2e3feef..dbbfd87 100644 --- a/app.py +++ b/app.py @@ -5,16 +5,28 @@ import os import hashlib import base64 import dotenv +from flask_limiter import Limiter +from flask_limiter.util import get_remote_address +import time + dotenv.load_dotenv() app = Flask(__name__) app.secret_key = os.getenv("SECRET") - USERS_FILE = "users.txt" DATA_DIR = "notes" os.makedirs(DATA_DIR, exist_ok=True) +app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 # 16 KB + +limiter = Limiter(key_func=get_remote_address) +limiter.init_app(app) + +@app.errorhandler(413) +def payload_too_large(e): + return "someone call caseoh, he's got competition — I think his number is 413?", 413 + # === UTILS === @@ -37,6 +49,7 @@ def get_key_for_user(user, password): # === ROUTES === @app.route("/api/", methods=["GET", "POST"]) +@limiter.limit("100 per hour", per_method=True, key_func=get_remote_address) def api(note): user = get_user() key = session.get("key") @@ -49,22 +62,35 @@ def api(note): if request.method == "GET": if not os.path.exists(path): return "", 200 - with open(path, "rb") as f: - try: + try: + with open(path, "rb") as f: return fernet.decrypt(f.read()).decode(), 200 - except Exception: - return "Corrupted note or invalid key", 500 + except Exception: + return "Corrupted note or invalid key", 500 if request.method == "POST": data = request.get_json() if not data or "content" not in data: return "Bad request", 400 + + # Check if this is a new note + is_new = not os.path.exists(path) + + if is_new: + now = time.time() + record = session.setdefault("note_creations", []) + # Clean up old timestamps + record = [t for t in record if now - t < 3600] + if len(record) >= 10: + return "Slow down, Picasso — max 10 new notes per hour", 429 + record.append(now) + session["note_creations"] = record + ciphertext = fernet.encrypt(data["content"].encode()) with open(path, "wb") as f: f.write(ciphertext) return jsonify({"status": "saved"}) - @app.route("/n/") @app.route("/notes/") def serve_note(note): diff --git a/static/note.js b/static/note.js index 4d2437d..4546358 100644 --- a/static/note.js +++ b/static/note.js @@ -1,11 +1,19 @@ const textarea = document.getElementById("editor"); const status = document.getElementById("status"); +const error = document.getElementById("error"); fetch("/api/" + noteName) - .then(res => res.ok ? res.text() : "") + .then(res => { + if (!res.ok) throw new Error("Failed to load note. Status: " + res.status); + return res.text(); + }) .then(text => { textarea.value = text; status.textContent = "Loaded"; + }) + .catch(err => { + error.textContent = "Error loading note: " + err.message; + status.textContent = "Load failed"; }); let timeout; @@ -21,17 +29,21 @@ textarea.addEventListener("input", () => { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content: text }) - }).then(res => { + }) + .then(async res => { if (res.ok) { last = text; status.textContent = "Saved"; } else { - status.textContent = "Save failed"; + const msg = await res.text(); + status.textContent = "Save failed: " + msg; } + }) + .catch(err => { + status.textContent = "Save failed: " + err.message; }); } else { status.textContent = "No changes"; } }, 500); }); - diff --git a/templates/note.html b/templates/note.html index aaf2f90..1420f8c 100644 --- a/templates/note.html +++ b/templates/note.html @@ -9,6 +9,7 @@ +
Loading...