/* 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/. */ "use strict"; const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); const { HttpsProxy } = ChromeUtils.importESModule( "resource://testing-common/mailnews/HttpsProxy.sys.mjs" ); const { ServerTestUtils } = ChromeUtils.importESModule( "resource://testing-common/mailnews/ServerTestUtils.sys.mjs" ); const { NetworkTestUtils } = ChromeUtils.importESModule( "resource://testing-common/mailnews/NetworkTestUtils.sys.mjs" ); const USER = "testExchange@exchange.test"; const PASSWORD = "hunter2"; const emailUser = { name: "John Doe", email: USER, password: PASSWORD, }; const AUTODISCOVER_RESPONSE = ` email settings True EXCH bb0f9083-1bfa-4ee3-8851-876b23ed0046@exchange.test /o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=bb0f9083-1bfa-4ee3-8851-876b23ed0046@exchange.test/cn=Microsoft Private MDB 73D49F70 /o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=bb0f9083-1bfa-4ee3-8851-876b23ed0046@exchange.test/cn=Microsoft Private MDB outlook.office365.com Anonymous https://outlook.office365.com/EWS/Exchange.asmx https://outlook.office365.com/EWS/Exchange.asmx https://outlook.office365.com/EWS/Exchange.asmx https://outlook.office365.com/EWS/Exchange.asmx https://outlook.office365.com/owa/ ?path=/options/callanswering ?path=/options/connectedaccounts options/ecp/PersonalSettings/DeliveryReport.aspx?rfr=olk&exsvurl=1&IsOWA=<IsOWA>&MsgID=<MsgID>&Mbx=<Mbx>&realm=exchange.test ?path=/options/retentionpolicies ?path=/options/calendarpublishing/id/<FldID> ?path=/options/myaccount/action/photo ?path=/options/socialnetworks&ignore1=<Action>&ignore2=<Provider> options/ecp/?rfr=olk&ftr=TeamMailbox&exsvurl=1&realm=exchange.test options/ecp/?rfr=olk&ftr=TeamMailboxCreating&SPUrl=<SPUrl>&Title=<Title>&SPTMAppUrl=<SPTMAppUrl>&exsvurl=1&realm=exchange.test options/ecp/?rfr=olk&ftr=TeamMailboxEditing&Id=<Id>&exsvurl=1&realm=exchange.test ?path=/options/manageapps https://outlook.office365.com/EWS/Exchange.asmx https://outlook.office365.com/OAB/6b838922-3d7e-4557-bf01-576e3b4e37fa/ off `; let redirectServer, autodiscoveryServer; let redirectAccepted = false; add_setup(async () => { redirectServer = new HttpServer(); redirectServer.start(-1); await Services.logins.initializationPromise; await SpecialPowers.pushPrefEnv({ set: [ ["mailnews.auto_config.fetchFromExchange.enabled", true], // Set the pref to load nothing. ["mailnews.auto_config_url", ""], ], }); // The initial server needs to be HTTP for the redirect to trigger. NetworkTestUtils.configureProxy( "autodiscover.exchange.test", 80, redirectServer.identity.primaryPort ); redirectServer.identity.add("http", "autodiscover.exchange.test", 80); redirectServer.registerPathHandler( "/autodiscover/autodiscover.xml", (request, response) => { response.setHeader("Cache-Control", "private"); response.setStatusLine(request.httpVersion, 301, "Moved Permanently"); response.setHeader( "Location", "https://dav.test/autodiscover/autodiscover.xml" ); } ); autodiscoveryServer = new HttpServer(); autodiscoveryServer.start(-1); // Set up a configuration file at // https://dav.test/autodiscover/autodiscover.xml" const redirectedAutodiscover = await HttpsProxy.create( autodiscoveryServer.identity.primaryPort, "dav", "dav.test" ); autodiscoveryServer.identity.add("https", "dav.test", 443); autodiscoveryServer.registerPathHandler( "/autodiscover/autodiscover.xml", (request, response) => { // We have to block the response here because one of the fetches in // autodisovery will find this config here instead of letting the above // server redirect to this one. info("autodiscovery"); if (redirectAccepted) { info("redirect has been accepted"); response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/xml"); response.write(AUTODISCOVER_RESPONSE); } else { response.setStatusLine(request.httpVersion, 404, "Not Found"); } } ); registerCleanupFunction(async () => { redirectServer.identity.remove("http", "autodiscover.exchange.test", 80); redirectServer.registerFile("/autodiscover/autodiscover.xml", null); redirectServer.stop(); redirectedAutodiscover.destroy(); autodiscoveryServer.identity.remove("https", "dav.test", 443); autodiscoveryServer.registerFile("/autodiscover/autodiscover.xml", null); autodiscoveryServer.stop(); Services.logins.removeAllLogins(); await SpecialPowers.popPrefEnv(); }); }); add_task(async function test_cancel_credentials_confirmation() { const dialog = await subtest_open_account_hub_dialog(); const emailTemplate = dialog.querySelector("email-auto-form"); const footerForward = dialog.querySelector("#emailFooter #forward"); const footerBack = dialog.querySelector("#emailFooter #back"); await fillUserInformation(emailTemplate); Assert.ok(!footerForward.disabled, "Continue button should be enabled"); // Click continue and wait for config found template to be in view. EventUtils.synthesizeMouseAtCenter(footerForward, {}); info("Expecting credentials confirmation prompt"); const confirmationStep = dialog.querySelector( "email-credentials-confirmation" ); await BrowserTestUtils.waitForAttributeRemoval("hidden", confirmationStep); const hostname = confirmationStep.querySelector("#hostname"); const username = confirmationStep.querySelector("#username"); const socketType = confirmationStep.querySelector("#socketType"); Assert.equal( hostname.textContent, "dav.test", "The hostname should be the redirect hostname" ); Assert.equal( username.textContent, emailUser.email, "The username should be email inputted" ); Assert.equal( socketType.textContent, "SSL/TLS", "The socket type should be set to secure" ); // Clicking back should go back to the email form. EventUtils.synthesizeMouseAtCenter(footerBack, {}); await BrowserTestUtils.waitForAttributeRemoval("hidden", emailTemplate); Services.logins.removeAllLogins(); await subtest_close_account_hub_dialog(dialog, emailTemplate); }); add_task(async function test_credentials_confirmation() { const dialog = await subtest_open_account_hub_dialog(); const emailTemplate = dialog.querySelector("email-auto-form"); const footerForward = dialog.querySelector("#emailFooter #forward"); await fillUserInformation(emailTemplate); Assert.ok(!footerForward.disabled, "Continue button should be enabled"); // Click continue and wait for credentials confirmation step to be in view. EventUtils.synthesizeMouseAtCenter(footerForward, {}); info("Expecting credentials confirmation prompt"); const confirmationStep = dialog.querySelector( "email-credentials-confirmation" ); await BrowserTestUtils.waitForAttributeRemoval("hidden", confirmationStep); const hostname = confirmationStep.querySelector("#hostname"); const username = confirmationStep.querySelector("#username"); const socketType = confirmationStep.querySelector("#socketType"); Assert.equal( hostname.textContent, "dav.test", "The hostname should be the redirect hostname" ); Assert.equal( username.textContent, emailUser.email, "The username should be email inputted" ); Assert.equal( socketType.textContent, "SSL/TLS", "The socket type should be set to secure" ); // Clicking continue should lead to the config found step. redirectAccepted = true; EventUtils.synthesizeMouseAtCenter(footerForward, {}); const configFoundTemplate = dialog.querySelector("email-config-found"); await BrowserTestUtils.waitForAttributeRemoval("hidden", configFoundTemplate); const ewsOption = configFoundTemplate.querySelector("#ews"); await TestUtils.waitForCondition( () => BrowserTestUtils.isVisible(ewsOption), "The IMAP config option should be visible" ); EventUtils.synthesizeMouseAtCenter(ewsOption, {}); Assert.equal( configFoundTemplate.querySelector("#incomingType").textContent, "ews", "Incoming type should be expected type" ); Assert.equal( configFoundTemplate.querySelector("#incomingHost").textContent, "outlook.office365.com", "Should have host from autoconfig" ); Assert.equal( configFoundTemplate.l10n.getAttributes( configFoundTemplate.querySelector("#incomingSocketType") ).id, "account-setup-result-ssl", "Incoming auth should be expected auth" ); Assert.equal( configFoundTemplate.querySelector("#incomingUsername").textContent, USER, "Incoming username should be expected username" ); redirectAccepted = false; Services.logins.removeAllLogins(); await subtest_close_account_hub_dialog(dialog, configFoundTemplate); }); add_task(async function test_credentials_confirmation_manual_configuration() { const dialog = await subtest_open_account_hub_dialog(); const emailTemplate = dialog.querySelector("email-auto-form"); const footerForward = dialog.querySelector("#emailFooter #forward"); await fillUserInformation(emailTemplate); Assert.ok(!footerForward.disabled, "Continue button should be enabled"); // Click continue and wait for credentials confirmation step to be in view. EventUtils.synthesizeMouseAtCenter(footerForward, {}); info("Expecting credentials confirmation prompt"); const confirmationStep = dialog.querySelector( "email-credentials-confirmation" ); await BrowserTestUtils.waitForAttributeRemoval("hidden", confirmationStep); const manualConfigButton = confirmationStep.querySelector( "#manualConfiguration" ); EventUtils.synthesizeMouseAtCenter(manualConfigButton, {}); const incomingConfigStep = dialog.querySelector( "#emailIncomingConfigSubview" ); await BrowserTestUtils.waitForAttributeRemoval("hidden", incomingConfigStep); Assert.equal( incomingConfigStep.querySelector("#incomingHostname").value, ".exchange.test", "The incoming hostname should be the domain with a period at the beginning" ); Assert.equal( incomingConfigStep.querySelector("#incomingAuthMethod").value, "0", "The auth method should be Autodetect" ); Assert.equal( incomingConfigStep.querySelector("#incomingUsername").value, "testExchange@exchange.test", "The username input should have the email that was submitted" ); Services.logins.removeAllLogins(); await subtest_close_account_hub_dialog(dialog, incomingConfigStep); }); /** * Fills the name and email inputs in the first step of account hub * email setup. * * @param {HTMLElement} emailStep - The email step HTML element. * @param {object} [userDetails] - Details to enter for the user. Defaults to the * emailUser object. */ async function fillUserInformation(emailStep, userDetails = emailUser) { const nameInput = emailStep.querySelector("#realName"); const emailInput = emailStep.querySelector("#email"); // Ensure fields are empty. nameInput.value = ""; emailInput.value = ""; EventUtils.synthesizeMouseAtCenter(nameInput, {}); let inputEvent = BrowserTestUtils.waitForEvent( nameInput, "input", false, event => event.target.value === userDetails.name ); EventUtils.sendString(userDetails.name, window); await inputEvent; EventUtils.synthesizeMouseAtCenter(emailInput, {}); inputEvent = BrowserTestUtils.waitForEvent( emailInput, "input", false, event => event.target.value === userDetails.email ); EventUtils.sendString(userDetails.email, window); await inputEvent; }