Source code
Revision control
Copy as Markdown
Other Tools
/**
* Loaded as a frame script to do privileged things in mochitest-plain tests.
* See pwmgr_common.js for the content process companion.
*/
/* eslint-env mozilla/chrome-script */
"use strict";
var { AppConstants } = ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
var { LoginHelper } = ChromeUtils.importESModule(
"resource://gre/modules/LoginHelper.sys.mjs"
);
var { LoginManagerParent } = ChromeUtils.importESModule(
"resource://gre/modules/LoginManagerParent.sys.mjs"
);
const { LoginTestUtils } = ChromeUtils.importESModule(
);
if (LoginHelper.relatedRealmsEnabled) {
let rsPromise =
LoginTestUtils.remoteSettings.setupWebsitesWithSharedCredentials();
async () => {
await rsPromise;
};
}
if (LoginHelper.improvedPasswordRulesEnabled) {
let rsPromise = LoginTestUtils.remoteSettings.setupImprovedPasswordRules({
rules: "",
});
async () => {
await rsPromise;
};
}
/**
* Init with a common login.
*/
async function commonInit(testDependsOnDeprecatedLogin) {
var pwmgr = Services.logins;
assert.ok(pwmgr != null, "Access LoginManager");
// Check that initial state has no logins
var logins = await pwmgr.getAllLogins();
assert.equal(logins.length, 0, "Not expecting logins to be present");
var disabledHosts = pwmgr.getAllDisabledHosts();
if (disabledHosts.length) {
assert.ok(false, "Warning: wasn't expecting disabled hosts to be present.");
for (var host of disabledHosts) {
pwmgr.setLoginSavingEnabled(host, true);
}
}
if (testDependsOnDeprecatedLogin) {
// Add a login that's used in multiple tests
var login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(
Ci.nsILoginInfo
);
login.init(
null,
"testuser",
"testpass",
"uname",
"pword"
);
await pwmgr.addLoginAsync(login);
}
// Last sanity check
logins = await pwmgr.getAllLogins();
assert.equal(
logins.length,
testDependsOnDeprecatedLogin ? 1 : 0,
"Checking for successful init login"
);
disabledHosts = pwmgr.getAllDisabledHosts();
assert.equal(disabledHosts.length, 0, "Checking for no disabled hosts");
}
async function dumpLogins() {
let logins = await Services.logins.getAllLogins();
assert.ok(true, "----- dumpLogins: have " + logins.length + " logins. -----");
for (var i = 0; i < logins.length; i++) {
dumpLogin("login #" + i + " --- ", logins[i]);
}
}
function dumpLogin(label, login) {
var loginText = "";
loginText += "origin: ";
loginText += login.origin;
loginText += " / formActionOrigin: ";
loginText += login.formActionOrigin;
loginText += " / realm: ";
loginText += login.httpRealm;
loginText += " / user: ";
loginText += login.username;
loginText += " / pass: ";
loginText += login.password;
loginText += " / ufield: ";
loginText += login.usernameField;
loginText += " / pfield: ";
loginText += login.passwordField;
assert.ok(true, label + loginText);
}
addMessageListener("storageChanged", async function ({ expectedChangeTypes }) {
return new Promise(resolve => {
function storageChanged(_subject, _topic, data) {
let changeType = expectedChangeTypes.shift();
if (data != changeType) {
resolve("Unexpected change type " + data + ", expected " + changeType);
} else if (expectedChangeTypes.length === 0) {
Services.obs.removeObserver(
storageChanged,
"passwordmgr-storage-changed"
);
resolve();
}
}
Services.obs.addObserver(storageChanged, "passwordmgr-storage-changed");
});
});
addMessageListener("promptShown", async function () {
return new Promise(resolve => {
function promptShown(_subject, topic, _data) {
Services.obs.removeObserver(promptShown, "passwordmgr-prompt-change");
Services.obs.removeObserver(promptShown, "passwordmgr-prompt-save");
resolve(topic);
}
Services.obs.addObserver(promptShown, "passwordmgr-prompt-change");
Services.obs.addObserver(promptShown, "passwordmgr-prompt-save");
});
});
addMessageListener("cleanup", () => {
Services.logins.removeAllUserFacingLogins();
});
// Begin message listeners
addMessageListener(
"setupParent",
async ({ testDependsOnDeprecatedLogin = false } = {}) => {
return commonInit(testDependsOnDeprecatedLogin);
}
);
addMessageListener("loadRecipes", async function (recipes) {
var recipeParent = await LoginManagerParent.recipeParentPromise;
await recipeParent.load(recipes);
return recipes;
});
addMessageListener("resetRecipes", async function () {
let recipeParent = await LoginManagerParent.recipeParentPromise;
await recipeParent.reset();
});
addMessageListener("getTelemetryEvents", options => {
options = Object.assign(
{
filterProps: {},
clear: false,
},
options
);
let snapshots = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
options.clear
);
let events = options.process in snapshots ? snapshots[options.process] : [];
// event is array of values like: [22476,"pwmgr","autocomplete_field","generatedpassword"]
let keys = ["id", "category", "method", "object", "value"];
events = events.filter(entry => {
for (let idx = 0; idx < keys.length; idx++) {
let key = keys[idx];
if (
key in options.filterProps &&
options.filterProps[key] !== entry[idx]
) {
return false;
}
}
return true;
});
return events;
});
addMessageListener("proxyLoginManager", async msg => {
// Recreate nsILoginInfo objects from vanilla JS objects.
let recreatedArgs = msg.args.map((arg, index) => {
if (msg.loginInfoIndices.includes(index)) {
return LoginHelper.vanillaObjectToLogin(arg);
}
return arg;
});
let rv = await Services.logins[msg.methodName](...recreatedArgs);
if (rv instanceof Ci.nsILoginInfo) {
rv = LoginHelper.loginToVanillaObject(rv);
} else if (
Array.isArray(rv) &&
!!rv.length &&
rv[0] instanceof Ci.nsILoginInfo
) {
rv = rv.map(login => LoginHelper.loginToVanillaObject(login));
}
return rv;
});
addMessageListener("isLoggedIn", () => {
// This can't use the LoginManager proxy in pwmgr_common.js since it's not a method.
return Services.logins.isLoggedIn;
});
addMessageListener("setPrimaryPassword", ({ enable }) => {
if (enable) {
LoginTestUtils.primaryPassword.enable();
} else {
LoginTestUtils.primaryPassword.disable();
}
});
LoginManagerParent.setListenerForTests((msg, { origin, data }) => {
if (msg == "ShowDoorhanger") {
sendAsyncMessage("formSubmissionProcessed", { origin, data });
} else if (msg == "PasswordEditedOrGenerated") {
sendAsyncMessage("passwordEditedOrGenerated", { origin, data });
} else if (msg == "FormProcessed") {
sendAsyncMessage("formProcessed", data);
}
});
addMessageListener("cleanup", () => {
LoginManagerParent.setListenerForTests(null);
});