forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Sanitizer] Regression tests for "MVP" Sanitizer.
The Sanitizer API spec is presently being heavily modified, and the public WPT test suite is expected to follow. We make a copy of the WPT test suite for the "MVP" launch of the Sanitizer, to act as regression tests that ensure backwards compatibility. Change-Id: Ic495554e6ece3f568d449b62630b1ab8d8cc85d6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4239585 Reviewed-by: Yifan Luo <lyf@chromium.org> Commit-Queue: Daniel Vogelheim <vogelheim@chromium.org> Cr-Commit-Position: refs/heads/main@{#1106732}
- Loading branch information
1 parent
98ef049
commit 5c7389f
Showing
14 changed files
with
695 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 0 additions & 5 deletions
5
third_party/blink/web_tests/wpt_internal/sanitizer-api/META.yml
This file was deleted.
Oops, something went wrong.
9 changes: 9 additions & 0 deletions
9
third_party/blink/web_tests/wpt_internal/sanitizer-api/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Sanitizer API MVP tests | ||
|
||
This is a copy of external/wpt/sanitizer-api, in the last state that where | ||
it passed for the initial Sanitizer "MVP" implementation. We put this copy | ||
here in wpt_internal/sanitizer-api to ensure backward compatibility with | ||
the launched Sanitizer state. I.e., as regression tests. | ||
|
||
The tests in external/wpt/sanitizer-api will be modified as the external | ||
Sanitizer spec evolves. |
111 changes: 111 additions & 0 deletions
111
third_party/blink/web_tests/wpt_internal/sanitizer-api/element-set-sanitized-html.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="support/testcases.sub.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
function buildNode(element_name, markup) { | ||
const e = document.createElement(element_name); | ||
e.innerHTML = markup; | ||
return e; | ||
} | ||
|
||
function assert_node_equals(node1, node2) { | ||
assert_true(node1 instanceof Node && node1.isEqualNode(node2), | ||
`Node[${node1.innerHTML}] == Node[${node2.innerHTML}]`); | ||
} | ||
|
||
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()); | ||
if (should_fail) { | ||
assert_throws_js(TypeError, probe_fn); | ||
} else { | ||
probe_fn(); | ||
} | ||
assert_equals(should_fail, !elem.firstChild); | ||
}, `${context}.setHTML should ${should_fail ? "fail" : "pass"}.`); | ||
} | ||
|
||
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()); | ||
elem2.innerHTML = probe; | ||
test(t => { | ||
assert_node_equals(elem2, elem1); | ||
}, `Sanitizer: <${context}>.setHTML("${probe}", ...) obeys parse context.`); | ||
} | ||
} | ||
|
||
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 }); | ||
assert_node_equals(buildNode(element.localName, testcase.result), element); | ||
}, "Sanitizer: Element.setHTML with config: " + testcase.message); | ||
} | ||
|
||
[ | ||
undefined, | ||
{}, | ||
{ sanitizer: new Sanitizer() }, | ||
{ sanitizer: undefined }, | ||
{ avocado: new Sanitizer() }, | ||
].forEach((options, index) => { | ||
test(t => { | ||
const e = document.createElement("div"); | ||
e.setHTML("<em>bla</em><script>bla<" + "/script>", options); | ||
assert_equals(e.innerHTML, "<em>bla</em>"); | ||
}, `Sanitizer: Element.setHTML options dictionary #${index} uses default.`); | ||
}); | ||
|
||
[ | ||
"tomato", | ||
{ sanitizer: null }, | ||
{ sanitizer: "avocado" }, | ||
{ sanitizer: { allowElements: [ "a", "b", "c" ] } }, | ||
].forEach((options, index) => { | ||
test(t => { | ||
assert_throws_js(TypeError, _ => { | ||
document.createElement("div").setHTML("bla", options); | ||
}); | ||
}, `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> |
12 changes: 12 additions & 0 deletions
12
third_party/blink/web_tests/wpt_internal/sanitizer-api/idlharness.https.window.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// META: script=/resources/WebIDLParser.js | ||
// META: script=/resources/idlharness.js | ||
|
||
idl_test( | ||
['sanitizer-api.tentative'], | ||
['html'], | ||
idl_array => { | ||
idl_array.add_objects({ | ||
Sanitizer: ['new Sanitizer({})'] | ||
}); | ||
} | ||
); |
90 changes: 90 additions & 0 deletions
90
third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-config.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
</head> | ||
|
||
<body> | ||
<script> | ||
test(t => { | ||
let s = new Sanitizer(); | ||
assert_true(s instanceof Sanitizer); | ||
}, "SanitizerAPI creator without config."); | ||
|
||
test(t => { | ||
let s = new Sanitizer({}); | ||
assert_true(s instanceof Sanitizer); | ||
}, "SanitizerAPI creator with empty config."); | ||
|
||
test(t => { | ||
let s = new Sanitizer(null); | ||
assert_true(s instanceof Sanitizer); | ||
}, "SanitizerAPI creator with null as config."); | ||
|
||
test(t => { | ||
let s = new Sanitizer(undefined); | ||
assert_true(s instanceof Sanitizer); | ||
}, "SanitizerAPI creator with undefined as config."); | ||
|
||
test(t => { | ||
let s = new Sanitizer({testConfig: [1,2,3], attr: ["test", "i", "am"]}); | ||
assert_true(s instanceof Sanitizer); | ||
}, "SanitizerAPI creator with config ignore unknown values."); | ||
|
||
// In-depth testing of sanitization is handled in other tests. Here we | ||
// do presence testing for each of the config options and test 3 things: | ||
// - One case where our test string is modified, | ||
// - one where it's unaffected, | ||
// - that a config can't be changed afterwards. | ||
// (I.e., that the Sanitizer won't hold on to a reference of the options.) | ||
|
||
// 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}); | ||
return probe_string == div.innerHTML; | ||
}; | ||
|
||
const should_stay_the_same = { | ||
allowElements: [ "div", "p" ], | ||
blockElements: [ "test" ], | ||
dropElements: [ "test" ], | ||
allowAttributes: { "id": ["*"]}, | ||
dropAttributes: { "bla": ["blubb"]}, | ||
}; | ||
const should_modify = { | ||
allowElements: [ "div", "span" ], | ||
blockElements: [ "div" ], | ||
dropElements: [ "p" ], | ||
allowAttributes: { "id": ["p"]}, | ||
dropAttributes: { "id": ["div"]}, | ||
}; | ||
|
||
assert_array_equals(Object.keys(should_stay_the_same), Object.keys(should_modify)); | ||
Object.keys(should_stay_the_same).forEach(option_key => { | ||
test(t => { | ||
const options = {}; | ||
options[option_key] = should_stay_the_same[option_key]; | ||
const s = new Sanitizer(options); | ||
assert_true(s instanceof Sanitizer); | ||
assert_true(probe(s)); | ||
}, `SanitizerAPI: ${option_key} stays is okay.`); | ||
|
||
const options = {}; | ||
options[option_key] = should_modify[option_key]; | ||
const s = new Sanitizer(options); | ||
test(t => { | ||
assert_true(s instanceof Sanitizer); | ||
assert_false(probe(s)); | ||
}, `SanitizerAPI: ${option_key} modify is okay.`); | ||
|
||
options[option_key] = should_stay_the_same[option_key]; | ||
test(t => { | ||
assert_false(probe(s)); | ||
}, `SanitizerAPI: ${option_key} config is not kept as reference.`); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
17 changes: 17 additions & 0 deletions
17
third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-insecure-context.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
// Currently, the Sanitizer requires a secure context. | ||
test(t => { | ||
assert_false(globalThis.isSecureContext); | ||
assert_equals("Sanitizer" in globalThis, globalThis.isSecureContext); | ||
assert_equals("setHTML" in document.body, globalThis.isSecureContext); | ||
}, "Sanitizer API in an insecure context."); | ||
</script> | ||
</body> | ||
</html> |
91 changes: 91 additions & 0 deletions
91
third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-names.https.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
</head> | ||
<body> | ||
<script> | ||
// Like assert_array_equals, but disregard element order. | ||
function assert_array_same(actual, expected) { | ||
assert_array_equals(actual.sort(), expected.sort()); | ||
} | ||
|
||
// Element names: | ||
const elems_valid = [ | ||
"p", "template", "span", "custom-elements", "svg", "potato", | ||
|
||
// Arguments will be stringified, so anything that stringifies to a valid | ||
// name is also valid. (E.g. null => "null") | ||
null, undefined, 123 | ||
]; | ||
const elems_invalid = [ | ||
"", "svg svg", "svg:svg", "potato:svg", [], ["*"], ["p"] | ||
]; | ||
|
||
// Attribute names: | ||
const attrs_valid = [ | ||
"href", "span" | ||
]; | ||
const attrs_invalid = [ | ||
"svg:href", "svg href", "xlink:span", "xlink:href" | ||
]; | ||
|
||
const all_elems = elems_valid.concat(elems_invalid); | ||
const all_attrs = attrs_valid.concat(attrs_invalid); | ||
for (const item of ["allowElements", "dropElements", "blockElements"]) { | ||
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"]) { | ||
test(t => { | ||
const sanitizer = new Sanitizer( | ||
{[item]: Object.fromEntries(all_attrs.map(x => [x, ["*"]]))}); | ||
assert_array_same(Object.keys(sanitizer.getConfiguration()[item]), | ||
attrs_valid.map(x => "" + x)); | ||
}, `Attribute names in config item: ${item}`); | ||
} | ||
|
||
// Quick sanity tests for namespaced elements. | ||
// Each test case is a duo or triplet: | ||
// - a Sanitizer config string for an element. | ||
// - an HTML probe string. | ||
// - the expected result. (If different from the probe.) | ||
[ | ||
[ "p", "<p>Hello</p>" ], | ||
[ "svg", "<svg>Hello</svg>", "" ], | ||
[ "svg:svg", "<svg>Hello</svg>", "" ], | ||
[ "math", "<math>Hello</math>", "" ], | ||
[ "svg:math", "<math>Hello</math>", "" ], | ||
[ "math:math", "<math>Hello</math>", "" ], | ||
[ "potato:math", "<math>Hello</math>", "" ], | ||
[ "potato:math", "<potato:math>Hello</potato:math>", "" ], | ||
].forEach(([elem, probe, expected], index) => { | ||
test(t => { | ||
const sanitizer = new Sanitizer({allowElements: [elem]}); | ||
assert_equals(sanitizer.sanitizeFor("template", probe).innerHTML, | ||
expected ?? probe); | ||
}, `Namespaced elements #${index}: allowElements: ["${elem}"]`); | ||
}); | ||
|
||
// Same for attributes: | ||
[ | ||
[ "style", "<p style=\"bla\"></p>" ], | ||
[ "href", "<p href=\"bla\"></p>" ], | ||
[ "xlink:href", "<p xlink:href=\"bla\"></p>", "<p></p>" ], | ||
[ "potato:href", "<p potato:href='bla'></p>", "<p></p>" ], | ||
[ "xlink:href", "<p href='bla'></p>", "<p></p>" ], | ||
[ "href", "<p xlink:href='bla'></p>", "<p></p>" ], | ||
].forEach(([attr, probe, expected], index) => { | ||
test(t => { | ||
const sanitizer = new Sanitizer({allowAttributes: {[attr]: ["*"]}}); | ||
assert_equals(sanitizer.sanitizeFor("template", probe).innerHTML, | ||
expected ?? probe); | ||
}, `Namespaced attributes #${index}: allowAttributes: {"${attr}": ["*"]}`); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.