services/fxaccounts/tests/xpcshell/test_client.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* Any copyright is dedicated to the Public Domain.
     2  * http://creativecommons.org/publicdomain/zero/1.0/ */
     4 "use strict";
     6 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
     7 Cu.import("resource://gre/modules/Promise.jsm");
     8 Cu.import("resource://services-common/utils.js");
     9 Cu.import("resource://services-crypto/utils.js");
    11 const FAKE_SESSION_TOKEN = "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
    13 function run_test() {
    14   run_next_test();
    15 }
    17 // https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#.2Faccount.2Fkeys
    18 let ACCOUNT_KEYS = {
    19   keyFetch:     h("8081828384858687 88898a8b8c8d8e8f"+
    20                   "9091929394959697 98999a9b9c9d9e9f"),
    22   response:     h("ee5c58845c7c9412 b11bbd20920c2fdd"+
    23                   "d83c33c9cd2c2de2 d66b222613364636"+
    24                   "c2c0f8cfbb7c6304 72c0bd88451342c6"+
    25                   "c05b14ce342c5ad4 6ad89e84464c993c"+
    26                   "3927d30230157d08 17a077eef4b20d97"+
    27                   "6f7a97363faf3f06 4c003ada7d01aa70"),
    29   kA:           h("2021222324252627 28292a2b2c2d2e2f"+
    30                   "3031323334353637 38393a3b3c3d3e3f"),
    32   wrapKB:       h("4041424344454647 48494a4b4c4d4e4f"+
    33                   "5051525354555657 58595a5b5c5d5e5f"),
    34 };
    36 // https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-use-session-certificatesign-etc
    37 let SESSION_KEYS = {
    38   sessionToken: h("a0a1a2a3a4a5a6a7 a8a9aaabacadaeaf"+
    39                   "b0b1b2b3b4b5b6b7 b8b9babbbcbdbebf"),
    41   tokenID:      h("c0a29dcf46174973 da1378696e4c82ae"+
    42                   "10f723cf4f4d9f75 e39f4ae3851595ab"),
    44   reqHMACkey:   h("9d8f22998ee7f579 8b887042466b72d5"+
    45                   "3e56ab0c094388bf 65831f702d2febc0"),
    46 };
    48 function deferredStop(server) {
    49   let deferred = Promise.defer();
    50   server.stop(deferred.resolve);
    51   return deferred.promise;
    52 }
    54 add_task(function test_authenticated_get_request() {
    55   let message = "{\"msg\": \"Great Success!\"}";
    56   let credentials = {
    57     id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    58     key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    59     algorithm: "sha256"
    60   };
    61   let method = "GET";
    63   let server = httpd_setup({"/foo": function(request, response) {
    64       do_check_true(request.hasHeader("Authorization"));
    66       response.setStatusLine(request.httpVersion, 200, "OK");
    67       response.bodyOutputStream.write(message, message.length);
    68     }
    69   });
    71   let client = new FxAccountsClient(server.baseURI);
    73   let result = yield client._request("/foo", method, credentials);
    74   do_check_eq("Great Success!", result.msg);
    76   yield deferredStop(server);
    77 });
    79 add_task(function test_authenticated_post_request() {
    80   let credentials = {
    81     id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
    82     key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
    83     algorithm: "sha256"
    84   };
    85   let method = "POST";
    87   let server = httpd_setup({"/foo": function(request, response) {
    88       do_check_true(request.hasHeader("Authorization"));
    90       response.setStatusLine(request.httpVersion, 200, "OK");
    91       response.setHeader("Content-Type", "application/json");
    92       response.bodyOutputStream.writeFrom(request.bodyInputStream, request.bodyInputStream.available());
    93     }
    94   });
    96   let client = new FxAccountsClient(server.baseURI);
    98   let result = yield client._request("/foo", method, credentials, {foo: "bar"});
    99   do_check_eq("bar", result.foo);
   101   yield deferredStop(server);
   102 });
   104 add_task(function test_500_error() {
   105   let message = "<h1>Ooops!</h1>";
   106   let method = "GET";
   108   let server = httpd_setup({"/foo": function(request, response) {
   109       response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
   110       response.bodyOutputStream.write(message, message.length);
   111     }
   112   });
   114   let client = new FxAccountsClient(server.baseURI);
   116   try {
   117     yield client._request("/foo", method);
   118     do_throw("Expected to catch an exception");
   119   } catch (e) {
   120     do_check_eq(500, e.code);
   121     do_check_eq("Internal Server Error", e.message);
   122   }
   124   yield deferredStop(server);
   125 });
   127 add_task(function test_backoffError() {
   128   let method = "GET";
   129   let server = httpd_setup({
   130     "/retryDelay": function(request, response) {
   131       response.setHeader("Retry-After", "30");
   132       response.setStatusLine(request.httpVersion, 429, "Client has sent too many requests");
   133       let message = "<h1>Ooops!</h1>";
   134       response.bodyOutputStream.write(message, message.length);
   135     },
   136     "/duringDelayIShouldNotBeCalled": function(request, response) {
   137       response.setStatusLine(request.httpVersion, 200, "OK");
   138       let jsonMessage = "{\"working\": \"yes\"}";
   139       response.bodyOutputStream.write(jsonMessage, jsonMessage.length);
   140     },
   141   });
   143   let client = new FxAccountsClient(server.baseURI);
   145   // Retry-After header sets client.backoffError
   146   do_check_eq(client.backoffError, null);
   147   try {
   148     yield client._request("/retryDelay", method);
   149   } catch (e) {
   150     do_check_eq(429, e.code);
   151     do_check_eq(30, e.retryAfter);
   152     do_check_neq(typeof(client.fxaBackoffTimer), "undefined");
   153     do_check_neq(client.backoffError, null);
   154   }
   155   // While delay is in effect, client short-circuits any requests
   156   // and re-rejects with previous error.
   157   try {
   158     yield client._request("/duringDelayIShouldNotBeCalled", method);
   159     throw new Error("I should not be reached");
   160   } catch (e) {
   161     do_check_eq(e.retryAfter, 30);
   162     do_check_eq(e.message, "Client has sent too many requests");
   163     do_check_neq(client.backoffError, null);
   164   }
   165   // Once timer fires, client nulls error out and HTTP calls work again.
   166   client._clearBackoff();
   167   let result = yield client._request("/duringDelayIShouldNotBeCalled", method);
   168   do_check_eq(client.backoffError, null);
   169   do_check_eq(result.working, "yes");
   171   yield deferredStop(server);
   172 });
   174 add_task(function test_signUp() {
   175   let creationMessage = JSON.stringify({
   176     uid: "uid",
   177     sessionToken: "sessionToken",
   178     keyFetchToken: "keyFetchToken"
   179   });
   180   let errorMessage = JSON.stringify({code: 400, errno: 101, error: "account exists"});
   181   let created = false;
   183   let server = httpd_setup({
   184     "/account/create": function(request, response) {
   185       let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
   186       let jsonBody = JSON.parse(body);
   188       // https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-test-vectors
   189       do_check_eq(jsonBody.email, "andré@example.org");
   191       if (!created) {
   192         do_check_eq(jsonBody.authPW, "247b675ffb4c46310bc87e26d712153abe5e1c90ef00a4784594f97ef54f2375");
   193         created = true;
   195         response.setStatusLine(request.httpVersion, 200, "OK");
   196         response.bodyOutputStream.write(creationMessage, creationMessage.length);
   197         return;
   198       }
   200       // Error trying to create same account a second time
   201       response.setStatusLine(request.httpVersion, 400, "Bad request");
   202       response.bodyOutputStream.write(errorMessage, errorMessage.length);
   203       return;
   204     },
   205   });
   207   let client = new FxAccountsClient(server.baseURI);
   208   let result = yield client.signUp('andré@example.org', 'pässwörd');
   209   do_check_eq("uid", result.uid);
   210   do_check_eq("sessionToken", result.sessionToken);
   211   do_check_eq("keyFetchToken", result.keyFetchToken);
   213   // Try to create account again.  Triggers error path.
   214   try {
   215     result = yield client.signUp('andré@example.org', 'pässwörd');
   216     do_throw("Expected to catch an exception");
   217   } catch(expectedError) {
   218     do_check_eq(101, expectedError.errno);
   219   }
   221   yield deferredStop(server);
   222 });
   224 add_task(function test_signIn() {
   225   let sessionMessage_noKey = JSON.stringify({
   226     sessionToken: FAKE_SESSION_TOKEN
   227   });
   228   let sessionMessage_withKey = JSON.stringify({
   229     sessionToken: FAKE_SESSION_TOKEN,
   230     keyFetchToken: "keyFetchToken"
   231   });
   232   let errorMessage_notExistent = JSON.stringify({
   233     code: 400,
   234     errno: 102,
   235     error: "doesn't exist"
   236   });
   237   let errorMessage_wrongCap = JSON.stringify({
   238     code: 400,
   239     errno: 120,
   240     error: "Incorrect email case",
   241     email: "you@example.com"
   242   });
   244   let server = httpd_setup({
   245     "/account/login": function(request, response) {
   246       let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
   247       let jsonBody = JSON.parse(body);
   249       if (jsonBody.email == "mé@example.com") {
   250         do_check_eq("", request._queryString);
   251         do_check_eq(jsonBody.authPW, "08b9d111196b8408e8ed92439da49206c8ecfbf343df0ae1ecefcd1e0174a8b6");
   252         response.setStatusLine(request.httpVersion, 200, "OK");
   253         response.bodyOutputStream.write(sessionMessage_noKey,
   254                                         sessionMessage_noKey.length);
   255         return;
   256       }
   257       else if (jsonBody.email == "you@example.com") {
   258         do_check_eq("keys=true", request._queryString);
   259         do_check_eq(jsonBody.authPW, "93d20ec50304d496d0707ec20d7e8c89459b6396ec5dd5b9e92809c5e42856c7");
   260         response.setStatusLine(request.httpVersion, 200, "OK");
   261         response.bodyOutputStream.write(sessionMessage_withKey,
   262                                         sessionMessage_withKey.length);
   263         return;
   264       }
   265       else if (jsonBody.email == "You@example.com") {
   266         // Error trying to sign in with a wrong capitalization
   267         response.setStatusLine(request.httpVersion, 400, "Bad request");
   268         response.bodyOutputStream.write(errorMessage_wrongCap,
   269                                         errorMessage_wrongCap.length);
   270         return;
   271       }
   272       else {
   273         // Error trying to sign in to nonexistent account
   274         response.setStatusLine(request.httpVersion, 400, "Bad request");
   275         response.bodyOutputStream.write(errorMessage_notExistent,
   276                                         errorMessage_notExistent.length);
   277         return;
   278       }
   279     },
   280   });
   282   // Login without retrieving optional keys
   283   let client = new FxAccountsClient(server.baseURI);
   284   let result = yield client.signIn('mé@example.com', 'bigsecret');
   285   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
   286   do_check_eq(result.unwrapBKey,
   287               "c076ec3f4af123a615157154c6e1d0d6293e514fd7b0221e32d50517ecf002b8");
   288   do_check_eq(undefined, result.keyFetchToken);
   290   // Login with retrieving optional keys
   291   let result = yield client.signIn('you@example.com', 'bigsecret', true);
   292   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
   293   do_check_eq(result.unwrapBKey,
   294               "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624");
   295   do_check_eq("keyFetchToken", result.keyFetchToken);
   297   // Retry due to wrong email capitalization
   298   let result = yield client.signIn('You@example.com', 'bigsecret', true);
   299   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
   300   do_check_eq(result.unwrapBKey,
   301               "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624");
   302   do_check_eq("keyFetchToken", result.keyFetchToken);
   304   // Don't retry due to wrong email capitalization
   305   try {
   306     let result = yield client.signIn('You@example.com', 'bigsecret', true, false);
   307     do_throw("Expected to catch an exception");
   308   } catch (expectedError) {
   309     do_check_eq(120, expectedError.errno);
   310     do_check_eq("you@example.com", expectedError.email);
   311   }
   313   // Trigger error path
   314   try {
   315     result = yield client.signIn("yøü@bad.example.org", "nofear");
   316     do_throw("Expected to catch an exception");
   317   } catch (expectedError) {
   318     do_check_eq(102, expectedError.errno);
   319   }
   321   yield deferredStop(server);
   322 });
   324 add_task(function test_signOut() {
   325   let signoutMessage = JSON.stringify({});
   326   let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
   327   let signedOut = false;
   329   let server = httpd_setup({
   330     "/session/destroy": function(request, response) {
   331       if (!signedOut) {
   332         signedOut = true;
   333         do_check_true(request.hasHeader("Authorization"));
   334         response.setStatusLine(request.httpVersion, 200, "OK");
   335         response.bodyOutputStream.write(signoutMessage, signoutMessage.length);
   336         return;
   337       }
   339       // Error trying to sign out of nonexistent account
   340       response.setStatusLine(request.httpVersion, 400, "Bad request");
   341       response.bodyOutputStream.write(errorMessage, errorMessage.length);
   342       return;
   343     },
   344   });
   346   let client = new FxAccountsClient(server.baseURI);
   347   let result = yield client.signOut("FakeSession");
   348   do_check_eq(typeof result, "object");
   350   // Trigger error path
   351   try {
   352     result = yield client.signOut("FakeSession");
   353     do_throw("Expected to catch an exception");
   354   } catch(expectedError) {
   355     do_check_eq(102, expectedError.errno);
   356   }
   358   yield deferredStop(server);
   359 });
   361 add_task(function test_recoveryEmailStatus() {
   362   let emailStatus = JSON.stringify({verified: true});
   363   let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
   364   let tries = 0;
   366   let server = httpd_setup({
   367     "/recovery_email/status": function(request, response) {
   368       do_check_true(request.hasHeader("Authorization"));
   370       if (tries === 0) {
   371         tries += 1;
   372         response.setStatusLine(request.httpVersion, 200, "OK");
   373         response.bodyOutputStream.write(emailStatus, emailStatus.length);
   374         return;
   375       }
   377       // Second call gets an error trying to query a nonexistent account
   378       response.setStatusLine(request.httpVersion, 400, "Bad request");
   379       response.bodyOutputStream.write(errorMessage, errorMessage.length);
   380       return;
   381     },
   382   });
   384   let client = new FxAccountsClient(server.baseURI);
   385   let result = yield client.recoveryEmailStatus(FAKE_SESSION_TOKEN);
   386   do_check_eq(result.verified, true);
   388   // Trigger error path
   389   try {
   390     result = yield client.recoveryEmailStatus("some bogus session");
   391     do_throw("Expected to catch an exception");
   392   } catch(expectedError) {
   393     do_check_eq(102, expectedError.errno);
   394   }
   396   yield deferredStop(server);
   397 });
   399 add_task(function test_resendVerificationEmail() {
   400   let emptyMessage = "{}";
   401   let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
   402   let tries = 0;
   404   let server = httpd_setup({
   405     "/recovery_email/resend_code": function(request, response) {
   406       do_check_true(request.hasHeader("Authorization"));
   407       if (tries === 0) {
   408         tries += 1;
   409         response.setStatusLine(request.httpVersion, 200, "OK");
   410         response.bodyOutputStream.write(emptyMessage, emptyMessage.length);
   411         return;
   412       }
   414       // Second call gets an error trying to query a nonexistent account
   415       response.setStatusLine(request.httpVersion, 400, "Bad request");
   416       response.bodyOutputStream.write(errorMessage, errorMessage.length);
   417       return;
   418     },
   419   });
   421   let client = new FxAccountsClient(server.baseURI);
   422   let result = yield client.resendVerificationEmail(FAKE_SESSION_TOKEN);
   423   do_check_eq(JSON.stringify(result), emptyMessage);
   425   // Trigger error path
   426   try {
   427     result = yield client.resendVerificationEmail("some bogus session");
   428     do_throw("Expected to catch an exception");
   429   } catch(expectedError) {
   430     do_check_eq(102, expectedError.errno);
   431   }
   433   yield deferredStop(server);
   434 });
   436 add_task(function test_accountKeys() {
   437   // Four calls to accountKeys().  The first one should work correctly, and we
   438   // should get a valid bundle back, in exchange for our keyFetch token, from
   439   // which we correctly derive kA and wrapKB.  The subsequent three calls
   440   // should all trigger separate error paths.
   441   let responseMessage = JSON.stringify({bundle: ACCOUNT_KEYS.response});
   442   let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
   443   let emptyMessage = "{}";
   444   let attempt = 0;
   446   let server = httpd_setup({
   447     "/account/keys": function(request, response) {
   448       do_check_true(request.hasHeader("Authorization"));
   449       attempt += 1;
   451       switch(attempt) {
   452         case 1:
   453           // First time succeeds
   454           response.setStatusLine(request.httpVersion, 200, "OK");
   455           response.bodyOutputStream.write(responseMessage, responseMessage.length);
   456           break;
   458         case 2:
   459           // Second time, return no bundle to trigger client error
   460           response.setStatusLine(request.httpVersion, 200, "OK");
   461           response.bodyOutputStream.write(emptyMessage, emptyMessage.length);
   462           break;
   464         case 3:
   465           // Return gibberish to trigger client MAC error
   466           // Tweak a byte
   467           let garbageResponse = JSON.stringify({
   468             bundle: ACCOUNT_KEYS.response.slice(0, -1) + "1"
   469           });
   470           response.setStatusLine(request.httpVersion, 200, "OK");
   471           response.bodyOutputStream.write(garbageResponse, garbageResponse.length);
   472           break;
   474         case 4:
   475           // Trigger error for nonexistent account
   476           response.setStatusLine(request.httpVersion, 400, "Bad request");
   477           response.bodyOutputStream.write(errorMessage, errorMessage.length);
   478           break;
   479       }
   480     },
   481   });
   483   let client = new FxAccountsClient(server.baseURI);
   485   // First try, all should be good
   486   let result = yield client.accountKeys(ACCOUNT_KEYS.keyFetch);
   487   do_check_eq(CommonUtils.hexToBytes(ACCOUNT_KEYS.kA), result.kA);
   488   do_check_eq(CommonUtils.hexToBytes(ACCOUNT_KEYS.wrapKB), result.wrapKB);
   490   // Second try, empty bundle should trigger error
   491   try {
   492     result = yield client.accountKeys(ACCOUNT_KEYS.keyFetch);
   493     do_throw("Expected to catch an exception");
   494   } catch(expectedError) {
   495     do_check_eq(expectedError.message, "failed to retrieve keys");
   496   }
   498   // Third try, bad bundle results in MAC error
   499   try {
   500     result = yield client.accountKeys(ACCOUNT_KEYS.keyFetch);
   501     do_throw("Expected to catch an exception");
   502   } catch(expectedError) {
   503     do_check_eq(expectedError.message, "error unbundling encryption keys");
   504   }
   506   // Fourth try, pretend account doesn't exist
   507   try {
   508     result = yield client.accountKeys(ACCOUNT_KEYS.keyFetch);
   509     do_throw("Expected to catch an exception");
   510   } catch(expectedError) {
   511     do_check_eq(102, expectedError.errno);
   512   }
   514   yield deferredStop(server);
   515 });
   517 add_task(function test_signCertificate() {
   518   let certSignMessage = JSON.stringify({cert: {bar: "baz"}});
   519   let errorMessage = JSON.stringify({code: 400, errno: 102, error: "doesn't exist"});
   520   let tries = 0;
   522   let server = httpd_setup({
   523     "/certificate/sign": function(request, response) {
   524       do_check_true(request.hasHeader("Authorization"));
   526       if (tries === 0) {
   527         tries += 1;
   528         let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
   529         let jsonBody = JSON.parse(body);
   530         do_check_eq(JSON.parse(jsonBody.publicKey).foo, "bar");
   531         do_check_eq(jsonBody.duration, 600);
   532         response.setStatusLine(request.httpVersion, 200, "OK");
   533         response.bodyOutputStream.write(certSignMessage, certSignMessage.length);
   534         return;
   535       }
   537       // Second attempt, trigger error
   538       response.setStatusLine(request.httpVersion, 400, "Bad request");
   539       response.bodyOutputStream.write(errorMessage, errorMessage.length);
   540       return;
   541     },
   542   });
   544   let client = new FxAccountsClient(server.baseURI);
   545   let result = yield client.signCertificate(FAKE_SESSION_TOKEN, JSON.stringify({foo: "bar"}), 600);
   546   do_check_eq("baz", result.bar);
   548   // Account doesn't exist
   549   try {
   550     result = yield client.signCertificate("bogus", JSON.stringify({foo: "bar"}), 600);
   551     do_throw("Expected to catch an exception");
   552   } catch(expectedError) {
   553     do_check_eq(102, expectedError.errno);
   554   }
   556   yield deferredStop(server);
   557 });
   559 add_task(function test_accountExists() {
   560   let sessionMessage = JSON.stringify({sessionToken: FAKE_SESSION_TOKEN});
   561   let existsMessage = JSON.stringify({error: "wrong password", code: 400, errno: 103});
   562   let doesntExistMessage = JSON.stringify({error: "no such account", code: 400, errno: 102});
   563   let emptyMessage = "{}";
   565   let server = httpd_setup({
   566     "/account/login": function(request, response) {
   567       let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
   568       let jsonBody = JSON.parse(body);
   570       switch (jsonBody.email) {
   571         // We'll test that these users' accounts exist
   572         case "i.exist@example.com":
   573         case "i.also.exist@example.com":
   574           response.setStatusLine(request.httpVersion, 400, "Bad request");
   575           response.bodyOutputStream.write(existsMessage, existsMessage.length);
   576           break;
   578         // This user's account doesn't exist
   579         case "i.dont.exist@example.com":
   580           response.setStatusLine(request.httpVersion, 400, "Bad request");
   581           response.bodyOutputStream.write(doesntExistMessage, doesntExistMessage.length);
   582           break;
   584         // This user throws an unexpected response
   585         // This will reject the client signIn promise
   586         case "i.break.things@example.com":
   587           response.setStatusLine(request.httpVersion, 500, "Alas");
   588           response.bodyOutputStream.write(emptyMessage, emptyMessage.length);
   589           break;
   591         default:
   592           throw new Error("Unexpected login from " + jsonBody.email);
   593           break;
   594       }
   595     },
   596   });
   598   let client = new FxAccountsClient(server.baseURI);
   599   let result;
   601   result = yield client.accountExists("i.exist@example.com");
   602   do_check_true(result);
   604   result = yield client.accountExists("i.also.exist@example.com");
   605   do_check_true(result);
   607   result = yield client.accountExists("i.dont.exist@example.com");
   608   do_check_false(result);
   610   try {
   611     result = yield client.accountExists("i.break.things@example.com");
   612     do_throw("Expected to catch an exception");
   613   } catch(unexpectedError) {
   614     do_check_eq(unexpectedError.code, 500);
   615   }
   617   yield deferredStop(server);
   618 });
   620 add_task(function test_email_case() {
   621   let canonicalEmail = "greta.garbo@gmail.com";
   622   let clientEmail = "Greta.Garbo@gmail.COM";
   623   let attempts = 0;
   625   function writeResp(response, msg) {
   626     if (typeof msg === "object") {
   627       msg = JSON.stringify(msg);
   628     }
   629     response.bodyOutputStream.write(msg, msg.length);
   630   }
   632   let server = httpd_setup(
   633     {
   634       "/account/login": function(request, response) {
   635         response.setHeader("Content-Type", "application/json; charset=utf-8");
   636         attempts += 1;
   637         if (attempts > 2) {
   638           response.setStatusLine(request.httpVersion, 429, "Sorry, you had your chance");
   639           return writeResp(response, "");
   640         }
   642         let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
   643         let jsonBody = JSON.parse(body);
   644         let email = jsonBody.email;
   646         // If the client has the wrong case on the email, we return a 400, with
   647         // the capitalization of the email as saved in the accounts database.
   648         if (email == canonicalEmail) {
   649           response.setStatusLine(request.httpVersion, 200, "Yay");
   650           return writeResp(response, {areWeHappy: "yes"});
   651         }
   653         response.setStatusLine(request.httpVersion, 400, "Incorrect email case");
   654         return writeResp(response, {
   655           code: 400,
   656           errno: 120,
   657           error: "Incorrect email case",
   658           email: canonicalEmail
   659         });
   660       },
   661     }
   662   );
   664   let client = new FxAccountsClient(server.baseURI);
   666   let result = yield client.signIn(clientEmail, "123456");
   667   do_check_eq(result.areWeHappy, "yes");
   668   do_check_eq(attempts, 2);
   670   yield deferredStop(server);
   671 });
   673 add_task(function test__deriveHawkCredentials() {
   674   let client = new FxAccountsClient("https://example.org");
   676   let credentials = client._deriveHawkCredentials(
   677     SESSION_KEYS.sessionToken, "sessionToken");
   679   do_check_eq(credentials.algorithm, "sha256");
   680   do_check_eq(credentials.id, SESSION_KEYS.tokenID);
   681   do_check_eq(CommonUtils.bytesAsHex(credentials.key), SESSION_KEYS.reqHMACkey);
   682 });
   684 // turn formatted test vectors into normal hex strings
   685 function h(hexStr) {
   686   return hexStr.replace(/\s+/g, "");
   687 }

mercurial