services/fxaccounts/tests/xpcshell/test_client.js

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:86ce1d460c45
1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
3
4 "use strict";
5
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");
10
11 const FAKE_SESSION_TOKEN = "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
12
13 function run_test() {
14 run_next_test();
15 }
16
17 // https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#.2Faccount.2Fkeys
18 let ACCOUNT_KEYS = {
19 keyFetch: h("8081828384858687 88898a8b8c8d8e8f"+
20 "9091929394959697 98999a9b9c9d9e9f"),
21
22 response: h("ee5c58845c7c9412 b11bbd20920c2fdd"+
23 "d83c33c9cd2c2de2 d66b222613364636"+
24 "c2c0f8cfbb7c6304 72c0bd88451342c6"+
25 "c05b14ce342c5ad4 6ad89e84464c993c"+
26 "3927d30230157d08 17a077eef4b20d97"+
27 "6f7a97363faf3f06 4c003ada7d01aa70"),
28
29 kA: h("2021222324252627 28292a2b2c2d2e2f"+
30 "3031323334353637 38393a3b3c3d3e3f"),
31
32 wrapKB: h("4041424344454647 48494a4b4c4d4e4f"+
33 "5051525354555657 58595a5b5c5d5e5f"),
34 };
35
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"),
40
41 tokenID: h("c0a29dcf46174973 da1378696e4c82ae"+
42 "10f723cf4f4d9f75 e39f4ae3851595ab"),
43
44 reqHMACkey: h("9d8f22998ee7f579 8b887042466b72d5"+
45 "3e56ab0c094388bf 65831f702d2febc0"),
46 };
47
48 function deferredStop(server) {
49 let deferred = Promise.defer();
50 server.stop(deferred.resolve);
51 return deferred.promise;
52 }
53
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";
62
63 let server = httpd_setup({"/foo": function(request, response) {
64 do_check_true(request.hasHeader("Authorization"));
65
66 response.setStatusLine(request.httpVersion, 200, "OK");
67 response.bodyOutputStream.write(message, message.length);
68 }
69 });
70
71 let client = new FxAccountsClient(server.baseURI);
72
73 let result = yield client._request("/foo", method, credentials);
74 do_check_eq("Great Success!", result.msg);
75
76 yield deferredStop(server);
77 });
78
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";
86
87 let server = httpd_setup({"/foo": function(request, response) {
88 do_check_true(request.hasHeader("Authorization"));
89
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 });
95
96 let client = new FxAccountsClient(server.baseURI);
97
98 let result = yield client._request("/foo", method, credentials, {foo: "bar"});
99 do_check_eq("bar", result.foo);
100
101 yield deferredStop(server);
102 });
103
104 add_task(function test_500_error() {
105 let message = "<h1>Ooops!</h1>";
106 let method = "GET";
107
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 });
113
114 let client = new FxAccountsClient(server.baseURI);
115
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 }
123
124 yield deferredStop(server);
125 });
126
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 });
142
143 let client = new FxAccountsClient(server.baseURI);
144
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");
170
171 yield deferredStop(server);
172 });
173
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;
182
183 let server = httpd_setup({
184 "/account/create": function(request, response) {
185 let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
186 let jsonBody = JSON.parse(body);
187
188 // https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#wiki-test-vectors
189 do_check_eq(jsonBody.email, "andré@example.org");
190
191 if (!created) {
192 do_check_eq(jsonBody.authPW, "247b675ffb4c46310bc87e26d712153abe5e1c90ef00a4784594f97ef54f2375");
193 created = true;
194
195 response.setStatusLine(request.httpVersion, 200, "OK");
196 response.bodyOutputStream.write(creationMessage, creationMessage.length);
197 return;
198 }
199
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 });
206
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);
212
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 }
220
221 yield deferredStop(server);
222 });
223
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 });
243
244 let server = httpd_setup({
245 "/account/login": function(request, response) {
246 let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
247 let jsonBody = JSON.parse(body);
248
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 });
281
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);
289
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);
296
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);
303
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 }
312
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 }
320
321 yield deferredStop(server);
322 });
323
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;
328
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 }
338
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 });
345
346 let client = new FxAccountsClient(server.baseURI);
347 let result = yield client.signOut("FakeSession");
348 do_check_eq(typeof result, "object");
349
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 }
357
358 yield deferredStop(server);
359 });
360
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;
365
366 let server = httpd_setup({
367 "/recovery_email/status": function(request, response) {
368 do_check_true(request.hasHeader("Authorization"));
369
370 if (tries === 0) {
371 tries += 1;
372 response.setStatusLine(request.httpVersion, 200, "OK");
373 response.bodyOutputStream.write(emailStatus, emailStatus.length);
374 return;
375 }
376
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 });
383
384 let client = new FxAccountsClient(server.baseURI);
385 let result = yield client.recoveryEmailStatus(FAKE_SESSION_TOKEN);
386 do_check_eq(result.verified, true);
387
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 }
395
396 yield deferredStop(server);
397 });
398
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;
403
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 }
413
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 });
420
421 let client = new FxAccountsClient(server.baseURI);
422 let result = yield client.resendVerificationEmail(FAKE_SESSION_TOKEN);
423 do_check_eq(JSON.stringify(result), emptyMessage);
424
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 }
432
433 yield deferredStop(server);
434 });
435
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;
445
446 let server = httpd_setup({
447 "/account/keys": function(request, response) {
448 do_check_true(request.hasHeader("Authorization"));
449 attempt += 1;
450
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;
457
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;
463
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;
473
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 });
482
483 let client = new FxAccountsClient(server.baseURI);
484
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);
489
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 }
497
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 }
505
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 }
513
514 yield deferredStop(server);
515 });
516
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;
521
522 let server = httpd_setup({
523 "/certificate/sign": function(request, response) {
524 do_check_true(request.hasHeader("Authorization"));
525
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 }
536
537 // Second attempt, trigger error
538 response.setStatusLine(request.httpVersion, 400, "Bad request");
539 response.bodyOutputStream.write(errorMessage, errorMessage.length);
540 return;
541 },
542 });
543
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);
547
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 }
555
556 yield deferredStop(server);
557 });
558
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 = "{}";
564
565 let server = httpd_setup({
566 "/account/login": function(request, response) {
567 let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
568 let jsonBody = JSON.parse(body);
569
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;
577
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;
583
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;
590
591 default:
592 throw new Error("Unexpected login from " + jsonBody.email);
593 break;
594 }
595 },
596 });
597
598 let client = new FxAccountsClient(server.baseURI);
599 let result;
600
601 result = yield client.accountExists("i.exist@example.com");
602 do_check_true(result);
603
604 result = yield client.accountExists("i.also.exist@example.com");
605 do_check_true(result);
606
607 result = yield client.accountExists("i.dont.exist@example.com");
608 do_check_false(result);
609
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 }
616
617 yield deferredStop(server);
618 });
619
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;
624
625 function writeResp(response, msg) {
626 if (typeof msg === "object") {
627 msg = JSON.stringify(msg);
628 }
629 response.bodyOutputStream.write(msg, msg.length);
630 }
631
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 }
641
642 let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
643 let jsonBody = JSON.parse(body);
644 let email = jsonBody.email;
645
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 }
652
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 );
663
664 let client = new FxAccountsClient(server.baseURI);
665
666 let result = yield client.signIn(clientEmail, "123456");
667 do_check_eq(result.areWeHappy, "yes");
668 do_check_eq(attempts, 2);
669
670 yield deferredStop(server);
671 });
672
673 add_task(function test__deriveHawkCredentials() {
674 let client = new FxAccountsClient("https://example.org");
675
676 let credentials = client._deriveHawkCredentials(
677 SESSION_KEYS.sessionToken, "sessionToken");
678
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 });
683
684 // turn formatted test vectors into normal hex strings
685 function h(hexStr) {
686 return hexStr.replace(/\s+/g, "");
687 }

mercurial