Skip to main content

Module md

Module md 

Source
Expand description

GFM markdown, parsed into a serializable node tree instead of HTML.

The web UI’s one hard rule is that DOM is built with createElement and textContent and never with innerHTML — an AI-authored chat reply, a question’s reasoning, and an operator’s task instruction are all arbitrary text, and any of them could contain a <script> tag. That rule used to force the front end into assets/ui/app.js’s own tiny hand-rolled markdown reader, which understood four constructs and left everything else — tables, task lists, links — as literal asterisks and brackets.

This module moves the actual parsing to comrak, a full GFM implementation, and hands the client a tree of Node instead of a string of HTML. The client walks the tree and builds elements directly; there is never a markup string to insert, so the no-innerHTML rule holds even though the markdown support is now complete.

Two things are deliberately stricter than the source markdown, both because this tree can carry attacker-authored text (an AI writes chat turns and question detail) into a browser with no server-side sanitizer standing between them:

  • [normalize_link] keeps only http:/https: link destinations.
  • [normalize_image] keeps only data: image URIs and, when the markdown came from a question, relative filenames resolved against that question’s existing sandboxed panel asset route (see ImageBase::QuestionPanel).

Raw HTML in the source (a <script> block, an <img onerror=…>) is never interpreted: to_nodes turns it into a Node::Text carrying the literal characters, so a client that renders it with textContent shows the tag rather than running it.

Structs§

TableCell
One cell of a Node::Table row.

Enums§

Align
Column alignment of a table cell, per the GFM table extension.
ImageBase
How a relative image path in the source markdown is allowed to resolve.
Node
One node of parsed markdown.

Functions§

to_nodes
Parse text as GFM markdown into a node tree.