Commit graph

303 commits

Author SHA1 Message Date
2fd71e9029 feat: map user-facing file extensions to pandoc format names in export URIs
Users hitting /api/v1/export/threads/{id}.md got 'Unsupported format: md'
because pandoc's internal name is 'markdown'. Add EXTENSION_ALIASES +
resolve_format() so common extensions map to the right pandoc format:
  .md    -> markdown
  .html  -> html5
  .tex   -> latex
  .txt   -> plain
  .epub  -> epub3
  .wiki  -> mediawiki
  .adoc  -> asciidoc
  ...
Pandoc's own format names pass through unchanged (commonmark_x, docbook5,
fb2, etc.) via fallback.
2026-04-24 12:53:53 -04:00
586f2366df ci: rebuild to pull remarkbox-theme-chaostheory fed3eea (call_to_action in wikibar-right) 2026-04-24 07:47:29 -04:00
1bf5111638 ci: rebuild to pull remarkbox-theme-chaostheory df04c0d (call_to_action block fix) 2026-04-23 19:17:51 -04:00
9db2407395 feat: wiki revision history — HTML tabs, diff view, export links
- New route /{node_id}/revisions rendered by revision-history.j2
- Show content/history tabs on wiki root nodes
- Export dropdown includes history (json + html) links on wiki namespaces
- Node action buttons now gate on can_wiki_edit (not can_alter_node)
  so wiki-mode members can edit their own root nodes
- Suppress Topic link when URI matches current domain (self-reference)
- Tests covering revision timestamps, wiki_edit(), can_wiki_edit(),
  /revisions endpoints, CSRF trusted origins, export menu gating,
  pandoc rst→html rendering
2026-04-22 11:37:06 -04:00
a5c3e36fce fix: Namespace.moderators returned all members; owners now imply mod
moderators property returned self.enabled_users (every enabled member),
so every user who had ever posted got moderator powers: spam
approve/deny, edit/delete other users' comments, moderator Slack
notifications. Bug was universal across all namespaces — any site where
users post was affected.

Fix: moderators now returns only users with role='moderator'.
Owners now implicitly pass is_moderator() checks, since NamespaceUser
is single-role per user per namespace; this keeps owners functional
without needing a data migration.
2026-04-21 19:59:40 -04:00
e1952cb1c4 ci: fix chaostheory requirement name (pip distribution is remarkbox-chaostheory) 2026-04-21 18:31:49 -04:00
ddbcdfa094 ci: install and bundle remarkbox-theme-chaostheory
Adds chaostheory theme to the shared env.tar.gz build so foxhop.net
(which sets app.theme = chaostheory and shares /opt/remarkbox/env with
my.remarkbox.com) has the theme's templates + static assets available
after deploy.
2026-04-21 18:27:49 -04:00
68ca0ef6e7 feat: foxhop.net support — /attachment/ static view, pandoc standalone fix, figure/figcaption tags, avatar null guard, html5lib body fragment, chaostheory palette in common.css 2026-04-08 15:05:22 -04:00
176be89319 docs: use make migration — never hand-write revision IDs 2026-04-06 14:23:16 -04:00
604c8407ee style: avoid "the", use "our" — writing style rule + sweep 2026-03-31 13:20:22 -04:00
f3815eb0ce fix: CWE-407 content length cap on browser form paths; tighten bleach pin; add tests
- views/__init__.py: add MAX_CONTENT_LENGTH = 500_000 (shared constant with comment
  explaining the CWE-407 / bleach ReDoS rationale)
- reply_node.py: reject oversized content before set_data() / clean_raw_html()
- modify_node.py: same guard on edit path
- new_thread.py: same guard on new thread path
- requirements.py3.txt: tighten bleach>=2.1.4 -> bleach>=6.0.0 with CVE note
- test_render.py: unit tests for bleach version contract, API stability,
  sanitization correctness, and ReDoS resistance timing
- test_views.py: functional tests for content length enforcement on all three
  browser form paths (reply, new thread)
2026-03-30 09:27:59 -04:00
d37c60481d docs: CWE-407 audit — bleach sanitization pipeline and build tools 2026-03-30 08:25:27 -04:00
67483f2b98 ops: operation voyeur — credential opsec protocol 2026-03-29 15:46:07 -04:00
b51cf4574d chore: trigger CI to pull updated meta theme 2026-03-29 09:47:07 -04:00
06d70b9e92 docs: never access credentials without explicit instruction 2026-03-28 15:44:13 -04:00
c87fb0bd1f fix: cap search keywords and query results to prevent CWE-407 amplification
- list_nodes.py: strip empty tokens, cap keywords to 10 before passing to model
- node.py: add .limit(200) per keyword query — was unbounded .all()
- namespace.py: add .limit(500) on root.children in dict_dump — was unbounded iteration
- __init__.py: cap page_number to 1000 — large offsets force full table scans
2026-03-28 15:12:39 -04:00
2061097e13 Skip PDF tests when wkhtmltopdf unavailable (fixes CI). 2026-03-10 11:22:01 -04:00
46bdf3a217 Add revision diff endpoint and progressive enhancement export/wiki UI.
Diff: GET /api/v1/revisions/{id}/diff/{other_id} — unified diff between two revisions.
UI: <details>-based export menus on thread and node views (works without JS).
UI: Revision history link for wiki-mode namespaces.
2026-03-10 11:13:39 -04:00
75bec564b2 Replace ASCII diagrams with Graphviz DOT in architecture and ticket docs. 2026-03-10 09:29:36 -04:00
b63277e4d1 Update docs for Operation Undigg: API reference, testing guide, architecture diagram. 2026-03-10 09:07:32 -04:00
6d1cfff91d Operation Undigg: multi-syntax input, pandoc export, wiki mode, auto-themes.
Phase 1: Pandoc export pipeline — 67 output formats for threads, namespaces, nodes.
Phase 2: Multi-syntax input — accept markdown, HTML, RST, MediaWiki, LaTeX, etc.
Phase 3: Wiki mode — per-namespace toggle, revision tracking, wiki-edit endpoint.
Phase 4: Auto-generated themes — deterministic CSS per namespace, light + dark mode.

Includes unit, integration, and functional tests (95 new, 544 total).
2026-03-10 00:35:51 -04:00
f45c42d343 modified: remarkbox/__init__.py
modified:   requirements.py3.txt
2026-03-09 19:50:36 -04:00
5bcd7df585 Document proxy architecture and domain routing in CLAUDE.md.
Maps which domains go through the edge proxy (142.93.73.64) vs direct to
origin (162.243.167.224). Prevents repeat of the 5-day meta/faq SSL outage
caused by missing proxy blocks.
2026-03-02 15:51:56 -05:00
a57187672c Update postmortem with actual root cause and add T14.
The 5-day meta/faq SSL outage was caused by missing proxy blocks in
proxy.unturf.com, not a Caddy cold-start issue. Fixed in proxy commit f12a56d.
2026-03-02 15:22:39 -05:00
4287aeee2c Add postmortem for 2026-02-25 SSL/TLS outage on meta and faq subdomains. 2026-02-26 07:06:48 -05:00
2d64d79b80 Trigger salt highstate: migrate from nginx to caddy 2026-02-13 13:51:40 -05:00
fa6b3aab73 Prevent long inline code from blowing out page width on mobile. 2026-02-09 09:44:38 -05:00
165aea2ca3 Document related repos and footer duplication in CLAUDE.md. 2026-02-09 07:32:10 -05:00
12f8364a61 Redeploy to pick up meta theme footer fix 2026-02-09 07:11:53 -05:00
7c85b6e77e Document theme system and deployment workflow in CLAUDE.md 2026-02-08 15:46:51 -05:00
f5c09d873e Pin setuptools<81 — version 82 removed pkg_resources
Pyramid imports pkg_resources which was removed in setuptools 82.
Pin across requirements, Makefile, and CI scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:19:33 -05:00
37bffe29aa Install setuptools directly in CI scripts before make targets
Belt-and-suspenders: ensure setuptools is in the cached venv
before any Make target runs. Shell executor preserves env/
between builds but Python 3.12+ venvs lack setuptools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:16:01 -05:00
a2e574d6b9 Install setuptools before editable install, not just in venv target
The venv target is a no-op on cached CI runners where env/bin/activate
already exists. Move setuptools install into install-source-dev-and-test
and install-source-prod so it runs every time, regardless of venv cache.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:11:09 -05:00
568e8757fe Bump version to 1.0.6
Forces pip to re-resolve dependencies on cached CI venvs,
pulling in setuptools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:04:27 -05:00
ef4d6da410 Install setuptools in venv creation step for Python 3.12+
The requirements.py3.txt change alone wasn't enough — pip treats
setuptools specially during editable installs and may not install
it as a runtime dependency. Installing it immediately after venv
creation ensures pkg_resources is available for Pyramid and theme
loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:03:44 -05:00
8d64fa11e4 Add setuptools to requirements for Python 3.12+ compatibility
pkg_resources (used for theme entry point loading) lives in
setuptools, which Python 3.12+ no longer bundles in venvs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:57:26 -05:00
7575f74837 Add C SDK (rb.h + rb.c) with API download endpoint and namespace settings links. 2026-02-08 11:11:54 -05:00
f661938820 AJAX progressive enhancement for all action buttons.
Lock/unlock, watch/unwatch, disable/enable, verify, approve/deny
now return JSON for XHR requests and swap client-side without a
page reload. Falls back to normal POST + redirect when JS is off.
2026-02-08 08:38:27 -05:00
637f5a7073 Respect preview visibility preference on AJAX-inserted nodes. 2026-02-08 08:27:37 -05:00
0b22261b97 Fix preview layout: indent text column to stay right of avatar. 2026-02-08 06:44:59 -05:00
393151261d Add margin-right to preview avatar for proper text spacing. 2026-02-08 06:29:04 -05:00
48e17ad0f8 Fix preview avatar hidden by nested-avatar negative margin.
The dynamic CSS sets margin-left: -48px on .nested-avatar to hang
avatars into .node padding. In the preview container (no matching
padding, overflow:hidden), this pushed the avatar off-screen.
Use plain .avatar class for preview avatars instead.
2026-02-08 06:19:02 -05:00
14379cc364 Create preview avatar via DOM API instead of hidden template element.
Browsers do not render images inside display:none containers and
re-assigning src does not reliably trigger re-render. Store the
avatar URL in a data attribute and create the img element via
document.createElement after the container is already visible.
2026-02-08 06:00:08 -05:00
3c4f5998f2 Force avatar re-render after showing preview-author div.
Browsers skip rendering images inside display:none containers.
Re-assign the src attribute after making the div visible to force
the browser to render the SVG data URI.
2026-02-08 05:37:41 -05:00
e6af04bfc6 Add cache-busting version parameter to custom.js URL.
Prevents stale JS from running against new templates after deploys.
Uses the git commit hash as a query parameter on the script URL.
2026-02-08 04:48:29 -05:00
ac5970044e Fix preview avatar: use persistent DOM element instead of innerHTML manipulation.
Move the preview author header (avatar + name + timestamp) inside the
preview div as a persistent child element that JS shows/hides, rather
than serializing it via innerHTML which was failing to render the image.
2026-02-08 04:17:46 -05:00
a42ed0dc7a Switch preview header from <template> to hidden div.
<template>.innerHTML has DocumentFragment quirks. Use a plain
hidden div instead — its innerHTML is read directly from the
normal DOM to clone the avatar and author header for previews.
2026-02-07 20:05:03 -05:00
18cd870956 Use server-rendered template for preview avatar and author header.
Replace data-attribute approach with a <template> element inside the
reply form. The server renders the avatar img and author name once;
JS clones the HTML for each preview update. This fixes the missing
avatar in the live preview and handles anonymous name updates.
2026-02-07 19:29:53 -05:00
56163ffda3 Show live preview as a node with avatar, name, and timestamp.
Reply form preview now wraps rendered markdown in node-like markup
showing the author's avatar, display name, and "just now" timestamp.
Authenticated users see their real avatar; anonymous users see their
typed name. Edit form previews are unaffected.
2026-02-07 19:14:13 -05:00
7bb2f7fa31 Render AJAX replies server-side for seamless insertion.
Instead of building minimal DOM in JS, the reply handler now renders
the full node HTML using the same Jinja2 macros (avatar, author,
date, actions, edit/reply forms) and returns it as node_html.
The JS inserts the pre-rendered fragment directly.
2026-02-07 19:01:24 -05:00