Port 4ducky to Rust (Axum + SQLite)

Same design, layout, URLs and features as the PHP version: browse grid,
image view with AJAX comments, BBCode, likes, uploads (file, URL and
bookmarklet), quicktagger, profile, block list, inbox, invites, Hall of
Ducks, Truhe, abuse reports and the admin tools.

- Parameterized SQL, escaped templates (askama), argon2 passwords,
  server-side sessions, CSRF tokens on every write, strict script CSP
- SSRF-safe remote image fetching, magic-byte upload checks
- Self-hosted captcha replaces reCAPTCHA v1; analytics/social widgets removed
- Vanilla JS replaces jQuery and its plugins with the same DOM behaviour
- Reverse proxy support (frontend_path, trust_proxy, secure_cookies)
- Admin CLI: admin, settings, invites

See README.md for running it and the full list of changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 02:15:05 +02:00
co-authored by Claude Opus 5.5
parent 664d8c6117
commit d0f2d526df
56 changed files with 11133 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
{% include "header.html" %}
<div align="center">
<form action="/login" method="post">
<fieldset>
<legend>Invites</legend>
<dl class="form">
<dt>Info:</dt>
<dd>
-Invitemissbrauch führt zum Ban. (Keine Reaktivierung) / Darunter fällt auch einem gebannten User einen Invite zu geben.
</dd>
<dt></dt>
<dd>-Nutzt die Invites weise. Baut euer Gast groben Unfug, seid ihr auch weg.</dd>
<dt>Howto:</dt>
<dd>Einfach den Link weiterschicken.</dd>
</dl>
<table class="table" width="100%" border="0" cellspacing="0">
<tr class="tabletop">
<td align="center" class="tabletoptd"><strong>InviteCode</strong></td>
<td align="center" class="tabletoptd" width="100px"><strong>Used</strong></td>
</tr>
{%- for i in invites %}
<tr class="tablelist">
<td align="center" class="tabletd">
{%- if i.used_by.is_none() %}
<strong><a href="{{ l.frontend_path }}invites/{{ i.code }}">{{ i.code }}</a></strong>
{%- else %}
{{ i.code }}
{%- endif %}
</td>
<td align="center" class="tabletd" width="50px">{% if let Some(n) = i.used_by %}{{ n }}{% else %}no{% endif %}</td>
</tr>
{%- else %}
<td align="center" class="tabletd">Zurzeit keine Invites für dich</td>
<td class="tabletd"></td>
{%- endfor %}
</table>
</fieldset>
</form>
</div>
{% include "footer.html" %}