test_disableScript.xhtml (13369B)
1 <?xml version="1.0"?> 2 <?xml-stylesheet type="text/css" href="chrome://global/skin"?> 3 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> 4 <!-- 5 https://bugzilla.mozilla.org/show_bug.cgi?id=840488 6 --> 7 <window title="Mozilla Bug 840488" 8 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 9 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> 10 11 <!-- test results are displayed in the html:body --> 12 <body xmlns="http://www.w3.org/1999/xhtml"> 13 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840488" 14 target="_blank">Mozilla Bug 840488</a> 15 </body> 16 17 <iframe id="root" name="root" type="content"/> 18 <iframe id="chromeFrame" name="chromeFrame" type="content"/> 19 20 <!-- test code goes here --> 21 <script type="application/javascript"> 22 /* eslint-disable mozilla/no-useless-parameters, no-redeclare, no-undef */ 23 <![CDATA[ 24 25 /** Test for all the different ways that script can be disabled for a given global. */ 26 27 SimpleTest.waitForExplicitFinish(); 28 const ssm = Services.scriptSecurityManager; 29 function makeURI(uri) { return Services.io.newURI(uri); } 30 const path = "/tests/caps/tests/mochitest/file_disableScript.html"; 31 const uri = "http://www.example.com" + path; 32 var rootFrame = document.getElementById('root'); 33 var chromeFrame = document.getElementById('chromeFrame'); 34 navigateFrame(rootFrame, uri + "?name=rootframe").then(function() { 35 navigateFrame(chromeFrame, "file_disableScript.html").then(go); 36 }); 37 38 function navigateFrame(ifr, src) { 39 return new Promise(resolve => { 40 function onload() { 41 ifr.removeEventListener('load', onload); 42 resolve(); 43 } 44 ifr.addEventListener('load', onload, false); 45 ifr.setAttribute('src', src); 46 }); 47 } 48 49 function navigateBack(ifr) { 50 return new Promise(resolve => { 51 52 // pageshow events don't fire on the iframe element, so we need to use the 53 // chrome event handler for the docshell. 54 var browser = ifr.contentWindow.docShell.chromeEventHandler; 55 function onpageshow(evt) { 56 info("Navigated back. Persisted: " + evt.persisted); 57 browser.removeEventListener('pageshow', onpageshow); 58 resolve(); 59 } 60 browser.addEventListener('pageshow', onpageshow, false); 61 ifr.contentWindow.history.back(); 62 }); 63 } 64 65 function addFrame(parentWin, name, expectOnload) { 66 let ifr = parentWin.document.createElement('iframe'); 67 parentWin.document.body.appendChild(ifr); 68 ifr.setAttribute('name', name); 69 return new Promise(resolve => { 70 // We need to append 'name' to avoid running afoul of recursive frame detection. 71 let frameURI = uri + "?name=" + name; 72 navigateFrame(ifr, frameURI).then(function() { 73 is(String(ifr.contentWindow.location), frameURI, "Successful load"); 74 is(!!ifr.contentWindow.wrappedJSObject.gFiredOnload, expectOnload, 75 "onload should only fire when scripts are enabled"); 76 resolve(); 77 }); 78 }); 79 } 80 81 function checkScriptEnabled(win, expectEnabled) { 82 win.wrappedJSObject.gFiredOnclick = false; 83 win.document.body.dispatchEvent(new win.Event('click')); 84 is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")"); 85 } 86 87 function setScriptEnabled(win, enabled) { 88 win.browsingContext.allowJavascript = enabled; 89 } 90 91 function testList(expectEnabled, win, list, idx) { 92 idx = idx || 0; 93 return new Promise(resolve => { 94 let target = list[idx] + path; 95 info("Testing scriptability for: " + target + ". expecting " + expectEnabled); 96 navigateFrame(win.frameElement, target).then(function() { 97 checkScriptEnabled(win, expectEnabled); 98 if (idx == list.length - 1) 99 resolve(); 100 else 101 testList(expectEnabled, win, list, idx + 1).then(function() { resolve(); }); 102 }); 103 }); 104 } 105 106 function testDomainPolicy(defaultScriptability, exceptions, superExceptions, 107 exempt, notExempt, set, superSet, win) { 108 // Populate our sets. 109 for (var e of exceptions) 110 set.add(makeURI(e)); 111 for (var e of superExceptions) 112 superSet.add(makeURI(e)); 113 114 return testList(defaultScriptability, win, notExempt).then(function() { 115 return testList(!defaultScriptability, win, exempt); 116 }); 117 } 118 119 function setScriptEnabledForBrowser(enabled) { 120 var prefname = "javascript.enabled"; 121 Services.prefs.setBoolPref(prefname, enabled); 122 } 123 124 function reloadFrame(frame) { 125 return new Promise(resolve => { 126 frame.addEventListener('load', function onload() { 127 resolve(); 128 frame.removeEventListener('load', onload); 129 }, false); 130 frame.contentWindow.location.reload(true); 131 }); 132 } 133 134 function go() { 135 var rootWin = rootFrame.contentWindow; 136 var chromeWin = chromeFrame.contentWindow; 137 138 // Test simple docshell enable/disable. 139 checkScriptEnabled(rootWin, true); 140 setScriptEnabled(rootWin, false); 141 checkScriptEnabled(rootWin, false); 142 setScriptEnabled(rootWin, true); 143 checkScriptEnabled(rootWin, true); 144 145 // Privileged frames are immune to docshell flags. 146 ok(chromeWin.document.nodePrincipal.isSystemPrincipal, "Sanity check for System Principal"); 147 setScriptEnabled(chromeWin, false); 148 checkScriptEnabled(chromeWin, true); 149 setScriptEnabled(chromeWin, true); 150 151 // Play around with the docshell tree and make sure everything works as 152 // we expect. 153 addFrame(rootWin, 'parent', true).then(function() { 154 checkScriptEnabled(rootWin[0], true); 155 return addFrame(rootWin[0], 'childA', true); 156 }).then(function() { 157 checkScriptEnabled(rootWin[0][0], true); 158 setScriptEnabled(rootWin[0], false); 159 checkScriptEnabled(rootWin, true); 160 checkScriptEnabled(rootWin[0], false); 161 checkScriptEnabled(rootWin[0][0], false); 162 return addFrame(rootWin[0], 'childB', false); 163 }).then(function() { 164 checkScriptEnabled(rootWin[0][1], false); 165 setScriptEnabled(rootWin[0][0], false); 166 setScriptEnabled(rootWin[0], true); 167 checkScriptEnabled(rootWin[0], true); 168 checkScriptEnabled(rootWin[0][0], false); 169 setScriptEnabled(rootWin[0][0], true); 170 171 // Flags are inherited from the parent docshell at attach time. Note that 172 // the flag itself is inherited, regardless of whether or not scripts are 173 // currently allowed on the parent (which could depend on the parent's 174 // parent). Check that. 175 checkScriptEnabled(rootWin[0][1], false); 176 setScriptEnabled(rootWin[0], false); 177 setScriptEnabled(rootWin[0][1], true); 178 return addFrame(rootWin[0][1], 'grandchild', false); 179 }).then(function() { 180 checkScriptEnabled(rootWin[0], false); 181 checkScriptEnabled(rootWin[0][1], false); 182 checkScriptEnabled(rootWin[0][1][0], false); 183 setScriptEnabled(rootWin[0], true); 184 checkScriptEnabled(rootWin[0], true); 185 checkScriptEnabled(rootWin[0][1], true); 186 checkScriptEnabled(rootWin[0][1][0], true); 187 188 // Try navigating two frames, then munging docshell scriptability, then 189 // pulling the frames out of the bfcache to make sure that flags are 190 // properly propagated to inactive inner windows. We do this both for an 191 // 'own' docshell, as well as for an ancestor docshell. 192 return navigateFrame(rootWin[0][0].frameElement, rootWin[0][0].location + '-navigated'); 193 }).then(function() { return navigateFrame(rootWin[0][1][0].frameElement, rootWin[0][1][0].location + '-navigated'); }) 194 .then(function() { 195 checkScriptEnabled(rootWin[0][0], true); 196 checkScriptEnabled(rootWin[0][1][0], true); 197 setScriptEnabled(rootWin[0][0], false); 198 setScriptEnabled(rootWin[0][1], false); 199 checkScriptEnabled(rootWin[0][0], false); 200 checkScriptEnabled(rootWin[0][1][0], false); 201 return navigateBack(rootWin[0][0].frameElement); 202 }).then(function() { return navigateBack(rootWin[0][1][0].frameElement); }) 203 .then(function() { 204 checkScriptEnabled(rootWin[0][0], false); 205 checkScriptEnabled(rootWin[0][1][0], false); 206 207 // Disable JS via the global pref pref. This is only guaranteed to have an effect 208 // for subsequent loads. 209 setScriptEnabledForBrowser(false); 210 return reloadFrame(rootFrame); 211 }).then(function() { 212 checkScriptEnabled(rootWin, false); 213 checkScriptEnabled(chromeWin, true); 214 setScriptEnabledForBrowser(true); 215 return reloadFrame(rootFrame); 216 }).then(function() { 217 checkScriptEnabled(rootWin, true); 218 219 // Play around with dynamically blocking script for a given global. 220 // This takes effect immediately. 221 Cu.blockScriptForGlobal(rootWin); 222 Cu.blockScriptForGlobal(rootWin); 223 Cu.unblockScriptForGlobal(rootWin); 224 checkScriptEnabled(rootWin, false); 225 Cu.unblockScriptForGlobal(rootWin); 226 checkScriptEnabled(rootWin, true); 227 Cu.blockScriptForGlobal(rootWin); 228 try { 229 Cu.blockScriptForGlobal(chromeWin); 230 ok(false, "Should have thrown"); 231 } catch (e) { 232 ok(/may not be disabled/.test(e), 233 "Shouldn't be able to programmatically block script for system globals"); 234 } 235 return reloadFrame(rootFrame); 236 }).then(function() { 237 checkScriptEnabled(rootWin, true); 238 239 // Test system-wide domain policy. This only takes effect for subsequently- 240 // loaded globals. 241 242 // Check the basic semantics of the sets. 243 is(ssm.domainPolicyActive, false, "not enabled"); 244 window.policy = ssm.activateDomainPolicy(); 245 ok(policy instanceof Ci.nsIDomainPolicy, "Got a policy"); 246 try { 247 ssm.activateDomainPolicy(); 248 ok(false, "Should have thrown"); 249 } catch (e) { 250 ok(true, "can't have two live domain policies"); 251 } 252 var sbRef = policy.superBlocklist; 253 isnot(sbRef, null, "superBlocklist non-null"); 254 ok(!sbRef.contains(makeURI('http://www.example.com'))); 255 sbRef.add(makeURI('http://www.example.com/foopy')); 256 ok(sbRef.contains(makeURI('http://www.example.com'))); 257 sbRef.remove(makeURI('http://www.example.com')); 258 ok(!sbRef.contains(makeURI('http://www.example.com'))); 259 sbRef.add(makeURI('http://www.example.com/foopy/this.that/')); 260 ok(sbRef.contains(makeURI('http://www.example.com/baz'))); 261 ok(!sbRef.contains(makeURI('https://www.example.com'))); 262 ok(!sbRef.contains(makeURI('https://www.example.com:88'))); 263 ok(!sbRef.contains(makeURI('http://foo.www.example.com'))); 264 ok(sbRef.containsSuperDomain(makeURI('http://foo.www.example.com'))); 265 ok(sbRef.containsSuperDomain(makeURI('http://foo.bar.www.example.com'))); 266 ok(!sbRef.containsSuperDomain(makeURI('http://foo.bar.www.exxample.com'))); 267 ok(!sbRef.containsSuperDomain(makeURI('http://example.com'))); 268 ok(!sbRef.containsSuperDomain(makeURI('http://com/this.that/'))); 269 ok(!sbRef.containsSuperDomain(makeURI('https://foo.www.example.com'))); 270 ok(sbRef.contains(makeURI('http://www.example.com'))); 271 policy.deactivate(); 272 is(ssm.domainPolicyActive, false, "back to inactive"); 273 ok(!sbRef.contains(makeURI('http://www.example.com')), 274 "Disabling domain policy clears the set"); 275 policy = ssm.activateDomainPolicy(); 276 ok(policy.superBlocklist); 277 isnot(sbRef, policy.superBlocklist, "Mint new sets each time!"); 278 policy.deactivate(); 279 is(policy.blocklist, null, "blocklist nulled out"); 280 policy = ssm.activateDomainPolicy(); 281 isnot(policy.blocklist, null, "non-null again"); 282 isnot(policy.blocklist, sbRef, "freshly minted"); 283 policy.deactivate(); 284 285 // 286 // Now, create and apply a mock-policy. We check the same policy both as 287 // a blocklist and as a allowlist. 288 // 289 290 window.testPolicy = { 291 // The policy. 292 exceptions: ['http://test1.example.com', 'http://example.com'], 293 superExceptions: ['http://test2.example.org', 'https://test1.example.com'], 294 295 // The testcases. 296 exempt: ['http://test1.example.com', 'http://example.com', 297 'http://test2.example.org', 'http://sub1.test2.example.org', 298 'https://sub1.test1.example.com'], 299 300 notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com', 301 'http://www.example.com', 'https://test2.example.com', 302 'https://example.com', 'http://test1.example.org'], 303 }; 304 305 policy = ssm.activateDomainPolicy(); 306 info("Testing Blocklist-style Domain Policy"); 307 return testDomainPolicy(true, testPolicy.exceptions, 308 testPolicy.superExceptions, testPolicy.exempt, 309 testPolicy.notExempt, policy.blocklist, 310 policy.superBlocklist, rootWin); 311 }).then(function() { 312 policy.deactivate(); 313 policy = ssm.activateDomainPolicy(); 314 info("Testing Allowlist-style Domain Policy"); 315 setScriptEnabledForBrowser(false); 316 return testDomainPolicy(false, testPolicy.exceptions, 317 testPolicy.superExceptions, testPolicy.exempt, 318 testPolicy.notExempt, policy.allowlist, 319 policy.superAllowlist, rootWin); 320 }).then(function() { 321 setScriptEnabledForBrowser(true); 322 policy.deactivate(); 323 324 SimpleTest.finish(); 325 }); 326 } 327 328 ]]> 329 </script> 330 </window>