max title (200) and body (10k) length limits, fix unescaped body in edit form

This commit is contained in:
lichenblankie 2026-06-05 01:04:17 +00:00
parent eed10f697c
commit 38d594ac50

View file

@ -5,7 +5,8 @@ from datetime import datetime
from urllib.parse import unquote
PER_PAGE = 20
MAX_TITLE_LENGTH = 200
MAX_BODY_LENGTH = 10000
RECENT_SECONDS = 86400 * 7 # "new" = within last 7 days
@ -222,9 +223,11 @@ class ForumHandlers:
f"<h1>new thread</h1>"
f'<form method="post" action="/forum/new">'
f'{self._csrf_field()}'
f'<input name="title" placeholder="title" size="50" required><br><br>'
f'<input name="title" placeholder="title" size="50" required><br>'
f"<small>max {MAX_TITLE_LENGTH} characters</small><br><br>"
f'<input name="url" placeholder="URL you want to share (optional)" size="50"><br><br>'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context (optional)"></textarea><br><br>'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context (optional)"></textarea><br>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>"
f'<input name="tags" placeholder="tags, comma-separated (optional)" size="50"><br><br>'
f'<button type="submit">post</button>'
f"</form>"
@ -239,6 +242,10 @@ class ForumHandlers:
tags = body.get("tags", [""])[0].strip()
if not title:
return self.handle_new_form("Title is required.")
if len(title) > MAX_TITLE_LENGTH:
return self.handle_new_form(f"Title too long (max {MAX_TITLE_LENGTH} characters).")
if len(body_text) > MAX_BODY_LENGTH:
return self.handle_new_form(f"Body too long (max {MAX_BODY_LENGTH} characters).")
thread_id = secrets.token_hex(16)
author_instance = self.identity.hash.hex() if self.identity else "local"
author_name = self.site_name
@ -308,7 +315,8 @@ class ForumHandlers:
reply_form = (
f'<form method="post" action="/forum/t/{thread["id"]}/reply">'
f'{self._csrf_field()}'
f'<textarea name="body" rows="4" cols="50" placeholder="share a URL or reply..." required></textarea><br><br>'
f'<textarea name="body" rows="4" cols="50" placeholder="share a URL or reply..." required></textarea><br>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>"
f'<button type="submit">reply</button>'
f"</form>"
)
@ -366,9 +374,11 @@ class ForumHandlers:
f"<h1>edit thread</h1>"
f'<form method="post" action="/forum/t/{thread_id}/edit">'
f'{self._csrf_field()}'
f'<input name="title" value="{esc(thread["title"])}" size="50" required><br><br>'
f'<input name="title" value="{esc(thread["title"])}" size="50" required><br>'
f"<small>max {MAX_TITLE_LENGTH} characters</small><br><br>"
f'<input name="url" value="{esc(thread["url"] or "")}" placeholder="URL" size="50"><br><br>'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context">{(thread["body"] or "")}</textarea><br><br>'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context">{esc(thread["body"] or "")}</textarea><br>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>"
f'<input name="tags" value="{esc(thread["tags"] or "")}" placeholder="tags, comma-separated" size="50"><br><br>'
f'<button type="submit">save</button>'
f"</form>"
@ -386,8 +396,12 @@ class ForumHandlers:
title = body.get("title", [""])[0].strip()
if not title:
return self.handle_edit_form(thread_id, "Title is required.")
if len(title) > MAX_TITLE_LENGTH:
return self.handle_edit_form(thread_id, f"Title too long (max {MAX_TITLE_LENGTH} characters).")
url = body.get("url", [""])[0].strip()
body_text = body.get("body", [""])[0].strip()
if len(body_text) > MAX_BODY_LENGTH:
return self.handle_edit_form(thread_id, f"Body too long (max {MAX_BODY_LENGTH} characters).")
tags = body.get("tags", [""])[0].strip()
now = self._now()
self.fdb.update_thread(thread_id, title, url, body_text, tags, now)
@ -397,6 +411,8 @@ class ForumHandlers:
body_text = body.get("body", [""])[0].strip()
if not body_text:
return self._redirect(f"/forum/t/{thread_id}")
if len(body_text) > MAX_BODY_LENGTH:
return self._respond(f"<p>Body too long (max {MAX_BODY_LENGTH} characters). <a href=\"/forum/t/{esc(thread_id)}\">back</a></p>")
parent_id = body.get("parent_id", [""])[0].strip()
author_instance = self.identity.hash.hex() if self.identity else "local"
author_name = self.site_name