tor-browser

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

head.js (13272B)


      1 function openIdentityPopup() {
      2  gIdentityHandler._initializePopup();
      3  let mainView = document.getElementById("identity-popup-mainView");
      4  let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
      5  gIdentityHandler._identityIconBox.click();
      6  return viewShown;
      7 }
      8 
      9 function openPermissionPopup() {
     10  gPermissionPanel._initializePopup();
     11  let mainView = document.getElementById("permission-popup-mainView");
     12  let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
     13  gPermissionPanel.openPopup();
     14  return viewShown;
     15 }
     16 
     17 function getIdentityMode(aWindow = window) {
     18  return aWindow.document.getElementById("identity-box").className;
     19 }
     20 
     21 // Compares the security state of the page with what is expected
     22 function isSecurityState(browser, expectedState) {
     23  let ui = browser.securityUI;
     24  if (!ui) {
     25    ok(false, "No security UI to get the security state");
     26    return;
     27  }
     28 
     29  const wpl = Ci.nsIWebProgressListener;
     30 
     31  // determine the security state
     32  let isSecure = ui.state & wpl.STATE_IS_SECURE;
     33  let isBroken = ui.state & wpl.STATE_IS_BROKEN;
     34  let isInsecure = ui.state & wpl.STATE_IS_INSECURE;
     35 
     36  let actualState;
     37  if (isSecure && !(isBroken || isInsecure)) {
     38    actualState = "secure";
     39  } else if (isBroken && !(isSecure || isInsecure)) {
     40    actualState = "broken";
     41  } else if (isInsecure && !(isSecure || isBroken)) {
     42    actualState = "insecure";
     43  } else {
     44    actualState = "unknown";
     45  }
     46 
     47  is(
     48    expectedState,
     49    actualState,
     50    "Expected state " +
     51      expectedState +
     52      " and the actual state is " +
     53      actualState +
     54      "."
     55  );
     56 }
     57 
     58 /**
     59 * Test the state of the identity box and control center to make
     60 * sure they are correctly showing the expected mixed content states.
     61 *
     62 * Note: The checks are done synchronously, but new code should wait on the
     63 * returned Promise object to ensure the identity panel has closed.
     64 * Bug 1221114 is filed to fix the existing code.
     65 *
     66 * @param tabbrowser
     67 * @param Object states
     68 *        MUST include the following properties:
     69 *        {
     70 *           activeLoaded: true|false,
     71 *           activeBlocked: true|false,
     72 *           passiveLoaded: true|false,
     73 *        }
     74 *
     75 * @returns {Promise<void>}
     76 *   Resolves when the operation has finished and the identity panel has closed.
     77 */
     78 async function assertMixedContentBlockingState(tabbrowser, states = {}) {
     79  if (
     80    !tabbrowser ||
     81    !("activeLoaded" in states) ||
     82    !("activeBlocked" in states) ||
     83    !("passiveLoaded" in states)
     84  ) {
     85    throw new Error(
     86      "assertMixedContentBlockingState requires a browser and a states object"
     87    );
     88  }
     89 
     90  let { passiveLoaded, activeLoaded, activeBlocked } = states;
     91  let { gIdentityHandler } = tabbrowser.ownerGlobal;
     92  let doc = tabbrowser.ownerDocument;
     93  let identityBox = gIdentityHandler._identityBox;
     94  let classList = identityBox.classList;
     95  let identityIcon = doc.getElementById("identity-icon");
     96  let identityIconImage = tabbrowser.ownerGlobal
     97    .getComputedStyle(identityIcon)
     98    .getPropertyValue("list-style-image");
     99 
    100  let stateSecure =
    101    gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_SECURE;
    102  let stateBroken =
    103    gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
    104  let stateInsecure =
    105    gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_INSECURE;
    106  let stateActiveBlocked =
    107    gIdentityHandler._state &
    108    Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
    109  let stateActiveLoaded =
    110    gIdentityHandler._state &
    111    Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT;
    112  let statePassiveLoaded =
    113    gIdentityHandler._state &
    114    Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT;
    115 
    116  is(
    117    activeBlocked,
    118    !!stateActiveBlocked,
    119    "Expected state for activeBlocked matches UI state"
    120  );
    121  is(
    122    activeLoaded,
    123    !!stateActiveLoaded,
    124    "Expected state for activeLoaded matches UI state"
    125  );
    126  is(
    127    passiveLoaded,
    128    !!statePassiveLoaded,
    129    "Expected state for passiveLoaded matches UI state"
    130  );
    131 
    132  if (stateInsecure) {
    133    // HTTP request, there should be a broken padlock shown always.
    134    ok(classList.contains("notSecure"), "notSecure on HTTP page");
    135    ok(
    136      !BrowserTestUtils.isHidden(identityIcon),
    137      "information icon should be visible"
    138    );
    139 
    140    ok(!classList.contains("mixedActiveContent"), "No MCB icon on HTTP page");
    141    ok(!classList.contains("mixedActiveBlocked"), "No MCB icon on HTTP page");
    142    ok(!classList.contains("mixedDisplayContent"), "No MCB icon on HTTP page");
    143    ok(
    144      !classList.contains("mixedDisplayContentLoadedActiveBlocked"),
    145      "No MCB icon on HTTP page"
    146    );
    147  } else {
    148    // Make sure the identity box UI has the correct mixedcontent states and icons
    149    is(
    150      classList.contains("mixedActiveContent"),
    151      activeLoaded,
    152      "identityBox has expected class for activeLoaded"
    153    );
    154    is(
    155      classList.contains("mixedActiveBlocked"),
    156      activeBlocked && !passiveLoaded,
    157      "identityBox has expected class for activeBlocked && !passiveLoaded"
    158    );
    159    is(
    160      classList.contains("mixedDisplayContent"),
    161      passiveLoaded && !(activeLoaded || activeBlocked),
    162      "identityBox has expected class for passiveLoaded && !(activeLoaded || activeBlocked)"
    163    );
    164    is(
    165      classList.contains("mixedDisplayContentLoadedActiveBlocked"),
    166      passiveLoaded && activeBlocked,
    167      "identityBox has expected class for passiveLoaded && activeBlocked"
    168    );
    169 
    170    ok(
    171      !BrowserTestUtils.isHidden(identityIcon),
    172      "information icon should be visible"
    173    );
    174    if (activeLoaded) {
    175      is(
    176        identityIconImage,
    177        'url("chrome://global/skin/icons/security-broken.svg")',
    178        "Using active loaded icon"
    179      );
    180    }
    181    if (activeBlocked && !passiveLoaded) {
    182      is(
    183        identityIconImage,
    184        'url("chrome://global/skin/icons/security.svg")',
    185        "Using active blocked icon"
    186      );
    187    }
    188    if (passiveLoaded && !(activeLoaded || activeBlocked)) {
    189      is(
    190        identityIconImage,
    191        'url("chrome://global/skin/icons/security-warning.svg")',
    192        "Using passive loaded icon"
    193      );
    194    }
    195    if (passiveLoaded && activeBlocked) {
    196      is(
    197        identityIconImage,
    198        'url("chrome://global/skin/icons/security-warning.svg")',
    199        "Using active blocked and passive loaded icon"
    200      );
    201    }
    202  }
    203 
    204  // Make sure the identity popup has the correct mixedcontent states
    205  let promisePanelOpen = BrowserTestUtils.waitForEvent(
    206    tabbrowser.ownerGlobal,
    207    "popupshown",
    208    true,
    209    event => event.target == gIdentityHandler._identityPopup
    210  );
    211  gIdentityHandler._identityIconBox.click();
    212  await promisePanelOpen;
    213  let popupAttr =
    214    doc.getElementById("identity-popup").getAttribute("mixedcontent") || "";
    215  let bodyAttr =
    216    doc
    217      .getElementById("identity-popup-securityView-extended-info")
    218      .getAttribute("mixedcontent") || "";
    219 
    220  is(
    221    popupAttr.includes("active-loaded"),
    222    activeLoaded,
    223    "identity-popup has expected attr for activeLoaded"
    224  );
    225  is(
    226    bodyAttr.includes("active-loaded"),
    227    activeLoaded,
    228    "securityView-body has expected attr for activeLoaded"
    229  );
    230 
    231  is(
    232    popupAttr.includes("active-blocked"),
    233    activeBlocked,
    234    "identity-popup has expected attr for activeBlocked"
    235  );
    236  is(
    237    bodyAttr.includes("active-blocked"),
    238    activeBlocked,
    239    "securityView-body has expected attr for activeBlocked"
    240  );
    241 
    242  is(
    243    popupAttr.includes("passive-loaded"),
    244    passiveLoaded,
    245    "identity-popup has expected attr for passiveLoaded"
    246  );
    247  is(
    248    bodyAttr.includes("passive-loaded"),
    249    passiveLoaded,
    250    "securityView-body has expected attr for passiveLoaded"
    251  );
    252 
    253  // Make sure the correct icon is visible in the Control Center.
    254  // This logic is controlled with CSS, so this helps prevent regressions there.
    255  let securityViewBG = tabbrowser.ownerGlobal
    256    .getComputedStyle(
    257      document
    258        .getElementById("identity-popup-securityView")
    259        .getElementsByClassName("identity-popup-security-connection")[0]
    260    )
    261    .getPropertyValue("list-style-image");
    262  let securityContentBG = tabbrowser.ownerGlobal
    263    .getComputedStyle(
    264      document
    265        .getElementById("identity-popup-mainView")
    266        .getElementsByClassName("identity-popup-security-connection")[0]
    267    )
    268    .getPropertyValue("list-style-image");
    269 
    270  if (stateInsecure) {
    271    is(
    272      securityViewBG,
    273      'url("chrome://global/skin/icons/security-broken.svg")',
    274      "CC using 'not secure' icon"
    275    );
    276    is(
    277      securityContentBG,
    278      'url("chrome://global/skin/icons/security-broken.svg")',
    279      "CC using 'not secure' icon"
    280    );
    281  }
    282 
    283  if (stateSecure) {
    284    is(
    285      securityViewBG,
    286      'url("chrome://global/skin/icons/security.svg")',
    287      "CC using secure icon"
    288    );
    289    is(
    290      securityContentBG,
    291      'url("chrome://global/skin/icons/security.svg")',
    292      "CC using secure icon"
    293    );
    294  }
    295 
    296  if (stateBroken) {
    297    if (activeLoaded) {
    298      is(
    299        securityViewBG,
    300        'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
    301        "CC using active loaded icon"
    302      );
    303      is(
    304        securityContentBG,
    305        'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")',
    306        "CC using active loaded icon"
    307      );
    308    } else if (activeBlocked || passiveLoaded) {
    309      is(
    310        securityViewBG,
    311        'url("chrome://global/skin/icons/security-warning.svg")',
    312        "CC using degraded icon"
    313      );
    314      is(
    315        securityContentBG,
    316        'url("chrome://global/skin/icons/security-warning.svg")',
    317        "CC using degraded icon"
    318      );
    319    } else {
    320      // There is a case here with weak ciphers, but no bc tests are handling this yet.
    321      is(
    322        securityViewBG,
    323        'url("chrome://global/skin/icons/security.svg")',
    324        "CC using degraded icon"
    325      );
    326      is(
    327        securityContentBG,
    328        'url("chrome://global/skin/icons/security.svg")',
    329        "CC using degraded icon"
    330      );
    331    }
    332  }
    333 
    334  if (activeLoaded || activeBlocked || passiveLoaded) {
    335    let promiseViewShown = BrowserTestUtils.waitForEvent(
    336      gIdentityHandler._identityPopup,
    337      "ViewShown"
    338    );
    339    doc.getElementById("identity-popup-security-button").click();
    340    await promiseViewShown;
    341    is(
    342      Array.prototype.filter.call(
    343        doc
    344          .getElementById("identity-popup-securityView")
    345          .querySelectorAll(".identity-popup-mcb-learn-more"),
    346        element => !BrowserTestUtils.isHidden(element)
    347      ).length,
    348      1,
    349      "The 'Learn more' link should be visible once."
    350    );
    351  }
    352 
    353  if (gIdentityHandler._identityPopup.state != "closed") {
    354    let hideEvent = BrowserTestUtils.waitForEvent(
    355      gIdentityHandler._identityPopup,
    356      "popuphidden"
    357    );
    358    info("Hiding identity popup");
    359    gIdentityHandler._identityPopup.hidePopup();
    360    await hideEvent;
    361  }
    362 }
    363 
    364 async function loadBadCertPage(url, feltPrivacyV1) {
    365  const loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
    366  const loadFlagsSkipCache =
    367    Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
    368    Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
    369  BrowserTestUtils.startLoadingURIString(
    370    gBrowser.selectedBrowser,
    371    url,
    372    loadFlagsSkipCache
    373  );
    374  await loaded;
    375  await SpecialPowers.spawn(
    376    gBrowser.selectedBrowser,
    377    [feltPrivacyV1],
    378    async prefFeltPrivacyV1 => {
    379      if (prefFeltPrivacyV1) {
    380        const netErrorCard =
    381          content.document.querySelector("net-error-card").wrappedJSObject;
    382        await netErrorCard.getUpdateComplete();
    383        EventUtils.synthesizeMouseAtCenter(
    384          netErrorCard.advancedButton,
    385          {},
    386          content
    387        );
    388        await ContentTaskUtils.waitForCondition(() => {
    389          return (
    390            netErrorCard.exceptionButton &&
    391            !netErrorCard.exceptionButton.disabled
    392          );
    393        }, "Waiting for exception button");
    394        netErrorCard.exceptionButton.scrollIntoView(true);
    395        EventUtils.synthesizeMouseAtCenter(
    396          netErrorCard.exceptionButton,
    397          {},
    398          content
    399        );
    400      } else {
    401        const advancedButton =
    402          content.document.getElementById("advancedButton");
    403        advancedButton.scrollIntoView(true);
    404        EventUtils.synthesizeMouseAtCenter(advancedButton, {}, content);
    405        const exceptionButton = content.document.getElementById(
    406          "exceptionDialogButton"
    407        );
    408        await ContentTaskUtils.waitForCondition(() => {
    409          return exceptionButton && !exceptionButton.disabled;
    410        }, "Waiting for exception button");
    411        exceptionButton.scrollIntoView(true);
    412        EventUtils.synthesizeMouseAtCenter(exceptionButton, {}, content);
    413      }
    414    }
    415  );
    416  await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
    417 }
    418 
    419 // nsITLSServerSocket needs a certificate with a corresponding private key
    420 // available. In mochitests, the certificate with the common name "Mochitest
    421 // client" has such a key.
    422 function getTestServerCertificate() {
    423  const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
    424    Ci.nsIX509CertDB
    425  );
    426  for (const cert of certDB.getCerts()) {
    427    if (cert.commonName == "Mochitest client") {
    428      return cert;
    429    }
    430  }
    431  return null;
    432 }