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/.
40 lines
2.1 KiB
Markdown
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.
|