Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Cc = Components.classes;
6 const Ci = Components.interfaces;
7 const Cu = Components.utils;
8 const Cr = Components.results;
10 //load('CSPUtils.jsm');
11 Cu.import('resource://gre/modules/CSPUtils.jsm');
12 Cu.import('resource://gre/modules/NetUtil.jsm');
14 var httpServer = new HttpServer();
15 httpServer.start(-1);
17 const POLICY_FROM_URI = "default-src 'self'; img-src *";
18 const POLICY_PORT = httpServer.identity.primaryPort;
19 const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
20 const POLICY_URI_RELATIVE = "/policy";
22 //converts string to nsIURI
23 function URI(uriString) {
24 var ioService = Cc["@mozilla.org/network/io-service;1"]
25 .getService(Ci.nsIIOService);
26 return ioService.newURI(uriString, null, null);
27 }
30 // helper to assert that an array has the given value somewhere.
31 function do_check_in_array(arr, val, stack) {
32 if (!stack)
33 stack = Components.stack.caller;
35 var text = val + " in [" + arr.join(",") + "]";
37 for(var i in arr) {
38 dump(".......... " + i + "> " + arr[i] + "\n");
39 if(arr[i] == val) {
40 //succeed
41 ++_passedChecks;
42 dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
43 stack.lineNumber + "] " + text + "\n");
44 return;
45 }
46 }
47 do_throw(text, stack);
48 }
50 // helper to assert that an object or array must have a given key
51 function do_check_has_key(foo, key, stack) {
52 if (!stack)
53 stack = Components.stack.caller;
55 var keys = [];
56 for (let k in foo) { keys.push(k); }
57 var text = key + " in [" + keys.join(",") + "]";
59 for (var x in foo) {
60 if (x == key) {
61 //succeed
62 ++_passedChecks;
63 dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
64 stack.lineNumber + "] " + text + "\n");
65 return;
66 }
67 }
68 do_throw(text, stack);
69 }
71 // helper to use .equals on stuff
72 function do_check_equivalent(foo, bar, stack) {
73 if (!stack)
74 stack = Components.stack.caller;
76 var text = foo + ".equals(" + bar + ")";
78 if(foo.equals && foo.equals(bar)) {
79 ++_passedChecks;
80 dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
81 stack.lineNumber + "] " + text + "\n");
82 return;
83 }
84 do_throw(text, stack);
85 }
87 var tests = [];
88 function test(fcn) {
89 tests.push(fcn);
90 }
92 test(
93 function test_CSPHost_fromstring() {
94 var h;
96 h = CSPHost.fromString("*");
97 do_check_neq(null, h); // "* lone wildcard should work"
99 h = CSPHost.fromString("foo.bar");
100 do_check_neq(null, h); // "standard tuple failed"
102 h = CSPHost.fromString("*.bar");
103 do_check_neq(null, h); // "wildcard failed"
105 h = CSPHost.fromString("foo.*.bar");
106 do_check_eq(null, h); // "wildcard in wrong place worked"
108 h = CSPHost.fromString("com");
109 do_check_neq(null, h); // "lone symbol should not fail"
111 h = CSPHost.fromString("f00b4r.com");
112 do_check_neq(null, h); // "Numbers in hosts should work"
114 h = CSPHost.fromString("foo-bar.com");
115 do_check_neq(null, h); // "dashes in hosts should work"
118 h = CSPHost.fromString("foo!bar.com");
119 do_check_eq(null, h); // "special chars in hosts should fail"
121 h = CSPHost.fromString("{app-url-is-uid}");
122 do_check_neq(null, h); // "Packaged apps URLs failed"
123 });
125 test(
126 function test_CSPHost_clone() {
127 h = CSPHost.fromString("*.a.b.c");
128 h2 = h.clone();
129 for(var i in h._segments) {
130 // "cloned segments should match"
131 do_check_eq(h._segments[i], h2._segments[i]);
132 }
133 });
135 test(
136 function test_CSPHost_permits() {
137 var h = CSPHost.fromString("*.b.c");
138 var h2 = CSPHost.fromString("a.b.c");
139 do_check_true( h.permits(h2)); //"CSPHost *.b.c should allow CSPHost a.b.c"
140 do_check_true( h.permits("a.b.c")); //"CSPHost *.b.c should allow string a.b.c"
141 do_check_false(h.permits("b.c")); //"CSPHost *.b.c should not allow string b.c"
142 do_check_false(h.permits("a.a.c")); //"CSPHost *.b.c should not allow string a.a.c"
143 do_check_false(h2.permits(h)); //"CSPHost a.b.c should not allow CSPHost *.b.c"
144 do_check_false(h2.permits("b.c")); //"CSPHost a.b.c should not allow string b.c"
145 do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
146 });
149 ///////////////////// Test the Source object //////////////////////
151 test(
152 function test_CSPSource_fromString() {
153 // can't do these tests because "self" is not defined.
154 //"basic source should not be null.");
155 do_check_neq(null, CSPSource.fromString("a.com", undefined, "http://abc.com"));
157 //"ldh characters should all work for host.");
158 do_check_neq(null, CSPSource.fromString("a2-c.com", undefined, "https://a.com"));
160 //"wildcard should work in first token for host.");
161 do_check_neq(null, CSPSource.fromString("*.a.com", undefined, "http://abc.com"));
163 //print(" --- Ignore the following two errors if they print ---");
164 //"wildcard should not work in non-first token for host.");
165 do_check_eq(null, CSPSource.fromString("x.*.a.com", undefined, "http://a.com"));
167 //"funny characters (#) should not work for host.");
168 do_check_eq(null, CSPSource.fromString("a#2-c.com", undefined, "http://a.com"));
170 //print(" --- Stop ignoring errors that print ---\n");
172 //"failed to parse host with port.");
173 do_check_neq(null, CSPSource.create("a.com:23", undefined, "http://a.com"));
174 //"failed to parse host with scheme.");
175 do_check_neq(null, CSPSource.create("https://a.com", undefined, "http://a.com"));
176 //"failed to parse host with scheme and port.");
177 do_check_neq(null, CSPSource.create("https://a.com:200", undefined, "http://a.com"));
179 //Check to make sure we don't match multiple instances with regex
180 do_check_eq(null, CSPSource.create("http://foo.com:bar.com:23"));
181 //Port parsing should work for all schemes
182 do_check_neq(null, CSPSource.create("data:"));
183 do_check_neq(null, CSPSource.create("javascript:"));
185 //"app:// URLs should work, including the {} characters.");
186 do_check_neq(null, CSPSource.fromString("{app-host-is-uid}", undefined, "app://{app-host-is-uid}"));
187 });
189 test(
190 function test_CSPSource_fromString_withSelf() {
191 var src;
192 src = CSPSource.create("a.com", undefined, "https://foobar.com:443");
193 //"src should inherit port *
194 do_check_true(src.permits("https://a.com:443"));
195 //"src should inherit and require https scheme
196 do_check_false(src.permits("http://a.com"));
197 //"src should inherit scheme 'https'"
198 do_check_true(src.permits("https://a.com"));
200 src = CSPSource.create("http://a.com", undefined, "https://foobar.com:443");
201 //"src should inherit and require http scheme"
202 do_check_false(src.permits("https://a.com"));
203 //"src should inherit scheme 'http'"
204 do_check_true(src.permits("http://a.com"));
205 //"src should inherit port and scheme from parent"
206 //"src should inherit default port for 'http'"
207 do_check_true(src.permits("http://a.com:80"));
209 src = CSPSource.create("'self'", undefined, "https://foobar.com:443");
210 //"src should inherit port *
211 do_check_true(src.permits("https://foobar.com:443"));
212 //"src should inherit and require https scheme
213 do_check_false(src.permits("http://foobar.com"));
214 //"src should inherit scheme 'https'"
215 do_check_true(src.permits("https://foobar.com"));
216 //"src should reject other hosts"
217 do_check_false(src.permits("https://a.com"));
219 src = CSPSource.create("javascript:", undefined, "https://foobar.com:443");
220 //"hostless schemes should be parseable."
221 var aUri = NetUtil.newURI("javascript:alert('foo');");
222 do_check_true(src.permits(aUri));
223 //"src should reject other hosts"
224 do_check_false(src.permits("https://a.com"));
225 //"nothing else should be allowed"
226 do_check_false(src.permits("https://foobar.com"));
228 src = CSPSource.create("{app-host-is-uid}", undefined, "app://{app-host-is-uid}");
229 //"src should inherit and require 'app' scheme"
230 do_check_false(src.permits("https://{app-host-is-uid}"));
231 //"src should inherit scheme 'app'"
232 do_check_true(src.permits("app://{app-host-is-uid}"));
234 });
236 ///////////////////// Test the source list //////////////////////
238 test(
239 function test_CSPSourceList_fromString() {
240 var sd = CSPSourceList.fromString("'none'");
241 //"'none' -- should parse"
242 do_check_neq(null,sd);
243 // "'none' should be a zero-length list"
244 do_check_eq(0, sd._sources.length);
245 do_check_true(sd.isNone());
247 sd = CSPSourceList.fromString("*");
248 //"'*' should be a zero-length list"
249 do_check_eq(0, sd._sources.length);
251 //print(" --- Ignore the following three errors if they print ---");
252 //"funny char in host"
253 do_check_true(CSPSourceList.fromString("f!oo.bar").isNone());
254 //"funny char in scheme"
255 do_check_true(CSPSourceList.fromString("ht!ps://f-oo.bar").isNone());
256 //"funny char in port"
257 do_check_true(CSPSourceList.fromString("https://f-oo.bar:3f").isNone());
258 //print(" --- Stop ignoring errors that print ---\n");
259 });
261 test(
262 function test_CSPSourceList_fromString_twohost() {
263 var str = "foo.bar:21 https://ras.bar";
264 var parsed = "http://foo.bar:21 https://ras.bar:443";
265 var sd = CSPSourceList.fromString(str, undefined, URI("http://self.com:80"));
266 //"two-host list should parse"
267 do_check_neq(null,sd);
268 //"two-host list should parse to two hosts"
269 do_check_eq(2, sd._sources.length);
270 //"two-host list should contain original data"
271 do_check_eq(parsed, sd.toString());
272 });
274 test(
275 function test_CSPSourceList_permits() {
276 var nullSourceList = CSPSourceList.fromString("'none'");
277 var simpleSourceList = CSPSourceList.fromString("a.com", undefined, URI("http://self.com"));
278 var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88",
279 undefined,
280 URI("http://self.com:88"));
281 var allSourceList = CSPSourceList.fromString("*");
282 var allAndMoreSourceList = CSPSourceList.fromString("* https://bar.com 'none'");
283 var wildcardHostSourceList = CSPSourceList.fromString("*.foo.com",
284 undefined, URI("http://self.com"));
285 var allDoubledHostSourceList = CSPSourceList.fromString("**");
286 var allGarbageHostSourceList = CSPSourceList.fromString("*a");
288 //'none' should permit none."
289 do_check_false( nullSourceList.permits("http://a.com"));
290 //a.com should permit a.com"
291 do_check_true( simpleSourceList.permits("http://a.com"));
292 //wrong host"
293 do_check_false( simpleSourceList.permits("http://b.com"));
294 //double list permits http://bar.com:88"
295 do_check_true( doubleSourceList.permits("http://bar.com:88"));
296 //double list permits https://bar.com:88"
297 do_check_false( doubleSourceList.permits("https://bar.com:88"));
298 //double list does not permit http://bar.com:443"
299 do_check_false( doubleSourceList.permits("http://bar.com:443"));
300 //"double list permits https://foo.com:88" (should not inherit port)
301 do_check_false( doubleSourceList.permits("https://foo.com:88"));
302 //"double list does not permit foo.com on http"
303 do_check_false( doubleSourceList.permits("http://foo.com"));
305 //"* does not permit specific host"
306 do_check_true( allSourceList.permits("http://x.com:23"));
307 //"* does not permit a long host with no port"
308 do_check_true( allSourceList.permits("http://a.b.c.d.e.f.g.h.i.j.k.l.x.com"));
310 //* short circuts parsing
311 do_check_true(allAndMoreSourceList.permits("http://a.com"));
313 //"** permits all"
314 do_check_false(allDoubledHostSourceList.permits("http://barbaz.com"));
315 //"*a permits all"
316 do_check_false(allGarbageHostSourceList.permits("http://barbaz.com"));
318 //"*.foo.com does not permit somerandom.foo.com"
319 do_check_true(wildcardHostSourceList.permits("http://somerandom.foo.com"));
320 //"*.foo.com permits all"
321 do_check_false(wildcardHostSourceList.permits("http://barbaz.com"));
322 });
324 ///////////////////// Test the Whole CSP rep object //////////////////////
326 test(
327 function test_CSPRep_fromString() {
329 // check default init
330 //ASSERT(!(new CSPRep())._isInitialized, "Uninitialized rep thinks it is.")
332 var cspr;
333 var cspr_allowval;
334 var SD = CSPRep.SRC_DIRECTIVES_OLD;
336 // check default policy "allow *"
337 cspr = CSPRep.fromString("allow *", URI("http://self.com:80"));
338 // "DEFAULT_SRC directive is missing when specified in fromString"
339 do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
341 });
344 test(
345 function test_CSPRep_defaultSrc() {
346 var cspr, cspr_default_val, cspr_allow;
347 var SD = CSPRep.SRC_DIRECTIVES_OLD;
349 // apply policy of "default-src *" (e.g. "allow *")
350 cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
351 // "DEFAULT_SRC directive is missing when specified in fromString"
352 do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
354 // check that |allow *| and |default-src *| are parsed equivalently and
355 // result in the same set of explicit policy directives
356 cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
357 cspr_allow = CSPRep.fromString("allow *", URI("http://self.com:80"));
359 do_check_equivalent(cspr._directives['default-src'],
360 cspr_allow._directives['default-src']);
361 });
364 test(
365 function test_CSPRep_fromString_oneDir() {
367 var cspr;
368 var SD = CSPRep.SRC_DIRECTIVES_OLD;
369 var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.FRAME_SRC];
371 // check one-directive policies
372 cspr = CSPRep.fromString("allow bar.com; script-src https://foo.com",
373 URI("http://self.com"));
375 for(var x in DEFAULTS) {
376 //DEFAULTS[x] + " does not use default rule."
377 do_check_false(cspr.permits("http://bar.com:22", DEFAULTS[x]));
378 //DEFAULTS[x] + " does not use default rule."
379 do_check_true(cspr.permits("http://bar.com:80", DEFAULTS[x]));
380 //DEFAULTS[x] + " does not use default rule."
381 do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
382 //DEFAULTS[x] + " does not use default rule."
383 do_check_false(cspr.permits("https://foo.com", DEFAULTS[x]));
384 }
385 //"script-src false positive in policy.
386 do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
387 //"script-src false negative in policy.
388 do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
389 });
391 test(
392 function test_CSPRep_fromString_twodir() {
393 var cspr;
394 var SD = CSPRep.SRC_DIRECTIVES_OLD;
395 var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC];
397 // check two-directive policies
398 var polstr = "allow allow.com; "
399 + "script-src https://foo.com; "
400 + "img-src bar.com:*";
401 cspr = CSPRep.fromString(polstr, URI("http://self.com"));
403 for(var x in DEFAULTS) {
404 do_check_true(cspr.permits("http://allow.com", DEFAULTS[x]));
405 //DEFAULTS[x] + " does not use default rule.
406 do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
407 //DEFAULTS[x] + " does not use default rule.
408 do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
409 //DEFAULTS[x] + " does not use default rule.
410 }
411 //"img-src does not use default rule.
412 do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
413 //"img-src does not use default rule.
414 do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
415 //"img-src does not use default rule.
416 do_check_true(cspr.permits("http://bar.com:88", SD.IMG_SRC));
418 //"script-src does not use default rule.
419 do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
420 //"script-src does not use default rule.
421 do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
422 //"script-src does not use default rule.
423 do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
424 });
426 test(function test_CSPRep_fromString_withself() {
427 var cspr;
428 var SD = CSPRep.SRC_DIRECTIVES_OLD;
429 var self = "https://self.com:34";
431 // check one-directive policies
432 cspr = CSPRep.fromString("allow 'self'; script-src 'self' https://*:*",
433 URI(self));
434 //"img-src does not enforce default rule, 'self'.
435 do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
436 //"img-src does not allow self
437 do_check_true(cspr.permits(self, SD.IMG_SRC));
438 //"script-src is too relaxed
439 do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
440 //"script-src should allow self
441 do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
442 //"script-src is too strict on host/port
443 do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
444 });
447 //////////////// TEST CSP REP SPEC COMPLIANT PARSER ////////////
448 test(
449 function test_CSPRep_fromStringSpecCompliant() {
451 var cspr;
452 var cspr_allowval;
453 var SD = CSPRep.SRC_DIRECTIVES_NEW;
454 var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC, SD.SCRIPT_SRC, SD.FONT_SRC,
455 SD.OBJECT_SRC, SD.FRAME_SRC, SD.CONNECT_SRC];
457 // check default policy "default-src *"
458 cspr = CSPRep.fromStringSpecCompliant("default-src *", URI("http://self.com:80"));
459 // "DEFAULT_SRC directive is missing when specified in
460 // fromStringSpecCompliant"
461 do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
463 for(var x in DEFAULTS) {
464 // each of these should be equivalent to DEFAULT_SRC
465 //DEFAULTS[x] + " does not use default rule."
466 do_check_true(cspr.permits("http://bar.com", DEFAULTS[x]));
467 }
468 });
471 test(
472 function test_CSPRep_fromStringSpecCompliant_oneDir() {
474 var cspr;
475 var SD = CSPRep.SRC_DIRECTIVES_NEW;
476 var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
477 SD.FRAME_SRC, SD.CONNECT_SRC];
479 // check one-directive policies
480 cspr = CSPRep.fromStringSpecCompliant("default-src bar.com; script-src https://foo.com",
481 URI("http://self.com"));
483 for(var x in DEFAULTS) {
484 //DEFAULTS[x] + " does not use default rule."
485 do_check_false(cspr.permits("http://bar.com:22", DEFAULTS[x]));
486 //DEFAULTS[x] + " does not use default rule."
487 do_check_true(cspr.permits("http://bar.com:80", DEFAULTS[x]));
488 //DEFAULTS[x] + " does not use default rule."
489 do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
490 //DEFAULTS[x] + " does not use default rule."
491 do_check_false(cspr.permits("https://foo.com", DEFAULTS[x]));
492 }
493 //"script-src false positive in policy.
494 do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
495 //"script-src false negative in policy.
496 do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
497 });
499 test(
500 function test_CSPRep_fromStringSpecCompliant_twodir() {
501 var cspr;
503 var SD = CSPRep.SRC_DIRECTIVES_NEW;
505 var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_SRC,
506 SD.CONNECT_SRC];
508 // check two-directive policies
509 var polstr = "default-src allow.com; " +
510 "script-src https://foo.com; " +
511 "img-src bar.com:*";
512 cspr = CSPRep.fromStringSpecCompliant(polstr, URI("http://self.com"));
514 for(var x in DEFAULTS) {
515 do_check_true(cspr.permits("http://allow.com", DEFAULTS[x]));
516 //DEFAULTS[x] + " does not use default rule.
517 do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
518 //DEFAULTS[x] + " does not use default rule.
519 do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
520 //DEFAULTS[x] + " does not use default rule.
521 }
522 //"img-src does not use default rule.
523 do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
524 //"img-src does not use default rule.
525 do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
526 //"img-src does not use default rule.
527 do_check_true(cspr.permits("http://bar.com:88", SD.IMG_SRC));
529 //"script-src does not use default rule.
530 do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
531 //"script-src does not use default rule.
532 do_check_true(cspr.permits("https://foo.com:443", SD.SCRIPT_SRC));
533 //"script-src does not use default rule.
534 do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
535 });
537 test(function test_CSPRep_fromStringSpecCompliant_withself() {
538 var cspr;
539 var self = "https://self.com:34";
540 var SD = CSPRep.SRC_DIRECTIVES_NEW;
542 // check one-directive policies
543 cspr = CSPRep.fromStringSpecCompliant("default-src 'self'; script-src 'self' https://*:*",
544 URI(self));
545 //"img-src does not enforce default rule, 'self'.
546 do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
547 //"img-src does not allow self
548 do_check_true(cspr.permits(self, SD.IMG_SRC));
549 //"script-src is too relaxed
550 do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
551 //"script-src should allow self
552 do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
553 //"script-src is too strict on host/port
554 do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
555 });
558 //////////////// TEST FRAME ANCESTOR DEFAULTS /////////////////
559 // (see bug 555068)
560 test(function test_FrameAncestor_defaults() {
561 var cspr;
562 var SD = CSPRep.SRC_DIRECTIVES_OLD;
563 var self = "http://self.com:34";
565 cspr = CSPRep.fromString("allow 'none'", URI(self));
567 //"frame-ancestors should default to * not 'allow' value"
568 do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
569 do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
570 do_check_true(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
571 do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
572 do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
574 cspr = CSPRep.fromString("allow 'none'; frame-ancestors 'self'", URI(self));
576 //"frame-ancestors should only allow self"
577 do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
578 do_check_false(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
579 do_check_false(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
580 do_check_false(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
581 do_check_false(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
582 });
584 test(function test_FrameAncestor_defaults_specCompliant() {
585 var cspr;
586 var self = "http://self.com:34";
587 var SD = CSPRep.SRC_DIRECTIVES_NEW;
589 cspr = CSPRep.fromStringSpecCompliant("default-src 'none'", URI(self));
591 //"frame-ancestors should default to * not 'default-src' value"
592 do_check_true(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
593 do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
594 do_check_true(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
595 do_check_true(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
596 do_check_true(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
598 cspr = CSPRep.fromStringSpecCompliant("default-src 'none'; frame-ancestors 'self'", URI(self));
600 //"frame-ancestors should only allow self"
601 do_check_true(cspr.permits("http://self.com:34", SD.FRAME_ANCESTORS));
602 do_check_false(cspr.permits("https://foo.com:400", SD.FRAME_ANCESTORS));
603 do_check_false(cspr.permits("https://self.com:34", SD.FRAME_ANCESTORS));
604 do_check_false(cspr.permits("http://self.com", SD.FRAME_ANCESTORS));
605 do_check_false(cspr.permits("http://subd.self.com:34", SD.FRAME_ANCESTORS));
606 });
609 test(function test_FrameAncestor_TLD_defaultPorts() {
610 var cspr;
611 var SD = CSPRep.SRC_DIRECTIVES_OLD;
612 var self = "http://self"; //TLD only, no .com or anything.
614 cspr = CSPRep.fromString("allow 'self'; frame-ancestors 'self' http://foo:80 bar:80 http://three", URI(self));
616 //"frame-ancestors should default to * not 'allow' value"
617 do_check_true(cspr.permits("http://self", SD.FRAME_ANCESTORS));
618 do_check_true(cspr.permits("http://self:80", SD.FRAME_ANCESTORS));
619 do_check_true(cspr.permits("http://foo", SD.FRAME_ANCESTORS));
620 do_check_true(cspr.permits("http://foo:80", SD.FRAME_ANCESTORS));
621 do_check_true(cspr.permits("http://bar", SD.FRAME_ANCESTORS));
622 do_check_true(cspr.permits("http://three:80", SD.FRAME_ANCESTORS));
624 do_check_false(cspr.permits("https://foo:400", SD.FRAME_ANCESTORS));
625 do_check_false(cspr.permits("https://self:34", SD.FRAME_ANCESTORS));
626 do_check_false(cspr.permits("https://bar", SD.FRAME_ANCESTORS));
627 do_check_false(cspr.permits("http://three:81", SD.FRAME_ANCESTORS));
628 do_check_false(cspr.permits("https://three:81", SD.FRAME_ANCESTORS));
629 });
631 test(function test_FrameAncestor_ignores_userpass_bug779918() {
632 var cspr;
633 var SD = CSPRep.SRC_DIRECTIVES_OLD;
634 var self = "http://self.com/bar";
635 var testPolicy = "default-src 'self'; frame-ancestors 'self'";
637 cspr = CSPRep.fromString(testPolicy, URI(self));
639 // wrapped in URI() because of source parsing
640 do_check_true(cspr.permits(URI("http://username:password@self.com/foo"), SD.FRAME_ANCESTORS));
641 do_check_true(cspr.permits(URI("http://other:pass1@self.com/foo"), SD.FRAME_ANCESTORS));
642 do_check_true(cspr.permits(URI("http://self.com:80/foo"), SD.FRAME_ANCESTORS));
643 do_check_true(cspr.permits(URI("http://self.com/foo"), SD.FRAME_ANCESTORS));
645 // construct fake ancestry with CSP applied to the child.
646 // [aChildUri] -> [aParentUri] -> (root/top)
647 // and then test "permitsAncestry" on the child/self docshell.
648 function testPermits(aChildUri, aParentUri, aContentType) {
649 let cspObj = Cc["@mozilla.org/contentsecuritypolicy;1"]
650 .createInstance(Ci.nsIContentSecurityPolicy);
651 cspObj.appendPolicy(testPolicy, aChildUri, false, false);
652 let docshellparent = Cc["@mozilla.org/docshell;1"]
653 .createInstance(Ci.nsIDocShell);
654 let docshellchild = Cc["@mozilla.org/docshell;1"]
655 .createInstance(Ci.nsIDocShell);
656 docshellparent.setCurrentURI(aParentUri);
657 docshellchild.setCurrentURI(aChildUri);
658 docshellparent.addChild(docshellchild);
659 return cspObj.permitsAncestry(docshellchild);
660 };
662 // check parent without userpass
663 do_check_true(testPermits(URI("http://username:password@self.com/foo"),
664 URI("http://self.com/bar")));
665 do_check_true(testPermits(URI("http://user1:pass1@self.com/foo"),
666 URI("http://self.com/bar")));
667 do_check_true(testPermits(URI("http://self.com/foo"),
668 URI("http://self.com/bar")));
670 // check parent with userpass
671 do_check_true(testPermits(URI("http://username:password@self.com/foo"),
672 URI("http://username:password@self.com/bar")));
673 do_check_true(testPermits(URI("http://user1:pass1@self.com/foo"),
674 URI("http://username:password@self.com/bar")));
675 do_check_true(testPermits(URI("http://self.com/foo"),
676 URI("http://username:password@self.com/bar")));
677 });
679 test(function test_CSP_ReportURI_parsing() {
680 var cspr;
681 var SD = CSPRep.SRC_DIRECTIVES_NEW;
682 var self = "http://self.com:34";
683 var parsedURIs = [];
685 var uri_valid_absolute = self + "/report.py";
686 var uri_other_host_absolute = "http://foo.org:34/report.py";
687 var uri_valid_relative = "/report.py";
688 var uri_valid_relative_expanded = self + uri_valid_relative;
689 var uri_valid_relative2 = "foo/bar/report.py";
690 var uri_valid_relative2_expanded = self + "/" + uri_valid_relative2;
691 var uri_invalid_relative = "javascript:alert(1)";
692 var uri_other_scheme_absolute = "https://self.com/report.py";
693 var uri_other_scheme_and_host_absolute = "https://foo.com/report.py";
695 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_absolute, URI(self));
696 parsedURIs = cspr.getReportURIs().split(/\s+/);
697 do_check_in_array(parsedURIs, uri_valid_absolute);
698 do_check_eq(parsedURIs.length, 1);
700 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_host_absolute, URI(self));
701 parsedURIs = cspr.getReportURIs().split(/\s+/);
702 do_check_in_array(parsedURIs, uri_other_host_absolute);
703 do_check_eq(parsedURIs.length, 1); // the empty string is in there.
705 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_invalid_relative, URI(self));
706 parsedURIs = cspr.getReportURIs().split(/\s+/);
707 do_check_in_array(parsedURIs, "");
708 do_check_eq(parsedURIs.length, 1);
710 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative, URI(self));
711 parsedURIs = cspr.getReportURIs().split(/\s+/);
712 do_check_in_array(parsedURIs, uri_valid_relative_expanded);
713 do_check_eq(parsedURIs.length, 1);
715 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative2, URI(self));
716 parsedURIs = cspr.getReportURIs().split(/\s+/);
717 dump(parsedURIs.length);
718 do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
719 do_check_eq(parsedURIs.length, 1);
721 // make sure cross-scheme reporting works
722 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_absolute, URI(self));
723 parsedURIs = cspr.getReportURIs().split(/\s+/);
724 dump(parsedURIs.length);
725 do_check_in_array(parsedURIs, uri_other_scheme_absolute);
726 do_check_eq(parsedURIs.length, 1);
728 // make sure cross-scheme, cross-host reporting works
729 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_and_host_absolute, URI(self));
730 parsedURIs = cspr.getReportURIs().split(/\s+/);
731 dump(parsedURIs.length);
732 do_check_in_array(parsedURIs, uri_other_scheme_and_host_absolute);
733 do_check_eq(parsedURIs.length, 1);
735 // combination!
736 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
737 uri_valid_relative2 + " " +
738 uri_valid_absolute, URI(self));
739 parsedURIs = cspr.getReportURIs().split(/\s+/);
740 do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
741 do_check_in_array(parsedURIs, uri_valid_absolute);
742 do_check_eq(parsedURIs.length, 2);
744 cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
745 uri_valid_relative2 + " " +
746 uri_other_host_absolute + " " +
747 uri_valid_absolute, URI(self));
748 parsedURIs = cspr.getReportURIs().split(/\s+/);
749 do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
750 do_check_in_array(parsedURIs, uri_other_host_absolute);
751 do_check_in_array(parsedURIs, uri_valid_absolute);
752 do_check_eq(parsedURIs.length, 3);
753 });
755 test(
756 function test_bug634778_duplicateDirective_Detection() {
757 var cspr;
758 var SD = CSPRep.SRC_DIRECTIVES_OLD;
759 var self = "http://self.com:34";
760 var firstDomain = "http://first.com";
761 var secondDomain = "http://second.com";
762 var thirdDomain = "http://third.com";
764 // check for duplicate "default-src" directives
765 cspr = CSPRep.fromString("default-src " + self + "; default-src " +
766 firstDomain, URI(self));
767 do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
768 do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
770 // check for duplicate "allow" directives
771 cspr = CSPRep.fromString("allow " + self + "; allow " + firstDomain,
772 URI(self));
773 do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
774 do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
776 // check for duplicate "allow" + "default-src" directives
777 cspr = CSPRep.fromString("allow " + self + "; default-src " + firstDomain,
778 URI(self));
779 do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
780 do_check_false(cspr.permits(firstDomain, SD.DEFAULT_SRC));
782 // check for duplicate report-uri directives
783 cspr = CSPRep.fromString("allow *; report-uri " + self + "/report.py; report-uri "
784 + firstDomain + "/report.py", URI(self));
785 parsedURIs = cspr.getReportURIs().split(/\s+/);
786 do_check_in_array(parsedURIs, self + "/report.py");
787 do_check_eq(parsedURIs.length, 1);
789 // check for three directives with duplicates
790 cspr = CSPRep.fromString("img-src " + firstDomain + "; default-src " + self
791 + "; img-src " + secondDomain, URI(self));
792 do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
793 do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
794 do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
796 // check for three directives with duplicates
797 cspr = CSPRep.fromString("img-src " + firstDomain + "; default-src " + self
798 + "; img-src " + secondDomain, URI(self));
799 do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
800 do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
802 // check for three directives with duplicates
803 cspr = CSPRep.fromString("default-src " + self + "; img-src " + firstDomain
804 + "; img-src " + secondDomain, URI(self));
805 do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
806 do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
808 // check for four directives with duplicates
809 cspr = CSPRep.fromString("default-src " + self + "; img-src " + firstDomain
810 + "; img-src " + secondDomain + "; img-src "
811 + thirdDomain, URI(self));
812 do_check_true(cspr.permits(firstDomain, SD.IMG_SRC));
813 do_check_false(cspr.permits(secondDomain, SD.IMG_SRC));
814 do_check_false(cspr.permits(thirdDomain, SD.IMG_SRC));
816 // check for four directives with two duplicates
817 cspr = CSPRep.fromString("default-src " + self + "; style-src "
818 + firstDomain + "; media-src " + firstDomain
819 + "; media-src " + secondDomain + "; style-src "
820 + thirdDomain, URI(self));
821 do_check_true(cspr.permits(self, SD.DEFAULT_SRC));
822 do_check_true(cspr.permits(firstDomain, SD.STYLE_SRC));
823 do_check_true(cspr.permits(firstDomain, SD.MEDIA_SRC));
824 do_check_false(cspr.permits(secondDomain, SD.MEDIA_SRC));
825 do_check_false(cspr.permits(thirdDomain, SD.STYLE_SRC));
826 });
828 test(
829 function test_bug672961_withNonstandardSelfPort() {
830 /**
831 * When a protected document has a non-standard port, other host names
832 * listed as sources should inherit the scheme of the protected document
833 * but NOT the port. Other hosts should use the default port for the
834 * inherited scheme. For example, since 443 is default for HTTPS:
835 *
836 * Document with CSP: https://foobar.com:4443
837 * Transmitted policy:
838 * "allow 'self' a.com"
839 * Explicit policy:
840 * "allow https://foobar.com:4443 https://a.com:443"
841 *
842 * This test examines scheme and nonstandard port inheritance.
843 */
845 var src;
846 src = CSPSource.create("a.com", undefined, "https://foobar.com:4443");
847 //"src should inherit and require https scheme
848 do_check_false(src.permits("http://a.com"));
849 //"src should inherit scheme 'https'"
850 do_check_true(src.permits("https://a.com"));
851 //"src should get default port
852 do_check_true(src.permits("https://a.com:443"));
854 src = CSPSource.create("http://a.com", undefined, "https://foobar.com:4443");
855 //"src should require http scheme"
856 do_check_false(src.permits("https://a.com"));
857 //"src should keep scheme 'http'"
858 do_check_true(src.permits("http://a.com"));
859 //"src should inherit default port for 'http'"
860 do_check_true(src.permits("http://a.com:80"));
862 src = CSPSource.create("'self'", undefined, "https://foobar.com:4443");
863 //"src should inherit nonstandard port from self
864 do_check_true(src.permits("https://foobar.com:4443"));
865 do_check_false(src.permits("https://foobar.com"));
866 do_check_false(src.permits("https://foobar.com:443"));
868 //"src should inherit and require https scheme from self
869 do_check_false(src.permits("http://foobar.com:4443"));
870 do_check_false(src.permits("http://foobar.com"));
872 });
874 test(
875 function test_bug634773_noneAndStarAreDifferent() {
876 /**
877 * Bug 634773 is that allow * and allow 'none' end up "equal" via
878 * CSPSourceList.prototype.equals(), which is wrong. This tests that
879 * doesn't happen.
880 */
882 var p_none = CSPSourceList.fromString("'none'", undefined, "http://foo.com", false);
883 var p_all = CSPSourceList.fromString("*", undefined, "http://foo.com", false);
884 var p_one = CSPSourceList.fromString("bar.com", undefined, "http://foo.com", false);
886 do_check_false(p_none.equals(p_all));
887 do_check_false(p_none.equals(p_one));
888 do_check_false(p_all.equals(p_none));
889 do_check_false(p_all.equals(p_one));
891 do_check_true(p_all.permits("http://bar.com"));
892 do_check_true(p_one.permits("http://bar.com"));
893 do_check_false(p_none.permits("http://bar.com"));
894 });
897 test(
898 function test_bug764937_defaultSrcMissing() {
899 var cspObjSpecCompliant = Cc["@mozilla.org/contentsecuritypolicy;1"]
900 .createInstance(Ci.nsIContentSecurityPolicy);
901 var cspObjOld = Cc["@mozilla.org/contentsecuritypolicy;1"]
902 .createInstance(Ci.nsIContentSecurityPolicy);
903 var selfURI = URI("http://self.com/");
905 function testPermits(cspObj, aUri, aContentType) {
906 return cspObj.shouldLoad(aContentType, aUri, null, null, null, null)
907 == Ci.nsIContentPolicy.ACCEPT;
908 };
910 const policy = "script-src 'self'";
911 cspObjSpecCompliant.appendPolicy(policy, selfURI, false, true);
913 // Spec-Compliant policy default-src defaults to *.
914 // This means all images are allowed, and only 'self'
915 // script is allowed.
916 do_check_true(testPermits(cspObjSpecCompliant,
917 URI("http://bar.com/foo.png"),
918 Ci.nsIContentPolicy.TYPE_IMAGE));
919 do_check_true(testPermits(cspObjSpecCompliant,
920 URI("http://self.com/foo.png"),
921 Ci.nsIContentPolicy.TYPE_IMAGE));
922 do_check_true(testPermits(cspObjSpecCompliant,
923 URI("http://self.com/foo.js"),
924 Ci.nsIContentPolicy.TYPE_SCRIPT));
925 do_check_false(testPermits(cspObjSpecCompliant,
926 URI("http://bar.com/foo.js"),
927 Ci.nsIContentPolicy.TYPE_SCRIPT));
929 cspObjOld.appendPolicy(policy, selfURI, false, false);
931 // non-Spec-Compliant policy default-src defaults to 'none'
932 // This means all images are blocked, and so are all scripts (because the
933 // policy is ignored and fails closed).
934 do_check_false(testPermits(cspObjOld,
935 URI("http://bar.com/foo.png"),
936 Ci.nsIContentPolicy.TYPE_IMAGE));
937 do_check_false(testPermits(cspObjOld,
938 URI("http://self.com/foo.png"),
939 Ci.nsIContentPolicy.TYPE_IMAGE));
940 do_check_false(testPermits(cspObjOld,
941 URI("http://self.com/foo.js"),
942 Ci.nsIContentPolicy.TYPE_SCRIPT));
943 do_check_false(testPermits(cspObjOld,
944 URI("http://bar.com/foo.js"),
945 Ci.nsIContentPolicy.TYPE_SCRIPT));
947 });
949 test(function test_equals_does_case_insensitive_comparison() {
950 // NOTE: For scheme, host and keyword-host:
951 // (1) compare the same lower-case in two distinct objects
952 // (2) compare upper-case with lower-case inputs
953 // to test case insensitivity.
955 // CSPSource equals ignores case
956 var upperCaseHost = "http://FOO.COM";
957 var lowerCaseHost = "http://foo.com";
958 src1 = CSPSource.fromString(lowerCaseHost);
959 src2 = CSPSource.fromString(lowerCaseHost);
960 do_check_true(src1.equals(src2))
961 src3 = CSPSource.fromString(upperCaseHost);
962 do_check_true(src1.equals(src3))
964 // CSPHost equals ignores case
965 var upperCaseScheme = "HTTP";
966 var lowerCaseScheme = "http";
967 src1 = CSPHost.fromString(lowerCaseScheme);
968 src2 = CSPHost.fromString(lowerCaseScheme);
969 do_check_true(src1.equals(src2));
970 src3 = CSPHost.fromString(upperCaseScheme);
971 do_check_true(src1.equals(src3));
973 // CSPSourceList equals (mainly for testing keywords)
974 var upperCaseKeywords = "'SELF'";
975 var lowerCaseKeywords = "'self'";
976 src1 = CSPSourceList.fromString(lowerCaseKeywords);
977 src2 = CSPSourceList.fromString(lowerCaseKeywords);
978 do_check_true(src1.equals(src2))
979 src3 = CSPSourceList.fromString(upperCaseKeywords);
980 do_check_true(src1.equals(src3))
982 });
984 test(function test_csp_permits_case_insensitive() {
985 var cspr;
986 var SD = CSPRep.SRC_DIRECTIVES_NEW;
988 // checks directives can be case-insensitive
989 var selfHost = "http://self.com";
990 var testPolicy1 = "DEFAULT-src 'self';";
991 cspr = CSPRep.fromString(testPolicy1, URI(selfHost));
992 do_check_true(cspr.permits(URI("http://self.com"), SD.DEFAULT_SRC));
994 // checks hosts can be case-insensitive
995 var testPolicy2 = "default-src 'self' http://FOO.COM";
996 cspr = CSPRep.fromString(testPolicy2, URI(selfHost));
997 do_check_true(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
999 // checks schemes can be case-insensitive
1000 var testPolicy3 = "default-src 'self' HTTP://foo.com";
1001 cspr = CSPRep.fromString(testPolicy3, URI(selfHost));
1002 do_check_true(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
1004 // checks keywords can be case-insensitive
1005 var testPolicy4 = "default-src 'NONE'";
1006 cspr = CSPRep.fromString(testPolicy4, URI(selfHost));
1007 do_check_false(cspr.permits(URI("http://foo.com"), SD.DEFAULT_SRC));
1008 });
1009 /*
1011 test(function test_CSPRep_fromPolicyURI_failswhenmixed() {
1012 var cspr;
1013 var self = "http://localhost:" + POLICY_PORT;
1014 var closed_policy = CSPRep.fromString("allow 'none'");
1015 var my_uri_policy = "policy-uri " + POLICY_URI;
1017 //print(" --- Ignore the following two errors if they print ---");
1018 cspr = CSPRep.fromString("allow *; " + my_uri_policy, URI(self));
1020 //"Parsing should fail when 'policy-uri' is mixed with allow directive"
1021 do_check_equivalent(cspr, closed_policy);
1022 cspr = CSPRep.fromString("img-src 'self'; " + my_uri_policy, URI(self));
1024 //"Parsing should fail when 'policy-uri' is mixed with other directives"
1025 do_check_equivalent(cspr, closed_policy);
1026 //print(" --- Stop ignoring errors that print ---\n");
1028 });
1029 */
1031 // TODO: test reporting
1032 // TODO: test refinements (?)
1033 // TODO: test 'eval' and 'inline' keywords
1035 function run_test() {
1036 function policyresponder(request,response) {
1037 response.setStatusLine(request.httpVersion, 200, "OK");
1038 response.setHeader("Content-Type", "text/csp", false);
1039 response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length);
1040 }
1041 //server.registerDirectory("/", nsILocalFileForBasePath);
1042 httpServer.registerPathHandler("/policy", policyresponder);
1044 for(let i in tests) {
1045 tests[i]();
1046 }
1048 //teardown
1049 httpServer.stop(function() { });
1050 do_test_finished();
1051 }