1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/caps/tests/mochitest/test_disableScript.xul Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,339 @@ 1.4 +<?xml version="1.0"?> 1.5 +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> 1.6 +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> 1.7 +<!-- 1.8 +https://bugzilla.mozilla.org/show_bug.cgi?id=840488 1.9 +--> 1.10 +<window title="Mozilla Bug 840488" 1.11 + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 1.12 + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> 1.13 + 1.14 + <!-- test results are displayed in the html:body --> 1.15 + <body xmlns="http://www.w3.org/1999/xhtml"> 1.16 + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=840488" 1.17 + target="_blank">Mozilla Bug 840488</a> 1.18 + </body> 1.19 + 1.20 + <iframe id="root" name="root" type="content"/> 1.21 + <iframe id="chromeFrame" name="chromeFrame" type="content"/> 1.22 + 1.23 + <!-- test code goes here --> 1.24 + <script type="application/javascript"> 1.25 + <![CDATA[ 1.26 + 1.27 + /** Test for all the different ways that script can be disabled for a given global. **/ 1.28 + 1.29 + SimpleTest.waitForExplicitFinish(); 1.30 + const Cu = Components.utils; 1.31 + const Ci = Components.interfaces; 1.32 + Cu.import("resource://gre/modules/Promise.jsm"); 1.33 + Cu.import("resource://gre/modules/Services.jsm"); 1.34 + const ssm = Services.scriptSecurityManager; 1.35 + function makeURI(uri) { return Services.io.newURI(uri, null, null); } 1.36 + const path = "/tests/caps/tests/mochitest/file_disableScript.html"; 1.37 + const uri = "http://www.example.com" + path; 1.38 + var rootFrame = document.getElementById('root'); 1.39 + var chromeFrame = document.getElementById('chromeFrame'); 1.40 + navigateFrame(rootFrame, uri + "?name=rootframe").then(function() { 1.41 + navigateFrame(chromeFrame, "file_disableScript.html").then(go); 1.42 + }); 1.43 + 1.44 + function navigateFrame(ifr, src) { 1.45 + let deferred = Promise.defer(); 1.46 + function onload() { 1.47 + ifr.removeEventListener('load', onload); 1.48 + deferred.resolve(); 1.49 + } 1.50 + ifr.addEventListener('load', onload, false); 1.51 + ifr.setAttribute('src', src); 1.52 + return deferred.promise; 1.53 + } 1.54 + 1.55 + function navigateBack(ifr) { 1.56 + let deferred = Promise.defer(); 1.57 + 1.58 + // pageshow events don't fire on the iframe element, so we need to use the 1.59 + // chrome event handler for the docshell. 1.60 + var browser = ifr.contentWindow 1.61 + .QueryInterface(Ci.nsIInterfaceRequestor) 1.62 + .getInterface(Ci.nsIWebNavigation) 1.63 + .QueryInterface(Ci.nsIDocShell) 1.64 + .chromeEventHandler; 1.65 + function onpageshow(evt) { 1.66 + info("Navigated back. Persisted: " + evt.persisted); 1.67 + browser.removeEventListener('pageshow', onpageshow); 1.68 + deferred.resolve(); 1.69 + } 1.70 + browser.addEventListener('pageshow', onpageshow, false); 1.71 + ifr.contentWindow.history.back(); 1.72 + return deferred.promise; 1.73 + } 1.74 + 1.75 + function addFrame(parentWin, name, expectOnload) { 1.76 + let ifr = parentWin.document.createElement('iframe'); 1.77 + parentWin.document.body.appendChild(ifr); 1.78 + ifr.setAttribute('name', name); 1.79 + let deferred = Promise.defer(); 1.80 + // We need to append 'name' to avoid running afoul of recursive frame detection. 1.81 + let frameURI = uri + "?name=" + name; 1.82 + navigateFrame(ifr, frameURI).then(function() { 1.83 + is(ifr.contentWindow.location, frameURI, "Successful load"); 1.84 + is(!!ifr.contentWindow.wrappedJSObject.gFiredOnload, expectOnload, 1.85 + "onload should only fire when scripts are enabled"); 1.86 + deferred.resolve(); 1.87 + }); 1.88 + return deferred.promise; 1.89 + } 1.90 + 1.91 + function checkScriptEnabled(win, expectEnabled) { 1.92 + win.wrappedJSObject.gFiredOnclick = false; 1.93 + win.document.body.dispatchEvent(new win.Event('click')); 1.94 + is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")"); 1.95 + } 1.96 + 1.97 + function setScriptEnabledForDocShell(win, enabled) { 1.98 + win.QueryInterface(Ci.nsIInterfaceRequestor) 1.99 + .getInterface(Ci.nsIDocShell) 1.100 + .allowJavascript = enabled; 1.101 + } 1.102 + 1.103 + function testList(expectEnabled, win, list, idx) { 1.104 + let idx = idx || 0; 1.105 + let deferred = Promise.defer(); 1.106 + let target = list[idx] + path; 1.107 + info("Testing scriptability for: " + target + ". expecting " + expectEnabled); 1.108 + navigateFrame(win.frameElement, target).then(function() { 1.109 + checkScriptEnabled(win, expectEnabled); 1.110 + if (idx == list.length - 1) 1.111 + deferred.resolve(); 1.112 + else 1.113 + testList(expectEnabled, win, list, idx + 1).then(function() { deferred.resolve(); }); 1.114 + }); 1.115 + return deferred.promise; 1.116 + } 1.117 + 1.118 + function testDomainPolicy(defaultScriptability, exceptions, superExceptions, 1.119 + exempt, notExempt, set, superSet, win) { 1.120 + // Populate our sets. 1.121 + for (var e of exceptions) 1.122 + set.add(makeURI(e)); 1.123 + for (var e of superExceptions) 1.124 + superSet.add(makeURI(e)); 1.125 + 1.126 + return testList(defaultScriptability, win, notExempt).then(function() { 1.127 + return testList(!defaultScriptability, win, exempt); 1.128 + }); 1.129 + } 1.130 + 1.131 + function setScriptEnabledForBrowser(enabled) { 1.132 + var prefname = "javascript.enabled"; 1.133 + Services.prefs.setBoolPref(prefname, enabled); 1.134 + } 1.135 + 1.136 + function reloadFrame(frame) { 1.137 + let deferred = Promise.defer(); 1.138 + frame.addEventListener('load', function onload() { 1.139 + deferred.resolve(); 1.140 + frame.removeEventListener('load', onload); 1.141 + }, false); 1.142 + frame.contentWindow.location.reload(true); 1.143 + return deferred.promise; 1.144 + } 1.145 + 1.146 + function go() { 1.147 + var rootWin = rootFrame.contentWindow; 1.148 + var chromeWin = chromeFrame.contentWindow; 1.149 + 1.150 + // Test simple docshell enable/disable. 1.151 + checkScriptEnabled(rootWin, true); 1.152 + setScriptEnabledForDocShell(rootWin, false); 1.153 + checkScriptEnabled(rootWin, false); 1.154 + setScriptEnabledForDocShell(rootWin, true); 1.155 + checkScriptEnabled(rootWin, true); 1.156 + 1.157 + // Privileged frames are immune to docshell flags. 1.158 + ok(ssm.isSystemPrincipal(chromeWin.document.nodePrincipal), "Sanity check for System Principal"); 1.159 + setScriptEnabledForDocShell(chromeWin, false); 1.160 + checkScriptEnabled(chromeWin, true); 1.161 + setScriptEnabledForDocShell(chromeWin, true); 1.162 + 1.163 + // Play around with the docshell tree and make sure everything works as 1.164 + // we expect. 1.165 + addFrame(rootWin, 'parent', true).then(function() { 1.166 + checkScriptEnabled(rootWin[0], true); 1.167 + return addFrame(rootWin[0], 'childA', true); 1.168 + }).then(function() { 1.169 + checkScriptEnabled(rootWin[0][0], true); 1.170 + setScriptEnabledForDocShell(rootWin[0], false); 1.171 + checkScriptEnabled(rootWin, true); 1.172 + checkScriptEnabled(rootWin[0], false); 1.173 + checkScriptEnabled(rootWin[0][0], false); 1.174 + return addFrame(rootWin[0], 'childB', false); 1.175 + }).then(function() { 1.176 + checkScriptEnabled(rootWin[0][1], false); 1.177 + setScriptEnabledForDocShell(rootWin[0][0], false); 1.178 + setScriptEnabledForDocShell(rootWin[0], true); 1.179 + checkScriptEnabled(rootWin[0], true); 1.180 + checkScriptEnabled(rootWin[0][0], false); 1.181 + setScriptEnabledForDocShell(rootWin[0][0], true); 1.182 + 1.183 + // Flags are inherited from the parent docshell at attach time. Note that 1.184 + // the flag itself is inherited, regardless of whether or not scripts are 1.185 + // currently allowed on the parent (which could depend on the parent's 1.186 + // parent). Check that. 1.187 + checkScriptEnabled(rootWin[0][1], false); 1.188 + setScriptEnabledForDocShell(rootWin[0], false); 1.189 + setScriptEnabledForDocShell(rootWin[0][1], true); 1.190 + return addFrame(rootWin[0][1], 'grandchild', false); 1.191 + }).then(function() { 1.192 + checkScriptEnabled(rootWin[0], false); 1.193 + checkScriptEnabled(rootWin[0][1], false); 1.194 + checkScriptEnabled(rootWin[0][1][0], false); 1.195 + setScriptEnabledForDocShell(rootWin[0], true); 1.196 + checkScriptEnabled(rootWin[0], true); 1.197 + checkScriptEnabled(rootWin[0][1], true); 1.198 + checkScriptEnabled(rootWin[0][1][0], true); 1.199 + 1.200 + // Try navigating two frames, then munging docshell scriptability, then 1.201 + // pulling the frames out of the bfcache to make sure that flags are 1.202 + // properly propagated to inactive inner windows. We do this both for an 1.203 + // 'own' docshell, as well as for an ancestor docshell. 1.204 + return navigateFrame(rootWin[0][0].frameElement, rootWin[0][0].location + '-navigated'); 1.205 + }).then(function() { return navigateFrame(rootWin[0][1][0].frameElement, rootWin[0][1][0].location + '-navigated'); }) 1.206 + .then(function() { 1.207 + checkScriptEnabled(rootWin[0][0], true); 1.208 + checkScriptEnabled(rootWin[0][1][0], true); 1.209 + setScriptEnabledForDocShell(rootWin[0][0], false); 1.210 + setScriptEnabledForDocShell(rootWin[0][1], false); 1.211 + checkScriptEnabled(rootWin[0][0], false); 1.212 + checkScriptEnabled(rootWin[0][1][0], false); 1.213 + return navigateBack(rootWin[0][0].frameElement); 1.214 + }).then(function() { return navigateBack(rootWin[0][1][0].frameElement); }) 1.215 + .then(function() { 1.216 + checkScriptEnabled(rootWin[0][0], false); 1.217 + checkScriptEnabled(rootWin[0][1][0], false); 1.218 + 1.219 + // Disable JS via the global pref pref. This is only guaranteed to have an effect 1.220 + // for subsequent loads. 1.221 + setScriptEnabledForBrowser(false); 1.222 + return reloadFrame(rootFrame); 1.223 + }).then(function() { 1.224 + checkScriptEnabled(rootWin, false); 1.225 + checkScriptEnabled(chromeWin, true); 1.226 + setScriptEnabledForBrowser(true); 1.227 + return reloadFrame(rootFrame); 1.228 + }).then(function() { 1.229 + checkScriptEnabled(rootWin, true); 1.230 + 1.231 + // Play around with dynamically blocking script for a given global. 1.232 + // This takes effect immediately. 1.233 + Cu.blockScriptForGlobal(rootWin); 1.234 + Cu.blockScriptForGlobal(rootWin); 1.235 + Cu.unblockScriptForGlobal(rootWin); 1.236 + checkScriptEnabled(rootWin, false); 1.237 + Cu.unblockScriptForGlobal(rootWin); 1.238 + checkScriptEnabled(rootWin, true); 1.239 + Cu.blockScriptForGlobal(rootWin); 1.240 + try { 1.241 + Cu.blockScriptForGlobal(chromeWin); 1.242 + ok(false, "Should have thrown"); 1.243 + } catch (e) { 1.244 + ok(/may not be disabled/.test(e), 1.245 + "Shouldn't be able to programmatically block script for system globals"); 1.246 + } 1.247 + return reloadFrame(rootFrame); 1.248 + }).then(function() { 1.249 + checkScriptEnabled(rootWin, true); 1.250 + 1.251 + // Test system-wide domain policy. This only takes effect for subsequently- 1.252 + // loaded globals. 1.253 + 1.254 + // Check the basic semantics of the sets. 1.255 + is(ssm.domainPolicyActive, false, "not enabled"); 1.256 + window.policy = ssm.activateDomainPolicy(); 1.257 + ok(policy instanceof Ci.nsIDomainPolicy, "Got a policy"); 1.258 + try { 1.259 + ssm.activateDomainPolicy(); 1.260 + ok(false, "Should have thrown"); 1.261 + } catch (e) { 1.262 + ok(true, "can't have two live domain policies"); 1.263 + } 1.264 + var sbRef = policy.superBlacklist; 1.265 + isnot(sbRef, null, "superBlacklist non-null"); 1.266 + ok(!sbRef.contains(makeURI('http://www.example.com'))); 1.267 + sbRef.add(makeURI('http://www.example.com/foopy')); 1.268 + ok(sbRef.contains(makeURI('http://www.example.com'))); 1.269 + sbRef.remove(makeURI('http://www.example.com')); 1.270 + ok(!sbRef.contains(makeURI('http://www.example.com'))); 1.271 + sbRef.add(makeURI('http://www.example.com/foopy/this.that/')); 1.272 + ok(sbRef.contains(makeURI('http://www.example.com/baz'))); 1.273 + ok(!sbRef.contains(makeURI('https://www.example.com'))); 1.274 + ok(!sbRef.contains(makeURI('https://www.example.com:88'))); 1.275 + ok(!sbRef.contains(makeURI('http://foo.www.example.com'))); 1.276 + ok(sbRef.containsSuperDomain(makeURI('http://foo.www.example.com'))); 1.277 + ok(sbRef.containsSuperDomain(makeURI('http://foo.bar.www.example.com'))); 1.278 + ok(!sbRef.containsSuperDomain(makeURI('http://foo.bar.www.exxample.com'))); 1.279 + ok(!sbRef.containsSuperDomain(makeURI('http://example.com'))); 1.280 + ok(!sbRef.containsSuperDomain(makeURI('http://com/this.that/'))); 1.281 + ok(!sbRef.containsSuperDomain(makeURI('https://foo.www.example.com'))); 1.282 + ok(sbRef.contains(makeURI('http://www.example.com'))); 1.283 + policy.deactivate(); 1.284 + is(ssm.domainPolicyActive, false, "back to inactive"); 1.285 + ok(!sbRef.contains(makeURI('http://www.example.com')), 1.286 + "Disabling domain policy clears the set"); 1.287 + policy = ssm.activateDomainPolicy(); 1.288 + ok(policy.superBlacklist); 1.289 + isnot(sbRef, policy.superBlacklist, "Mint new sets each time!"); 1.290 + policy.deactivate(); 1.291 + is(policy.blacklist, null, "blacklist nulled out"); 1.292 + policy = ssm.activateDomainPolicy(); 1.293 + isnot(policy.blacklist, null, "non-null again"); 1.294 + isnot(policy.blacklist, sbRef, "freshly minted"); 1.295 + policy.deactivate(); 1.296 + 1.297 + // 1.298 + // Now, create and apply a mock-policy. We check the same policy both as 1.299 + // a blacklist and as a whitelist. 1.300 + // 1.301 + 1.302 + window.testPolicy = { 1.303 + // The policy. 1.304 + exceptions: ['http://test1.example.com', 'http://example.com'], 1.305 + superExceptions: ['http://test2.example.org', 'https://test1.example.com'], 1.306 + 1.307 + // The testcases. 1.308 + exempt: ['http://test1.example.com', 'http://example.com', 1.309 + 'http://test2.example.org', 'http://sub1.test2.example.org', 1.310 + 'https://sub1.test1.example.com'], 1.311 + 1.312 + notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com', 1.313 + 'http://www.example.com', 'https://test2.example.com', 1.314 + 'https://example.com', 'http://test1.example.org'], 1.315 + }; 1.316 + 1.317 + policy = ssm.activateDomainPolicy(); 1.318 + info("Testing Blacklist-style Domain Policy"); 1.319 + return testDomainPolicy(true, testPolicy.exceptions, 1.320 + testPolicy.superExceptions, testPolicy.exempt, 1.321 + testPolicy.notExempt, policy.blacklist, 1.322 + policy.superBlacklist, rootWin); 1.323 + }).then(function() { 1.324 + policy.deactivate(); 1.325 + policy = ssm.activateDomainPolicy(); 1.326 + info("Testing Whitelist-style Domain Policy"); 1.327 + setScriptEnabledForBrowser(false); 1.328 + return testDomainPolicy(false, testPolicy.exceptions, 1.329 + testPolicy.superExceptions, testPolicy.exempt, 1.330 + testPolicy.notExempt, policy.whitelist, 1.331 + policy.superWhitelist, rootWin); 1.332 + }).then(function() { 1.333 + setScriptEnabledForBrowser(true); 1.334 + policy.deactivate(); 1.335 + 1.336 + SimpleTest.finish(); 1.337 + }); 1.338 + } 1.339 + 1.340 + ]]> 1.341 + </script> 1.342 +</window>