Bug 1388238 - Implement waitForMasterPasswordDialog helper which handles open dialogs. r=MattN draft
authorsteveck-chung <schung@mozilla.com>
Tue, 08 Aug 2017 20:53:49 -0700
changeset 644699 5134c7015cd5259c72aa2937047ecd31477d574f
parent 644465 253a8560dc34456d2e8a13065e4b3eb5ecf6704f
child 644700 faeeb134323e552d335327e86552b035345a670b
child 646256 8546a7ff37828cdaa07f76c862ca0bfe15631e8f
child 646404 45e7a58b274f0088de1e860edd852956349e9233
push id73526
push userschung@mozilla.com
push dateFri, 11 Aug 2017 09:18:08 +0000
reviewersMattN
bugs1388238
milestone57.0a1
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;