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
|
/*
* Description of the tests:
* Tests check that default-src can be overridden by manifest-src.
*/
/*globals Cu, is, ok*/
"use strict";
const {
ManifestObtainer
} = Cu.import("resource://gre/modules/ManifestObtainer.jsm", {});
const path = "/tests/dom/security/test/csp/";
const testFile = `${path}file_web_manifest.html`;
const mixedContentFile = `${path}file_web_manifest_mixed_content.html`;
const server = `${path}file_testserver.sjs`;
const defaultURL = new URL(`http://example.org${server}`);
const mixedURL = new URL(`http://mochi.test:8888${server}`);
const tests = [
// Check interaction with default-src and another origin,
// CSP allows fetching from example.org, so manifest should load.
{
expected: `CSP manifest-src overrides default-src of elsewhere.com`,
get tabURL() {
const url = new URL(defaultURL);
url.searchParams.append("file", testFile);
url.searchParams.append("cors", "*");
url.searchParams.append("csp", "default-src http://elsewhere.com; manifest-src http://example.org");
return url.href;
},
run(manifest) {
is(manifest.name, "loaded", this.expected);
}
},
// Check interaction with default-src none,
// CSP allows fetching manifest from example.org, so manifest should load.
{
expected: `CSP manifest-src overrides default-src`,
get tabURL() {
const url = new URL(mixedURL);
url.searchParams.append("file", mixedContentFile);
url.searchParams.append("cors", "http://test:80");
url.searchParams.append("csp", "default-src 'self'; manifest-src http://test:80");
return url.href;
},
run(manifest) {
is(manifest.name, "loaded", this.expected);
}
},
];
//jscs:disable
add_task(function* () {
//jscs:enable
const testPromises = tests.map((test) => {
const tabOptions = {
gBrowser,
url: test.tabURL,
skipAnimation: true,
};
return BrowserTestUtils.withNewTab(tabOptions, (browser) => testObtainingManifest(browser, test));
});
yield Promise.all(testPromises);
});
function* testObtainingManifest(aBrowser, aTest) {
const expectsBlocked = aTest.expected.includes("block");
const observer = (expectsBlocked) ? createNetObserver(aTest) : null;
// Expect an exception (from promise rejection) if there a content policy
// that is violated.
try {
const manifest = yield ManifestObtainer.browserObtainManifest(aBrowser);
aTest.run(manifest);
} catch (e) {
const wasBlocked = e.message.includes("NetworkError when attempting to fetch resource");
ok(wasBlocked,`Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}`);
if (observer) {
yield observer.untilFinished;
}
}
}
// Helper object used to observe policy violations. It waits 1 seconds
// for a response, and then times out causing its associated test to fail.
function createNetObserver(test) {
let finishedTest;
let success = false;
const finished = new Promise((resolver) => {
finishedTest = resolver;
});
const timeoutId = setTimeout(() => {
if (!success) {
test.run("This test timed out.");
finishedTest();
}
}, 1000);
var observer = {
get untilFinished(){
return finished;
},
observe(subject, topic) {
SpecialPowers.removeObserver(observer, "csp-on-violate-policy");
test.run(topic);
finishedTest();
clearTimeout(timeoutId);
success = true;
},
};
SpecialPowers.addObserver(observer, "csp-on-violate-policy", false);
return observer;
}
|