Close the web-feasible 100% gaps: REST write/token API, tickets, draw-badge, /me, sanitisation, dusk, radio SSE
Final parity push (web-tier only): - REST API write + token auth: POST /api/tokens (issue a personal_access_token for the session user), Bearer auth via src/lib/api-auth.ts, POST /api/articles/[slug]/comment, GET/DELETE /api/me/tokens, full tickets API (/api/tickets +[id] +[id]/reply), radio current-dj/points/points-leaderboard/ embed-config + POST shouts, and a real-time /api/radio/stream (SSE). 31 public API routes total. - Pages: /draw-badge (buy a custom profile badge → credits + RCON), /me dashboard (stats + online friends + referral claim). Wired into the nav. - HTML sanitisation (sanitize-html) — the HTMLPurifier equivalent — applied to writeable boxes + article bodies before dangerouslySetInnerHTML. - "Dusk" dark theme preset + a default-dark site option honoured by the no-flash boot script. Verified live (prod, amx_test): token issue → Bearer endpoint 200, no-token 401; /api/me/tokens lists it; current-dj/leaderboard JSON; /me + /draw-badge 200; reverted the test user + tokens. tsc 0, vitest 49/49, next build 0.
This commit is contained in:
1 parent
8cedf5614e
commit
f7b3845131
30 files changed
+1734
-10
No files matched your search
@@ -0,0 +1,45 @@
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
|
||||
/**
|
||||
* Server-side HTML sanitiser for user/staff-authored rich content before it is
|
||||
* injected via dangerouslySetInnerHTML — the AtomCMS HTMLPurifier equivalent.
|
||||
* Allows a safe formatting subset (no <script>/<style>/<iframe>, no on* event
|
||||
* handlers, no javascript: URLs); images/links are permitted with safe schemes.
|
||||
*/
|
||||
const OPTIONS: sanitizeHtml.IOptions = {
|
||||
allowedTags: [
|
||||
"a", "b", "i", "em", "strong", "u", "s", "p", "br", "hr", "span", "div",
|
||||
"ul", "ol", "li", "blockquote", "code", "pre",
|
||||
"h1", "h2", "h3", "h4", "h5", "h6",
|
||||
"img", "figure", "figcaption", "table", "thead", "tbody", "tr", "th", "td",
|
||||
],
|
||||
allowedAttributes: {
|
||||
a: ["href", "title", "target", "rel"],
|
||||
img: ["src", "alt", "title", "width", "height"],
|
||||
"*": ["style", "class"],
|
||||
},
|
||||
allowedSchemes: ["http", "https", "mailto"],
|
||||
allowedSchemesByTag: { img: ["http", "https", "data"] },
|
||||
// Drop any style declarations that aren't simple, safe properties.
|
||||
allowedStyles: {
|
||||
"*": {
|
||||
color: [/.*/],
|
||||
"background-color": [/.*/],
|
||||
"text-align": [/^left$|^right$|^center$|^justify$/],
|
||||
"font-weight": [/.*/],
|
||||
"font-style": [/.*/],
|
||||
"text-decoration": [/.*/],
|
||||
"font-size": [/.*/],
|
||||
margin: [/.*/],
|
||||
padding: [/.*/],
|
||||
},
|
||||
},
|
||||
transformTags: {
|
||||
a: sanitizeHtml.simpleTransform("a", { rel: "noopener noreferrer nofollow" }),
|
||||
},
|
||||
};
|
||||
|
||||
export function sanitize(html: string | null | undefined): string {
|
||||
if (!html) return "";
|
||||
return sanitizeHtml(html, OPTIONS);
|
||||
}
|
||||
Reference in new issue
Block a user