michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {utils: Cu} = Components; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://services-common/utils.js"); michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsMgmtService", michael@0: "resource://gre/modules/FxAccountsMgmtService.jsm", michael@0: "FxAccountsMgmtService"); michael@0: michael@0: // At end of test, restore original state michael@0: const ORIGINAL_AUTH_URI = Services.prefs.getCharPref("identity.fxaccounts.auth.uri"); michael@0: let { SystemAppProxy } = Cu.import("resource://gre/modules/FxAccountsMgmtService.jsm"); michael@0: const ORIGINAL_SENDCUSTOM = SystemAppProxy._sendCustomEvent; michael@0: do_register_cleanup(function() { michael@0: Services.prefs.setCharPref("identity.fxaccounts.auth.uri", ORIGINAL_AUTH_URI); michael@0: SystemAppProxy._sendCustomEvent = ORIGINAL_SENDCUSTOM; michael@0: }); michael@0: michael@0: // Make profile available so that fxaccounts can store user data michael@0: do_get_profile(); michael@0: michael@0: // Mock the system app proxy; make message passing possible michael@0: let mockSendCustomEvent = function(aEventName, aMsg) { michael@0: Services.obs.notifyObservers({wrappedJSObject: aMsg}, aEventName, null); michael@0: }; michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_task(function test_overall() { michael@0: do_check_neq(FxAccountsMgmtService, null); michael@0: }); michael@0: michael@0: // Check that invalid email capitalization is corrected on signIn. michael@0: // https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#post-v1accountlogin michael@0: add_test(function test_invalidEmailCase_signIn() { michael@0: do_test_pending(); michael@0: let clientEmail = "greta.garbo@gmail.com"; michael@0: let canonicalEmail = "Greta.Garbo@gmail.COM"; michael@0: let attempts = 0; michael@0: michael@0: function writeResp(response, msg) { michael@0: if (typeof msg === "object") { michael@0: msg = JSON.stringify(msg); michael@0: } michael@0: response.bodyOutputStream.write(msg, msg.length); michael@0: } michael@0: michael@0: // Mock of the fxa accounts auth server, reproducing the behavior of michael@0: // /account/login when email capitalization is incorrect on signIn. michael@0: let server = httpd_setup({ michael@0: "/account/login": function(request, response) { michael@0: response.setHeader("Content-Type", "application/json"); michael@0: attempts += 1; michael@0: michael@0: // Ensure we don't get in an endless loop michael@0: if (attempts > 2) { michael@0: response.setStatusLine(request.httpVersion, 429, "Sorry, you had your chance"); michael@0: writeResp(response, {}); michael@0: return; michael@0: } michael@0: michael@0: let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream); michael@0: let jsonBody = JSON.parse(body); michael@0: let email = jsonBody.email; michael@0: michael@0: // The second time through, the accounts client will call the api with michael@0: // the correct email capitalization. michael@0: if (email == canonicalEmail) { michael@0: response.setStatusLine(request.httpVersion, 200, "Yay"); michael@0: writeResp(response, { michael@0: uid: "your-uid", michael@0: sessionToken: "your-sessionToken", michael@0: keyFetchToken: "your-keyFetchToken", michael@0: verified: true, michael@0: authAt: 1392144866, michael@0: }); michael@0: return; michael@0: } michael@0: michael@0: // If the client has the wrong case on the email, we return a 400, with michael@0: // the capitalization of the email as saved in the accounts database. michael@0: response.setStatusLine(request.httpVersion, 400, "Incorrect email case"); michael@0: writeResp(response, { michael@0: code: 400, michael@0: errno: 120, michael@0: error: "Incorrect email case", michael@0: email: canonicalEmail, michael@0: }); michael@0: return; michael@0: }, michael@0: }); michael@0: michael@0: // Point the FxAccountsClient's hawk rest request client to the mock server michael@0: Services.prefs.setCharPref("identity.fxaccounts.auth.uri", server.baseURI); michael@0: michael@0: // Receive a mozFxAccountsChromeEvent message michael@0: function onMessage(subject, topic, data) { michael@0: let message = subject.wrappedJSObject; michael@0: michael@0: switch (message.id) { michael@0: // When we signed in as "Greta.Garbo", the server should have told us michael@0: // that the proper capitalization is really "greta.garbo". Call michael@0: // getAccounts to get the signed-in user and ensure that the michael@0: // capitalization is correct. michael@0: case "signIn": michael@0: FxAccountsMgmtService.handleEvent({ michael@0: detail: { michael@0: id: "getAccounts", michael@0: data: { michael@0: method: "getAccounts", michael@0: } michael@0: } michael@0: }); michael@0: break; michael@0: michael@0: // Having initially signed in as "Greta.Garbo", getAccounts should show michael@0: // us that the signed-in user has the properly-capitalized email, michael@0: // "greta.garbo". michael@0: case "getAccounts": michael@0: Services.obs.removeObserver(onMessage, "mozFxAccountsChromeEvent"); michael@0: michael@0: do_check_eq(message.data.accountId, canonicalEmail); michael@0: michael@0: do_test_finished(); michael@0: server.stop(run_next_test); michael@0: break; michael@0: michael@0: // We should not receive any other mozFxAccountsChromeEvent messages michael@0: default: michael@0: do_throw("wat!"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: Services.obs.addObserver(onMessage, "mozFxAccountsChromeEvent", false); michael@0: michael@0: SystemAppProxy._sendCustomEvent = mockSendCustomEvent; michael@0: michael@0: // Trigger signIn using an email with incorrect capitalization michael@0: FxAccountsMgmtService.handleEvent({ michael@0: detail: { michael@0: id: "signIn", michael@0: data: { michael@0: method: "signIn", michael@0: accountId: clientEmail, michael@0: password: "123456", michael@0: }, michael@0: }, michael@0: }); michael@0: }); michael@0: michael@0: // End of tests michael@0: // Utility functions follow michael@0: michael@0: function httpd_setup (handlers, port=-1) { michael@0: let server = new HttpServer(); michael@0: for (let path in handlers) { michael@0: server.registerPathHandler(path, handlers[path]); michael@0: } michael@0: try { michael@0: server.start(port); michael@0: } catch (ex) { michael@0: dump("ERROR starting server on port " + port + ". Already a process listening?"); michael@0: do_throw(ex); michael@0: } michael@0: michael@0: // Set the base URI for convenience. michael@0: let i = server.identity; michael@0: server.baseURI = i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort; michael@0: michael@0: return server; michael@0: } michael@0: michael@0: