Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!doctype html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/trusted-types/support/helper.sub.js"></script>
<meta
http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script';"
/>
</head>
<body>
<div id="container"></div>
<script>
const container = document.querySelector("#container");
// We have to replace this global because we are overriding the default policy from within the test.
trustedTypes.createPolicy("default", {
createHTML: (html) => html,
createParserOptions: (options) => {
options.modified = true;
if (options.sanitizer instanceof Sanitizer) {
options.sanitizer.removeElement("span");
options.sanitizer.allowAttribute("id");
} else if (
options.sanitizer &&
typeof options.sanitizer === "object"
) {
options.sanitizer.removeElements = ["span"];
}
return options;
},
});
test((t) => {
let d = document.createElement("div");
document.querySelector("#container").appendChild(d);
t.add_cleanup(() => d.remove());
const options = { sanitizer: {}, modified: false };
d.setHTMLUnsafe(
"<div id='allowed'><span id=forbidden></span></div>",
options,
);
assert_false(
options.modified,
"trusted types policy should not modify given options",
);
assert_false(
"removeElements" in options.sanitizer,
"trusted types policy should not modify sanitizer",
);
assert_equals(d.querySelector("#forbidden"), null);
assert_not_equals(d.querySelector("#allowed"), null);
}, `createParserOptions doesn't mutate original object`);
test((t) => {
let d = document.createElement("div");
document.querySelector("#container").appendChild(d);
t.add_cleanup(() => d.remove());
const options = { sanitizer: new Sanitizer() };
d.setHTMLUnsafe(
"<div id=allowed><span id=forbidden></span></div>",
options,
);
const elements = options.sanitizer.get().elements;
const hasSpan = elements.some(el => el.name === "span");
assert_true(
hasSpan,
"trusted types policy should not modify original sanitizer elements list",
);
assert_false(
"removeElements" in options.sanitizer.get(),
"trusted types policy should not modify sanitizer structure",
);
assert_equals(d.querySelector("#forbidden"), null);
assert_not_equals(d.querySelector("#allowed"), null);
}, `createParserOptions doesn't mutate sanitizer object`);
test((t) => {
let callback_sanitizer = null;
const policy = trustedTypes.createPolicy("p1", {
createHTML: (html) => html,
createParserOptions: (options) => {
callback_sanitizer = options.sanitizer;
return options;
}
});
// 1. Passing a config, check that the callback receives a Sanitizer object.
const options = policy.createParserOptions({ sanitizer: { removeElements: ["span"] } });
assert_true(callback_sanitizer instanceof Sanitizer, "callback should receive a Sanitizer object");
// 2. Check that the returned TrustedParserOptions contains a Sanitizer object.
assert_true(options.sanitizer() instanceof Sanitizer, "TrustedParserOptions.sanitizer() should return a Sanitizer");
assert_not_equals(options.sanitizer(), options.sanitizer(), "calling sanitizer() twice should return different objects");
// 3. Mutating the Sanitizer returned by the method does not affect sanitizing.
// The config had removeElements: ["span"]. Let's try to mutate the returned sanitizer to also remove "div".
options.sanitizer().removeElement("div");
const d = document.createElement("div");
document.querySelector("#container").appendChild(d);
t.add_cleanup(() => d.remove());
d.setHTMLUnsafe("<div>Allowed<span>Forbidden</span></div>", options);
// "div" should NOT be removed (because mutation on options.sanitizer() has no effect on the clone used for parsing).
assert_not_equals(d.querySelector("div"), null, "div should not be removed by mutated sanitizer");
// "span" should still be removed (because the original config specified removeElements: ["span"]).
assert_equals(d.querySelector("span"), null, "span should be removed by original sanitizer configuration");
}, "TrustedParserOptions sanitizer clone testing with config input");
test((t) => {
let callback_sanitizer = null;
const policy = trustedTypes.createPolicy("p2", {
createHTML: (html) => html,
createParserOptions: (options) => {
callback_sanitizer = options.sanitizer;
return options;
}
});
const s = new Sanitizer();
const options = policy.createParserOptions({ sanitizer: s });
assert_true(callback_sanitizer instanceof Sanitizer, "callback should receive a Sanitizer object");
assert_not_equals(callback_sanitizer, s, "callback sanitizer should be a clone, not the original");
assert_true(options.sanitizer() instanceof Sanitizer, "TrustedParserOptions.sanitizer() should return a Sanitizer");
assert_not_equals(options.sanitizer(), s, "method sanitizer() should return a clone, not the original");
assert_not_equals(options.sanitizer(), options.sanitizer(), "method sanitizer() should return different object references in every call");
}, "TrustedParserOptions sanitizer clone testing with Sanitizer object input");
test((t) => {
let callback_sanitizer = null;
const policy = trustedTypes.createPolicy("p3", {
createHTML: (html) => html,
createParserOptions: (options) => {
callback_sanitizer = options.sanitizer;
return options;
}
});
const options = policy.createParserOptions({ sanitizer: "default" });
assert_true(callback_sanitizer instanceof Sanitizer, "callback should receive a Sanitizer object when preset is passed");
assert_true(options.sanitizer() instanceof Sanitizer, "TrustedParserOptions.sanitizer() should return a Sanitizer when preset is passed");
}, "TrustedParserOptions sanitizer clone testing with Preset string input");
</script>
</body>
</html>