(|attribute|) method steps are:
-
-1. Let |name| be the result of [=canonicalize a sanitizer name=] |attribute| with the `null` as the default namespace.
-1. [=SanitizerConfig/Add=] |name| to [=this=]'s [=internal slot=]'s {{SanitizerConfig/removeAttributes}}.
-1. [=list/Remove=] |name| from [=this=]'s [=internal slot=]'s
- {{SanitizerConfig/attributes}}.
+
## The Configuration Dictionary ## {#config}
@@ -418,8 +351,6 @@ dictionary SanitizerConfig {
};
-ISSUE: Sould members be required, or have declared defaults?
-
# Algorithms # {#algorithms}
@@ -461,18 +392,18 @@ an options dictionary |options|, do:
For the main sanitize operation, using a {{ParentNode}} |node|, a
-{{Sanitizer}} |sanitizer| and a [=boolean=] |safe|, run these steps:
+{{Sanitizer}} |sanitizer|, and a [=boolean=] |safe|, run these steps:
-1. Let |config| be the value of |sanitizer|'s [=internal slot=].
-1. If |safe|, let |config| be the result of calling [=remove unsafe=] on |config|.
-1. Call [=sanitize core=] on |node|, |config|, and |safe| (as value for
+1. Let |configuration| be the value of |sanitizer|'s [=Sanitizer/configuration=].
+1. If |safe| is true, then set |configuration| to the result of calling [=remove unsafe=] on |configuration|.
+1. Call [=sanitize core=] on |node|, |configuration|, and |safe| (as value for
handling javascript navigation urls).
The sanitize core operation,
-using a {{ParentNode}} |node|, a {{SanitizerConfig}} |config|, and a
+using a {{ParentNode}} |node|, a {{SanitizerConfig}} |configuration|, and a
[=boolean=] |handle javascript navigation urls|, iterates over the DOM tree
beginning with |node|, and may recurse to handle some special cases (e.g.
template contents). It consistes of these steps:
@@ -488,51 +419,130 @@ template contents). It consistes of these steps:
1. If |child| [=implements=] {{Text}}:
1. [=continue=].
1. else if |child| [=implements=] {{Comment}}:
- 1. If |config|'s {{SanitizerConfig/comments}} is not true:
+ 1. If |configuration|["{{SanitizerConfig/comments}}"] is not true:
1. [=/remove=] |child|.
1. else:
1. Let |elementName| be a {{SanitizerElementNamespace}} with |child|'s
[=Element/local name=] and [=Element/namespace=].
- 1. If |config|["{{SanitizerConfig/removeElements}}"] [=SanitizerConfig/contains=] |elementName|, or if |config|["{{SanitizerConfig/elements}}"] is not [=list/empty=] and does not [=SanitizerConfig/contain=] |elementName|:
+ 1. If |configuration|["{{SanitizerConfig/removeElements}}"] [=SanitizerConfig/contains=] |elementName|, or if |configuration|["{{SanitizerConfig/elements}}"] is not [=list/empty=] and does not [=SanitizerConfig/contain=] |elementName|:
1. [=/remove=] |child|.
- 1. If |config|["{{SanitizerConfig/replaceWithChildrenElements}}"] [=SanitizerConfig/contains=] |elementName|:
- 1. Call [=sanitize core=] on |child| with |config| and
+ 1. If |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"] [=SanitizerConfig/contains=] |elementName|:
+ 1. Call [=sanitize core=] on |child| with |configuration| and
|handle javascript navigation urls|.
1. Call [=replace all=] with |child|'s [=tree/children=] within |child|.
1. If |elementName| [=equals=] «[ "`name`" → "`template`",
"`namespace`" → [=HTML namespace=] ]»
1. Then call [=sanitize core=] on |child|'s [=template contents=] with
- |config| and |handle javascript navigation urls|.
+ |configuration| and |handle javascript navigation urls|.
1. If |child| is a [=shadow host=]:
1. Then call [=sanitize core=] on |child|'s [=Element/shadow root=] with
- |config| and |handle javascript navigation urls|.
- 1. [=list/iterate|For each=] |attr| in |child|'s [=Element/attribute list=]:
- 1. Let |attrName| be a {{SanitizerAttributeNamespace}} with |attr|'s
+ |configuration| and |handle javascript navigation urls|.
+ 1. [=list/iterate|For each=] |attribute| in |child|'s [=Element/attribute list=]:
+ 1. Let |attrName| be a {{SanitizerAttributeNamespace}} with |attribute|'s
[=Attr/local name=] and [=Attr/namespace=].
- 1. If |config|["{{SanitizerConfig/removeAttributes}}"]
+ 1. If |configuration|["{{SanitizerConfig/removeAttributes}}"]
[=SanitizerConfig/contains=] |attrName|:
- 1. Remove |attr| from |child|.
- 1. If |config|["{{SanitizerConfig/elements}}"]["{{SanitizerElementNamespaceWithAttributes/removeAttributes}}"]
+ 1. Remove |attribute| from |child|.
+ 1. If |configuration|["{{SanitizerConfig/elements}}"]["{{SanitizerElementNamespaceWithAttributes/removeAttributes}}"]
[=SanitizerConfig/contains=] |attrName|:
- 1. Remove |attr| from |child|.
+ 1. Remove |attribute| from |child|.
- 1. If all of the following are false, then remove |attr| from |child|.
- - |config|["{{SanitizerConfig/attributes}}"] [=list/exists=] and
+ 1. If all of the following are false, then remove |attribute| from |child|.
+ - |configuration|["{{SanitizerConfig/attributes}}"] [=list/exists=] and
[=SanitizerConfig/contains=] |attrName|
- - |config|["{{SanitizerConfig/elements}}"]["{{SanitizerElementNamespaceWithAttributes/attributes}}"]
+ - |configuration|["{{SanitizerConfig/elements}}"]["{{SanitizerElementNamespaceWithAttributes/attributes}}"]
[=SanitizerConfig/contains=] |attrName|
- "data-" is a [=code unit prefix=] of [=Attr/local name=] and
[=Attr/namespace=] is `null` and
- |config|["{{SanitizerConfig/dataAttributes}}"] is true
+ |configuration|["{{SanitizerConfig/dataAttributes}}"] is true
1. If |handle javascript navigation urls| and «[|elementName|, |attrName|]» matches an entry in the
- [=navigating URL attributes list=], and if |attr|'s [=protocol=] is
+ [=navigating URL attributes list=], and if |attribute|'s [=protocol=] is
"`javascript:`":
- 1. Then remove |attr| from |child|.
+ 1. Then remove |attribute| from |child|.
## Configuration Processing ## {#configuration-processing}
+
+To allow an element |element| with a {{SanitizerConfig}} |configuration|, do:
+
+1. Let |name| be the result of [=canonicalize a sanitizer name=] |element| with [=HTML namespace=] as the default namespace.
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/elements}}"].
+1. [=list/Append=] |name| to |configuration|["{{SanitizerConfig/elements}}"].
+1. [=list/iterate|For each=] |attribute| in
+ |element|["{{SanitizerElementNamespaceWithAttributes/attributes}}"],
+ [=SanitizerConfig/add=] |attribute| to
+ |configuration|["{{SanitizerConfig/elements}}"][|name|]["{{SanitizerElementNamespaceWithAttributes/attributes}}"].
+1. [=list/iterate|For each=] |attribute| in
+ |element|["{{SanitizerElementNamespaceWithAttributes/removeAttributes}}"],
+ [=SanitizerConfig/add=] |attribute| to
+ |configuration|["{{SanitizerConfig/elements}}"][|name|]["{{SanitizerElementNamespaceWithAttributes/removeAttributes}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/removeElements}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"].
+
+NOTE: Handling of [=allowElement=] is a little more complicated than the other
+ methods, because the element allow list can have per-element allow- and
+ remove-attribute lists. We first remove the given element from the list
+ before then adding it, which has the effect of re-setting (rather than
+ merging or elsehow modifying) the per-element list to whatever is passed
+ in. In other words, the per-element allow- and remove-lists can only be
+ set as a whole.
+
+
+
+
+To remove an element |element| from a {{SanitizerConfig}} |configuration|, do:
+
+1. Let |name| be the result of [=canonicalize a sanitizer name=] |element| with [=HTML namespace=] as the default namespace.
+1. [=SanitizerConfig/Add=] |name| to |configuration|["{{SanitizerConfig/removeElements}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/elements}}"] list.
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"].
+
+
+
+
+To replace an element |element| from a {{SanitizerConfig}} |configuration|, do:
+
+1. Let |name| be the result of [=canonicalize a sanitizer name=] |element| with [=HTML namespace=] as the default namespace.
+1. [=SanitizerConfig/Add=] |name| to |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/removeElements}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/elements}}"] list.
+
+
+
+
+To allow an attribute |attribute| on a {{SanitizerConfig}} |configuration|, do:
+
+1. Let |name| be the result of [=canonicalize a sanitizer name=] |attribute| with the `null` as the default namespace.
+1. [=SanitizerConfig/Add=] |name| to |configuration|["{{SanitizerConfig/attributes}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/removeAttributes}}"].
+
+
+
+
+To remove an attribute |attribute| from a {{SanitizerConfig}} |configuration|, do:
+
+1. Let |name| be the result of [=canonicalize a sanitizer name=] |attribute| with the `null` as the default namespace.
+1. [=SanitizerConfig/Add=] |name| to |configuration|["{{SanitizerConfig/removeAttributes}}"].
+1. [=SanitizerConfig/Remove=] |name| from |configuration|["{{SanitizerConfig/attributes}}"].
+
+
+
+
+To allow comments with |allow| on a {{SanitizerConfig}} |configuration|, do:
+
+1. Set |configuration|["{{SanitizerConfig/comments}}"] to |allow|.
+
+
+
+
+To allow data attributes with |allow| on a {{SanitizerConfig}} |configuration|, do:
+
+1. Set |configuration|["{{SanitizerConfig/dataAttributes}}"] to |allow|.
+
+
+
Note: While this algorithm is called [=remove unsafe=], we use
@@ -541,56 +551,56 @@ Note: While this algorithm is called [=remove unsafe=], we use
execute JavaScript when inserted into the document. In other words, this
method will remove oportunities for XSS.
-To remove unsafe from a |config|, do this:
+To remove unsafe from a |configuration|, do this:
1. [=Assert=]: The [=built-in safe baseline config=] has
{{SanitizerConfig/removeElements}} and {{SanitizerConfig/removeAttributes}}
keys set, but not {{SanitizerConfig/elements}},
{{SanitizerConfig/replaceWithChildrenElements}}, or
{{SanitizerConfig/attributes}}.
-1. Let |result| be a copy of |config|.
-1. [=list/For each=] |elem| in
+1. Let |result| be a copy of |configuration|.
+1. [=list/For each=] |element| in
[=built-in safe baseline config=][{{SanitizerConfig/removeElements}}]:
- 1. Call |result|.{{Sanitizer/removeElement()|removeElement}}(|elem|)
-1. [=list/For each=] |attr| in
+ 1. Call [=remove an element=] with |element| and |result|.
+1. [=list/For each=] |attribute| in
[=built-in safe baseline config=][{{SanitizerConfig/removeAttributes}}]:
- 1. Call |result|.{{Sanitizer/removeAttribute()|removeAttribute}}(|attr|)
+ 1. Call [=Sanitizer/remove an attribute=] with |attribute| and |result|.
1. Return |result|.
-To set a config |config| on a {{Sanitizer}} |sanitizer|, do this:
-
-1. [=Assert=]: |config| is a [=dictionary=].
-1. [=list/iterate|For each=] |item| of |config|[{{SanitizerConfig/elements}}] do:
- 1. Call |sanitizer|.{{Sanitizer/allowElement()|allowElement}}(|item|).
-1. [=list/iterate|For each=] |item| of |config|[{{SanitizerConfig/removeElements}}] do:
- 1. Call |sanitizer|.{{Sanitizer/removeElement()|removeElement}}(|item|).
-1. [=list/iterate|For each=] |item| of |config|[{{SanitizerConfig/replaceWithChildrenElements}}] do:
- 1. Call |sanitizer|.{{Sanitizer/replaceWithChildrenElement()|replaceWithChildrenElement}}(|item|).
-1. [=list/iterate|For each=] |item| of |config|[{{SanitizerConfig/attributes}}] do:
- 1. Call |sanitizer|.{{Sanitizer/allowAttribute()|allowAttribute}}(|item|).
-1. [=list/iterate|For each=] |item| of |config|[{{SanitizerConfig/removeAttributes}}] do:
- 1. Call |sanitizer|.{{Sanitizer/removeAttribute()|removeAttribute}}(|item|).
-1. Call |sanitizer|.{{Sanitizer/setComment()|setComment}}(|config|[{{SanitizerConfig/comments}}]).
-1. Call |sanitizer|.{{Sanitizer/setDataAttributes()|setDataAttributes}}(|config|[{{SanitizerConfig/dataAttributes}}]).
+To set a config |configuration| on a {{Sanitizer}} |sanitizer|, do this:
+
+1. [=Assert=]: |configuration| is a [=dictionary=].
+1. [=list/iterate|For each=] |element| of |configuration|["{{SanitizerConfig/elements}}"] do:
+ 1. Call [=allow an element=] with |element| and |sanitizer|.
+1. [=list/iterate|For each=] |element| of |configuration|["{{SanitizerConfig/removeElements}}"] do:
+ 1. Call [=remove an element=] with |element| and |sanitizer|.
+1. [=list/iterate|For each=] |element| of |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"] do:
+ 1. Call [=replace an element=] with |element| and |sanitizer|.
+1. [=list/iterate|For each=] |attribute| of |configuration|["{{SanitizerConfig/attributes}}"] do:
+ 1. Call [=allow an attribute=] with |attribute| and |sanitizer|.
+1. [=list/iterate|For each=] |attribute| of |configuration|["{{SanitizerConfig/removeAttributes}}"] do:
+ 1. Call [=Sanitizer/remove an attribute=] with |attribute| and |sanitizer|.
+1. Call [=allow comments=] with |configuration|["{{SanitizerConfig/comments}}"] and |sanitizer|.
+1. Call [=allow data attributes=] with |configuration|["{{SanitizerConfig/dataAttributes}}"] and |sanitizer|.
1. Return whether all of the following are true:
- - [=list/size=] of |config|[{{SanitizerConfig/elements}}] equals
- [=list/size=] of [=this=]'s [=internal slot=]'s {{SanitizerConfig/elements}}.
- - [=list/size=] of |config|[{{SanitizerConfig/removeElements}}] equals
- [=list/size=] of [=this=]'s [=internal slot=]'s {{SanitizerConfig/removeElements}}.
- - [=list/size=] of |config|[{{SanitizerConfig/replaceWithChildrenElements}}] equals
- [=list/size=] of [=this=]'s [=internal slot=]'s {{SanitizerConfig/replaceWithChildrenElements}}.
- - [=list/size=] of |config|[{{SanitizerConfig/attributes}}] equals
- [=list/size=] of [=this=]'s [=internal slot=]'s {{SanitizerConfig/attributes}}.
- - [=list/size=] of |config|[{{SanitizerConfig/removeAttributes}}] equals
- [=list/size=] of [=this=]'s [=internal slot=]'s {{SanitizerConfig/removeAttributes}}.
- - Either |config|[{{SanitizerConfig/elements}}] or
- |config|[{{SanitizerConfig/removeElements}}] [=map/exist=],
+ - [=list/size=] of |configuration|["{{SanitizerConfig/elements}}"] equals
+ [=list/size=] of [=this=]'s [=Sanitizer/configuration=]["{{SanitizerConfig/elements}}"].
+ - [=list/size=] of |configuration|["{{SanitizerConfig/removeElements}}"] equals
+ [=list/size=] of [=this=]'s [=Sanitizer/configuration=]["{{SanitizerConfig/removeElements}}"].
+ - [=list/size=] of |configuration|["{{SanitizerConfig/replaceWithChildrenElements}}"] equals
+ [=list/size=] of [=this=]'s [=Sanitizer/configuration=]["{{SanitizerConfig/replaceWithChildrenElements}}"].
+ - [=list/size=] of |configuration|["{{SanitizerConfig/attributes}}"] equals
+ [=list/size=] of [=this=]'s [=Sanitizer/configuration=]["{{SanitizerConfig/attributes}}"].
+ - [=list/size=] of |configuration|["{{SanitizerConfig/removeAttributes}}"] equals
+ [=list/size=] of [=this=]'s [=Sanitizer/configuration=]["{{SanitizerConfig/removeAttributes}}"].
+ - Either |configuration|["{{SanitizerConfig/elements}}"] or
+ |configuration|["{{SanitizerConfig/removeElements}}"] [=map/exist=],
or neither, but not both.
- - Either |config|[{{SanitizerConfig/attributes}}] or
- |config|[{{SanitizerConfig/removeAttributes}}] [=map/exist=],
+ - Either |configuration|["{{SanitizerConfig/attributes}}"] or
+ |configuration|["{{SanitizerConfig/removeAttributes}}"] [=map/exist=],
or neither, but not both.
Note: Previous versions of this spec had elaborate definitions of how to
@@ -645,7 +655,13 @@ A Sanitizer name |list| contains an |item|
if there exists an |entry| of |list| that is an [=ordered map=], and where
|item|["name"] [=equals=] |entry|["name"] and
|item|["namespace"] [=equals=] |entry|["namespace"].
+
+
+To remove an |item| from a |list| that is an
+[=ordered map=], [=list/remove=] all |entry| from |list|
+where |item|["name"] [=equals=] |entry|["name"] and
+|item|["namespace"] [=equals=] |entry|["namespace"].
@@ -653,7 +669,6 @@ Equality for [=ordered sets=] is equality of its members, but without
regard to order:
[=Ordered sets=] |A| and |B| are equal if both |A| is a
[=superset=] of |B| and |B| is a [=superset=] of |A|.
-
## Defaults ## {#sanitization-defaults}
@@ -667,7 +682,7 @@ There are four builtins:
The
built-in safe default config is the same as the [=built-in safe baseline config=].
-ISSUE: Determine if this actually holds.
+ISSUE(233): Determine if this actually holds.
The
built-in unsafe default config is meant to allow anything.