Revision control
Copy as Markdown
Other Tools
/* 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
"use strict";
const { AccountConfig } = ChromeUtils.importESModule(
);
const { ConfigVerifier } = ChromeUtils.importESModule(
);
/**
* Drive a ConfigVerifier's tryNextLogon() with every attempt failing, and
* record the username and auth method of each logon attempt it makes.
*
* @param {AccountConfig} config - The config to verify.
* @returns {string[]} the attempted "username:authMethod" combinations, in
* order, including the initial attempt.
*/
function driveFailingLogons(config) {
const verifier = new ConfigVerifier(null, new AbortController().signal);
verifier.config = config;
verifier.server = {
username: config.incoming.username,
password: config.incoming.password,
authMethod: config.incoming.auth,
};
const attempts = [`${config.incoming.username}:${config.incoming.auth}`];
let failed = false;
verifier.verifyLogon = () => {
attempts.push(`${config.incoming.username}:${config.incoming.auth}`);
};
verifier._failed = () => {
failed = true;
};
// Each tryNextLogon() call simulates the previous attempt failing. Cap the
// iterations so a regression to the old infinite loop fails the test
// instead of hanging it.
for (let i = 0; !failed && i < 20; i++) {
verifier.tryNextLogon(null);
}
Assert.ok(failed, "Verifier should give up after trying all variations");
return attempts;
}
/**
* Set up the auth methods so there is one alternative to fall back to.
*
* @param {AccountConfig} config - The config to set up.
*/
function setupAuthMethods(config) {
config.incoming.auth = Ci.nsMsgAuthMethod.passwordEncrypted;
config.incoming.authAlternatives = [Ci.nsMsgAuthMethod.passwordCleartext];
config.outgoing.auth = Ci.nsMsgAuthMethod.passwordEncrypted;
config.outgoing.authAlternatives = [Ci.nsMsgAuthMethod.passwordCleartext];
}
add_task(function test_guessConfigLogonOrder() {
const config = AccountConfig.guessConfigFromEmail("user@example.invalid");
config.identity.emailAddress = "user@example.invalid";
setupAuthMethods(config);
const attempts = driveFailingLogons(config);
const encrypted = Ci.nsMsgAuthMethod.passwordEncrypted;
const cleartext = Ci.nsMsgAuthMethod.passwordCleartext;
Assert.deepEqual(
attempts,
[
`user@example.invalid:${encrypted}`,
`user:${encrypted}`,
`user:${cleartext}`,
`user@example.invalid:${cleartext}`,
],
"Should try the full e-mail address before the local part, both usernames per auth method, with no duplicate attempts"
);
});
add_task(function test_localPartConfigLogonOrder() {
const config = new AccountConfig();
config.incoming.username = "user";
config.outgoing.username = "user";
config.identity.emailAddress = "user@example.invalid";
setupAuthMethods(config);
const attempts = driveFailingLogons(config);
const encrypted = Ci.nsMsgAuthMethod.passwordEncrypted;
const cleartext = Ci.nsMsgAuthMethod.passwordCleartext;
Assert.deepEqual(
attempts,
[
`user:${encrypted}`,
`user@example.invalid:${encrypted}`,
`user:${cleartext}`,
`user@example.invalid:${cleartext}`,
],
"Should fall back to the full e-mail address, both usernames per auth method, with no duplicate attempts"
);
});