Bug 1304001 - Move LoginUtils._getPasswordOrigin to LoginHelper. r=sfoster
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Fri, 22 Feb 2019 15:41:03 +0000
changeset 460596 e25db31b4a158194ddd1a9742ea14fdf39a4f2e5
parent 460595 06877b0fd1a95ec218992e15d8ff08cbf96e99a1
child 460597 32398fe05ec236a52a01c27bae96637b222c2bbd
push id35596
push userrmaries@mozilla.com
push dateSat, 23 Feb 2019 04:13:22 +0000
treeherdermozilla-central@fdd04819e350 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1304001
milestone67.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 1304001 - Move LoginUtils._getPasswordOrigin to LoginHelper. r=sfoster There were too many top-level objects in that large JSM and LoginHelper didn't exist when it was added. Differential Revision: https://phabricator.services.mozilla.com/D20393
toolkit/components/passwordmgr/LoginHelper.jsm
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/test/unit/test_getPasswordOrigin.js
toolkit/components/passwordmgr/test/unit/test_getUserNameAndPasswordFields.js
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -214,16 +214,41 @@ var LoginHelper = {
       return uri.hostPort;
     } catch (ex) {
       // No need to warn for javascript:/data:/about:/chrome:/etc.
     }
     return aURL;
   },
 
   /**
+   * Get the parts of the URL we want for identification.
+   * Strip out things like the userPass portion and handle javascript:.
+   */
+  getLoginOrigin(uriString, allowJS) {
+    let realm = "";
+    try {
+      let uri = Services.io.newURI(uriString);
+
+      if (allowJS && uri.scheme == "javascript") {
+        return "javascript:";
+      }
+
+      // Build this manually instead of using prePath to avoid including the userPass portion.
+      realm = uri.scheme + "://" + uri.displayHostPort;
+    } catch (e) {
+      // bug 159484 - disallow url types that don't support a hostPort.
+      // (although we handle "javascript:..." as a special case above.)
+      log.warn("Couldn't parse origin for", uriString, e);
+      realm = null;
+    }
+
+    return realm;
+  },
+
+  /**
    * @param {String} aLoginOrigin - An origin value from a stored login's
    *                                hostname or formSubmitURL properties.
    * @param {String} aSearchOrigin - The origin that was are looking to match
    *                                 with aLoginOrigin. This would normally come
    *                                 from a form or page that we are considering.
    * @param {nsILoginFindOptions} aOptions - Options to affect whether the origin
    *                                         from the login (aLoginOrigin) is a
    *                                         match for the origin we're looking
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -276,17 +276,17 @@ var LoginManagerContent = {
    * @param {HTMLFormElement} form - form to get login data for
    * @param {Object} options
    * @param {boolean} options.showMasterPassword - whether to show a master password prompt
    */
   _getLoginDataFromParent(form, options) {
     let doc = form.ownerDocument;
     let win = doc.defaultView;
 
-    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let formOrigin = LoginHelper.getLoginOrigin(doc.documentURI);
     if (!formOrigin) {
       return Promise.reject("_getLoginDataFromParent: A form origin is required");
     }
     let actionOrigin = LoginUtils._getActionOrigin(form);
 
     let messageManager = win.docShell.messageManager;
 
     // XXX Weak??
@@ -301,17 +301,17 @@ var LoginManagerContent = {
   },
 
   _autoCompleteSearchAsync(aSearchString, aPreviousResult,
                            aElement, aRect) {
     let doc = aElement.ownerDocument;
     let form = LoginFormFactory.createFromField(aElement);
     let win = doc.defaultView;
 
-    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let formOrigin = LoginHelper.getLoginOrigin(doc.documentURI);
     let actionOrigin = LoginUtils._getActionOrigin(form);
 
     let messageManager = win.docShell.messageManager;
 
     let previousResult = aPreviousResult ?
                            { searchString: aPreviousResult.searchString,
                              logins: LoginHelper.loginsToVanillaObjects(aPreviousResult.logins) } :
                            null;
@@ -517,19 +517,19 @@ var LoginManagerContent = {
    *            Username or password input element from the form we want to fill.
    *        }
    */
   fillForm({ topDocument, loginFormOrigin, loginsFound, recipes, inputElement }) {
     if (!inputElement) {
       log("fillForm: No input element specified");
       return;
     }
-    if (LoginUtils._getPasswordOrigin(topDocument.documentURI) != loginFormOrigin) {
+    if (LoginHelper.getLoginOrigin(topDocument.documentURI) != loginFormOrigin) {
       if (!inputElement ||
-          LoginUtils._getPasswordOrigin(inputElement.ownerDocument.documentURI) != loginFormOrigin) {
+          LoginHelper.getLoginOrigin(inputElement.ownerDocument.documentURI) != loginFormOrigin) {
         log("fillForm: The requested origin doesn't match the one form the",
             "document. This may mean we navigated to a document from a different",
             "site before we had a chance to indicate this change in the user",
             "interface.");
         return;
       }
     }
 
@@ -547,17 +547,17 @@ var LoginManagerContent = {
       userTriggered: true,
     });
   },
 
   loginsFound({ form, loginsFound, recipes }) {
     let doc = form.ownerDocument;
     let autofillForm = LoginHelper.autofillForms && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView);
 
-    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let formOrigin = LoginHelper.getLoginOrigin(doc.documentURI);
     LoginRecipesContent.cacheRecipes(formOrigin, doc.defaultView, recipes);
 
     this._fillForm(form, loginsFound, recipes, {autofillForm});
   },
 
   /**
    * Focus event handler for username fields to decide whether to show autocomplete.
    * @param {FocusEvent} event
@@ -634,17 +634,17 @@ var LoginManagerContent = {
     if (!acInputField.value) {
       return;
     }
 
     log("onUsernameInput from", event.type);
 
     let acForm = LoginFormFactory.createFromField(acInputField);
     let doc = acForm.ownerDocument;
-    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let formOrigin = LoginHelper.getLoginOrigin(doc.documentURI);
     let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView);
 
     // Make sure the username field fillForm will use is the
     // same field as the autocomplete was activated on.
     var [usernameField, passwordField, ignored] =
         this._getFormFields(acForm, false, recipes);
     if (usernameField == acInputField && passwordField) {
       this._getLoginDataFromParent(acForm, { showMasterPassword: false })
@@ -930,17 +930,17 @@ var LoginManagerContent = {
       return;
     }
 
     // If password saving is disabled globally, bail out now.
     if (!LoginHelper.enabled) {
       return;
     }
 
-    var hostname = LoginUtils._getPasswordOrigin(doc.documentURI);
+    var hostname = LoginHelper.getLoginOrigin(doc.documentURI);
     if (!hostname) {
       log("(form submission ignored -- invalid hostname)");
       return;
     }
 
     let formSubmitURL = LoginUtils._getActionOrigin(form);
     let messageManager = win.docShell.messageManager;
 
@@ -1391,17 +1391,17 @@ var LoginManagerContent = {
         (aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
         aField.nodePrincipal.isNullPrincipal ||
         !aField.ownerDocument) {
       return [null, null, null];
     }
     let form = LoginFormFactory.createFromField(aField);
 
     let doc = aField.ownerDocument;
-    let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
+    let formOrigin = LoginHelper.getLoginOrigin(doc.documentURI);
     let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView);
 
     return this._getFormFields(form, false, recipes);
   },
 
   /**
    * Verify if a field is a valid login form field and
    * returns some information about it's FormLike.
@@ -1440,50 +1440,25 @@ var LoginManagerContent = {
         found: !!newPasswordField,
         disabled: newPasswordField && (newPasswordField.disabled || newPasswordField.readOnly),
       },
     };
   },
 };
 
 var LoginUtils = {
-  /**
-   * Get the parts of the URL we want for identification.
-   * Strip out things like the userPass portion
-   */
-  _getPasswordOrigin(uriString, allowJS) {
-    var realm = "";
-    try {
-      var uri = Services.io.newURI(uriString);
-
-      if (allowJS && uri.scheme == "javascript") {
-        return "javascript:";
-      }
-
-      // Build this manually instead of using prePath to avoid including the userPass portion.
-      realm = uri.scheme + "://" + uri.displayHostPort;
-    } catch (e) {
-      // bug 159484 - disallow url types that don't support a hostPort.
-      // (although we handle "javascript:..." as a special case above.)
-      log("Couldn't parse origin for", uriString, e);
-      realm = null;
-    }
-
-    return realm;
-  },
-
   _getActionOrigin(form) {
     var uriString = form.action;
 
     // A blank or missing action submits to where it came from.
     if (uriString == "") {
       uriString = form.baseURI;
     } // ala bug 297761
 
-    return this._getPasswordOrigin(uriString, true);
+    return LoginHelper.getLoginOrigin(uriString, true);
   },
 };
 
 // nsIAutoCompleteResult implementation
 function UserAutoCompleteResult(aSearchString, matchingLogins, {isSecure, messageManager, isPasswordField}) {
   function loginSort(a, b) {
     var userA = a.username.toLowerCase();
     var userB = b.username.toLowerCase();
@@ -1694,17 +1669,17 @@ var LoginFormFactory = {
       throw new Error("createFromField requires a password or username field in a document");
     }
 
     if (aField.form) {
       return this.createFromForm(aField.form);
     }
 
     let formLike = FormLikeFactory.createFromField(aField);
-    formLike.action = LoginUtils._getPasswordOrigin(aField.ownerDocument.baseURI);
+    formLike.action = LoginHelper.getLoginOrigin(aField.ownerDocument.baseURI);
     log("Created non-form FormLike for rootElement:", aField.ownerDocument.documentElement);
 
     let state = LoginManagerContent.stateForDocument(formLike.ownerDocument);
     state.loginFormRootElements.add(formLike.rootElement);
     log("adding", formLike.rootElement, "to loginFormRootElements for", formLike.ownerDocument);
 
 
     LoginManagerContent._formLikeByRootElement.set(formLike.rootElement, formLike);
--- a/toolkit/components/passwordmgr/test/unit/test_getPasswordOrigin.js
+++ b/toolkit/components/passwordmgr/test/unit/test_getPasswordOrigin.js
@@ -1,15 +1,14 @@
-/*
- * Test for LoginUtils._getPasswordOrigin
+/**
+ * Test for LoginHelper.getLoginOrigin
  */
 
 "use strict";
 
-const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", null);
 const TESTCASES = [
   ["javascript:void(0);", null],
   ["javascript:void(0);", "javascript:", true],
   ["chrome://MyAccount", null],
   ["data:text/html,example", null],
   ["http://username:password@example.com:80/foo?bar=baz#fragment", "http://example.com", true],
   ["http://127.0.0.1:80/foo", "http://127.0.0.1"],
   ["http://[::1]:80/foo", "http://[::1]"],
@@ -18,11 +17,11 @@ const TESTCASES = [
   ["http://[::1]:8080/foo", "http://[::1]:8080"],
   ["https://example.com:443/foo", "https://example.com"],
   ["https://[::1]:443/foo", "https://[::1]"],
   ["https://[::1]:8443/foo", "https://[::1]:8443"],
   ["ftp://username:password@[::1]:2121/foo", "ftp://[::1]:2121"],
 ];
 
 for (let [input, expected, allowJS] of TESTCASES) {
-  let actual = LMCBackstagePass.LoginUtils._getPasswordOrigin(input, allowJS);
+  let actual = LoginHelper.getLoginOrigin(input, allowJS);
   Assert.strictEqual(actual, expected, "Checking: " + input);
 }
--- a/toolkit/components/passwordmgr/test/unit/test_getUserNameAndPasswordFields.js
+++ b/toolkit/components/passwordmgr/test/unit/test_getUserNameAndPasswordFields.js
@@ -1,16 +1,14 @@
-/*
+/**
  * Test for LoginManagerContent.getUserNameAndPasswordFields
  */
 
 "use strict";
 
-// Services.prefs.setBoolPref("signon.debug", true);
-
 XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
 
 const LMCBackstagePass = ChromeUtils.import("resource://gre/modules/LoginManagerContent.jsm", null);
 const { LoginManagerContent, LoginFormFactory } = LMCBackstagePass;
 const TESTCASES = [
   {
     description: "1 password field outside of a <form>",
     document: `<input id="pw1" type=password>`,
@@ -90,17 +88,17 @@ for (let tc of TESTCASES) {
       MockDocument.mockOwnerDocumentProperty(input, document, "http://localhost:8080/test/");
       MockDocument.mockNodePrincipalProperty(input, "http://localhost:8080/test/");
 
       // Additional mock to cache recipes
       let win = {};
       Object.defineProperty(document, "defaultView", {
         value: win,
       });
-      let formOrigin = LMCBackstagePass.LoginUtils._getPasswordOrigin(document.documentURI);
+      let formOrigin = LoginHelper.getLoginOrigin(document.documentURI);
       LoginRecipesContent.cacheRecipes(formOrigin, win, new Set());
 
       let actual = LoginManagerContent.getUserNameAndPasswordFields(input);
 
       Assert.strictEqual(testcase.returnedFieldIDs.length, 3,
                          "getUserNameAndPasswordFields returns 3 elements");
 
       for (let i = 0; i < testcase.returnedFieldIDs.length; i++) {