Make Posts id autoincrement, make working posts page on home which shows the pumpkins and comment, reduce bloat by making a lightbtn setup function, fix XSS

This commit is contained in:
csd4ni3l
2025-10-24 18:01:50 +02:00
parent ed274a24e4
commit ab44901dc0
4 changed files with 78 additions and 42 deletions

28
app.py
View File

@@ -1,10 +1,11 @@
from flask import Flask, Response, render_template, redirect, url_for, g, request
from flask import Flask, Response, render_template, redirect, url_for, g, request, json
from flask_login import LoginManager, login_required
from datetime import datetime
from pattern import Pattern
import sqlite3, os, flask_login, dotenv, secrets
import sqlite3, os, flask_login, dotenv, secrets, html
if os.path.exists(".env"):
dotenv.load_dotenv(".env")
@@ -31,8 +32,8 @@ def get_db():
db.execute("""
CREATE TABLE IF NOT EXISTS Posts (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
comment TEXT NOT NULL,
pattern TEXT NOT NULL,
creation_time INTEGER NOT NULL
@@ -69,13 +70,23 @@ def main():
cur = get_db().cursor()
cur.execute("SELECT * FROM Posts LIMIT 20")
cur.execute("SELECT * FROM Posts LIMIT 15")
posts = cur.fetchall()
cur.close()
return render_template("index.jinja2", username=username, posts=posts)
for post in posts:
if not isinstance(post[0], int):
print("Post ID is not int. Exiting for safety.")
return "Post ID is not int. Exiting for safety."
if not isinstance(post[4], int):
print("Post Timestamp is not int. Exiting for safety.")
return "Post Timestamp is not int. Exiting for safety."
new_posts = [[post[0], html.escape(post[1], quote=True), html.escape(post[2], quote=True), [html.escape(f"{pos[0]},{pos[1]}", quote=True) for pos in json.loads(post[3])], datetime.fromtimestamp(post[4]).strftime('%Y-%m-%d %H:%M:%S')] for post in posts]
return render_template("index.jinja2", username=username, posts=new_posts, grid_size=os.getenv("GRID_SIZE", 15))
@app.route("/countdown")
def countdown():
@@ -120,7 +131,10 @@ def register():
return render_template("register.jinja2", grid_size=os.getenv("GRID_SIZE", 15))
elif request.method == "POST":
username = request.form["username"]
if request.form["username"] != html.escape(request.form["username"], quote=True):
return "No XSS please"
username = html.escape(request.form["username"], quote=True)
pattern = Pattern.from_str(request.form["pattern"])
cur = get_db().cursor()

View File

@@ -151,6 +151,23 @@ function unlight_pumpkin(ctx, cell_size, currentPattern) {
}
}
function setup_lightbtn(ctx, cell_size, lightbtn_id, pattern) {
let lit = { value: false };
document.getElementById(lightbtn_id).addEventListener('click', function(event) {
if (lit.value) {
lit.value = false;
unlight_pumpkin(ctx, cell_size, pattern);
}
else {
lit.value = true;
light_pumpkin(ctx, cell_size, pattern);
}
});
return lit;
}
function setup_pumpkin(canvas_id, clearbtn_id, lightbtn_id, form_id, pattern_field_id, grid_size, allow_drawing=true) {
const canvas = document.getElementById(canvas_id);
const ctx = canvas.getContext('2d');
@@ -160,29 +177,20 @@ function setup_pumpkin(canvas_id, clearbtn_id, lightbtn_id, form_id, pattern_fie
const CELL_SIZE = canvas.width / GRID_SIZE;
let currentPattern = [];
let lit = { value: false };
img.onload = () => {
clearCanvas(ctx, canvas, img, GRID_SIZE, currentPattern);
};
if (allow_drawing) {
let lit = false;
document.getElementById(lightbtn_id).addEventListener('click', function(event) {
if (lit) {
lit = false;
unlight_pumpkin(ctx, CELL_SIZE, currentPattern);
}
else {
lit = true;
light_pumpkin(ctx, CELL_SIZE, currentPattern);
}
});
lit = setup_lightbtn(ctx, CELL_SIZE, lightbtn_id, currentPattern);
let drawing = false;
canvas.addEventListener('mousedown', () => { drawing = true; });
canvas.addEventListener('mouseup', () => { drawing = false; });
canvas.addEventListener('mousemove', (e) => draw(e, ctx, CELL_SIZE, drawing, canvas, currentPattern, lit));
canvas.addEventListener('click', (e) => {draw(e, ctx, CELL_SIZE, true, canvas, currentPattern, lit)});
canvas.addEventListener('mousemove', (e) => draw(e, ctx, CELL_SIZE, drawing, canvas, currentPattern, lit.value));
canvas.addEventListener('click', (e) => {draw(e, ctx, CELL_SIZE, true, canvas, currentPattern, lit.value)});
document.getElementById(clearbtn_id).addEventListener('click', () => clearCanvas(ctx, canvas, img, GRID_SIZE, currentPattern));
document.getElementById(form_id).addEventListener('submit', function(event) {

View File

@@ -90,18 +90,7 @@ img.addEventListener('load', function() {
setInterval(update, 1500);
});
let lit = false;
document.getElementById("lightBtn").addEventListener('click', function(event) {
if (lit) {
lit = false;
unlight_pumpkin(ctx, CELL_SIZE, pattern.slice(0, pattern.length - last_days));
}
else {
lit = true;
light_pumpkin(ctx, CELL_SIZE, pattern.slice(0, pattern.length - last_days));
}
});
setup_lightbtn(ctx, CELL_SIZE, "lightBtn", pattern.slice(0, pattern.length - last_days));
</script>
{% endblock body %}

View File

@@ -18,15 +18,40 @@
{% endblock %}
{% block body %}
<div class="position-absolute top-50 start-50 translate-middle text-center">
{% for post in posts %}
<div class="card" style="width: 18rem;">
<canvas class="card-img-top"></canvas>
<div class="card-body">
<h5 class="card-title">{{ post.1 }}: {{ post.3 }}</h5>
<p class="card-text">{{ post.2 }}</p>
</div>
</div>
{% endfor %}
<div class="text-center mt-3">
<h1>Posts</h1>
</div>
<div class="container mt-4">
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
{% for post in posts %}
<div class="col">
<div class="card h-100">
<canvas id="pumpkin-canvas-{{ post.0 }}" width="600" height="600" class="card-img-top"></canvas>
<div class="card-body">
<h5 class="card-title">{{ post.2 }}</h5>
<p class="card-text">By: {{ post.1 }}<br>Created at: {{ post.4 }}</p>
<button type="button" id="lightBtn-{{ post.0 }}" class="btn btn-warning">Light!</button>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<script>
let CELL_SIZE = 0;
{% for post in posts %}
const [ctx_{{ post.0 }}, canvas_{{ post.0 }}, img_{{ post.0 }}] = setup_pumpkin("pumpkin-canvas-{{ post.0 }}", null, null, null, null, {{ grid_size }}, false);
let lit_{{ post.0 }} = false;
let pattern_{{ post.0 }} = {{ post.3 }};
CELL_SIZE = canvas_{{ post.0 }}.width / 15;
img_{{ post.0 }}.addEventListener('load', function() {
unlight_pumpkin(ctx_{{ post.0 }}, CELL_SIZE, pattern_{{ post.0 }});
});
setup_lightbtn(ctx_{{ post.0 }}, CELL_SIZE, "lightBtn-{{ post.0 }}", pattern_{{ post.0 }})
{% endfor %}
</script>
{% endblock body %}