Bug 1388238 - Implement waitForMasterPasswordDialog helper which handles open dialogs. r=MattN
authorsteveck-chung <schung@mozilla.com>
Tue, 08 Aug 2017 20:53:49 -0700
changeset 421384 966d4487c72ec7ac5a386cb7f4e28695c9e05c8e
parent 421383 786925d985fb84c5b58ed14bd792308a006486da
child 421385 d0ea76640bfd864ac3638fe5e99a73ddd0d02f97
push id7664
push usermozilla@noorenberghe.ca
push dateThu, 24 Aug 2017 16:38:56 +0000
treeherdermozilla-beta@33a4e7ead964 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1388238
milestone56.0
Bug 1388238 - Implement waitForMasterPasswordDialog helper which handles open dialogs. r=MattN MozReview-Commit-ID: A8jx8s37f1k
browser/extensions/formautofill/MasterPassword.jsm
toolkit/components/prompts/src/CommonDialog.jsm
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/MasterPassword.jsm
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Helpers for the Master Password Dialog.
+ * In the future the Master Password implementation may move here.
+ */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [
+  "MasterPassword",
+];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+
+this.MasterPassword = {
+  /**
+   * Resolve when master password dialogs are closed, immediately if none are open.
+   *
+   * An existing MP dialog will be focused and will request attention.
+   *
+   * @returns {Promise<boolean>}
+   *          Resolves with whether the user is logged in to MP.
+   */
+  async waitForExistingDialog() {
+    if (!Services.logins.uiBusy) {
+      log.debug("waitForExistingDialog: Dialog isn't showing. isLoggedIn:",
+                Services.logins.isLoggedIn);
+      return Services.logins.isLoggedIn;
+    }
+
+    return new Promise((resolve) => {
+      log.debug("waitForExistingDialog: Observing the open dialog");
+      let observer = {
+        QueryInterface: XPCOMUtils.generateQI([
+          Ci.nsIObserver,
+          Ci.nsISupportsWeakReference,
+        ]),
+
+        observe(subject, topic, data) {
+          log.debug("waitForExistingDialog: Got notification:", topic);
+          // Only run observer once.
+          Services.obs.removeObserver(this, "passwordmgr-crypto-login");
+          Services.obs.removeObserver(this, "passwordmgr-crypto-loginCanceled");
+          if (topic == "passwordmgr-crypto-loginCanceled") {
+            resolve(false);
+            return;
+          }
+
+          resolve(true);
+        },
+      };
+
+      // Possible leak: it's possible that neither of these notifications
+      // will fire, and if that happens, we'll leak the observer (and
+      // never return). We should guarantee that at least one of these
+      // will fire.
+      // See bug XXX.
+      Services.obs.addObserver(observer, "passwordmgr-crypto-login");
+      Services.obs.addObserver(observer, "passwordmgr-crypto-loginCanceled");
+
+      // Focus and draw attention to the existing master password dialog for the
+      // occassions where it's not attached to the current window.
+      let promptWin = Services.wm.getMostRecentWindow("prompt:promptPassword");
+      promptWin.focus();
+      promptWin.getAttention();
+    });
+  },
+};
+
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+  return new ConsoleAPI({
+    maxLogLevelPref: "masterPassword.loglevel",
+    prefix: "Master Password",
+  });
+});
--- a/toolkit/components/prompts/src/CommonDialog.jsm
+++ b/toolkit/components/prompts/src/CommonDialog.jsm
@@ -86,16 +86,20 @@ CommonDialog.prototype = {
             // Clear the label, since the message presumably indicates its purpose.
             this.ui.password1Label.setAttribute("value", "");
             break;
           default:
             Cu.reportError("commonDialog opened for unknown type: " + this.args.promptType);
             throw "unknown dialog type";
         }
 
+        if (xulDialog) {
+            xulDialog.setAttribute("windowtype", "prompt:" + this.args.promptType);
+        }
+
         // set the document title
         let title = this.args.title;
         // OS X doesn't have a title on modal dialogs, this is hidden on other platforms.
         let infoTitle = this.ui.infoTitle;
         infoTitle.appendChild(infoTitle.ownerDocument.createTextNode(title));
         if (xulDialog)
             xulDialog.ownerDocument.title = title;