tor-browser

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

mixedContentTest.js (6162B)


      1 "use strict";
      2 
      3 /**
      4 * Helper script for mixed content testing. It opens a new top-level window
      5 * from a secure origin and '?runtest' query. That tells us to run the test
      6 * body, function runTest(). Then we wait for call of finish(). On its first
      7 * call it loads helper page 'backward.html' that immediately navigates
      8 * back to the test secure test. This checks the bfcache. We got second call
      9 * to onload and this time we call afterNavigationTest() function to let the
     10 * test check security state after re-navigation back. Then we again wait for
     11 * finish() call, that this time finishes completelly the test.
     12 */
     13 
     14 // Tells the framework if to load the test in an insecure page (http://)
     15 var loadAsInsecure = false;
     16 // Set true to bypass the navigation forward/back test
     17 var bypassNavigationTest = false;
     18 // Set true to do forward/back navigation over an http:// page, test state leaks
     19 var navigateToInsecure = false;
     20 // Open the test in two separate windows, test requests sharing among windows
     21 var openTwoWindows = false;
     22 // Override the name of the test page to load, useful e.g. to prevent load
     23 // of images or other content before the test starts; this is actually
     24 // a 'redirect' to a different test page.
     25 var testPage = "";
     26 // Assign a function to this variable to have a clean up at the end
     27 var testCleanUp = null;
     28 // Contains mixed active content that needs to load to run the test
     29 var hasMixedActiveContent = false;
     30 
     31 // Internal variables
     32 var _windowCount = 0;
     33 
     34 window.onload = async function onLoad() {
     35  if (location.search == "?runtest") {
     36    try {
     37      if (history.length == 1) {
     38        // Each test that includes this helper file is supposed to define
     39        // runTest(). See the top level comment.
     40        await runTest(); // eslint-disable-line no-undef
     41      } else {
     42        // Each test that includes this helper file is supposed to define
     43        // afterNavigationTest(). See the top level comment.
     44        await afterNavigationTest(); // eslint-disable-line no-undef
     45      }
     46    } catch (ex) {
     47      ok(false, "Exception thrown during test: " + ex);
     48      finish();
     49    }
     50  } else {
     51    window.addEventListener("message", onMessageReceived);
     52 
     53    let secureTestLocation = loadAsInsecure
     54      ? "http://example.com"
     55      : "https://example.com";
     56    secureTestLocation += location.pathname;
     57    if (testPage != "") {
     58      let array = secureTestLocation.split("/");
     59      array.pop();
     60      array.push(testPage);
     61      secureTestLocation = array.join("/");
     62    }
     63    secureTestLocation += "?runtest";
     64 
     65    if (hasMixedActiveContent) {
     66      SpecialPowers.pushPrefEnv(
     67        { set: [["security.mixed_content.block_active_content", false]] },
     68        null
     69      );
     70    }
     71    if (openTwoWindows) {
     72      _windowCount = 2;
     73      window.open(secureTestLocation, "_new1", "");
     74      window.open(secureTestLocation, "_new2", "");
     75    } else {
     76      _windowCount = 1;
     77      window.open(secureTestLocation);
     78    }
     79  }
     80 };
     81 
     82 function onMessageReceived(event) {
     83  switch (event.data) {
     84    // Indication of all test parts finish (from any of the frames)
     85    case "done":
     86      if (--_windowCount == 0) {
     87        if (testCleanUp) {
     88          testCleanUp();
     89        }
     90        if (hasMixedActiveContent) {
     91          SpecialPowers.popPrefEnv(null);
     92        }
     93 
     94        SimpleTest.finish();
     95      }
     96      break;
     97 
     98    // Any other message is an error or success message of a test.
     99    default:
    100      SimpleTest.ok(!event.data.match(/^FAILURE/), event.data);
    101      break;
    102  }
    103 }
    104 
    105 function postMsg(message) {
    106  opener.postMessage(message, "http://mochi.test:8888");
    107 }
    108 
    109 function finish() {
    110  if (history.length == 1 && !bypassNavigationTest) {
    111    window.setTimeout(() => {
    112      window.location.assign(
    113        navigateToInsecure
    114          ? "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html"
    115          : "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html"
    116      );
    117    }, 0);
    118  } else {
    119    postMsg("done");
    120    window.close();
    121  }
    122 }
    123 
    124 function ok(a, message) {
    125  if (!a) {
    126    postMsg("FAILURE: " + message);
    127  } else {
    128    postMsg(message);
    129  }
    130 }
    131 
    132 function is(a, b, message) {
    133  if (a != b) {
    134    postMsg(`FAILURE: ${message}, expected ${b} got ${a}`);
    135  } else {
    136    postMsg(`${message}, expected ${b} got ${a}`);
    137  }
    138 }
    139 
    140 async function isSecurityState(expectedState, message, test) {
    141  if (!test) {
    142    test = ok;
    143  }
    144 
    145  let state = await SpecialPowers.getSecurityState(window);
    146 
    147  let isInsecure =
    148    state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_INSECURE;
    149  let isBroken =
    150    state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_BROKEN;
    151  let isEV =
    152    state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
    153 
    154  let gotState = "secure";
    155  if (isInsecure) {
    156    gotState = "insecure";
    157  } else if (isBroken) {
    158    gotState = "broken";
    159  } else if (isEV) {
    160    gotState = "EV";
    161  }
    162 
    163  test(
    164    gotState == expectedState,
    165    (message || "") + ", expected " + expectedState + " got " + gotState
    166  );
    167 
    168  switch (expectedState) {
    169    case "insecure":
    170      test(
    171        isInsecure && !isBroken && !isEV,
    172        "for 'insecure' excpected flags [1,0,0], " + (message || "")
    173      );
    174      break;
    175    case "broken":
    176      test(
    177        !isInsecure && isBroken && !isEV,
    178        "for 'broken' expected  flags [0,1,0], " + (message || "")
    179      );
    180      break;
    181    case "secure":
    182      test(
    183        !isInsecure && !isBroken && !isEV,
    184        "for 'secure' expected flags [0,0,0], " + (message || "")
    185      );
    186      break;
    187    case "EV":
    188      test(
    189        !isInsecure && !isBroken && isEV,
    190        "for 'EV' expected flags [0,0,1], " + (message || "")
    191      );
    192      break;
    193    default:
    194      throw new Error("Invalid isSecurityState state");
    195  }
    196 }
    197 
    198 function waitForSecurityState(expectedState, callback) {
    199  let roundsLeft = 200; // Wait for 20 seconds (=200*100ms)
    200  let interval = window.setInterval(async () => {
    201    await isSecurityState(expectedState, "", isok => {
    202      if (isok) {
    203        roundsLeft = 0;
    204      }
    205    });
    206    if (!roundsLeft--) {
    207      window.clearInterval(interval);
    208      callback();
    209    }
    210  }, 100);
    211 }