T-HUB/packages/safe-content/README.md
glass beadian aa5e262f3a Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives:
publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style
column wall with hostile-content-safe rendering, live control room with Auto
Director, bridged chat governance with polls and quorum, distributed sandboxed
transcode workers, encrypted content-addressed archive, monthly analytics.

MIT licensed. See README.md and docs/.
2026-10-10 11:56:42 +00:00

40 lines
2.1 KiB
Markdown

# Safe content
The only sanctioned way to render provider content (posts, bios, comments,
messages, link previews, display names) in the web UI. Proposal §4.5.
Provider text becomes a closed rich-text AST (`text`, `linebreak`, `emoji`,
`link`, `mention`, `hashtag` inside `paragraph`s) before it reaches React. No
node can hold HTML, attributes or styles.
- `parsePlainText` handles plain provider text. `parseProviderHtml` handles the
Mastodon/PeerTube HTML subset. Neither renders HTML. `script`, `style`,
`iframe`, `svg`, `math`, `form`, `template` and similar elements are dropped
along with their content. Other tags are unwrapped to text.
- Links must be absolute http(s) URLs with no credentials, checked by
`parseSafeHttpUrl`. Anything else stays as plain text that can't be clicked.
Hosts are shown in punycode, and the real host is shown when a link's label
doesn't start with it.
- All media (`emoji`, preview images) goes through `toProxiedMediaUrl`
(default `/api/media-proxy?url=…`). The renderer drops any `src` that isn't
a canonical proxy URL.
- Bidi override/isolate characters are stripped from all text. Display names
also lose zero-width characters, and `DisplayName` flags mixed-script names
that use look-alike letters.
- Limits: 20k input chars, 2,000 nodes, nesting depth 32, 2,048-char URLs. The
tokenizer makes one forward pass, so its run time grows linearly with input
size.
`@tactical-media-broadcast-hub/safe-content/react` exports `RichText`, `LinkPreviewCard`,
`DisplayName` and `SafeLink`. They re-validate every prop with
`coerceRichTextDocument`/`parseLinkPreview`, so an AST loaded from the DB or
the network is as safe as a freshly parsed one.
`@tactical-media-broadcast-hub/safe-content/eslint` exports `noRawHtmlSinks`, a flat-config
block that bans `dangerouslySetInnerHTML`, `innerHTML`/`outerHTML`,
`insertAdjacentHTML`, `document.write`, `DOMParser.parseFromString`, `eval`
and `new Function` outside this package. Spread it into the root
`eslint.config.mjs`.
`@tactical-media-broadcast-hub/safe-content/corpus` exports the malicious-content corpus for
`packages/testing` and the Playwright suites.