You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-23 17:02:25 +03:00
210 lines
7.4 KiB
JavaScript
210 lines
7.4 KiB
JavaScript
/*
|
|
Copyright 2017 Vector Creations Ltd
|
|
Copyright 2018, 2019 New Vector Ltd
|
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
import { logger } from "../../../src/logger";
|
|
import * as utils from "../../../src/utils";
|
|
import { MemoryCryptoStore } from "../../../src/crypto/store/memory-crypto-store";
|
|
import { DeviceList } from "../../../src/crypto/DeviceList";
|
|
|
|
const signedDeviceList = {
|
|
"failures": {},
|
|
"device_keys": {
|
|
"@test1:sw1v.org": {
|
|
"HGKAWHRVJQ": {
|
|
"signatures": {
|
|
"@test1:sw1v.org": {
|
|
"ed25519:HGKAWHRVJQ":
|
|
"8PB450fxKDn5s8IiRZ2N2t6MiueQYVRLHFEzqIi1eLdxx1w" +
|
|
"XEPC1/1Uz9T4gwnKlMVAKkhB5hXQA/3kjaeLABw",
|
|
},
|
|
},
|
|
"user_id": "@test1:sw1v.org",
|
|
"keys": {
|
|
"ed25519:HGKAWHRVJQ":
|
|
"0gI/T6C+mn1pjtvnnW2yB2l1IIBb/5ULlBXi/LXFSEQ",
|
|
"curve25519:HGKAWHRVJQ":
|
|
"mbIZED1dBsgIgkgzxDpxKkJmsr4hiWlGzQTvUnQe3RY",
|
|
},
|
|
"algorithms": [
|
|
"m.olm.v1.curve25519-aes-sha2",
|
|
"m.megolm.v1.aes-sha2",
|
|
],
|
|
"device_id": "HGKAWHRVJQ",
|
|
"unsigned": {},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const signedDeviceList2 = {
|
|
"failures": {},
|
|
"device_keys": {
|
|
"@test2:sw1v.org": {
|
|
"QJVRHWAKGH": {
|
|
"signatures": {
|
|
"@test2:sw1v.org": {
|
|
"ed25519:QJVRHWAKGH":
|
|
"w1xxdLe1iIqzEFHLRVYQeuiM6t2N2ZRiI8s5nDKxf054BP8" +
|
|
"1CPEX/AQXh5BhkKAVMlKnwg4T9zU1/wBALeajk3",
|
|
},
|
|
},
|
|
"user_id": "@test2:sw1v.org",
|
|
"keys": {
|
|
"ed25519:QJVRHWAKGH":
|
|
"Ig0/C6T+bBII1l2By2Wnnvtjp1nm/iXBlLU5/QESFXL",
|
|
"curve25519:QJVRHWAKGH":
|
|
"YR3eQnUvTQzGlWih4rsmJkKxpDxzgkgIgsBd1DEZIbm",
|
|
},
|
|
"algorithms": [
|
|
"m.olm.v1.curve25519-aes-sha2",
|
|
"m.megolm.v1.aes-sha2",
|
|
],
|
|
"device_id": "QJVRHWAKGH",
|
|
"unsigned": {},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
describe('DeviceList', function() {
|
|
let downloadSpy;
|
|
let cryptoStore;
|
|
let deviceLists = [];
|
|
|
|
beforeEach(function() {
|
|
deviceLists = [];
|
|
|
|
downloadSpy = jest.fn();
|
|
cryptoStore = new MemoryCryptoStore();
|
|
});
|
|
|
|
afterEach(function() {
|
|
for (const dl of deviceLists) {
|
|
dl.stop();
|
|
}
|
|
});
|
|
|
|
function createTestDeviceList(keyDownloadChunkSize = 250) {
|
|
const baseApis = {
|
|
downloadKeysForUsers: downloadSpy,
|
|
getUserId: () => '@test1:sw1v.org',
|
|
deviceId: 'HGKAWHRVJQ',
|
|
};
|
|
const mockOlm = {
|
|
verifySignature: function(key, message, signature) {},
|
|
};
|
|
const dl = new DeviceList(baseApis, cryptoStore, mockOlm, keyDownloadChunkSize);
|
|
deviceLists.push(dl);
|
|
return dl;
|
|
}
|
|
|
|
it("should successfully download and store device keys", function() {
|
|
const dl = createTestDeviceList();
|
|
|
|
dl.startTrackingDeviceList('@test1:sw1v.org');
|
|
|
|
const queryDefer1 = utils.defer();
|
|
downloadSpy.mockReturnValue(queryDefer1.promise);
|
|
|
|
const prom1 = dl.refreshOutdatedDeviceLists();
|
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
|
queryDefer1.resolve(utils.deepCopy(signedDeviceList));
|
|
|
|
return prom1.then(() => {
|
|
const storedKeys = dl.getRawStoredDevicesForUser('@test1:sw1v.org');
|
|
expect(Object.keys(storedKeys)).toEqual(['HGKAWHRVJQ']);
|
|
});
|
|
});
|
|
|
|
it("should have an outdated devicelist on an invalidation while an " +
|
|
"update is in progress", function() {
|
|
const dl = createTestDeviceList();
|
|
|
|
dl.startTrackingDeviceList('@test1:sw1v.org');
|
|
|
|
const queryDefer1 = utils.defer();
|
|
downloadSpy.mockReturnValue(queryDefer1.promise);
|
|
|
|
const prom1 = dl.refreshOutdatedDeviceLists();
|
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
|
downloadSpy.mockReset();
|
|
|
|
// outdated notif arrives while the request is in flight.
|
|
const queryDefer2 = utils.defer();
|
|
downloadSpy.mockReturnValue(queryDefer2.promise);
|
|
|
|
dl.invalidateUserDeviceList('@test1:sw1v.org');
|
|
dl.refreshOutdatedDeviceLists();
|
|
|
|
dl.saveIfDirty().then(() => {
|
|
// the first request completes
|
|
queryDefer1.resolve({
|
|
device_keys: {
|
|
'@test1:sw1v.org': {},
|
|
},
|
|
});
|
|
return prom1;
|
|
}).then(() => {
|
|
// uh-oh; user restarts before second request completes. The new instance
|
|
// should know we never got a complete device list.
|
|
logger.log("Creating new devicelist to simulate app reload");
|
|
downloadSpy.mockReset();
|
|
const dl2 = createTestDeviceList();
|
|
const queryDefer3 = utils.defer();
|
|
downloadSpy.mockReturnValue(queryDefer3.promise);
|
|
|
|
const prom3 = dl2.refreshOutdatedDeviceLists();
|
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
|
|
|
queryDefer3.resolve(utils.deepCopy(signedDeviceList));
|
|
|
|
// allow promise chain to complete
|
|
return prom3;
|
|
}).then(() => {
|
|
const storedKeys = dl.getRawStoredDevicesForUser('@test1:sw1v.org');
|
|
expect(Object.keys(storedKeys)).toEqual(['HGKAWHRVJQ']);
|
|
});
|
|
});
|
|
|
|
it("should download device keys in batches", function() {
|
|
const dl = createTestDeviceList(1);
|
|
|
|
dl.startTrackingDeviceList('@test1:sw1v.org');
|
|
dl.startTrackingDeviceList('@test2:sw1v.org');
|
|
|
|
const queryDefer1 = utils.defer();
|
|
downloadSpy.mockReturnValueOnce(queryDefer1.promise);
|
|
const queryDefer2 = utils.defer();
|
|
downloadSpy.mockReturnValueOnce(queryDefer2.promise);
|
|
|
|
const prom1 = dl.refreshOutdatedDeviceLists();
|
|
expect(downloadSpy).toBeCalledTimes(2);
|
|
expect(downloadSpy).toHaveBeenNthCalledWith(1, ['@test1:sw1v.org'], {});
|
|
expect(downloadSpy).toHaveBeenNthCalledWith(2, ['@test2:sw1v.org'], {});
|
|
queryDefer1.resolve(utils.deepCopy(signedDeviceList));
|
|
queryDefer2.resolve(utils.deepCopy(signedDeviceList2));
|
|
|
|
return prom1.then(() => {
|
|
const storedKeys1 = dl.getRawStoredDevicesForUser('@test1:sw1v.org');
|
|
expect(Object.keys(storedKeys1)).toEqual(['HGKAWHRVJQ']);
|
|
const storedKeys2 = dl.getRawStoredDevicesForUser('@test2:sw1v.org');
|
|
expect(Object.keys(storedKeys2)).toEqual(['QJVRHWAKGH']);
|
|
});
|
|
});
|
|
});
|