Kotoba.Sanitizer (Kotoba v0.5.0)

Copy Markdown View Source

The structural checks that Kotoba.Renderer does before it renders a node.

Kotoba never passes raw HTML through. The renderer escapes every string, and the sanitizer adds these checks:

  • Attributes. The node must pass its own validate/1. Each string attribute must have no control characters, and its length must be in the limit: 200 characters for label, name, title, kind, id, rel, target, language and content_type, and 2048 characters for the other string attributes, url included. The text of a Kotoba.Nodes.Text or Kotoba.Nodes.CodeHighlight node and the style of a text node are not attributes; they have no limit. The URL of a link is checked by link_url/2.
  • Nesting. A list holds only list items, and a list item is valid only inside a list. A list item holds inline nodes, decorators and one nested list (by position: a second list at the same level renders as unknown, even when it repeats the first). A table is valid only under the root, a quote of blocks or a footnote, and holds only table rows; a table row is valid only in a table and holds only table cells; a table cell is valid only in a table row, and holds no table. A gallery is valid only under the root and holds only attachments. A footnote is valid only under the root. A code block holds only code highlight, text, line break and tab nodes. A paragraph, a heading, a quote and a link hold only inline nodes and decorators, and a link holds no other link; a quote of blocks (shadowRoot) holds blocks too. A decorator has no children. horizontalrule and attachment (block decorators) are valid only under the root, a list item, a table cell, a quote of blocks or a footnote (and an attachment in a gallery); elsewhere they render as unknown.
  • Links. link_url/2 accepts a URL with an allowed scheme, or a relative URL. A link with a URL that is not safe renders as its text. An attachment with a URL or a preview that is not safe fails the check.

When a node fails a check, the renderer renders it as an unknown node (inert, with no content). It does not raise.

The allowed schemes come from the application config. The default is ~w(http https mailto):

config :kotoba, allowed_link_schemes: ~w(http https mailto tel)

Policies

  • :default - links render as anchors and attachments render as figures.
  • :untrusted - for content from people that the app does not trust. Links render as their text, with no anchor. Attachments render as their file name, with no image and no link.

Summary

Types

A policy. links is true when links render as anchors. attachments is true when attachments render as figures.

The name of a policy.

Functions

Returns the allowed link schemes, in lower case.

Checks one node in its parent. parent is nil for the root node. The :schemes option is the same as in link_url/2. :index is the position of the node among its parent's children; Kotoba.Renderer sets it for every node it renders, and it decides whether a list nested in a list item is the one allowed nested list. A direct call that checks a nested list without :index always refuses it.

Returns the URL for an href or a src, or nil when it is not safe.

Returns the policy for a name. A policy map is returned with no change.

Types

policy()

@type policy() :: %{name: policy_name(), links: boolean(), attachments: boolean()}

A policy. links is true when links render as anchors. attachments is true when attachments render as figures.

policy_name()

@type policy_name() :: :default | :untrusted

The name of a policy.

Functions

allowed_schemes(opts \\ [])

@spec allowed_schemes(keyword()) :: [String.t()]

Returns the allowed link schemes, in lower case.

The editor gets the same list (see Kotoba.Components.kotoba/1), so that it keeps the links that the server keeps.

Options

  • :schemes - the allowed schemes. The default comes from config :kotoba, allowed_link_schemes:, else ~w(http https mailto).

Examples

iex> Kotoba.Sanitizer.allowed_schemes(schemes: ["HTTPS", "tel"])
["https", "tel"]

check(node, parent, opts \\ [])

@spec check(Kotoba.Node.t(), Kotoba.Node.t() | nil, keyword()) ::
  :ok | {:error, String.t()}

Checks one node in its parent. parent is nil for the root node. The :schemes option is the same as in link_url/2. :index is the position of the node among its parent's children; Kotoba.Renderer sets it for every node it renders, and it decides whether a list nested in a list item is the one allowed nested list. A direct call that checks a nested list without :index always refuses it.

Returns :ok, or {:error, reason} when the renderer must render the node as an unknown node.

policy(policy)

@spec policy(policy_name() | policy()) :: policy()

Returns the policy for a name. A policy map is returned with no change.

Raises ArgumentError for an unknown name.

Examples

iex> Kotoba.Sanitizer.policy(:untrusted)
%{name: :untrusted, links: false, attachments: false}