Bug 1585904 - Avoids opening the same certificate in multiple tabs each time.r=johannh,nhnt11
☠☠ backed out by af28127350c3 ☠ ☠
authorCarolina <carolina.jimenez.g@gmail.com>
Fri, 22 Nov 2019 17:40:18 +0000
changeset 503461 e9d1379c65f5bf7c7682ed49a72e2922c4026009
parent 503460 ed4d544f3db4b9e03836f500685ddfb8a92c54ec
child 503462 007007b06317aba21a5d445dbc38dd6fee0811b0
push id101335
push usercsabou@mozilla.com
push dateFri, 22 Nov 2019 19:41:48 +0000
treeherderautoland@e9d1379c65f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh, nhnt11
bugs1585904
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1585904 - Avoids opening the same certificate in multiple tabs each time.r=johannh,nhnt11 Differential Revision: https://phabricator.services.mozilla.com/D50110
browser/actors/NetErrorParent.jsm
browser/base/content/pageinfo/security.js
security/manager/pki/resources/content/pippki.js
toolkit/components/certviewer/tests/browser/browser.ini
toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js
toolkit/components/certviewer/tests/browser/head.js
--- a/browser/actors/NetErrorParent.jsm
+++ b/browser/actors/NetErrorParent.jsm
@@ -338,19 +338,17 @@ class NetErrorParent extends JSWindowAct
             ) {
               let certChain = securityInfo.failedCertChain;
               let certs = certChain.map(elem =>
                 encodeURIComponent(elem.getBase64DERString())
               );
               let certsStringURL = certs.map(elem => `cert=${elem}`);
               certsStringURL = certsStringURL.join("&");
               let url = `about:certificate?${certsStringURL}`;
-              if (window.openTrustedLinkIn) {
-                window.openTrustedLinkIn(url, "tab");
-              }
+              window.switchToTabHavingURI(url, true, {});
             } else {
               Services.ww.openWindow(
                 window,
                 "chrome://pippki/content/certViewer.xul",
                 "_blank",
                 "centerscreen,chrome",
                 cert
               );
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -34,17 +34,17 @@ var security = {
     if (Services.prefs.getBoolPref("security.aboutcertificate.enabled")) {
       let certChain = this.securityInfo.certChain;
       let certs = certChain.map(elem =>
         encodeURIComponent(elem.getBase64DERString())
       );
       let certsStringURL = certs.map(elem => `cert=${elem}`);
       certsStringURL = certsStringURL.join("&");
       let url = `about:certificate?${certsStringURL}`;
-      openTrustedLinkIn(url, "tab");
+      window.switchToTabHavingURI(url, true, {});
     } else {
       Services.ww.openWindow(
         window,
         "chrome://pippki/content/certViewer.xul",
         "_blank",
         "centerscreen,chrome",
         this.securityInfo.cert
       );
--- a/security/manager/pki/resources/content/pippki.js
+++ b/security/manager/pki/resources/content/pippki.js
@@ -29,17 +29,20 @@ function viewCertHelper(parent, cert, op
   if (!cert) {
     return;
   }
 
   if (Services.prefs.getBoolPref("security.aboutcertificate.enabled")) {
     let win = Services.wm.getMostRecentWindow("navigator:browser");
     let derb64 = encodeURIComponent(cert.getBase64DERString());
     let url = `about:certificate?cert=${derb64}`;
-    win.openTrustedLinkIn(url, openingOption);
+    let opened = win.switchToTabHavingURI(url, false, {});
+    if (!opened) {
+      win.openTrustedLinkIn(url, openingOption);
+    }
   } else {
     Services.ww.openWindow(
       parent && parent.docShell.rootTreeItem.domWindow,
       "chrome://pippki/content/certViewer.xul",
       "_blank",
       "centerscreen,chrome",
       cert
     );
--- a/toolkit/components/certviewer/tests/browser/browser.ini
+++ b/toolkit/components/certviewer/tests/browser/browser.ini
@@ -1,14 +1,16 @@
 [DEFAULT]
 support-files =
+  head.js
   adjustedCerts.js
 [browser_aboutcertificateviewer.js]
 [browser_checkLongHex.js]
 [browser_checkNonEmptyFields.js]
+[browser_checkNonRepeatedCertTabs.js]
 [browser_checkNonUndefinedStrings.js]
 [browser_checkOCSP.js]
 [browser_checkValiditySection.js]
 [browser_handleMultipleCertsURL.js]
 [browser_openTabAndSendCertInfo.js]
 support-files =
   dummy_page.html
 [browser_renderCertToUI.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js
@@ -0,0 +1,143 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const PREF = "security.aboutcertificate.enabled";
+
+function checkCertTabs() {
+  let certificatePages = 0;
+  for (let tab of gBrowser.tabs) {
+    let spec = tab.linkedBrowser.documentURI.spec;
+    if (spec.includes("about:certificate")) {
+      certificatePages++;
+    }
+  }
+  Assert.equal(certificatePages, 1, "Do not open repeated certificate pages!");
+}
+
+add_task(async function testBadCert() {
+  info("Testing bad cert");
+
+  let tab = await openErrorPage();
+
+  SpecialPowers.pushPrefEnv({
+    set: [[PREF, true]],
+  });
+
+  let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+  for (let i = 0; i < 2; i++) {
+    // try opening two certificates that are the same
+    await SpecialPowers.spawn(tab.linkedBrowser, [], async function() {
+      let advancedButton = content.document.getElementById("advancedButton");
+      Assert.ok(advancedButton, "advancedButton found");
+      Assert.equal(
+        advancedButton.hasAttribute("disabled"),
+        false,
+        "advancedButton should be clickable"
+      );
+      advancedButton.click();
+      let viewCertificate = content.document.getElementById("viewCertificate");
+      Assert.ok(viewCertificate, "viewCertificate found");
+      Assert.equal(
+        viewCertificate.hasAttribute("disabled"),
+        false,
+        "viewCertificate should be clickable"
+      );
+
+      viewCertificate.click();
+    });
+    await loaded;
+  }
+  checkCertTabs();
+
+  gBrowser.removeCurrentTab(); // closes about:certificate
+  gBrowser.removeCurrentTab(); // closes https://expired.example.com/
+});
+
+add_task(async function testGoodCert() {
+  info("Testing page info");
+  let url = "https://example.com/";
+
+  SpecialPowers.pushPrefEnv({
+    set: [[PREF, true]],
+  });
+
+  info(`Loading ${url}`);
+  await BrowserTestUtils.withNewTab({ gBrowser, url }, async function() {
+    info("Opening pageinfo");
+    let pageInfo = BrowserPageInfo(url, "securityTab", {});
+    await BrowserTestUtils.waitForEvent(pageInfo, "load");
+
+    let securityTab = pageInfo.document.getElementById("securityTab");
+    await TestUtils.waitForCondition(
+      () => BrowserTestUtils.is_visible(securityTab),
+      "Security tab should be visible."
+    );
+    Assert.ok(securityTab, "Security tab is available");
+    let viewCertButton = pageInfo.document.getElementById("security-view-cert");
+    await TestUtils.waitForCondition(
+      () => BrowserTestUtils.is_visible(viewCertButton),
+      "view cert button should be visible."
+    );
+
+    let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+    for (let i = 0; i < 2; i++) {
+      checkAndClickButton(pageInfo.document, "security-view-cert");
+      await loaded;
+    }
+
+    pageInfo.close();
+    checkCertTabs();
+  });
+
+  gBrowser.removeCurrentTab();
+});
+
+add_task(async function testPreferencesCert() {
+  info("Testing preferences cert");
+  let url = "about:preferences#privacy";
+
+  SpecialPowers.pushPrefEnv({
+    set: [[PREF, true]],
+  });
+
+  info(`Loading ${url}`);
+  await BrowserTestUtils.withNewTab({ gBrowser, url }, async function(browser) {
+    checkAndClickButton(browser.contentDocument, "viewCertificatesButton");
+
+    let certDialogLoaded = promiseLoadSubDialog(
+      "chrome://pippki/content/certManager.xul"
+    );
+    let dialogWin = await certDialogLoaded;
+    let doc = dialogWin.document;
+    Assert.ok(doc, "doc loaded");
+
+    doc.getElementById("certmanagertabs").selectedTab = doc.getElementById(
+      "ca_tab"
+    );
+    let treeView = doc.getElementById("ca-tree").view;
+    let selectedCert;
+
+    for (let i = 0; i < treeView.rowCount; i++) {
+      treeView.selection.select(i);
+      dialogWin.getSelectedCerts();
+      let certs = dialogWin.selected_certs;
+      if (certs && certs.length == 1 && certs[0]) {
+        selectedCert = certs[0];
+        break;
+      }
+    }
+    Assert.ok(selectedCert, "A cert should be selected");
+    let viewButton = doc.getElementById("ca_viewButton");
+    Assert.equal(viewButton.disabled, false, "Should enable view button");
+
+    let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+    for (let i = 0; i < 2; i++) {
+      viewButton.click();
+      await loaded;
+    }
+    checkCertTabs();
+  });
+  gBrowser.removeCurrentTab(); // closes about:certificate
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/head.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function checkAndClickButton(document, id) {
+  let button = document.getElementById(id);
+  Assert.ok(button, `${id} button found`);
+  Assert.equal(
+    button.hasAttribute("disabled"),
+    false,
+    "button should be clickable"
+  );
+  button.click();
+}
+
+function is_element_visible(aElement, aMsg) {
+  isnot(aElement, null, "Element should not be null, when checking visibility");
+  Assert.ok(!BrowserTestUtils.is_hidden(aElement), aMsg);
+}
+
+// Extracted from https://searchfox.org/mozilla-central/rev/40ef22080910c2e2c27d9e2120642376b1d8b8b2/browser/components/preferences/in-content/tests/head.js#41
+function promiseLoadSubDialog(aURL) {
+  return new Promise((resolve, reject) => {
+    content.gSubDialog._dialogStack.addEventListener(
+      "dialogopen",
+      function dialogopen(aEvent) {
+        if (
+          aEvent.detail.dialog._frame.contentWindow.location == "about:blank"
+        ) {
+          return;
+        }
+        content.gSubDialog._dialogStack.removeEventListener(
+          "dialogopen",
+          dialogopen
+        );
+
+        Assert.equal(
+          aEvent.detail.dialog._frame.contentWindow.location.toString(),
+          aURL,
+          "Check the proper URL is loaded"
+        );
+
+        // Check visibility
+        is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
+
+        // Check that stylesheets were injected
+        let expectedStyleSheetURLs = aEvent.detail.dialog._injectedStyleSheets.slice(
+          0
+        );
+        for (let styleSheet of aEvent.detail.dialog._frame.contentDocument
+          .styleSheets) {
+          let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
+          if (i >= 0) {
+            info("found " + styleSheet.href);
+            expectedStyleSheetURLs.splice(i, 1);
+          }
+        }
+        Assert.equal(
+          expectedStyleSheetURLs.length,
+          0,
+          "All expectedStyleSheetURLs should have been found"
+        );
+
+        // Wait for the next event tick to make sure the remaining part of the
+        // testcase runs after the dialog gets ready for input.
+        executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow));
+      }
+    );
+  });
+}
+
+async function openErrorPage() {
+  let src = "https://expired.example.com/";
+  let certErrorLoaded;
+  let tab = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    () => {
+      gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, src);
+      let browser = gBrowser.selectedBrowser;
+      certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
+    },
+    false
+  );
+  info("Loading and waiting for the cert error");
+  await certErrorLoaded;
+  return tab;
+}