summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/content-security-policy/support/testharness-helper.js
blob: 5c36e286da2b0ad68da22f7c0e9f68e29ea7857b (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
139
140
141
142
function assert_no_csp_event_for_url(test, url) {
  self.addEventListener("securitypolicyviolation", test.step_func(e => {
    if (e.blockedURI !== url)
      return;
    assert_unreached("SecurityPolicyViolation event fired for " + url);
  }));
}

function assert_no_event(test, obj, name) {
  obj.addEventListener(name, test.unreached_func("The '" + name + "' event should not have fired."));
}

function waitUntilCSPEventForURLOrLine(test, url, line) {
  return new Promise((resolve, reject) => {
    self.addEventListener("securitypolicyviolation", test.step_func(e => {
      if (e.blockedURI == url && (!line || line == e.lineNumber))
        resolve(e);
    }));
  });
}

function waitUntilCSPEventForURL(test, url) {
  return waitUntilCSPEventForURLOrLine(test, url);
}

function waitUntilCSPEventForEval(test, line) {
  return waitUntilCSPEventForURLOrLine(test, "eval", line);
}

function waitUntilCSPEventForTrustedTypes(test) {
  return waitUntilCSPEventForURLOrLine(test, "trusted-types-sink");
}

function waitUntilEvent(obj, name) {
  return new Promise((resolve, reject) => {
    obj.addEventListener(name, resolve);
  });
}

// Given the URL of a worker that pings its opener upon load, this
// function builds a test that asserts that the ping is received,
// and that no CSP event fires.
function assert_worker_is_loaded(url, description, expected_message = "ping") {
  async_test(t => {
    assert_no_csp_event_for_url(t, url);
    var w = new Worker(url);
    assert_no_event(t, w, "error");
    waitUntilEvent(w, "message")
      .then(t.step_func_done(e => {
        assert_equals(e.data, expected_message);
      }));
  }, description);
}

function assert_shared_worker_is_loaded(url, description, expected_message = "ping") {
  async_test(t => {
    assert_no_csp_event_for_url(t, url);
    var w = new SharedWorker(url);
    assert_no_event(t, w, "error");
    waitUntilEvent(w.port, "message")
      .then(t.step_func_done(e => {
        assert_equals(e.data, expected_message);
      }));
    w.port.start();
  }, description);
}

function assert_service_worker_is_loaded(url, description) {
  promise_test(t => {
    assert_no_csp_event_for_url(t, url);
    return Promise.all([
      waitUntilEvent(navigator.serviceWorker, "message")
        .then(e => {
          assert_equals(e.data, "ping");
        }),
      navigator.serviceWorker.register(url, { scope: url })
        .then(r => {
          var sw = r.active || r.installing || r.waiting;
          t.add_cleanup(_ => r.unregister());
          sw.postMessage("pong?");
        })
    ]);
  }, description);
}

// Given the URL of a worker that pings its opener upon load, this
// function builds a test that asserts that the constructor throws
// a SecurityError, and that a CSP event fires.
function assert_worker_is_blocked(url, description) {
  async_test(t => {
    // If |url| is a blob, it will be stripped down to "blob" for reporting.
    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
    waitUntilCSPEventForURL(t, reportedURL)
      .then(t.step_func_done(e => {
        assert_equals(e.blockedURI, reportedURL);
        assert_equals(e.violatedDirective, "worker-src");
        assert_equals(e.effectiveDirective, "worker-src");
      }));

    // TODO(mkwst): We shouldn't be throwing here. We should be firing an
    // `error` event on the Worker. https://crbug.com/663298
    assert_throws_dom("SecurityError", function () {
      var w = new Worker(url);
    });
  }, description);
}

function assert_shared_worker_is_blocked(url, description) {
  async_test(t => {
    // If |url| is a blob, it will be stripped down to "blob" for reporting.
    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
    waitUntilCSPEventForURL(t, reportedURL)
      .then(t.step_func_done(e => {
        assert_equals(e.blockedURI, reportedURL);
        assert_equals(e.violatedDirective, "worker-src");
        assert_equals(e.effectiveDirective, "worker-src");
      }));

    // TODO(mkwst): We shouldn't be throwing here. We should be firing an
    // `error` event on the SharedWorker. https://crbug.com/663298
    assert_throws_dom("SecurityError", function () {
      var w = new SharedWorker(url);
    });
  }, description);
}

function assert_service_worker_is_blocked(url, description) {
  promise_test(t => {
    assert_no_event(t, navigator.serviceWorker, "message");
    // If |url| is a blob, it will be stripped down to "blob" for reporting.
    var reportedURL = new URL(url).protocol == "blob:" ? "blob" : url;
    return Promise.all([
      waitUntilCSPEventForURL(t, reportedURL)
        .then(t.step_func_done(e => {
          assert_equals(e.blockedURI, reportedURL);
          assert_equals(e.violatedDirective, "worker-src");
          assert_equals(e.effectiveDirective, "worker-src");
        })),
      promise_rejects_dom(t, "SecurityError", navigator.serviceWorker.register(url, { scope: url }))
    ]);
  }, description);
}