tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>