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