test_disableScript.xul 14 KB

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