From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- .../components/passwordmgr/test/LoginTestUtils.jsm | 295 +++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 toolkit/components/passwordmgr/test/LoginTestUtils.jsm (limited to 'toolkit/components/passwordmgr/test/LoginTestUtils.jsm') diff --git a/toolkit/components/passwordmgr/test/LoginTestUtils.jsm b/toolkit/components/passwordmgr/test/LoginTestUtils.jsm new file mode 100644 index 000000000..2fd8a31a3 --- /dev/null +++ b/toolkit/components/passwordmgr/test/LoginTestUtils.jsm @@ -0,0 +1,295 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Shared functions generally available for testing login components. + */ + +"use strict"; + +this.EXPORTED_SYMBOLS = [ + "LoginTestUtils", +]; + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +Cu.import("resource://gre/modules/Promise.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +Cu.import("resource://testing-common/TestUtils.jsm"); + +const LoginInfo = + Components.Constructor("@mozilla.org/login-manager/loginInfo;1", + "nsILoginInfo", "init"); + +// For now, we need consumers to provide a reference to Assert.jsm. +var Assert = null; + +this.LoginTestUtils = { + set Assert(assert) { + Assert = assert; // eslint-disable-line no-native-reassign + }, + + /** + * Forces the storage module to save all data, and the Login Manager service + * to replace the storage module with a newly initialized instance. + */ + * reloadData() { + Services.obs.notifyObservers(null, "passwordmgr-storage-replace", null); + yield TestUtils.topicObserved("passwordmgr-storage-replace-complete"); + }, + + /** + * Erases all the data stored by the Login Manager service. + */ + clearData() { + Services.logins.removeAllLogins(); + for (let hostname of Services.logins.getAllDisabledHosts()) { + Services.logins.setLoginSavingEnabled(hostname, true); + } + }, + + /** + * Checks that the currently stored list of nsILoginInfo matches the provided + * array. The comparison uses the "equals" method of nsILoginInfo, that does + * not include nsILoginMetaInfo properties in the test. + */ + checkLogins(expectedLogins) { + this.assertLoginListsEqual(Services.logins.getAllLogins(), expectedLogins); + }, + + /** + * Checks that the two provided arrays of nsILoginInfo have the same length, + * and every login in "expected" is also found in "actual". The comparison + * uses the "equals" method of nsILoginInfo, that does not include + * nsILoginMetaInfo properties in the test. + */ + assertLoginListsEqual(actual, expected) { + Assert.equal(expected.length, actual.length); + Assert.ok(expected.every(e => actual.some(a => a.equals(e)))); + }, + + /** + * Checks that the two provided arrays of strings contain the same values, + * maybe in a different order, case-sensitively. + */ + assertDisabledHostsEqual(actual, expected) { + Assert.deepEqual(actual.sort(), expected.sort()); + }, + + /** + * Checks whether the given time, expressed as the number of milliseconds + * since January 1, 1970, 00:00:00 UTC, falls within 30 seconds of now. + */ + assertTimeIsAboutNow(timeMs) { + Assert.ok(Math.abs(timeMs - Date.now()) < 30000); + }, +}; + +/** + * This object contains functions that return new instances of nsILoginInfo for + * every call. The returned instances can be compared using their "equals" or + * "matches" methods, or modified for the needs of the specific test being run. + * + * Any modification to the test data requires updating the tests accordingly, in + * particular the search tests. + */ +this.LoginTestUtils.testData = { + /** + * Returns a new nsILoginInfo for use with form submits. + * + * @param modifications + * Each property of this object replaces the property of the same name + * in the returned nsILoginInfo or nsILoginMetaInfo. + */ + formLogin(modifications) { + let loginInfo = new LoginInfo("http://www3.example.com", + "http://www.example.com", null, + "the username", "the password", + "form_field_username", "form_field_password"); + loginInfo.QueryInterface(Ci.nsILoginMetaInfo); + if (modifications) { + for (let [name, value] of Object.entries(modifications)) { + loginInfo[name] = value; + } + } + return loginInfo; + }, + + /** + * Returns a new nsILoginInfo for use with HTTP authentication. + * + * @param modifications + * Each property of this object replaces the property of the same name + * in the returned nsILoginInfo or nsILoginMetaInfo. + */ + authLogin(modifications) { + let loginInfo = new LoginInfo("http://www.example.org", null, + "The HTTP Realm", "the username", + "the password", "", ""); + loginInfo.QueryInterface(Ci.nsILoginMetaInfo); + if (modifications) { + for (let [name, value] of Object.entries(modifications)) { + loginInfo[name] = value; + } + } + return loginInfo; + }, + + /** + * Returns an array of typical nsILoginInfo that could be stored in the + * database. + */ + loginList() { + return [ + // --- Examples of form logins (subdomains of example.com) --- + + // Simple form login with named fields for username and password. + new LoginInfo("http://www.example.com", "http://www.example.com", null, + "the username", "the password for www.example.com", + "form_field_username", "form_field_password"), + + // Different schemes are treated as completely different sites. + new LoginInfo("https://www.example.com", "https://www.example.com", null, + "the username", "the password for https", + "form_field_username", "form_field_password"), + + // Subdomains are treated as completely different sites. + new LoginInfo("https://example.com", "https://example.com", null, + "the username", "the password for example.com", + "form_field_username", "form_field_password"), + + // Forms found on the same host, but with different hostnames in the + // "action" attribute, are handled independently. + new LoginInfo("http://www3.example.com", "http://www.example.com", null, + "the username", "the password", + "form_field_username", "form_field_password"), + new LoginInfo("http://www3.example.com", "https://www.example.com", null, + "the username", "the password", + "form_field_username", "form_field_password"), + new LoginInfo("http://www3.example.com", "http://example.com", null, + "the username", "the password", + "form_field_username", "form_field_password"), + + // It is not possible to store multiple passwords for the same username, + // however multiple passwords can be stored when the usernames differ. + // An empty username is a valid case and different from the others. + new LoginInfo("http://www4.example.com", "http://www4.example.com", null, + "username one", "password one", + "form_field_username", "form_field_password"), + new LoginInfo("http://www4.example.com", "http://www4.example.com", null, + "username two", "password two", + "form_field_username", "form_field_password"), + new LoginInfo("http://www4.example.com", "http://www4.example.com", null, + "", "password three", + "form_field_username", "form_field_password"), + + // Username and passwords fields in forms may have no "name" attribute. + new LoginInfo("http://www5.example.com", "http://www5.example.com", null, + "multi username", "multi password", "", ""), + + // Forms with PIN-type authentication will typically have no username. + new LoginInfo("http://www6.example.com", "http://www6.example.com", null, + "", "12345", "", "form_field_password"), + + // --- Examples of authentication logins (subdomains of example.org) --- + + // Simple HTTP authentication login. + new LoginInfo("http://www.example.org", null, "The HTTP Realm", + "the username", "the password", "", ""), + + // Simple FTP authentication login. + new LoginInfo("ftp://ftp.example.org", null, "ftp://ftp.example.org", + "the username", "the password", "", ""), + + // Multiple HTTP authentication logins can be stored for different realms. + new LoginInfo("http://www2.example.org", null, "The HTTP Realm", + "the username", "the password", "", ""), + new LoginInfo("http://www2.example.org", null, "The HTTP Realm Other", + "the username other", "the password other", "", ""), + + // --- Both form and authentication logins (example.net) --- + + new LoginInfo("http://example.net", "http://example.net", null, + "the username", "the password", + "form_field_username", "form_field_password"), + new LoginInfo("http://example.net", "http://www.example.net", null, + "the username", "the password", + "form_field_username", "form_field_password"), + new LoginInfo("http://example.net", "http://www.example.net", null, + "username two", "the password", + "form_field_username", "form_field_password"), + new LoginInfo("http://example.net", null, "The HTTP Realm", + "the username", "the password", "", ""), + new LoginInfo("http://example.net", null, "The HTTP Realm Other", + "username two", "the password", "", ""), + new LoginInfo("ftp://example.net", null, "ftp://example.net", + "the username", "the password", "", ""), + + // --- Examples of logins added by extensions (chrome scheme) --- + + new LoginInfo("chrome://example_extension", null, "Example Login One", + "the username", "the password one", "", ""), + new LoginInfo("chrome://example_extension", null, "Example Login Two", + "the username", "the password two", "", ""), + ]; + }, +}; + +this.LoginTestUtils.recipes = { + getRecipeParent() { + let { LoginManagerParent } = Cu.import("resource://gre/modules/LoginManagerParent.jsm", {}); + if (!LoginManagerParent.recipeParentPromise) { + return null; + } + return LoginManagerParent.recipeParentPromise.then((recipeParent) => { + return recipeParent; + }); + }, +}; + +this.LoginTestUtils.masterPassword = { + masterPassword: "omgsecret!", + + _set(enable) { + let oldPW, newPW; + if (enable) { + oldPW = ""; + newPW = this.masterPassword; + } else { + oldPW = this.masterPassword; + newPW = ""; + } + + let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"] + .getService(Ci.nsIPKCS11ModuleDB); + let slot = secmodDB.findSlotByName(""); + if (!slot) { + throw new Error("Can't find slot"); + } + + // Set master password. Note that this does not log you in, so the next + // invocation of pwmgr can trigger a MP prompt. + let pk11db = Cc["@mozilla.org/security/pk11tokendb;1"] + .getService(Ci.nsIPK11TokenDB); + let token = pk11db.findTokenByName(""); + if (slot.status == Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED) { + dump("MP initialized to " + newPW + "\n"); + token.initPassword(newPW); + } else { + token.checkPassword(oldPW); + dump("MP change from " + oldPW + " to " + newPW + "\n"); + token.changePassword(oldPW, newPW); + } + }, + + enable() { + this._set(true); + }, + + disable() { + this._set(false); + }, +}; -- cgit v1.2.3