# `Kotoba.Sanitizer`
[🔗](https://github.com/hattoriai/kotoba/blob/v0.5.0/lib/kotoba/sanitizer.ex#L1)

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.

## Link schemes

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.

# `policy`

```elixir
@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`

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

The name of a policy.

# `allowed_schemes`

```elixir
@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`

```elixir
@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.

# `link_url`

```elixir
@spec link_url(term(), keyword()) :: String.t() | nil
```

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

The URL is trimmed. It is accepted when it has a scheme from the allowed
schemes, or when it has no scheme (a relative URL). A URL with a control
character, or with more than 2048 characters, is refused.

## Options

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

## Examples

    iex> Kotoba.Sanitizer.link_url("https://example.com")
    "https://example.com"

    iex> Kotoba.Sanitizer.link_url("/docs#top")
    "/docs#top"

    iex> Kotoba.Sanitizer.link_url("javascript:alert(1)")
    nil

# `policy`

```elixir
@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}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
