# nh3

Python bindings to the ammonia HTML sanitization library.

## Installation

    pip install nh3

## Usage

Use `clean()` to sanitize HTML fragments:

    >>> import nh3
    >>> nh3.clean("<unknown>hi")
    'hi'
    >>> nh3.clean("<b><img src='' onerror='alert(\\'hax\\')'>XSS?</b>")
    '<b><img src="">XSS?</b>'

It has many options to customize the sanitization, as documented below. For example, to only allow `<b>` tags:

    >>> nh3.clean("<b><a href='https://example.com'>Hello</a></b>", tags={"b"})
    '<b>Hello</b>'

## API reference

Python bindings to the ammonia HTML sanitization library ( https://github.com/rust-ammonia/ammonia ).

class nh3.Cleaner(tags=None, clean_content_tags=None, attributes=None, attribute_filter=None, strip_comments=True, link_rel='noopener noreferrer', generic_attribute_prefixes=None, tag_attribute_values=None, set_tag_attribute_values=None, url_schemes=None, allowed_classes=None, filter_style_properties=None)

  Create a reusable sanitizer according to the given options.

  Parameters:

    - tags (`set[str]`, optional) – Sets the tags that are allowed.

    - clean_content_tags (`set[str]`, optional) – Sets the tags whose contents will be completely removed from the output.

    - attributes (`dict[str, set[str]]`, optional) – Sets the HTML attributes that are allowed on specific tags, `*` key means the attributes are allowed on any tag.

    - attribute_filter (`Callable[[str, str, str], str | None]`, optional) – Allows rewriting of all attributes using a callback. The callback takes name of the element, attribute and its value. Returns `None` to remove the attribute, or a value to use.

    - strip_comments (`bool`) – Configures the handling of HTML comments, defaults to `True`.

    - link_rel (`str`) –

      Configures a `rel` attribute that will be added on links, defaults to `noopener noreferrer`. To turn on rel-insertion, pass a space-separated list. If `rel` is in the generic or tag attributes, this must be set to `None`. Common `rel` values to include:

      - `noopener`: This prevents a particular type of XSS attack, and should usually be turned on for untrusted HTML.

      - `noreferrer`: This prevents the browser from sending the source URL to the website that is linked to.

      - `nofollow`: This prevents search engines from using this link for ranking, which disincentivizes spammers.

    - generic_attribute_prefixes (`set[str]`, optional) – Sets the prefix of attributes that are allowed on any tag.

    - tag_attribute_values (`dict[str, dict[str, set[str]]]`, optional) – Sets the values of HTML attributes that are allowed on specific tags. The value is structured as a map from tag names to a map from attribute names to a set of attribute values. If a tag is not itself whitelisted, adding entries to this map will do nothing.

    - set_tag_attribute_values (`dict[str, dict[str, str]]`, optional) – Sets the values of HTML attributes that are to be set on specific tags. The value is structured as a map from tag names to a map from attribute names to an attribute value. If a tag is not itself whitelisted, adding entries to this map will do nothing.

    - url_schemes (`set[str]`, optional) – Sets the URL schemes permitted on `href` and `src` attributes.

    - allowed_classes (`dict[str, set[str]]`, optional) – Sets the CSS classes that are allowed on specific tags. The values is structured as a map from tag names to a set of class names. The class attribute itself should not be whitelisted if this parameter is used.

    - filter_style_properties (`set[str]`, optional) – Only allows the specified properties in style attributes. Irrelevant if style is not an allowed attribute. Note that if style filtering is enabled style properties will be normalised e.g. invalid declarations and @rules will be removed, with only syntactically valid declarations kept.

  Example usage:

      >>> import nh3
      >>> cleaner = nh3.Cleaner(tags={"b", "i"}, attributes={})
      >>> cleaner.clean("<b><i>safe</i></b><script>xss</script>")
      '<b><i>safe</i></b>'
      >>> cleaner.clean("<b>another</b> <em>fragment</em>")
      '<b>another</b> fragment'

  clean(html)

    Sanitize an HTML fragment

nh3.clean(html, tags=None, clean_content_tags=None, attributes=None, attribute_filter=None, strip_comments=True, link_rel='noopener noreferrer', generic_attribute_prefixes=None, tag_attribute_values=None, set_tag_attribute_values=None, url_schemes=None, allowed_classes=None, filter_style_properties=None)

  Sanitize an HTML fragment according to the given options. See `Cleaner()` for detailed sanitizer options.

  Parameters:

    html (`str`) – Input HTML fragment

  Returns:

    Sanitized HTML fragment

  Return type:

    `str`

  For example:

      >>> import nh3
      >>> nh3.clean("<unknown>hi")
      'hi'
      >>> nh3.clean("<b><img src='' onerror='alert(\\'hax\\')'>XSS?</b>")
      '<b><img src="">XSS?</b>'

  Use `tags` to only allow certain HTML tags:

      >>> nh3.clean("<b><i>bold italic</i></b>", tags={"b"})
      '<b>bold italic</b>'

  `clean_content_tags` removes both the tag and its content, unlike `tags` which strips the tag but keeps the text:

      >>> nh3.clean(
      ...     "<script>alert('xss')</script>safe",
      ...     clean_content_tags={"script"},
      ... )
      'safe'

  The `attributes` parameter controls which attributes are kept per tag. Use `"*"` as a key to allow an attribute on all tags:

      >>> nh3.clean(
      ...     '<a href="/" id="link">click</a>',
      ...     attributes={"*": {"id"}, "a": {"href"}},
      ... )
      '<a href="/" id="link" rel="noopener noreferrer">click</a>'

  `tag_attribute_values` restricts an attribute to a set of allowed values, while `set_tag_attribute_values` unconditionally adds attributes:

      >>> nh3.clean(
      ...     "<div role='alert'>warning</div>",
      ...     tag_attribute_values={"div": {"role": {"alert", "status"}}},
      ... )
      '<div role="alert">warning</div>'
      >>> nh3.clean(
      ...     "<div>content</div>",
      ...     set_tag_attribute_values={"div": {"class": "safe"}},
      ... )
      '<div class="safe">content</div>'

  `allowed_classes` filters CSS class names per tag:

      >>> nh3.clean(
      ...     '<span class="highlight bold">text</span>',
      ...     allowed_classes={"span": {"highlight"}},
      ... )
      '<span class="highlight">text</span>'

  To filter individual `style` properties, first allow the `style` attribute, then use `filter_style_properties`:

      >>> nh3.clean(
      ...     '<span style="color: red; position: fixed">text</span>',
      ...     attributes={"span": {"style"}},
      ...     filter_style_properties={"color"},
      ... )
      '<span style="color:red">text</span>'

  Example of using `attribute_filter`:

      >>> from copy import deepcopy
      >>> attributes = deepcopy(nh3.ALLOWED_ATTRIBUTES)
      >>> attributes["a"].add("class")
      >>> def attribute_filter(tag, attr, value):
      ...     if tag == "a" and attr == "class":
      ...         if "mention" in value.split(" "):
      ...             return "mention"
      ...         return None
      ...     return value
      >>> nh3.clean("<a class='mention unwanted'>@foo</a>",
      ...     attributes=attributes,
      ...     attribute_filter=attribute_filter)
      '<a class="mention" rel="noopener noreferrer">@foo</a>'

  Example of maintaining the `rel` attribute:

      >>> from copy import deepcopy
      >>> attributes = deepcopy(nh3.ALLOWED_ATTRIBUTES)
      >>> attributes["a"].add("rel")
      >>> nh3.clean("<a href='https://tag.example' rel='tag'>#tag</a>",
      ...     link_rel=None, attributes=attributes)
      '<a href="https://tag.example" rel="tag">#tag</a>'

nh3.clean_text(html, tags=None)

  Turn an arbitrary string into unformatted HTML.

  Roughly equivalent to Python’s html.escape() or PHP’s htmlspecialchars and htmlentities. Escaping is as strict as possible, encoding every character that has special meaning to the HTML parser.

  If `tags` is given, those tags are passed through with no attributes; everything else is stripped (content kept). Behaves like `clean()` with `attributes={}` restricted to the given tag set.

  Parameters:

    - html (`str`) – Input HTML fragment

    - tags (`set[str]`, optional) – Tags to preserve; when omitted the string is fully escaped.

  Returns:

    Cleaned text

  Return type:

    `str`

  For example:

      >>> import nh3
      >>> nh3.clean_text('Robert"); abuse();//')
      'Robert&quot;);&#32;abuse();&#47;&#47;'
      >>> nh3.clean_text('<span>hello <mention>moto</mention>!</span>', tags={'mention'})
      'hello <mention>moto</mention>!'

nh3.is_html(html)

  Determine if a given string contains HTML.

  This function parses the full string and checks for any HTML syntax.

  Note: This function will return True for strings that contain invalid HTML syntax like `<g>` and even `Vec::<u8>::new()`.

  Parameters:

    html (`str`) – Input string

  Return type:

    `bool`

  For example:

      >>> nh3.is_html("plain text")
      False
      >>> nh3.is_html("<p>html!</p>")
      True

nh3.ALLOWED_TAGS

  The default set of tags allowed by `clean()`. Useful for customizing the default to add or remove some tags:

      >>> tags = nh3.ALLOWED_TAGS - {"b"}
      >>> nh3.clean("<b><i>yeah</i></b>", tags=tags)
      '<i>yeah</i>'

nh3.ALLOWED_ATTRIBUTES

  The default mapping of tags to allowed attributes for `clean()`. Useful for customizing the default to add or remove some attributes:

      >>> from copy import deepcopy
      >>> attributes = deepcopy(nh3.ALLOWED_ATTRIBUTES)
      >>> attributes["img"].add("data-invert")
      >>> nh3.clean("<img src='example.jpeg' data-invert=true>", attributes=attributes)
      '<img src="example.jpeg" data-invert="true">'

nh3.ALLOWED_URL_SCHEMES

  The default set of URL schemes permitted on `href` and `src` attributes. Useful for customizing the default to add or remove some URL schemes:

      >>> url_schemes = nh3.ALLOWED_URL_SCHEMES - {'tel'}
      >>> nh3.clean('<a href="tel:+1">Call</a> or <a href="mailto:contact@me">email</a> me.', url_schemes=url_schemes)
      '<a rel="noopener noreferrer">Call</a> or <a href="mailto:contact@me" rel="noopener noreferrer">email</a> me.'