(function () {
// Get values from the substitution engine.
// We can't just pull these from the document context
// because this script is intended to be transcluded into
// another document, and we want the GET values used to request it,
// not the values for the including document
// XXX these are unencoded, so there's an unavoidable
// injection vulnerability in constructing this file...
// need to upgrade the template engine.
var reportField = "{{GET[reportField]}}";
var reportValue = "{{GET[reportValue]}}";
var reportExists = "{{GET[reportExists]}}";
var noCookies = "{{GET[noCookies]}}";
var reportCookieName = "{{GET[reportCookieName]}}"
var testName = "{{GET[testName]}}"
var cookiePresent = "{{GET[cookiePresent]}}"
var reportCount = "{{GET[reportCount]}}"
var location = window.location;
if (reportCookieName == "") {
// fallback on test file name if cookie name not specified
reportCookieName = location.pathname.split('/')[location.pathname.split('/').length - 1].split('.')[0];
}
var reportID = "{{GET[reportID]}}";
if (reportID == "") {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookieName = cookies[i].split('=')[0].trim();
var cookieValue = cookies[i].split('=')[1].trim();
if (cookieName == reportCookieName) {
reportID = cookieValue;
var cookieToDelete = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" + document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/') + 1);
document.cookie = cookieToDelete;
break;
}
}
}
// There is no real way to test (in this particular layer) that a CSP report
// has *not* been sent, at least not without some major reworks and
// involvement from all the platform participants. So the current "solution"
// is to wait for some reasonable amount of time and if no report has been
// received to conclude that no report has been generated. These timeouts must
// not exceed the test timeouts set by vendors otherwise the test would fail.
var timeout = document.querySelector("meta[name=timeout][content=long]") ? 20 : 3;
var reportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_report&timeout=" + timeout + "&reportID=" + reportID;
if (testName == "") testName = "Violation report status OK.";
var reportTest = async_test(testName);
function assert_field_value(field, value, field_name) {
assert_true(field.indexOf(value.split(" ")[0]) != -1,
field_name + " value of \"" + field + "\" did not match " +
value.split(" ")[0] + ".");
}
reportTest.step(function () {
var report = new XMLHttpRequest();
report.onload = reportTest.step_func(function () {
var data = JSON.parse(report.responseText);
if (data.error) {
assert_equals("false", reportExists, data.error);
} else {
if (reportExists === "false") {
assert_equals(data.length, 0,
"CSP report sent, but not expecting one.");
} else {
// With the 'report-uri' directive, the report is contained in
// `data[0]["csp-report"]`. With the 'report-to' directive, the report
// is contained in `data[0]["body"]`.
const reportBody = data[0]["body"]
? data[0]["body"]
: data[0]["csp-report"];
assert_true(reportBody !== undefined,
"No CSP report sent, but expecting one.");
// Firefox expands 'self' or origins in a policy to the actual origin value
// so "www.example.com" becomes "http://www.example.com:80".
// Accomodate this by just testing that the correct directive name
// is reported, not the details...
if (reportBody[reportField] !== undefined) {
assert_field_value(reportBody[reportField], reportValue, reportField);
} else {
assert_equals(reportField, "", "Expected report field could not be found in report.");
}
}
}
reportTest.done();
});
report.open("GET", reportLocation, true);
report.send();
});
if (noCookies || cookiePresent) {
var cookieTest = async_test("Test report cookies.");
var cookieReport = new XMLHttpRequest();
cookieReport.onload = cookieTest.step_func(function () {
var data = JSON.parse(cookieReport.responseText);
if (noCookies) {
assert_equals(data.reportCookies, "None", "Report should not contain any cookies");
}
if (cookiePresent) {
assert_true(data.reportCookies.hasOwnProperty(cookiePresent), "Report should contain cookie: " + cookiePresent);
}
cookieTest.done();
});
var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_cookies&timeout=" + timeout + "&reportID=" + reportID;
cookieReport.open("GET", cReportLocation, true);
cookieReport.send();
}
if (reportCount != "") {
var reportCountTest = async_test("Test number of sent reports.");
var reportCountReport = new XMLHttpRequest();
reportCountReport.onload = reportCountTest.step_func(function () {
var data = JSON.parse(reportCountReport.responseText);
assert_equals(data.report_count, +reportCount, "Report count was not what was expected.");
reportCountTest.done();
});
var cReportLocation = location.protocol + "//" + location.host + "/reporting/resources/report.py?op=retrieve_count&timeout=" + timeout + "&reportID=" + reportID;
reportCountReport.open("GET", cReportLocation, true);
reportCountReport.send();
}
})();