|
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/. */ |
|
4 |
|
5 const Cc = Components.classes; |
|
6 const Ci = Components.interfaces; |
|
7 const Cu = Components.utils; |
|
8 const Cr = Components.results; |
|
9 |
|
10 Cu.import('resource://gre/modules/CSPUtils.jsm'); |
|
11 Cu.import('resource://gre/modules/NetUtil.jsm'); |
|
12 |
|
13 var httpServer = new HttpServer(); |
|
14 httpServer.start(-1); |
|
15 var testsToFinish = 0; |
|
16 |
|
17 const REPORT_SERVER_PORT = httpServer.identity.primaryPort; |
|
18 const REPORT_SERVER_URI = "http://localhost"; |
|
19 const REPORT_SERVER_PATH = "/report"; |
|
20 |
|
21 /** |
|
22 * Construct a callback that listens to a report submission and either passes |
|
23 * or fails a test based on what it gets. |
|
24 */ |
|
25 function makeReportHandler(testpath, message, expectedJSON) { |
|
26 return function(request, response) { |
|
27 // we only like "POST" submissions for reports! |
|
28 if (request.method !== "POST") { |
|
29 do_throw("violation report should be a POST request"); |
|
30 return; |
|
31 } |
|
32 |
|
33 // obtain violation report |
|
34 var reportObj = JSON.parse( |
|
35 NetUtil.readInputStreamToString( |
|
36 request.bodyInputStream, |
|
37 request.bodyInputStream.available())); |
|
38 |
|
39 dump("GOT REPORT:\n" + JSON.stringify(reportObj) + "\n"); |
|
40 dump("TESTPATH: " + testpath + "\n"); |
|
41 dump("EXPECTED: \n" + JSON.stringify(expectedJSON) + "\n\n"); |
|
42 |
|
43 for (var i in expectedJSON) |
|
44 do_check_eq(expectedJSON[i], reportObj['csp-report'][i]); |
|
45 |
|
46 testsToFinish--; |
|
47 httpServer.registerPathHandler(testpath, null); |
|
48 if (testsToFinish < 1) |
|
49 httpServer.stop(do_test_finished); |
|
50 else |
|
51 do_test_finished(); |
|
52 }; |
|
53 } |
|
54 |
|
55 /** |
|
56 * Everything created by this assumes it will cause a report. If you want to |
|
57 * add a test here that will *not* cause a report to go out, you're gonna have |
|
58 * to make sure the test cleans up after itself. |
|
59 */ |
|
60 function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) { |
|
61 testsToFinish++; |
|
62 do_test_pending(); |
|
63 |
|
64 // set up a new CSP instance for each test. |
|
65 var csp = Cc["@mozilla.org/contentsecuritypolicy;1"] |
|
66 .createInstance(Ci.nsIContentSecurityPolicy); |
|
67 var policy = "allow 'none'; " + |
|
68 "report-uri " + REPORT_SERVER_URI + |
|
69 ":" + REPORT_SERVER_PORT + |
|
70 "/test" + id; |
|
71 var selfuri = NetUtil.newURI(REPORT_SERVER_URI + |
|
72 ":" + REPORT_SERVER_PORT + |
|
73 "/foo/self"); |
|
74 var selfchan = NetUtil.newChannel(selfuri); |
|
75 |
|
76 dump("Created test " + id + " : " + policy + "\n\n"); |
|
77 |
|
78 // make the reports seem authentic by "binding" them to a channel. |
|
79 csp.setRequestContext(selfuri, null, null, selfchan); |
|
80 |
|
81 // Load up the policy |
|
82 // set as report-only if that's the case |
|
83 csp.appendPolicy(policy, selfuri, useReportOnlyPolicy, false); |
|
84 |
|
85 // prime the report server |
|
86 var handler = makeReportHandler("/test" + id, "Test " + id, expectedJSON); |
|
87 httpServer.registerPathHandler("/test" + id, handler); |
|
88 |
|
89 //trigger the violation |
|
90 callback(csp); |
|
91 } |
|
92 |
|
93 function run_test() { |
|
94 var selfuri = NetUtil.newURI(REPORT_SERVER_URI + |
|
95 ":" + REPORT_SERVER_PORT + |
|
96 "/foo/self"); |
|
97 |
|
98 // test that inline script violations cause a report. |
|
99 makeTest(0, {"blocked-uri": "self"}, false, |
|
100 function(csp) { |
|
101 let inlineOK = true, oReportViolation = {'value': false}; |
|
102 inlineOK = csp.getAllowsInlineScript(oReportViolation); |
|
103 |
|
104 // this is not a report only policy, so it better block inline scripts |
|
105 do_check_false(inlineOK); |
|
106 // ... and cause reports to go out |
|
107 do_check_true(oReportViolation.value); |
|
108 |
|
109 if (oReportViolation.value) { |
|
110 // force the logging, since the getter doesn't. |
|
111 csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT, |
|
112 selfuri.asciiSpec, |
|
113 "script sample", |
|
114 0); |
|
115 } |
|
116 }); |
|
117 |
|
118 // test that eval violations cause a report. |
|
119 makeTest(1, {"blocked-uri": "self"}, false, |
|
120 function(csp) { |
|
121 let evalOK = true, oReportViolation = {'value': false}; |
|
122 evalOK = csp.getAllowsEval(oReportViolation); |
|
123 |
|
124 // this is not a report only policy, so it better block eval |
|
125 do_check_false(evalOK); |
|
126 // ... and cause reports to go out |
|
127 do_check_true(oReportViolation.value); |
|
128 |
|
129 if (oReportViolation.value) { |
|
130 // force the logging, since the getter doesn't. |
|
131 csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL, |
|
132 selfuri.asciiSpec, |
|
133 "script sample", |
|
134 1); |
|
135 } |
|
136 }); |
|
137 |
|
138 makeTest(2, {"blocked-uri": "http://blocked.test/foo.js"}, false, |
|
139 function(csp) { |
|
140 // shouldLoad creates and sends out the report here. |
|
141 csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT, |
|
142 NetUtil.newURI("http://blocked.test/foo.js"), |
|
143 null, null, null, null); |
|
144 }); |
|
145 |
|
146 // test that inline script violations cause a report in report-only policy |
|
147 makeTest(3, {"blocked-uri": "self"}, true, |
|
148 function(csp) { |
|
149 let inlineOK = true, oReportViolation = {'value': false}; |
|
150 inlineOK = csp.getAllowsInlineScript(oReportViolation); |
|
151 |
|
152 // this is a report only policy, so it better allow inline scripts |
|
153 do_check_true(inlineOK); |
|
154 |
|
155 // ... and cause reports to go out |
|
156 do_check_true(oReportViolation.value); |
|
157 |
|
158 if (oReportViolation.value) { |
|
159 // force the logging, since the getter doesn't. |
|
160 csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT, |
|
161 selfuri.asciiSpec, |
|
162 "script sample", |
|
163 3); |
|
164 } |
|
165 }); |
|
166 |
|
167 // test that eval violations cause a report in report-only policy |
|
168 makeTest(4, {"blocked-uri": "self"}, true, |
|
169 function(csp) { |
|
170 let evalOK = true, oReportViolation = {'value': false}; |
|
171 evalOK = csp.getAllowsEval(oReportViolation); |
|
172 |
|
173 // this is a report only policy, so it better allow eval |
|
174 do_check_true(evalOK); |
|
175 // ... but still cause reports to go out |
|
176 do_check_true(oReportViolation.value); |
|
177 |
|
178 if (oReportViolation.value) { |
|
179 // force the logging, since the getter doesn't. |
|
180 csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT, |
|
181 selfuri.asciiSpec, |
|
182 "script sample", |
|
183 4); |
|
184 } |
|
185 }); |
|
186 } |