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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
var { EwsServer } = ChromeUtils.importESModule(
);
var { MailServices } = ChromeUtils.importESModule(
);
var { PromiseTestUtils } = ChromeUtils.importESModule(
);
var { localAccountUtils } = ChromeUtils.importESModule(
);
var { TestUtils } = ChromeUtils.importESModule(
);
// The mock EWS server to direct our traffic to.
var ewsServer;
// The `nsIMsgOutgoingServer` instance used to send messages using EWS.
var outgoingServer;
// The credentials to use for authenticating on the server.
const username = "alice@local.test";
const password = "thispassword";
add_setup(async () => {
// Ensure we have an on-disk profile.
do_get_profile();
// Create a new mock EWS server, and start it.
ewsServer = new EwsServer({
username,
password,
});
ewsServer.start();
// Create and initialize an EWS outgoing server.
outgoingServer = MailServices.outgoingServer.createServer("ews");
const ewsOutgoingServer = outgoingServer.QueryInterface(Ci.nsIEwsServer);
ewsOutgoingServer.initialize(
`http://127.0.0.1:${ewsServer.port}/EWS/Exchange.asmx`
);
// Configure the outgoing server to use Basic/password auth (which we map to
// `nsMsgAuthMethod.passwordCleartext`).
outgoingServer.authMethod = Ci.nsMsgAuthMethod.passwordCleartext;
outgoingServer.username = username;
// Store the password in the login manager. Note that the URI we use does not
// include the port.
const passwordURI = "ews://127.0.0.1";
const login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(
Ci.nsILoginInfo
);
login.init(
passwordURI,
null,
passwordURI,
outgoingServer.username,
password,
"",
""
);
await Services.logins.addLoginAsync(login);
registerCleanupFunction(() => {
ewsServer.stop();
MailServices.outgoingServer.deleteServer(outgoingServer);
Services.logins.removeAllLogins();
});
});
/**
* Tests that the EWS outgoing server implementation properly authenticates when
* configured to use Basic (password) auth.
*/
add_task(async function test_basic_auth() {
// Send the dummy message, and wait for the request to complete.
const listener = new PromiseTestUtils.PromiseMsgOutgoingListener();
const testFile = do_get_file("data/simple_email.eml");
outgoingServer.sendMailMessage(
testFile,
[],
[],
{},
null,
null,
null,
false,
"testmessage@local.test",
listener
);
await listener.promise;
// Ensure the `Authorization` header's value from the previous request is
// correctly formatted, and makes an attempt to authenticate using Basic auth
// and the credentials we've previously configured.
Assert.greater(
ewsServer.lastAuthorizationValue.length,
0,
"the value for the Authorization header should not be empty"
);
const parts = ewsServer.lastAuthorizationValue.split(" ");
Assert.equal(
parts.length,
2,
"the value for the Authorization header should contain exactly two values"
);
Assert.equal(parts[0], "Basic", "the EWS client should use Basic auth");
Assert.equal(
parts[1],
btoa(`${username}:${password}`),
"the credentials should match those configured for this server"
);
});
/**
* Tests that a sent message is correctly moved to the folder with the
* "sentitems" distinguished folder ID (herein refered to as the "FCC" folder).
*/
add_task(async function test_moved_to_fcc_folder() {
// Create an incoming server so we can check the content of the FCC folder
// later.
const incomingServer = localAccountUtils.create_incoming_server(
"ews",
ewsServer.port,
username,
password
);
incomingServer.setStringValue(
"ews_url",
`http://127.0.0.1:${ewsServer.port}/EWS/Exchange.asmx`
);
// Associate the outgoing server to the account and retrieve the resulting
// `nsIMsgIdentity`, since we'll need it for sending the message.
const account = MailServices.accounts.findAccountForServer(incomingServer);
localAccountUtils.associate_servers(account, outgoingServer, true);
const identity = account.defaultIdentity;
// Create a folder that has the correct distinguished folder ID but a name
// that is NOT "Sent", to make sure we don't fall back onto IMAP-style logic
// to identify folders by static names.
const folderName = "sentItemsTest";
ewsServer.setRemoteFolders([
new RemoteFolder("root", null, "Root", "msgfolderroot"),
new RemoteFolder("inbox", "root", "Inbox", "inbox"),
new RemoteFolder(folderName, "root", folderName, "sentitems"),
]);
const rootFolder = incomingServer.rootFolder;
await syncFolder(incomingServer, rootFolder);
const fccFolder = rootFolder.getChildNamed(folderName);
// Make sure the FCC folder URI hasn't been set yet. We haven't tried sending
// a message yet, which is (currently) when we look at folder flags to figure
// out which folder to use. If the URI has already been set, then it means it
// was set based on the folder's name, not its flags.
Assert.ok(
!identity.fccFolderURI,
"the identity should not have an FCC folder URI yet"
);
Assert.equal(
fccFolder.getTotalMessages(false),
0,
"before sending, the FCC folder has no message"
);
// Send a message from this account.
const compFields = Cc[
"@mozilla.org/messengercompose/composefields;1"
].createInstance(Ci.nsIMsgCompFields);
compFields.from = identity.email;
compFields.to = "bob@local.test";
const msgSend = Cc["@mozilla.org/messengercompose/send;1"].createInstance(
Ci.nsIMsgSend
);
const testFile = do_get_file("data/simple_email.eml");
const sendListener = new PromiseTestUtils.SendListener();
msgSend.sendMessageFile(
identity,
"",
compFields,
testFile,
false,
false,
Ci.nsIMsgSend.nsMsgDeliverNow,
null,
sendListener,
null
);
await sendListener.promise;
// A copy of the message should end up in the FCC folder.
await TestUtils.waitForCondition(
() => fccFolder.getTotalMessages(false) == 1,
"waiting for sent message to be moved to the FCC folder"
);
});