UNPKG

27 kBJavaScriptView Raw
1/*
2Copyright 2016 OpenMarket Ltd
3Copyright 2017 Vector Creations Ltd
4Copyright 2018 New Vector Ltd
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19/* This file consists of a set of integration tests which try to simulate
20 * communication via an Olm-encrypted room between two users, Alice and Bob.
21 *
22 * Note that megolm (group) conversation is not tested here.
23 *
24 * See also `megolm.spec.js`.
25 */
26
27"use strict";
28import 'source-map-support/register';
29
30// load olm before the sdk if possible
31import '../olm-loader';
32
33import expect from 'expect';
34const sdk = require("../..");
35import Promise from 'bluebird';
36const utils = require("../../lib/utils");
37const testUtils = require("../test-utils");
38const TestClient = require('../TestClient').default;
39import logger from '../../src/logger';
40
41let aliTestClient;
42const roomId = "!room:localhost";
43const aliUserId = "@ali:localhost";
44const aliDeviceId = "zxcvb";
45const aliAccessToken = "aseukfgwef";
46let bobTestClient;
47const bobUserId = "@bob:localhost";
48const bobDeviceId = "bvcxz";
49const bobAccessToken = "fewgfkuesa";
50let aliMessages;
51let bobMessages;
52
53function bobUploadsDeviceKeys() {
54 bobTestClient.expectDeviceKeyUpload();
55 return Promise.all([
56 bobTestClient.client.uploadKeys(),
57 bobTestClient.httpBackend.flush(),
58 ]).then(() => {
59 expect(Object.keys(bobTestClient.deviceKeys).length).toNotEqual(0);
60 });
61}
62
63/**
64 * Set an expectation that ali will query bobs keys; then flush the http request.
65 *
66 * @return {promise} resolves once the http request has completed.
67 */
68function expectAliQueryKeys() {
69 // can't query keys before bob has uploaded them
70 expect(bobTestClient.deviceKeys).toBeTruthy();
71
72 const bobKeys = {};
73 bobKeys[bobDeviceId] = bobTestClient.deviceKeys;
74 aliTestClient.httpBackend.when("POST", "/keys/query")
75 .respond(200, function(path, content) {
76 expect(content.device_keys[bobUserId]).toEqual(
77 {},
78 "Expected Alice to key query for " + bobUserId + ", got " +
79 Object.keys(content.device_keys),
80 );
81 const result = {};
82 result[bobUserId] = bobKeys;
83 return {device_keys: result};
84 });
85 return aliTestClient.httpBackend.flush("/keys/query", 1);
86}
87
88/**
89 * Set an expectation that bob will query alis keys; then flush the http request.
90 *
91 * @return {promise} which resolves once the http request has completed.
92 */
93function expectBobQueryKeys() {
94 // can't query keys before ali has uploaded them
95 expect(aliTestClient.deviceKeys).toBeTruthy();
96
97 const aliKeys = {};
98 aliKeys[aliDeviceId] = aliTestClient.deviceKeys;
99 logger.log("query result will be", aliKeys);
100
101 bobTestClient.httpBackend.when(
102 "POST", "/keys/query",
103 ).respond(200, function(path, content) {
104 expect(content.device_keys[aliUserId]).toEqual(
105 {},
106 "Expected Bob to key query for " + aliUserId + ", got " +
107 Object.keys(content.device_keys),
108 );
109 const result = {};
110 result[aliUserId] = aliKeys;
111 return {device_keys: result};
112 });
113 return bobTestClient.httpBackend.flush("/keys/query", 1);
114}
115
116/**
117 * Set an expectation that ali will claim one of bob's keys; then flush the http request.
118 *
119 * @return {promise} resolves once the http request has completed.
120 */
121function expectAliClaimKeys() {
122 return bobTestClient.awaitOneTimeKeyUpload().then((keys) => {
123 aliTestClient.httpBackend.when(
124 "POST", "/keys/claim",
125 ).respond(200, function(path, content) {
126 const claimType = content.one_time_keys[bobUserId][bobDeviceId];
127 expect(claimType).toEqual("signed_curve25519");
128 let keyId = null;
129 for (keyId in keys) {
130 if (bobTestClient.oneTimeKeys.hasOwnProperty(keyId)) {
131 if (keyId.indexOf(claimType + ":") === 0) {
132 break;
133 }
134 }
135 }
136 const result = {};
137 result[bobUserId] = {};
138 result[bobUserId][bobDeviceId] = {};
139 result[bobUserId][bobDeviceId][keyId] = keys[keyId];
140 return {one_time_keys: result};
141 });
142 }).then(() => {
143 // it can take a while to process the key query, so give it some extra
144 // time, and make sure the claim actually happens rather than ploughing on
145 // confusingly.
146 return aliTestClient.httpBackend.flush("/keys/claim", 1, 500).then((r) => {
147 expect(r).toEqual(1, "Ali did not claim Bob's keys");
148 });
149 });
150}
151
152
153function aliDownloadsKeys() {
154 // can't query keys before bob has uploaded them
155 expect(bobTestClient.getSigningKey()).toBeTruthy();
156
157 const p1 = aliTestClient.client.downloadKeys([bobUserId]).then(function() {
158 return aliTestClient.client.getStoredDevicesForUser(bobUserId);
159 }).then((devices) => {
160 expect(devices.length).toEqual(1);
161 expect(devices[0].deviceId).toEqual("bvcxz");
162 });
163 const p2 = expectAliQueryKeys();
164
165 // check that the localStorage is updated as we expect (not sure this is
166 // an integration test, but meh)
167 return Promise.all([p1, p2]).then(() => {
168 return aliTestClient.client._crypto._deviceList.saveIfDirty();
169 }).then(() => {
170 aliTestClient.cryptoStore.getEndToEndDeviceData(null, (data) => {
171 const devices = data.devices[bobUserId];
172 expect(devices[bobDeviceId].keys).toEqual(bobTestClient.deviceKeys.keys);
173 expect(devices[bobDeviceId].verified).
174 toBe(0); // DeviceVerification.UNVERIFIED
175 });
176 });
177}
178
179function aliEnablesEncryption() {
180 return aliTestClient.client.setRoomEncryption(roomId, {
181 algorithm: "m.olm.v1.curve25519-aes-sha2",
182 }).then(function() {
183 expect(aliTestClient.client.isRoomEncrypted(roomId)).toBeTruthy();
184 });
185}
186
187function bobEnablesEncryption() {
188 return bobTestClient.client.setRoomEncryption(roomId, {
189 algorithm: "m.olm.v1.curve25519-aes-sha2",
190 }).then(function() {
191 expect(bobTestClient.client.isRoomEncrypted(roomId)).toBeTruthy();
192 });
193}
194
195/**
196 * Ali sends a message, first claiming e2e keys. Set the expectations and
197 * check the results.
198 *
199 * @return {promise} which resolves to the ciphertext for Bob's device.
200 */
201function aliSendsFirstMessage() {
202 return Promise.all([
203 sendMessage(aliTestClient.client),
204 expectAliQueryKeys()
205 .then(expectAliClaimKeys)
206 .then(expectAliSendMessageRequest),
207 ]).spread(function(_, ciphertext) {
208 return ciphertext;
209 });
210}
211
212/**
213 * Ali sends a message without first claiming e2e keys. Set the expectations
214 * and check the results.
215 *
216 * @return {promise} which resolves to the ciphertext for Bob's device.
217 */
218function aliSendsMessage() {
219 return Promise.all([
220 sendMessage(aliTestClient.client),
221 expectAliSendMessageRequest(),
222 ]).spread(function(_, ciphertext) {
223 return ciphertext;
224 });
225}
226
227/**
228 * Bob sends a message, first querying (but not claiming) e2e keys. Set the
229 * expectations and check the results.
230 *
231 * @return {promise} which resolves to the ciphertext for Ali's device.
232 */
233function bobSendsReplyMessage() {
234 return Promise.all([
235 sendMessage(bobTestClient.client),
236 expectBobQueryKeys()
237 .then(expectBobSendMessageRequest),
238 ]).spread(function(_, ciphertext) {
239 return ciphertext;
240 });
241}
242
243/**
244 * Set an expectation that Ali will send a message, and flush the request
245 *
246 * @return {promise} which resolves to the ciphertext for Bob's device.
247 */
248function expectAliSendMessageRequest() {
249 return expectSendMessageRequest(aliTestClient.httpBackend).then(function(content) {
250 aliMessages.push(content);
251 expect(utils.keys(content.ciphertext)).toEqual([bobTestClient.getDeviceKey()]);
252 const ciphertext = content.ciphertext[bobTestClient.getDeviceKey()];
253 expect(ciphertext).toBeTruthy();
254 return ciphertext;
255 });
256}
257
258/**
259 * Set an expectation that Bob will send a message, and flush the request
260 *
261 * @return {promise} which resolves to the ciphertext for Bob's device.
262 */
263function expectBobSendMessageRequest() {
264 return expectSendMessageRequest(bobTestClient.httpBackend).then(function(content) {
265 bobMessages.push(content);
266 const aliKeyId = "curve25519:" + aliDeviceId;
267 const aliDeviceCurve25519Key = aliTestClient.deviceKeys.keys[aliKeyId];
268 expect(utils.keys(content.ciphertext)).toEqual([aliDeviceCurve25519Key]);
269 const ciphertext = content.ciphertext[aliDeviceCurve25519Key];
270 expect(ciphertext).toBeTruthy();
271 return ciphertext;
272 });
273}
274
275function sendMessage(client) {
276 return client.sendMessage(
277 roomId, {msgtype: "m.text", body: "Hello, World"},
278 );
279}
280
281function expectSendMessageRequest(httpBackend) {
282 const path = "/send/m.room.encrypted/";
283 const deferred = Promise.defer();
284 httpBackend.when("PUT", path).respond(200, function(path, content) {
285 deferred.resolve(content);
286 return {
287 event_id: "asdfgh",
288 };
289 });
290
291 // it can take a while to process the key query
292 return httpBackend.flush(path, 1).then(() => deferred.promise);
293}
294
295function aliRecvMessage() {
296 const message = bobMessages.shift();
297 return recvMessage(
298 aliTestClient.httpBackend, aliTestClient.client, bobUserId, message,
299 );
300}
301
302function bobRecvMessage() {
303 const message = aliMessages.shift();
304 return recvMessage(
305 bobTestClient.httpBackend, bobTestClient.client, aliUserId, message,
306 );
307}
308
309function recvMessage(httpBackend, client, sender, message) {
310 const syncData = {
311 next_batch: "x",
312 rooms: {
313 join: {
314
315 },
316 },
317 };
318 syncData.rooms.join[roomId] = {
319 timeline: {
320 events: [
321 testUtils.mkEvent({
322 type: "m.room.encrypted",
323 room: roomId,
324 content: message,
325 sender: sender,
326 }),
327 ],
328 },
329 };
330 httpBackend.when("GET", "/sync").respond(200, syncData);
331
332 const eventPromise = new Promise((resolve, reject) => {
333 const onEvent = function(event) {
334 // ignore the m.room.member events
335 if (event.getType() == "m.room.member") {
336 return;
337 }
338 logger.log(client.credentials.userId + " received event",
339 event);
340
341 client.removeListener("event", onEvent);
342 resolve(event);
343 };
344 client.on("event", onEvent);
345 });
346
347 httpBackend.flush();
348
349 return eventPromise.then((event) => {
350 expect(event.isEncrypted()).toBeTruthy();
351
352 // it may still be being decrypted
353 return testUtils.awaitDecryption(event);
354 }).then((event) => {
355 expect(event.getType()).toEqual("m.room.message");
356 expect(event.getContent()).toEqual({
357 msgtype: "m.text",
358 body: "Hello, World",
359 });
360 expect(event.isEncrypted()).toBeTruthy();
361 });
362}
363
364
365/**
366 * Send an initial sync response to the client (which just includes the member
367 * list for our test room).
368 *
369 * @param {TestClient} testClient
370 * @returns {Promise} which resolves when the sync has been flushed.
371 */
372function firstSync(testClient) {
373 // send a sync response including our test room.
374 const syncData = {
375 next_batch: "x",
376 rooms: {
377 join: { },
378 },
379 };
380 syncData.rooms.join[roomId] = {
381 state: {
382 events: [
383 testUtils.mkMembership({
384 mship: "join",
385 user: aliUserId,
386 }),
387 testUtils.mkMembership({
388 mship: "join",
389 user: bobUserId,
390 }),
391 ],
392 },
393 timeline: {
394 events: [],
395 },
396 };
397
398 testClient.httpBackend.when("GET", "/sync").respond(200, syncData);
399 return testClient.flushSync();
400}
401
402
403describe("MatrixClient crypto", function() {
404 if (!sdk.CRYPTO_ENABLED) {
405 return;
406 }
407
408 beforeEach(async function() {
409 testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
410
411 aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
412 await aliTestClient.client.initCrypto();
413
414 bobTestClient = new TestClient(bobUserId, bobDeviceId, bobAccessToken);
415 await bobTestClient.client.initCrypto();
416
417 aliMessages = [];
418 bobMessages = [];
419 });
420
421 afterEach(function() {
422 aliTestClient.httpBackend.verifyNoOutstandingExpectation();
423 bobTestClient.httpBackend.verifyNoOutstandingExpectation();
424
425 return Promise.all([aliTestClient.stop(), bobTestClient.stop()]);
426 });
427
428 it("Bob uploads device keys", function() {
429 return Promise.resolve()
430 .then(bobUploadsDeviceKeys);
431 });
432
433 it("Ali downloads Bobs device keys", function(done) {
434 Promise.resolve()
435 .then(bobUploadsDeviceKeys)
436 .then(aliDownloadsKeys)
437 .nodeify(done);
438 });
439
440 it("Ali gets keys with an invalid signature", function(done) {
441 Promise.resolve()
442 .then(bobUploadsDeviceKeys)
443 .then(function() {
444 // tamper bob's keys
445 const bobDeviceKeys = bobTestClient.deviceKeys;
446 expect(bobDeviceKeys.keys["curve25519:" + bobDeviceId]).toBeTruthy();
447 bobDeviceKeys.keys["curve25519:" + bobDeviceId] += "abc";
448
449 return Promise.all([
450 aliTestClient.client.downloadKeys([bobUserId]),
451 expectAliQueryKeys(),
452 ]);
453 }).then(function() {
454 return aliTestClient.client.getStoredDevicesForUser(bobUserId);
455 }).then((devices) => {
456 // should get an empty list
457 expect(devices).toEqual([]);
458 })
459 .nodeify(done);
460 });
461
462 it("Ali gets keys with an incorrect userId", function(done) {
463 const eveUserId = "@eve:localhost";
464
465 const bobDeviceKeys = {
466 algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
467 device_id: 'bvcxz',
468 keys: {
469 'ed25519:bvcxz': 'pYuWKMCVuaDLRTM/eWuB8OlXEb61gZhfLVJ+Y54tl0Q',
470 'curve25519:bvcxz': '7Gni0loo/nzF0nFp9847RbhElGewzwUXHPrljjBGPTQ',
471 },
472 user_id: '@eve:localhost',
473 signatures: {
474 '@eve:localhost': {
475 'ed25519:bvcxz': 'CliUPZ7dyVPBxvhSA1d+X+LYa5b2AYdjcTwG' +
476 '0stXcIxjaJNemQqtdgwKDtBFl3pN2I13SEijRDCf1A8bYiQMDg',
477 },
478 },
479 };
480
481 const bobKeys = {};
482 bobKeys[bobDeviceId] = bobDeviceKeys;
483 aliTestClient.httpBackend.when(
484 "POST", "/keys/query",
485 ).respond(200, function(path, content) {
486 const result = {};
487 result[bobUserId] = bobKeys;
488 return {device_keys: result};
489 });
490
491 Promise.all([
492 aliTestClient.client.downloadKeys([bobUserId, eveUserId]),
493 aliTestClient.httpBackend.flush("/keys/query", 1),
494 ]).then(function() {
495 return Promise.all([
496 aliTestClient.client.getStoredDevicesForUser(bobUserId),
497 aliTestClient.client.getStoredDevicesForUser(eveUserId),
498 ]);
499 }).spread((bobDevices, eveDevices) => {
500 // should get an empty list
501 expect(bobDevices).toEqual([]);
502 expect(eveDevices).toEqual([]);
503 }).nodeify(done);
504 });
505
506 it("Ali gets keys with an incorrect deviceId", function(done) {
507 const bobDeviceKeys = {
508 algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
509 device_id: 'bad_device',
510 keys: {
511 'ed25519:bad_device': 'e8XlY5V8x2yJcwa5xpSzeC/QVOrU+D5qBgyTK0ko+f0',
512 'curve25519:bad_device': 'YxuuLG/4L5xGeP8XPl5h0d7DzyYVcof7J7do+OXz0xc',
513 },
514 user_id: '@bob:localhost',
515 signatures: {
516 '@bob:localhost': {
517 'ed25519:bad_device': 'fEFTq67RaSoIEVBJ8DtmRovbwUBKJ0A' +
518 'me9m9PDzM9azPUwZ38Xvf6vv1A7W1PSafH4z3Y2ORIyEnZgHaNby3CQ',
519 },
520 },
521 };
522
523 const bobKeys = {};
524 bobKeys[bobDeviceId] = bobDeviceKeys;
525 aliTestClient.httpBackend.when(
526 "POST", "/keys/query",
527 ).respond(200, function(path, content) {
528 const result = {};
529 result[bobUserId] = bobKeys;
530 return {device_keys: result};
531 });
532
533 Promise.all([
534 aliTestClient.client.downloadKeys([bobUserId]),
535 aliTestClient.httpBackend.flush("/keys/query", 1),
536 ]).then(function() {
537 return aliTestClient.client.getStoredDevicesForUser(bobUserId);
538 }).then((devices) => {
539 // should get an empty list
540 expect(devices).toEqual([]);
541 }).nodeify(done);
542 });
543
544
545 it("Bob starts his client and uploads device keys and one-time keys", function() {
546 return Promise.resolve()
547 .then(() => bobTestClient.start())
548 .then(() => bobTestClient.awaitOneTimeKeyUpload())
549 .then((keys) => {
550 expect(Object.keys(keys).length).toEqual(5);
551 expect(Object.keys(bobTestClient.deviceKeys).length).toNotEqual(0);
552 });
553 });
554
555 it("Ali sends a message", function(done) {
556 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
557 Promise.resolve()
558 .then(() => aliTestClient.start())
559 .then(() => bobTestClient.start())
560 .then(() => firstSync(aliTestClient))
561 .then(aliEnablesEncryption)
562 .then(aliSendsFirstMessage)
563 .nodeify(done);
564 });
565
566 it("Bob receives a message", function() {
567 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
568 return Promise.resolve()
569 .then(() => aliTestClient.start())
570 .then(() => bobTestClient.start())
571 .then(() => firstSync(aliTestClient))
572 .then(aliEnablesEncryption)
573 .then(aliSendsFirstMessage)
574 .then(bobRecvMessage);
575 });
576
577 it("Bob receives a message with a bogus sender", function() {
578 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
579 return Promise.resolve()
580 .then(() => aliTestClient.start())
581 .then(() => bobTestClient.start())
582 .then(() => firstSync(aliTestClient))
583 .then(aliEnablesEncryption)
584 .then(aliSendsFirstMessage)
585 .then(function() {
586 const message = aliMessages.shift();
587 const syncData = {
588 next_batch: "x",
589 rooms: {
590 join: {
591
592 },
593 },
594 };
595 syncData.rooms.join[roomId] = {
596 timeline: {
597 events: [
598 testUtils.mkEvent({
599 type: "m.room.encrypted",
600 room: roomId,
601 content: message,
602 sender: "@bogus:sender",
603 }),
604 ],
605 },
606 };
607 bobTestClient.httpBackend.when("GET", "/sync").respond(200, syncData);
608
609 const eventPromise = new Promise((resolve, reject) => {
610 const onEvent = function(event) {
611 logger.log(bobUserId + " received event",
612 event);
613 resolve(event);
614 };
615 bobTestClient.client.once("event", onEvent);
616 });
617
618 bobTestClient.httpBackend.flush();
619 return eventPromise;
620 }).then((event) => {
621 expect(event.isEncrypted()).toBeTruthy();
622
623 // it may still be being decrypted
624 return testUtils.awaitDecryption(event);
625 }).then((event) => {
626 expect(event.getType()).toEqual("m.room.message");
627 expect(event.getContent().msgtype).toEqual("m.bad.encrypted");
628 });
629 });
630
631 it("Ali blocks Bob's device", function(done) {
632 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
633 Promise.resolve()
634 .then(() => aliTestClient.start())
635 .then(() => bobTestClient.start())
636 .then(() => firstSync(aliTestClient))
637 .then(aliEnablesEncryption)
638 .then(aliDownloadsKeys)
639 .then(function() {
640 aliTestClient.client.setDeviceBlocked(bobUserId, bobDeviceId, true);
641 const p1 = sendMessage(aliTestClient.client);
642 const p2 = expectSendMessageRequest(aliTestClient.httpBackend)
643 .then(function(sentContent) {
644 // no unblocked devices, so the ciphertext should be empty
645 expect(sentContent.ciphertext).toEqual({});
646 });
647 return Promise.all([p1, p2]);
648 }).nodeify(done);
649 });
650
651 it("Bob receives two pre-key messages", function(done) {
652 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
653 Promise.resolve()
654 .then(() => aliTestClient.start())
655 .then(() => bobTestClient.start())
656 .then(() => firstSync(aliTestClient))
657 .then(aliEnablesEncryption)
658 .then(aliSendsFirstMessage)
659 .then(bobRecvMessage)
660 .then(aliSendsMessage)
661 .then(bobRecvMessage)
662 .nodeify(done);
663 });
664
665 it("Bob replies to the message", function() {
666 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
667 bobTestClient.expectKeyQuery({device_keys: {[bobUserId]: {}}});
668 return Promise.resolve()
669 .then(() => aliTestClient.start())
670 .then(() => bobTestClient.start())
671 .then(() => firstSync(aliTestClient))
672 .then(() => firstSync(bobTestClient))
673 .then(aliEnablesEncryption)
674 .then(aliSendsFirstMessage)
675 .then(bobRecvMessage)
676 .then(bobEnablesEncryption)
677 .then(bobSendsReplyMessage).then(function(ciphertext) {
678 expect(ciphertext.type).toEqual(1, "Unexpected cipghertext type.");
679 }).then(aliRecvMessage);
680 });
681
682 it("Ali does a key query when encryption is enabled", function() {
683 // enabling encryption in the room should make alice download devices
684 // for both members.
685 aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
686 return Promise.resolve()
687 .then(() => aliTestClient.start())
688 .then(() => firstSync(aliTestClient))
689 .then(() => {
690 const syncData = {
691 next_batch: '2',
692 rooms: {
693 join: {},
694 },
695 };
696 syncData.rooms.join[roomId] = {
697 state: {
698 events: [
699 testUtils.mkEvent({
700 type: 'm.room.encryption',
701 skey: '',
702 content: {
703 algorithm: 'm.olm.v1.curve25519-aes-sha2',
704 },
705 }),
706 ],
707 },
708 };
709
710 aliTestClient.httpBackend.when('GET', '/sync').respond(
711 200, syncData);
712 return aliTestClient.httpBackend.flush('/sync', 1);
713 }).then(() => {
714 aliTestClient.expectKeyQuery({
715 device_keys: {
716 [bobUserId]: {},
717 },
718 });
719 return aliTestClient.httpBackend.flushAllExpected();
720 });
721 });
722
723 it("Upload new oneTimeKeys based on a /sync request - no count-asking", function() {
724 // Send a response which causes a key upload
725 const httpBackend = aliTestClient.httpBackend;
726 const syncDataEmpty = {
727 next_batch: "a",
728 device_one_time_keys_count: {
729 signed_curve25519: 0,
730 },
731 };
732
733 // enqueue expectations:
734 // * Sync with empty one_time_keys => upload keys
735
736 return Promise.resolve()
737 .then(() => {
738 logger.log(aliTestClient + ': starting');
739 httpBackend.when("GET", "/pushrules").respond(200, {});
740 httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
741 aliTestClient.expectDeviceKeyUpload();
742
743 // we let the client do a very basic initial sync, which it needs before
744 // it will upload one-time keys.
745 httpBackend.when("GET", "/sync").respond(200, syncDataEmpty);
746
747 aliTestClient.client.startClient({});
748
749 return httpBackend.flushAllExpected().then(() => {
750 logger.log(aliTestClient + ': started');
751 });
752 })
753 .then(() => httpBackend.when("POST", "/keys/upload")
754 .respond(200, (path, content) => {
755 expect(content.one_time_keys).toBeTruthy();
756 expect(content.one_time_keys).toNotEqual({});
757 expect(Object.keys(content.one_time_keys).length)
758 .toBeGreaterThanOrEqualTo(1);
759 logger.log('received %i one-time keys',
760 Object.keys(content.one_time_keys).length);
761 // cancel futher calls by telling the client
762 // we have more than we need
763 return {
764 one_time_key_counts: {
765 signed_curve25519: 70,
766 },
767 };
768 }))
769 .then(() => httpBackend.flushAllExpected());
770 });
771});