summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/content-security-policy/support/checkReport.sub.js
blob: 9cc242662bc6ba227dd209d5b65843ae68236dc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(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();
  }

})();