Skip to content

Commit

Permalink
Bug 1943646 [wpt PR 50276] - Add more tests for trusted-types-sink vi…
Browse files Browse the repository at this point in the history
…olation reports., a=testonly

Automatic update from web-platform-tests
Add more tests for trusted-types-sink violation reports. (#50276)

This covers all Window-only sinks listed in
w3c/trusted-types#494 (comment)

This also relies on connect-src / EventSource / self.add/removeEventListner, so
that the file could be usable in Workers in the future.

--

wpt-commits: 2817c97998d0a383907a211967965a071d58b44a
wpt-pr: 50276
  • Loading branch information
fred-wang authored and moz-wptsync-bot committed Feb 1, 2025
1 parent 8354df3 commit 154d744
Show file tree
Hide file tree
Showing 31 changed files with 533 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<script src="support/helper.sub.js"></script>
<script src="./support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy" content="trusted-types 'none'">
<meta http-equiv="Content-Security-Policy" content="object-src 'none'">
<meta http-equiv="Content-Security-Policy" content="connect-src 'none'">
<body>
<script>
promise_test(async t => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<script src="./support/csp-violations.js"></script>

<meta http-equiv="Content-Security-Policy" content="trusted-types SomeName JustOneMoreName AnotherName">
<meta http-equiv="Content-Security-Policy" content="object-src 'none'">
<meta http-equiv="Content-Security-Policy" content="connect-src 'none'">
<body>
<script>
// Allowed name test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'
Content-Security-Policy: object-src 'none'
Content-Security-Policy: connect-src 'none'
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<script src="/resources/testharnessreport.js"></script>
<script src="./support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'">
<meta http-equiv="Content-Security-Policy" content="object-src 'none'">
<meta http-equiv="Content-Security-Policy" content="connect-src 'none'">
</head>
<body>
<script>
Expand Down
33 changes: 19 additions & 14 deletions testing/web-platform/tests/trusted-types/support/csp-violations.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,45 @@ const cspDirectives = [
"script-src",
];

// A generic helper that runs function fn and return a promise resolving with
// an array of reported violations for trusted type directives and a possible
// exception thrown.
// A generic helper that runs function fn and returns a promise resolving with
// an array of reported violations and a possible exception thrown. This forces
// a "connect-src" violation before and after calling fn, to make sure we are
// not gathering violations reported before fn, and that all the violations
// reported by fn have been delivered. This assumes that the test file contains
// the CSP directive connect-src 'none' and that fn is not itself triggering
// a "connect-src" violation report.
function trusted_type_violations_and_exception_for(fn) {
return new Promise((resolve, reject) => {
// Listen for security policy violations.
let result = { violations: [], exception: null };
let handler = e => {
if (cspDirectives.includes(e.effectiveDirective)) {
result.violations.push(e);
} else if (e.effectiveDirective === "object-src") {
document.removeEventListener("securitypolicyviolation", handler);
} else if (e.effectiveDirective === "connect-src") {
self.removeEventListener("securitypolicyviolation", handler);
e.stopPropagation();
resolve(result);
} else {
reject(`Unexpected violation for directive ${e.effectiveDirective}`);
}
}
document.addEventListener("securitypolicyviolation", handler);
self.addEventListener("securitypolicyviolation", handler);

// Run the specified function and record any exception.
try {
fn();
} catch(e) {
result.exception = e;
}

// Force an "object-src" violation, to make sure all the previous violations
// have been delivered. This assumes the test file's associated .headers
// file contains Content-Security-Policy: object-src 'none'.
var o = document.createElement('object');
o.type = "video/mp4";
o.data = "dummy.webm";
document.body.appendChild(o);
// Force a connect-src violation. WebKit additionally throws a SecurityError
// so ignore that. See https://bugs.webkit.org/show_bug.cgi?id=286744
try {
new EventSource("/common/blank.html");
} catch(e) {
if (!e instanceof DOMException || e.name !== "SecurityError") {
throw e;
}
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
// headers are set in the .headers file:
//
// Content-Security-Policy: script-src 'unsafe-inline'; report-uri ...
// Content-Security-Policy: object-src 'none'
// Content-Security-Policy: connect-src 'none'
// Content-Security-Policy: require-trusted-types-for 'script'
//
// The second rule is there so we can provoke a CSP violation report at will.
// The intent is that in order to test that a violation has *not* been thrown
// (and without resorting to abominations like timeouts), we force a *another*
// CSP violation (by violating the object-src rule) and when that event is
// CSP violation (by violating the connect-src rule) and when that event is
// processed we can we sure that an earlier event - if it indeed occurred -
// must have already been processed.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Content-Security-Policy: script-src http: https: 'nonce-123' 'report-sample'
Content-Security-Policy: object-src 'none'
Content-Security-Policy: connect-src 'none'
Content-Security-Policy: require-trusted-types-for 'script'
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// headers are set in the .headers file:
//
// Content-Security-Policy: script-src 'unsafe-inline' 'unsafe-eval'; report-uri ...
// Content-Security-Policy: object-src 'none'
// Content-Security-Policy: connect-src 'none'
// Content-Security-Policy-Report-Only: require-trusted-types-for 'script'
//
// The last rule is there so we can provoke a CSP violation report at will.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Content-Security-Policy: script-src http: https: 'nonce-123' 'unsafe-eval'
Content-Security-Policy: object-src 'none'
Content-Security-Policy: connect-src 'none'
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// headers are set in the .headers file:
//
// Content-Security-Policy: script-src 'unsafe-inline' 'unsafe-eval'; report-uri ...
// Content-Security-Policy: object-src 'none'
// Content-Security-Policy: connect-src 'none'
// Content-Security-Policy: require-trusted-types-for 'script'
//
// The last rule is there so we can provoke a CSP violation report at will.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Content-Security-Policy: script-src http: https: 'nonce-123' 'unsafe-eval'
Content-Security-Policy: object-src 'none'
Content-Security-Policy: connect-src 'none'
Content-Security-Policy: require-trusted-types-for 'script'

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Content-Security-Policy-Report-Only: trusted-types two; report-uri /content-security-policy/resources/dummy-report.php; require-trusted-types-for 'script';
Content-Security-Policy: object-src 'none'
Content-Security-Policy: connect-src 'none'
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
(new DOMParser()).parseFromString(policy.createHTML(input), "text/html")
);
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
(new DOMParser()).parseFromString(input, "text/html")
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `DOMParser parseFromString|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ => {
["insertHTML", "paste"].forEach(command => {
document.execCommand(command, false, policy.createHTML(input));
});
});
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
document.execCommand("paste", false, input)
);
}, "No violation reported (paste command).");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
document.execCommand("insertHTML", false, input)
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Document execCommand|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string (insertHTML command).");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
Document.parseHTMLUnsafe(policy.createHTML(input))
);
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
Document.parseHTMLUnsafe(input)
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Document parseHTMLUnsafe|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<div id="log"></div>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = [`<p>${'A'.repeat(50)}</p>`,
`<p>${'B'.repeat(30)}</p>`,
`<p>${'C'.repeat(20)}</p>`];
const joinedInput = input.join('');
const trustedInput = input.map(x => policy.createHTML(input));

// Create a separate document for testing, so write calls don't mess up with
// how testharness writes its output in the main document.
const doc = (new DOMParser()).
parseFromString(policy.createHTML("<body></body>"), "text/html");

["write", "writeln"].forEach(methodName => {
promise_test(async t => {
await no_trusted_type_violation_for(_ =>
doc[methodName](...trustedInput)
);
}, `No violation reported for ${methodName}() with TrustedHTML arguments.`);

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
doc[methodName](trustedInput[0], input[1], trustedInput[2])
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Document ${methodName}|${clipSampleIfNeeded(joinedInput)}`);
}, `Violation report for plain string for ${methodName}() with at least one plain string argument.`);
});
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
document.createElement("div").innerHTML = policy.createHTML(input)
);
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
document.createElement("div").innerHTML = input
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Element innerHTML|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
document.createElement("div").
insertAdjacentHTML("beforeend", policy.createHTML(input))
);
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
document.createElement("div").insertAdjacentHTML("beforeend", input)
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Element insertAdjacentHTML|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/csp-violations.js"></script>
<meta http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; connect-src 'none';">
<body>
<script>
const policy = trustedTypes.createPolicy("dummy", { createHTML: x => x });
const input = `<p>${'A'.repeat(100)}</p>`;

promise_test(async t => {
await no_trusted_type_violation_for(_ =>
document.createElement("div").outerHTML = policy.createHTML(input)
);
}, "No violation reported for TrustedHTML.");

promise_test(async t => {
let violation = await trusted_type_violation_for(TypeError, _ =>
document.createElement("div").outerHTML = input
);
assert_equals(violation.blockedURI, "trusted-types-sink");
assert_equals(violation.sample, `Element outerHTML|${clipSampleIfNeeded(input)}`);
}, "Violation report for plain string.");
</script>
</body>
Loading

0 comments on commit 154d744

Please sign in to comment.