Bug 1864838 - Update sanitizer tests. r=freddyb

Differential Revision: https://phabricator.services.mozilla.com/D194072
This commit is contained in:
Tom Schuster 2023-11-28 11:04:03 +00:00
Родитель 8196b63ea4
Коммит ec0dceb4c1
11 изменённых файлов: 323 добавлений и 295 удалений

Просмотреть файл

@ -52,23 +52,23 @@ SimpleTest.waitForExplicitFinish();
sanitizerOptions: {},
},
{
// test for the allowElements option
// test for the elements option
testString: "<p>hello <i>folks</i></p>",
testExpected: "<p>hello folks</p>",
sanitizerOptions: { allowElements: ["p"] },
sanitizerOptions: { elements: ["p"] },
},
{
// test for the blockElements option
// test for the replaceWithChildrenElements option
testString: "<p>hello <i>folks</i></p>",
testExpected: "<p>hello folks</p>",
sanitizerOptions: { blockElements: ["i"] },
sanitizerOptions: { replaceWithChildrenElements: ["i"] },
},
// TODO: Unknown attributes aren't supported yet.
// {
// // test for the allowAttributes option
// testString: `<p haha="lol">hello</p>`,
// testExpected: `<p haha="lol">hello</p>`,
// sanitizerOptions: { allowUnknownMarkup: true, allowAttributes: { 'haha': ['p'] } },
// sanitizerOptions: { unknownMarkup: true, attributes: ["haha"] },
// },
{
// confirming the inverse
@ -77,10 +77,10 @@ SimpleTest.waitForExplicitFinish();
sanitizerOptions: {},
},
{
// test for the dropAttributes option
// test for the removeAttributes option
testString: `<p title="dropme">hello</p>`,
testExpected: `<p>hello</p>`,
sanitizerOptions: { dropAttributes: [{name: 'title', elements: ['p']}] },
sanitizerOptions: { removeAttributes: ['title'] },
},
{
// confirming the inverse
@ -89,12 +89,12 @@ SimpleTest.waitForExplicitFinish();
sanitizerOptions: {},
},
{
// if an attribute is allowed and dropped, the drop will take preference
// if an attribute is allowed and removed, the remove will take preference
testString: `<p title="lol">hello</p>`,
testExpected: `<p>hello</p>`,
sanitizerOptions: {
allowAttributes: [{ name: 'title', elements: ['p'] }],
dropAttributes: [{ name: 'title', elements: ['p'] }]
attributes: ["title"],
removeAttributes: ["title"],
},
},
];
@ -123,7 +123,7 @@ SimpleTest.waitForExplicitFinish();
else {
// test setHTML:
try {
div.setHTML(testString, { sanitizer: testSanitizer });
div.setHTML(testString, { sanitizer: sanitizerOptions });
is(div.innerHTML, testExpected, `div.setHTML() should turn(${testType}) '${testInput}' into '${testExpected}'`);
}
catch (e) {

Просмотреть файл

@ -0,0 +1,3 @@
[element-set-sanitized-html.https.html]
[Sanitizer: Element.setHTML with config: attributes: unknown attributes and with unknownMarkup]
expected: FAIL

Просмотреть файл

@ -1,22 +1,22 @@
[sanitizer-names.https.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Element names in config item: allowElements]
[Element names in config item: elements]
expected: FAIL
[Element names in config item: dropElements]
[Element names in config item: removeElements]
expected: FAIL
[Element names in config item: blockElements]
[Element names in config item: replaceWithChildrenElements]
expected: FAIL
[Attribute names in config item: allowAttributes]
[Attribute names in config item: attributes]
expected: FAIL
[Attribute names in config item: dropAttributes]
[Attribute names in config item: removeAttributes]
expected: FAIL
[Namespaced attributes #2: allowAttributes: [{"name":"xlink:href","elements":"*"}\]]
[Namespaced attributes #2: attributes: [{"name":"xlink:href"}\]]
expected: FAIL
[Lower-case element names #0: "svg:feblend"]

Просмотреть файл

@ -1,15 +1,15 @@
[sanitizer-sanitize.https.tentative.html]
max-asserts: 120
expected:
if (os == "android") and fission: [OK, TIMEOUT]
max-asserts: 120
[SanitizerAPI with config: plaintext, sanitize from document function for <body>]
expected: FAIL
[SanitizerAPI with config: allowAttributes unknown attributes and with allowUnknownMarkup, sanitize from document function for <body>]
[SanitizerAPI with config: attributes: unknown attributes and with unknownMarkup, sanitize from document function for <body>]
expected: FAIL
[SanitizerAPI with config: plaintext, sanitize from document fragment function for <template>]
expected: FAIL
[SanitizerAPI with config: allowAttributes unknown attributes and with allowUnknownMarkup, sanitize from document fragment function for <template>]
[SanitizerAPI with config: attributes: unknown attributes and with unknownMarkup, sanitize from document fragment function for <template>]
expected: FAIL

Просмотреть файл

@ -1,21 +1,51 @@
[sanitizer-sanitizeFor.https.tentative.html]
expected:
if (os == "android") and debug: [OK, TIMEOUT]
[Sanitizer.sanitizeFor("script", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor("iframe", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor("object", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor("div", ...) should pass.]
expected: FAIL
[Sanitizer.sanitizeFor function shouldn't load the image.]
expected: FAIL
[Sanitizer.sanitizeFor(element, ..)]
expected: FAIL
[Sanitizer.sanitizeFor("div", "<em>Hello</em>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor("div", "<td>data</td>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor("template", "<em>Hello</em>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor("template", "<td>data</td>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor("table", "<em>Hello</em>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor("table", "<td>data</td>") obeys parse context.]
expected: FAIL
[Sanitizer.sanitizeFor with config: string]
expected: FAIL
[Sanitizer.sanitizeFor with config: html fragment]
expected: FAIL
[Sanitizer.sanitizeFor with config: broken html]
expected: FAIL
[Sanitizer.sanitizeFor with config: empty object]
expected: FAIL
@ -28,6 +58,9 @@
[Sanitizer.sanitizeFor with config: arithmetic]
expected: FAIL
[Sanitizer.sanitizeFor with config: empty string]
expected: FAIL
[Sanitizer.sanitizeFor with config: undefined]
expected: FAIL
@ -37,6 +70,15 @@
[Sanitizer.sanitizeFor with config: html without close tag]
expected: FAIL
[Sanitizer.sanitizeFor with config: scripts for default configs]
expected: FAIL
[Sanitizer.sanitizeFor with config: script not as root]
expected: FAIL
[Sanitizer.sanitizeFor with config: script deeper in the tree]
expected: FAIL
[Sanitizer.sanitizeFor with config: onclick scripts]
expected: FAIL
@ -49,10 +91,10 @@
[Sanitizer.sanitizeFor with config: invalid config_input]
expected: FAIL
[Sanitizer.sanitizeFor with config: empty dropElements list]
[Sanitizer.sanitizeFor with config: empty removeElements list]
expected: FAIL
[Sanitizer.sanitizeFor with config: test html without close tag with dropElements list ['div'\]]
[Sanitizer.sanitizeFor with config: test html without close tag with removeElements list ['div'\]]
expected: FAIL
[Sanitizer.sanitizeFor with config: default behavior for custom elements]
@ -70,43 +112,43 @@
[Sanitizer.sanitizeFor with config: allow custom elements with drop list contains ["custom-element"\]]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements list ["test-element", "i"\]}]
[Sanitizer.sanitizeFor with config: test script with ["script"\] as removeElements list]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements list ["I", "DL"\]}]
[Sanitizer.sanitizeFor with config: removeElements list ["test-element", "i"\]}]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements list ["dl", "p"\]}]
[Sanitizer.sanitizeFor with config: removeElements list ["dl", "p"\]}]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowElements list ["p"\]]
[Sanitizer.sanitizeFor with config: elements list ["p"\]]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowElements list has no influence to dropElements]
[Sanitizer.sanitizeFor with config: elements list has no influence to removeElements]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"style": ["p"\]} with style attribute]
[Sanitizer.sanitizeFor with config: empty removeAttributes list with id attribute]
expected: FAIL
[Sanitizer.sanitizeFor with config: empty dropAttributes list with id attribute]
[Sanitizer.sanitizeFor with config: removeAttributes list ["id"\] with id attribute]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"id": ["*"\]} with id attribute]
[Sanitizer.sanitizeFor with config: removeAttributes list ["data-attribute-with-dashes"\] with dom dataset js access]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"ID": ["*"\]} with id attribute]
[Sanitizer.sanitizeFor with config: elements list with <p> attributes: ["title"\] and div attributes: ["id"\] lists]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"data-attribute-with-dashes": ["*"\]} with dom dataset js access]
[Sanitizer.sanitizeFor with config: elements list with <p> removeAttributes: ["title"\] and div removeAttributes: ["id"\] lists]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowAttributes list {"id": ["div"\]} with id attribute]
[Sanitizer.sanitizeFor with config: elements list with div attributes: ["id"\] and removeAttributes: ["id"\] lists]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowAttributes list {"id": ["*"\]} with id attribute and onclick scripts]
[Sanitizer.sanitizeFor with config: attributes list ["id"\] with id attribute and onclick scripts]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowAttributes list has no influence to dropAttributes]
[Sanitizer.sanitizeFor with config: attributes list has no influence to removeAttributes list]
expected: FAIL
[Sanitizer.sanitizeFor with config: Template element]
@ -163,34 +205,19 @@
[Sanitizer.sanitizeFor with config: HTML with comments; comments not allowed]
expected: FAIL
[Sanitizer.sanitizeFor with config: HTML with comments; allowComments]
[Sanitizer.sanitizeFor with config: HTML with comments; comments]
expected: FAIL
[Sanitizer.sanitizeFor with config: HTML with comments; !allowComments]
[Sanitizer.sanitizeFor with config: HTML with comments; !comments]
expected: FAIL
[Sanitizer.sanitizeFor with config: HTML with comments deeper in the tree]
expected: FAIL
[Sanitizer.sanitizeFor with config: HTML with comments deeper in the tree, allowComments]
[Sanitizer.sanitizeFor with config: HTML with comments deeper in the tree, comments]
expected: FAIL
[Sanitizer.sanitizeFor with config: HTML with comments deeper in the tree, !allowComments]
expected: FAIL
[Sanitizer.sanitizeFor("script", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor("object", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor("iframe", ...) should fail.]
expected: FAIL
[Sanitizer.sanitizeFor with config: script not as root]
expected: FAIL
[Sanitizer.sanitizeFor with config: script deeper in the tree]
[Sanitizer.sanitizeFor with config: HTML with comments deeper in the tree, !comments]
expected: FAIL
[Sanitizer.sanitizeFor with config: Unknown HTML names (HTMLUnknownElement instances) should not match elements parsed as non-HTML namespaces.]
@ -199,74 +226,62 @@
[Sanitizer.sanitizeFor with config: Unknown HTML names (HTMLUnknownElement instances) should not match elements parsed as non-HTML namespaces when nested.]
expected: FAIL
[Sanitizer.sanitizeFor("div", ...) should pass.]
[Sanitizer.sanitizeFor with config: removeElements list ["I", "DL"\]}]
expected: FAIL
[Sanitizer.sanitizeFor function shouldn't load the image.]
[Sanitizer.sanitizeFor with config: removeElements list ["i", "dl"\]}]
expected: FAIL
[Sanitizer.sanitizeFor("div", "<em>Hello</em>") obeys parse context.]
[Sanitizer.sanitizeFor with config: removeElements list ["i", "dl"\]} with uppercase HTML]
expected: FAIL
[Sanitizer.sanitizeFor("div", "<td>data</td>") obeys parse context.]
[Sanitizer.sanitizeFor with config: removeAttributes list ["ID"\] with id attribute]
expected: FAIL
[Sanitizer.sanitizeFor("table", "<em>Hello</em>") obeys parse context.]
[Sanitizer.sanitizeFor with config: removeAttributes list ["ID"\] with ID attribute]
expected: FAIL
[Sanitizer.sanitizeFor("table", "<td>data</td>") obeys parse context.]
[Sanitizer.sanitizeFor with config: removeAttributes list ["id"\] with ID attribute]
expected: FAIL
[Sanitizer.sanitizeFor with config: broken html]
[Sanitizer.sanitizeFor with config: removeElements with unknown elements and without unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: empty string]
[Sanitizer.sanitizeFor with config: replaceWithChildrenElements with unknown elements and without unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: scripts for default configs]
[Sanitizer.sanitizeFor with config: elements with unknown elements and without unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: test script with ["script"\] as dropElements list]
[Sanitizer.sanitizeFor with config: removeElements with unknown elements and with unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements list ["i", "dl"\]}]
[Sanitizer.sanitizeFor with config: replaceWithChildrenElements with unknown elements and with unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements list ["i", "dl"\]} with uppercase HTML]
[Sanitizer.sanitizeFor with config: elements with unknown elements and with unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"ID": ["*"\]} with ID attribute]
[Sanitizer.sanitizeFor with config: attributes: unknown attributes and without unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes list {"id": ["*"\]} with ID attribute]
[Sanitizer.sanitizeFor with config: attributes: unknown attributes and with unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements with unknown elements and without allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: removeAttributes: unknown attributes and without unknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: blockElements with unknown elements and without allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: removeAttributes unknown attributes and with allowUnknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowElements with unknown elements and without allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: elements list with <div> attributes: ["id"\] and removeAttributes: ["id"\] lists]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropElements with unknown elements and with allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: elements list with <div> attributes: ["id", "title"\] does not override empty attributes: [\] list]
expected: FAIL
[Sanitizer.sanitizeFor with config: blockElements with unknown elements and with allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: elements list with <div> attributes: ["id", "title"\] does not override removeAttributes: ["id", "title"\] list]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowElements with unknown elements and with allowUnknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowAttributes unknown attributes and without allowUnknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: allowAttributes unknown attributes and with allowUnknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes unknown attributes and without allowUnknownMarkup]
expected: FAIL
[Sanitizer.sanitizeFor with config: dropAttributes unknown attributes and with allowUnknownMarkup]
[Sanitizer.sanitizeFor with config: elements list with <div> removeAttributes: ["id", "title"\] is effective even with attributes: ["id", "title"\] list]
expected: FAIL

Просмотреть файл

@ -1,5 +1,3 @@
[sanitizer-unknown.https.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Unknown attribute names pass with allowUnknownMarkup.]
[Unknown attribute names pass with unknownMarkup.]
expected: FAIL

Просмотреть файл

@ -14,15 +14,22 @@
}
function assert_node_equals(node1, node2) {
assert_true(node1 instanceof Node && node1.isEqualNode(node2),
assert_equals(node2.innerHTML, node1.innerHTML);
assert_true(node1.isEqualNode(node2),
`Node[${node1.innerHTML}] == Node[${node2.innerHTML}]`);
// TODO(https://github.com/WICG/sanitizer-api/issues/202)
/*
if (node1 instanceof HTMLTemplateElement) {
assert_true(node1.content.isEqualNode(node2.content), "<template> content is equal");
}
*/
}
for (const context of ["script", "iframe", "object", "div"]) {
const should_fail = context != "div";
test(t => {
let elem = document.createElement(context);
let probe_fn = _ => elem.setHTML("<div>Hello!</div>", new Sanitizer());
let probe_fn = _ => elem.setHTML("<div>Hello!</div>");
if (should_fail) {
assert_throws_js(TypeError, probe_fn);
} else {
@ -32,11 +39,11 @@
}, `${context}.setHTML should ${should_fail ? "fail" : "pass"}.`);
}
for(const context of ["div", "template", "table"]) {
for (const context of ["div", "template", "table"]) {
const elem1 = document.createElement(context);
const elem2 = document.createElement(context);
for (const probe of ["<em>Hello</em>", "<td>data</td>"]) {
elem1.setHTML(probe, new Sanitizer());
elem1.setHTML(probe, {});
elem2.innerHTML = probe;
test(t => {
assert_node_equals(elem2, elem1);
@ -47,8 +54,7 @@
for (const testcase of testcases) {
const element = document.createElement("template");
test(t => {
let s = new Sanitizer(testcase.config_input);
element.setHTML(testcase.value, {sanitizer: s });
element.setHTML(testcase.value, {sanitizer: testcase.config_input });
assert_node_equals(buildNode(element.localName, testcase.result), element);
}, "Sanitizer: Element.setHTML with config: " + testcase.message);
}
@ -56,9 +62,9 @@
[
undefined,
{},
{ sanitizer: new Sanitizer() },
{ sanitizer: {} },
{ sanitizer: undefined },
{ avocado: new Sanitizer() },
{ avocado: {} },
].forEach((options, index) => {
test(t => {
const e = document.createElement("div");
@ -69,9 +75,8 @@
[
"tomato",
{ sanitizer: null },
{ sanitizer: false },
{ sanitizer: "avocado" },
{ sanitizer: { allowElements: [ "a", "b", "c" ] } },
].forEach((options, index) => {
test(t => {
assert_throws_js(TypeError, _ => {
@ -79,33 +84,6 @@
});
}, `Sanitizer: Element.setHTML invalid options dictionary #${index}`);
});
test(t => {
const sanitizer = new Sanitizer({allowElements: ["b"]});
const element = document.createElement("div");
// WebIDL magic: An IDL dictionary is mapped to a JS object. Thus, a plain
// Sanitizer instance will be accepted as an options dictionary. However,
// it will then try to read the .sanitizer property of the Sanitizer, and
// since that doesn't usually exist will treat it as an empty dictionary.
//
// Ref: https://webidl.spec.whatwg.org/#es-dictionary
// Sanitizer instance in the dictionary: Config is applied.
element.setHTML("<em>celery</em>", {sanitizer: sanitizer});
assert_equals(element.innerHTML, "celery");
// Same Sanitizer instance, passed directly: Is like an empty dictionary
// and config is not applied.
element.setHTML("<em>celery</em>", sanitizer);
assert_equals(element.innerHTML, "<em>celery</em>");
// Sanitizer-ception: Set the Sanitizer as the .sanitizer property on itself.
// Now the config is applied. It's magic. Just not the good kind of magic.
sanitizer.sanitizer = sanitizer;
element.setHTML("<em>celery</em>", sanitizer);
assert_equals(element.innerHTML, "celery");
}, "Sanitizer: Element.setHTML with sanitizer instance.");
</script>
</body>
</html>

Просмотреть файл

@ -42,24 +42,27 @@
// The probe determines whether the Sanitizer modifies the probe string.
const probe_string = "<div id=\"i\">balabala</div><p>test</p>";
const probe = sanitizer => {
const div = document.createElement("div");
div.setHTML(probe_string, {sanitizer: sanitizer});
let template = document.createElement("template");
template.innerHTML = probe_string;
let fragment = sanitizer.sanitize(template.content);
let div = document.createElement("div");
div.append(fragment);
return probe_string == div.innerHTML;
};
const should_stay_the_same = {
allowElements: [ "div", "p" ],
blockElements: [ "test" ],
dropElements: [ "test" ],
allowAttributes: [{ name: "id", elements: "*"}],
dropAttributes: [{ name: "bla", elements: ["blubb"]}],
elements: [ "div", "p" ],
replaceWithChildrenElements: [ "test" ],
removeElements: [ "test" ],
attributes: ["id"],
removeAttributes: ["bla"],
};
const should_modify = {
allowElements: [ "div", "span" ],
blockElements: [ "div" ],
dropElements: [ "p" ],
allowAttributes: [{ name: "id", elements: ["p"] }],
dropAttributes: [{ name: "id", elements: ["div"] }],
elements: [ "div", "span" ],
replaceWithChildrenElements: [ "div" ],
removeElements: [ "p" ],
attributes: ["test"],
removeAttributes: ["id"],
};
assert_array_equals(Object.keys(should_stay_the_same), Object.keys(should_modify));

Просмотреть файл

@ -14,13 +14,12 @@
// Element names:
const elems_valid = [
"p", "template", "span", "custom-elements", "potato",
// Arguments will be stringified, so anything that stringifies to a valid
// name is also valid. (E.g. null => "null")
null, undefined, 123
// name is also valid.
123
];
const elems_invalid = [
"", [], ["*"], ["p"]
"", {name: ""},
];
// Attribute names:
@ -32,17 +31,16 @@
const all_elems = elems_valid.concat(elems_invalid);
const all_attrs = attrs_valid.concat(attrs_invalid);
for (const item of ["allowElements", "dropElements", "blockElements"]) {
for (const item of ["elements", "removeElements", "replaceWithChildrenElements"]) {
test(t => {
const sanitizer = new Sanitizer({[item]: all_elems});
assert_array_same(sanitizer.getConfiguration()[item],
elems_valid.map(x => "" + x));
}, `Element names in config item: ${item}`);
}
for (const item of ["allowAttributes", "dropAttributes"]) {
for (const item of ["attributes", "removeAttributes"]) {
test(t => {
const sanitizer = new Sanitizer(
{[item]: Object.fromEntries(all_attrs.map(x => [x, ["*"]]))});
const sanitizer = new Sanitizer({[item]: all_attrs});
assert_array_same(Object.keys(sanitizer.getConfiguration()[item]),
attrs_valid.map(x => "" + x));
}, `Attribute names in config item: ${item}`);
@ -64,46 +62,50 @@
[ { name: "math", namespace: MATHML_NS }, "<math>Hello</math>" ],
].forEach(([elem, probe, expected], index) => {
test(t => {
const sanitizer = new Sanitizer({allowElements: [elem],
const options = { elements: [elem],
// TODO(https://github.com/WICG/sanitizer-api/issues/167)
allowUnknownMarkup: true});
unknownMarkup: true};
const template = document.createElement("template");
template.setHTML(probe, {sanitizer});
template.setHTML(probe, {sanitizer: options});
assert_equals(template.innerHTML, expected ?? probe);
}, `Namespaced elements #${index}: allowElements: [${JSON.stringify(elem)}]`);
}, `Namespaced elements #${index}: elements: [${JSON.stringify(elem)}]`);
});
// Same for attributes:
const XLINK_NS = "http://www.w3.org/1999/xlink";
[
[ { name: "style", elements: "*" }, "<p style=\"bla\"></p>" ],
[ { name: "href", elements: "*" }, "<p href=\"bla\"></p>" ],
[ { name: "xlink:href", elements: "*" }, "<p xlink:href=\"bla\"></p>" ],
[ { name: "href", namespace: XLINK_NS, elements: "*" }, "<p xlink:href=\"bla\"></p>", "<p></p>" ],
[ { name: "href", namespace: XLINK_NS, elements: "*" }, "<p href='bla'></p>", "<p></p>" ],
[ { name: "href", elements: "*" }, "<p xlink:href='bla'></p>", "<p></p>" ],
[ { name: "style"}, "<p style=\"bla\"></p>" ],
[ { name: "href"}, "<p href=\"bla\"></p>" ],
[ { name: "xlink:href"}, "<p xlink:href=\"bla\"></p>" ],
[ { name: "href", namespace: XLINK_NS}, "<p xlink:href=\"bla\"></p>", "<p></p>" ],
[ { name: "href", namespace: XLINK_NS}, "<p href='bla'></p>", "<p></p>" ],
[ { name: "href"}, "<p xlink:href='bla'></p>", "<p></p>" ],
].forEach(([attr, probe, expected], index) => {
test(t => {
const sanitizer = new Sanitizer({allowAttributes: [attr],
const options = {attributes: [attr],
// TODO(https://github.com/WICG/sanitizer-api/issues/167)
allowUnknownMarkup: true});
unknownMarkup: true};
const template = document.createElement("template");
template.setHTML(probe, {sanitizer});
template.setHTML(probe, {sanitizer: options});
assert_equals(template.innerHTML, expected ?? probe);
}, `Namespaced attributes #${index}: allowAttributes: [${JSON.stringify(attr)}]`);
}, `Namespaced attributes #${index}: attributes: [${JSON.stringify(attr)}]`);
});
// Test for namespaced attribute inside namespace element
test(t => {
const probe = `<svg><a xlink:href="bla"></a></svg>`;
const sanitizer = new Sanitizer({
allowAttributes: [{ name: "href", namespace: XLINK_NS, elements: "*" }],
allowElements: [{ name: "svg", namespace: SVG_NS }, { name: "a", namespace: SVG_NS }],
const options = {
elements: [
{name: "svg", namespace: SVG_NS},
{name: "a", namespace: SVG_NS, attributes: [
{ name: "href", namespace: XLINK_NS }
]}
],
// TODO(https://github.com/WICG/sanitizer-api/issues/167)
allowUnknownMarkup: true});
unknownMarkup: true};
const template = document.createElement("template");
template.setHTML(probe, {sanitizer});
template.setHTML(probe, {sanitizer: options});
assert_equals(template.innerHTML, probe);
}, "Namespaced attribute xlink:href inside SVG tree");
@ -115,14 +117,14 @@
[ "textPath", "<textPath></textPath>" ],
].forEach(([elem, probe], index) => {
const sanitize = (elem, probe) => {
const sanitizer = new Sanitizer({allowElements: [
const options = {elements: [
{ name: "svg", namespace: SVG_NS },
{ name: elem, namespace: SVG_NS }
],
// TODO(https://github.com/WICG/sanitizer-api/issues/167)
allowUnknownMarkup: true});
unknownMarkup: true};
const template = document.createElement("template");
template.setHTML(`<svg>${probe}</svg>`, {sanitizer});
template.setHTML(`<svg>${probe}</svg>`, {sanitizer: options});
return template.content.firstElementChild.innerHTML;
};
test(t => {
@ -138,7 +140,7 @@
test(t => {
const elems = ["svg:" + elem];
assert_array_equals(
new Sanitizer({allowElements: elems}).getConfiguration().allowElements,
new Sanitizer({elements: elems}).getConfiguration().allowElements,
elems);
}, `Mixed case element names #${index}: "${elem}" is preserved in config.`);
});

Просмотреть файл

@ -9,37 +9,30 @@
test(t => {
d = document.createElement("div")
d.setHTML("<hello><world>",
{ sanitizer: new Sanitizer({allowElements: ["hello", "world"]}) });
{ sanitizer: { elements: ["hello", "world"] } });
assert_equals(d.innerHTML, "");
}, "Unknown element names get blocked without allowUnknownMarkup.");
}, "Unknown element names get blocked without unknownMarkup.");
test(t => {
d = document.createElement("div")
d.setHTML("<hello><world>",
{ sanitizer: new Sanitizer({allowUnknownMarkup: true,
allowElements: ["hello", "world"]}) });
{ sanitizer: { unknownMarkup: true, elements: ["hello", "world"] } });
assert_equals(d.innerHTML, "<hello><world></world></hello>");
}, "Unknown element names pass with allowUnknownMarkup.");
}, "Unknown element names pass with unknownMarkup.");
test(t => {
d = document.createElement("div")
d.setHTML("<b hello='1' world>", { sanitizer:
new Sanitizer({allowAttributes: [{name: "hello", elements: "*"},
{name: "world", elements: "*"}]}) });
d.setHTML("<b hello='1' world>",
{ sanitizer: { attributes: ["name", "world"] } });
assert_equals(d.innerHTML, "<b></b>");
}, "Unknown attributes names get blocked without allowUnknownMarkup.");
}, "Unknown attributes names get blocked without unknownMarkup.");
test(t => {
d = document.createElement("div")
d.setHTML("<b hello='1' world>", { sanitizer:
new Sanitizer({allowUnknownMarkup: true,
allowAttributes: [
{name: "hello", elements: "*"},
{name: "world", elements: "*"}
]})
});
d.setHTML("<b hello='1' world>",
{ sanitizer: { unknownMarkup: true, attributes: ["name", "world"] } });
assert_equals(d.innerHTML, `<b hello="1" world=""></b>`);
}, "Unknown attribute names pass with allowUnknownMarkup.");
}, "Unknown attribute names pass with unknownMarkup.");
</script>
</body>
</html>

Просмотреть файл

@ -78,16 +78,16 @@ const testcases = [
message: "invalid config_input",
},
{
config_input: { dropElements: [] },
config_input: { removeElements: [] },
value: "test",
result: "test",
message: "empty dropElements list",
message: "empty removeElements list",
},
{
config_input: { dropElements: ["div"] },
config_input: { removeElements: ["div"] },
value: "<div>test</div><p>bla",
result: "<p>bla</p>",
message: "test html without close tag with dropElements list ['div']",
message: "test html without close tag with removeElements list ['div']",
},
{
config_input: {},
@ -96,120 +96,168 @@ const testcases = [
message: "default behavior for custom elements",
},
{
config_input: { allowCustomElements: true },
config_input: { customElements: true },
value: "<custom-element>test</custom-element>bla",
result: "testbla",
message: "allow custom elements",
},
{
config_input: {
allowCustomElements: true,
allowElements: ["custom-element"],
customElements: true,
elements: ["custom-element"],
},
value: "<custom-element>test</custom-element>bla",
result: "<custom-element>test</custom-element>bla",
message: "allow custom elements with allow elements",
},
{
config_input: { allowCustomElements: false },
config_input: { customElements: false },
value: "<custom-element>test</custom-element>bla",
result: "bla",
message: "disallow custom elements",
},
{
config_input: {
dropElements: ["custom-element"],
allowCustomElements: true,
removeElements: ["custom-element"],
customElements: true,
},
value: "<custom-element>test</custom-element>bla",
result: "bla",
message: 'allow custom elements with drop list contains ["custom-element"]',
},
{
config_input: { dropElements: ["script"] },
config_input: { removeElements: ["script"] },
value: "<script>alert('i am a test')</script>",
result: "",
message: 'test script with ["script"] as dropElements list',
message: 'test script with ["script"] as removeElements list',
},
{
config_input: { dropElements: ["test-element", "i"] },
config_input: { removeElements: ["test-element", "i"] },
value: "<div>balabala<i>test</i></div><test-element>t</test-element>",
result: "<div>balabala</div>",
message: 'dropElements list ["test-element", "i"]}',
message: 'removeElements list ["test-element", "i"]}',
},
{
config_input: { dropElements: ["dl", "p"] },
config_input: { removeElements: ["dl", "p"] },
value: "<div>balabala<i>i</i><p>t</p></div>",
result: "<div>balabala<i>i</i></div>",
message: 'dropElements list ["dl", "p"]}',
message: 'removeElements list ["dl", "p"]}',
},
{
config_input: { allowElements: ["p"] },
config_input: { elements: ["p"] },
value: "<div>test<div>p</div>tt<p>div</p></div>",
result: "testptt<p>div</p>",
message: 'allowElements list ["p"]',
message: 'elements list ["p"]',
},
{
config_input: { dropElements: ["div"], allowElements: ["div"] },
config_input: { removeElements: ["div"], elements: ["div"] },
value: "<div>test</div><p>bla",
result: "bla",
message: "allowElements list has no influence to dropElements",
message: "elements list has no influence to removeElements",
},
{
config_input: { dropAttributes: [{ name: "style", elements: ["p"] }] },
value:
"<p style='color: black'>Click.</p><div style='color: white'>div</div>",
result: '<p>Click.</p><div style="color: white">div</div>',
message: 'dropAttributes list {"style": ["p"]} with style attribute',
},
// {config_input: {dropAttributes: [{name: "*": ["a"]}}, value: "<a id='a' style='color: black'>Click.</a><div style='color: white'>div</div>", result: "<a>Click.</a><div style=\"color: white\">div</div>", message: "dropAttributes list {\"*\": [\"a\"]} with style attribute"},
{
config_input: { dropAttributes: [] },
config_input: { removeAttributes: [] },
value: "<p id='test'>Click.</p>",
result: '<p id="test">Click.</p>',
message: "empty dropAttributes list with id attribute",
message: "empty removeAttributes list with id attribute",
},
{
config_input: { dropAttributes: [{ name: "id", elements: "*" }] },
config_input: { removeAttributes: ["id"] },
value: "<p id='test'>Click.</p>",
result: "<p>Click.</p>",
message: 'dropAttributes list {"id": ["*"]} with id attribute',
message: 'removeAttributes list ["id"] with id attribute',
},
{
config_input: {
dropAttributes: [{ name: "data-attribute-with-dashes", elements: "*" }],
removeAttributes: ["data-attribute-with-dashes"],
},
value:
"<p id='p' data-attribute-with-dashes='123'>Click.</p><script>document.getElementById('p').dataset.attributeWithDashes=123;</script>",
result: '<p id="p">Click.</p>',
message:
'dropAttributes list {"data-attribute-with-dashes": ["*"]} with dom dataset js access',
'removeAttributes list ["data-attribute-with-dashes"] with dom dataset js access',
},
{
config_input: { allowAttributes: [{ name: "id", elements: ["div"] }] },
value: "<p id='p'>P</p><div id='div'>DIV</div>",
result: '<p>P</p><div id="div">DIV</div>',
message: 'allowAttributes list {"id": ["div"]} with id attribute',
config_input: {
elements: [
{ name: "p", attributes: ["title"] },
{ name: "div", attributes: ["id"] },
],
},
value: "<p id='p' title='p'>P</p><div id='div' title='div'>DIV</div>",
result: '<p title="p">P</p><div id="div">DIV</div>',
message:
'elements list with <p> attributes: ["title"] and div attributes: ["id"] lists',
},
{
config_input: { allowAttributes: [{ name: "id", elements: "*" }] },
config_input: {
elements: [
{ name: "p", removeAttributes: ["title"] },
{ name: "div", removeAttributes: ["id"] },
],
},
value: "<p id='p' title='p'>P</p><div id='div' title='div'>DIV</div>",
result: '<p id="p">P</p><div title="div">DIV</div>',
message:
'elements list with <p> removeAttributes: ["title"] and div removeAttributes: ["id"] lists',
},
{
config_input: {
elements: [{ name: "div", attributes: ["id"], removeAttributes: ["id"] }],
},
value: "<div id='div' title='div'>DIV</div>",
result: "<div>DIV</div>",
message:
'elements list with <div> attributes: ["id"] and removeAttributes: ["id"] lists',
},
{
config_input: {
elements: [{ name: "div", attributes: ["id", "title"] }],
attributes: []
},
value: "<div id='div' title='div'>DIV</div>",
result: "<div>DIV</div>",
message:
'elements list with <div> attributes: ["id", "title"] does not override empty attributes: [] list',
},
{
config_input: {
elements: [{ name: "div", attributes: ["id", "title"] }],
removeAttributes: ["id", "title"]
},
value: "<div id='div' title='div'>DIV</div>",
result: "<div>DIV</div>",
message:
'elements list with <div> attributes: ["id", "title"] does not override removeAttributes: ["id", "title"] list',
},
{
config_input: {
elements: [{ name: "div", removeAttributes: ["id", "title"] }],
attributes: ["id", "title"]
},
value: "<div id='div' title='div'>DIV</div>",
result: "<div>DIV</div>",
message:
'elements list with <div> removeAttributes: ["id", "title"] is effective even with attributes: ["id", "title"] list',
},
{
config_input: { attributes: ["id"] },
value: "<p id='test' onclick='a= 123'>Click.</p>",
result: '<p id="test">Click.</p>',
message:
'allowAttributes list {"id": ["*"]} with id attribute and onclick scripts',
message: 'attributes list ["id"] with id attribute and onclick scripts',
},
// {config_input: {allowAttributes: {"*": ["a"]}}, value: "<a id='a' style='color: black'>Click.</a><div style='color: white'>div</div>", result: "<a id=\"a\" style=\"color: black\">Click.</a><div>div</div>", message: "allowAttributes list {\"*\": [\"a\"]} with style attribute"},
{
config_input: {
dropAttributes: [{ name: "style", elements: "*" }],
allowAttributes: [{ name: "style", elements: "*" }],
removeAttributes: ["style"],
attributes: ["style"],
},
value: "<p style='color: black'>Click.</p>",
result: "<p>Click.</p>",
message: "allowAttributes list has no influence to dropAttributes",
message: "attributes list has no influence to removeAttributes list",
},
{
config_input: { allowElements: ["template", "div"] },
config_input: { elements: ["template", "div"] },
value: "<template><script>test</script><div>hello</div></template>",
result: "<template><div>hello</div></template>",
message: "Template element",
@ -318,16 +366,16 @@ const testcases = [
message: "HTML with comments; comments not allowed",
},
{
config_input: { allowComments: true },
config_input: { comments: true },
value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>",
result: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>",
message: "HTML with comments; allowComments",
message: "HTML with comments; comments",
},
{
config_input: { allowComments: false },
config_input: { comments: false },
value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>",
result: "<p>Some text</p><p>Some more text</p>",
message: "HTML with comments; !allowComments",
message: "HTML with comments; !comments",
},
{
config_input: {},
@ -336,26 +384,26 @@ const testcases = [
message: "HTML with comments deeper in the tree",
},
{
config_input: { allowComments: true },
config_input: { comments: true },
value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>",
result: "<p>comment<!-- hello -->in<!-- </p> -->text</p>",
message: "HTML with comments deeper in the tree, allowComments",
message: "HTML with comments deeper in the tree, comments",
},
{
config_input: { allowComments: false },
config_input: { comments: false },
value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>",
result: "<p>commentintext</p>",
message: "HTML with comments deeper in the tree, !allowComments",
message: "HTML with comments deeper in the tree, !comments",
},
{
config_input: { allowElements: ["svg"] },
config_input: { elements: ["svg"] },
value: "<svg></svg>",
result: "",
message:
"Unknown HTML names (HTMLUnknownElement instances) should not match elements parsed as non-HTML namespaces.",
},
{
config_input: { allowElements: ["div", "svg"] },
config_input: { elements: ["div", "svg"] },
value: "<div><svg></svg></div>",
result: "<div></div>",
message:
@ -364,139 +412,127 @@ const testcases = [
// Case normalization (actually: lack of)
{
config_input: { dropElements: ["I", "DL"] },
config_input: { removeElements: ["I", "DL"] },
value: "<div>balabala<dl>test</dl></div>",
result: "<div>balabala<dl>test</dl></div>",
message: 'dropElements list ["I", "DL"]}',
message: 'removeElements list ["I", "DL"]}',
},
{
config_input: { dropElements: ["i", "dl"] },
config_input: { removeElements: ["i", "dl"] },
value: "<div>balabala<dl>test</dl></div>",
result: "<div>balabala</div>",
message: 'dropElements list ["i", "dl"]}',
message: 'removeElements list ["i", "dl"]}',
},
{
config_input: { dropElements: ["i", "dl"] },
config_input: { removeElements: ["i", "dl"] },
value: "<DIV>balabala<DL>test</DL></DIV>",
result: "<div>balabala</div>",
message: 'dropElements list ["i", "dl"]} with uppercase HTML',
message: 'removeElements list ["i", "dl"]} with uppercase HTML',
},
{
config_input: { dropAttributes: [{ name: "ID", elements: "*" }] },
config_input: { removeAttributes: ["ID"] },
value: '<p id="test">Click.</p>',
result: '<p id="test">Click.</p>',
message: 'dropAttributes list {"ID": ["*"]} with id attribute',
message: 'removeAttributes list ["ID"] with id attribute',
},
{
config_input: { dropAttributes: [{ name: "ID", elements: "*" }] },
config_input: { removeAttributes: ["ID"] },
value: '<p ID="test">Click.</p>',
result: '<p id="test">Click.</p>',
message: 'dropAttributes list {"ID": ["*"]} with ID attribute',
message: 'removeAttributes list ["ID"] with ID attribute',
},
{
config_input: { dropAttributes: [{ name: "id", elements: "*" }] },
config_input: { removeAttributes: ["id"] },
value: '<p ID="test">Click.</p>',
result: "<p>Click.</p>",
message: 'dropAttributes list {"id": ["*"]} with ID attribute',
message: 'removeAttributes list ["id"] with ID attribute',
},
// allowUnknownMarkup for elements (with and without)
// unknownMarkup for elements (with and without)
{
config_input: { dropElements: [123, "test", "i", "custom-element"] },
config_input: { removeElements: [123, "test", "i", "custom-element"] },
value:
"<div>balabala<i>test</i></div><test>t</test><custom-element>custom-element</custom-element>",
result: "<div>balabala</div>",
message:
"dropElements with unknown elements and without allowUnknownMarkup",
message: "removeElements with unknown elements and without unknownMarkup",
},
{
config_input: { blockElements: [123, "test", "i", "custom-element"] },
config_input: {
replaceWithChildrenElements: [123, "test", "i", "custom-element"],
},
value:
"<div>balabala<i>test</i></div><test>t</test><custom-element>custom-element</custom-element>",
result: "<div>balabalatest</div>",
message:
"blockElements with unknown elements and without allowUnknownMarkup",
"replaceWithChildrenElements with unknown elements and without unknownMarkup",
},
{
config_input: { allowElements: ["p", "test"] },
config_input: { elements: ["p", "test"] },
value: "<div>test<div>p</div>tt<p>div</p></div><test>test</test>",
result: "testptt<p>div</p>",
message:
"allowElements with unknown elements and without allowUnknownMarkup",
message: "elements with unknown elements and without unknownMarkup",
},
{
config_input: {
dropElements: [123, "test", "i", "custom-element"],
allowUnknownMarkup: true,
removeElements: [123, "test", "i", "custom-element"],
unknownMarkup: true,
},
value:
"<div>balabala<i>test</i></div><test>t</test><custom-element>custom-element</custom-element>",
result: "<div>balabala</div>",
message: "dropElements with unknown elements and with allowUnknownMarkup",
message: "removeElements with unknown elements and with unknownMarkup",
},
{
config_input: {
blockElements: [123, "test", "i", "custom-element"],
allowUnknownMarkup: true,
replaceWithChildrenElements: [123, "test", "i", "custom-element"],
unknownMarkup: true,
},
value:
"<div>balabala<i>test</i></div><test>t</test><custom-element>custom-element</custom-element>",
result: "<div>balabalatest</div>t",
message: "blockElements with unknown elements and with allowUnknownMarkup",
message:
"replaceWithChildrenElements with unknown elements and with unknownMarkup",
},
{
config_input: { allowElements: ["p", "test"], allowUnknownMarkup: true },
config_input: { elements: ["p", "test"], unknownMarkup: true },
value: "<div>test<div>p</div>tt<p>div</p><test>test</test></div>",
result: "testptt<p>div</p><test>test</test>",
message: "allowElements with unknown elements and with allowUnknownMarkup",
message: "elements with unknown elements and with unknownMarkup",
},
// allowUnknownMarkup for attributes (with and without)
// unknownMarkup for attributes (with and without)
{
config_input: {
allowAttributes: [
{ name: "hello", elements: "*" },
{ name: "world", elements: ["b"] },
],
attributes: ["hello", "world"],
},
value: "<div hello='1' world='2'><b hello='3' world='4'>",
result: "<div><b></b></div>",
message:
"allowAttributes unknown attributes and without allowUnknownMarkup",
message: "attributes: unknown attributes and without unknownMarkup",
},
{
config_input: {
allowAttributes: [
{ name: "hello", elements: "*" },
{ name: "world", elements: ["b"] },
],
allowUnknownMarkup: true,
attributes: ["hello", "world"],
unknownMarkup: true,
},
value: "<div hello='1' world='2'><b hello='3' world='4'>",
result: '<div hello="1"><b hello="3" world="4"></b></div>',
message: "allowAttributes unknown attributes and with allowUnknownMarkup",
result: '<div hello="1" world="2"><b hello="3" world="4"></b></div>',
message: "attributes: unknown attributes and with unknownMarkup",
},
{
config_input: {
dropAttributes: [
{ name: "hello", elements: "*" },
{ name: "world", elements: ["b"] },
],
removeAttributes: ["hello", "world"],
},
value: "<div hello='1' world='2'><b hello='3' world='4'>",
result: "<div><b></b></div>",
message: "dropAttributes unknown attributes and without allowUnknownMarkup",
message: "removeAttributes: unknown attributes and without unknownMarkup",
},
{
config_input: {
dropAttributes: [
{ name: "hello", elements: "*" },
{ name: "world", elements: ["b"] },
],
allowUnknownMarkup: true,
removeAttributes: ["hello", "world"],
unknownMarkup: true,
},
value: "<div hello='1' world='2'><b hello='3' world='4'>",
result: "<div><b></b></div>",
message: "dropAttributes unknown attributes and with allowUnknownMarkup",
message: "removeAttributes unknown attributes and with allowUnknownMarkup",
},
];