1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-07 23:02:56 +03:00

Test typescriptification - crypto unit tests pt 1 (#2440)

* enamed:    spec/unit/crypto/secrets.spec.js -> spec/unit/crypto/secrets.spec.ts

Signed-off-by: Kerry Archibald <kerrya@element.io>

* fix ts issues in secrets.spec

Signed-off-by: Kerry Archibald <kerrya@element.io>

* renamed:    spec/unit/crypto/outgoing-room-key-requests.spec.js -> spec/unit/crypto/outgoing-room-key-requests.spec.ts

Signed-off-by: Kerry Archibald <kerrya@element.io>

* fix ts issues in outgoing-room-key-requests.spec.ts

Signed-off-by: Kerry Archibald <kerrya@element.io>

* renamed:    spec/unit/crypto/DeviceList.spec.js -> spec/unit/crypto/DeviceList.spec.ts

Signed-off-by: Kerry Archibald <kerrya@element.io>

* fix ts issues in DeviceList.spec

Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
Kerry
2022-06-08 12:39:08 +02:00
committed by GitHub
parent 2982bd79f6
commit 8f5162c40d
3 changed files with 83 additions and 61 deletions

View File

@@ -1,7 +1,7 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018, 2019 New Vector Ltd Copyright 2018, 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C. Copyright 2019, 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -20,8 +20,10 @@ import { logger } from "../../../src/logger";
import * as utils from "../../../src/utils"; import * as utils from "../../../src/utils";
import { MemoryCryptoStore } from "../../../src/crypto/store/memory-crypto-store"; import { MemoryCryptoStore } from "../../../src/crypto/store/memory-crypto-store";
import { DeviceList } from "../../../src/crypto/DeviceList"; import { DeviceList } from "../../../src/crypto/DeviceList";
import { IDownloadKeyResult, MatrixClient } from "../../../src";
import { OlmDevice } from "../../../src/crypto/OlmDevice";
const signedDeviceList = { const signedDeviceList: IDownloadKeyResult = {
"failures": {}, "failures": {},
"device_keys": { "device_keys": {
"@test1:sw1v.org": { "@test1:sw1v.org": {
@@ -45,13 +47,15 @@ const signedDeviceList = {
"m.megolm.v1.aes-sha2", "m.megolm.v1.aes-sha2",
], ],
"device_id": "HGKAWHRVJQ", "device_id": "HGKAWHRVJQ",
"unsigned": {}, "unsigned": {
"device_display_name": "",
},
}, },
}, },
}, },
}; };
const signedDeviceList2 = { const signedDeviceList2: IDownloadKeyResult = {
"failures": {}, "failures": {},
"device_keys": { "device_keys": {
"@test2:sw1v.org": { "@test2:sw1v.org": {
@@ -75,7 +79,9 @@ const signedDeviceList2 = {
"m.megolm.v1.aes-sha2", "m.megolm.v1.aes-sha2",
], ],
"device_id": "QJVRHWAKGH", "device_id": "QJVRHWAKGH",
"unsigned": {}, "unsigned": {
"device_display_name": "",
},
}, },
}, },
}, },
@@ -104,10 +110,10 @@ describe('DeviceList', function() {
downloadKeysForUsers: downloadSpy, downloadKeysForUsers: downloadSpy,
getUserId: () => '@test1:sw1v.org', getUserId: () => '@test1:sw1v.org',
deviceId: 'HGKAWHRVJQ', deviceId: 'HGKAWHRVJQ',
}; } as unknown as MatrixClient;
const mockOlm = { const mockOlm = {
verifySignature: function(key, message, signature) {}, verifySignature: function(key, message, signature) {},
}; } as unknown as OlmDevice;
const dl = new DeviceList(baseApis, cryptoStore, mockOlm, keyDownloadChunkSize); const dl = new DeviceList(baseApis, cryptoStore, mockOlm, keyDownloadChunkSize);
deviceLists.push(dl); deviceLists.push(dl);
return dl; return dl;
@@ -118,7 +124,7 @@ describe('DeviceList', function() {
dl.startTrackingDeviceList('@test1:sw1v.org'); dl.startTrackingDeviceList('@test1:sw1v.org');
const queryDefer1 = utils.defer(); const queryDefer1 = utils.defer<IDownloadKeyResult>();
downloadSpy.mockReturnValue(queryDefer1.promise); downloadSpy.mockReturnValue(queryDefer1.promise);
const prom1 = dl.refreshOutdatedDeviceLists(); const prom1 = dl.refreshOutdatedDeviceLists();
@@ -138,7 +144,7 @@ describe('DeviceList', function() {
dl.startTrackingDeviceList('@test1:sw1v.org'); dl.startTrackingDeviceList('@test1:sw1v.org');
const queryDefer1 = utils.defer(); const queryDefer1 = utils.defer<IDownloadKeyResult>();
downloadSpy.mockReturnValue(queryDefer1.promise); downloadSpy.mockReturnValue(queryDefer1.promise);
const prom1 = dl.refreshOutdatedDeviceLists(); const prom1 = dl.refreshOutdatedDeviceLists();
@@ -155,6 +161,7 @@ describe('DeviceList', function() {
dl.saveIfDirty().then(() => { dl.saveIfDirty().then(() => {
// the first request completes // the first request completes
queryDefer1.resolve({ queryDefer1.resolve({
failures: {},
device_keys: { device_keys: {
'@test1:sw1v.org': {}, '@test1:sw1v.org': {},
}, },
@@ -166,7 +173,7 @@ describe('DeviceList', function() {
logger.log("Creating new devicelist to simulate app reload"); logger.log("Creating new devicelist to simulate app reload");
downloadSpy.mockReset(); downloadSpy.mockReset();
const dl2 = createTestDeviceList(); const dl2 = createTestDeviceList();
const queryDefer3 = utils.defer(); const queryDefer3 = utils.defer<IDownloadKeyResult>();
downloadSpy.mockReturnValue(queryDefer3.promise); downloadSpy.mockReturnValue(queryDefer3.promise);
const prom3 = dl2.refreshOutdatedDeviceLists(); const prom3 = dl2.refreshOutdatedDeviceLists();
@@ -190,9 +197,9 @@ describe('DeviceList', function() {
dl.startTrackingDeviceList('@test1:sw1v.org'); dl.startTrackingDeviceList('@test1:sw1v.org');
dl.startTrackingDeviceList('@test2:sw1v.org'); dl.startTrackingDeviceList('@test2:sw1v.org');
const queryDefer1 = utils.defer(); const queryDefer1 = utils.defer<IDownloadKeyResult>();
downloadSpy.mockReturnValueOnce(queryDefer1.promise); downloadSpy.mockReturnValueOnce(queryDefer1.promise);
const queryDefer2 = utils.defer(); const queryDefer2 = utils.defer<IDownloadKeyResult>();
downloadSpy.mockReturnValueOnce(queryDefer2.promise); downloadSpy.mockReturnValueOnce(queryDefer2.promise);
const prom1 = dl.refreshOutdatedDeviceLists(); const prom1 = dl.refreshOutdatedDeviceLists();

View File

@@ -48,8 +48,10 @@ describe.each([
() => new IndexedDBCryptoStore(undefined, "tests")], () => new IndexedDBCryptoStore(undefined, "tests")],
["MemoryCryptoStore", () => { ["MemoryCryptoStore", () => {
const store = new IndexedDBCryptoStore(undefined, "tests"); const store = new IndexedDBCryptoStore(undefined, "tests");
store._backend = new MemoryCryptoStore(); // @ts-ignore set private properties
store._backendPromise = Promise.resolve(store._backend); store.backend = new MemoryCryptoStore();
// @ts-ignore
store.backendPromise = Promise.resolve(store.backend);
return store; return store;
}], }],
])("Outgoing room key requests [%s]", function(name, dbFactory) { ])("Outgoing room key requests [%s]", function(name, dbFactory) {

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2019 The Matrix.org Foundation C.I.C. Copyright 2019, 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -24,15 +24,18 @@ import { encryptAES } from "../../../src/crypto/aes";
import { resetCrossSigningKeys, createSecretStorageKey } from "./crypto-utils"; import { resetCrossSigningKeys, createSecretStorageKey } from "./crypto-utils";
import { logger } from '../../../src/logger'; import { logger } from '../../../src/logger';
import * as utils from "../../../src/utils"; import * as utils from "../../../src/utils";
import { ICreateClientOpts } from '../../../src';
import { ISecretStorageKeyInfo } from '../../../src/crypto/api';
try { try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const crypto = require('crypto'); const crypto = require('crypto');
utils.setCrypto(crypto); utils.setCrypto(crypto);
} catch (err) { } catch (err) {
logger.log('nodejs was compiled without crypto support'); logger.log('nodejs was compiled without crypto support');
} }
async function makeTestClient(userInfo, options) { async function makeTestClient(userInfo: { userId: string, deviceId: string}, options: Partial<ICreateClientOpts> = {}) {
const client = (new TestClient( const client = (new TestClient(
userInfo.userId, userInfo.deviceId, undefined, undefined, options, userInfo.userId, userInfo.deviceId, undefined, undefined, options,
)).client; )).client;
@@ -46,7 +49,7 @@ async function makeTestClient(userInfo, options) {
await client.initCrypto(); await client.initCrypto();
// No need to download keys for these tests // No need to download keys for these tests
client.crypto.downloadKeys = async function() {}; jest.spyOn(client.crypto, 'downloadKeys').mockResolvedValue({});
return client; return client;
} }
@@ -54,7 +57,7 @@ async function makeTestClient(userInfo, options) {
// Wrapper around pkSign to return a signed object. pkSign returns the // Wrapper around pkSign to return a signed object. pkSign returns the
// signature, rather than the signed object. // signature, rather than the signed object.
function sign(obj, key, userId) { function sign(obj, key, userId) {
olmlib.pkSign(obj, key, userId); olmlib.pkSign(obj, key, userId, '');
return obj; return obj;
} }
@@ -84,7 +87,7 @@ describe("Secrets", function() {
}, },
}; };
const getKey = jest.fn(e => { const getKey = jest.fn().mockImplementation(async e => {
expect(Object.keys(e.keys)).toEqual(["abc"]); expect(Object.keys(e.keys)).toEqual(["abc"]);
return ['abc', key]; return ['abc', key];
}); });
@@ -93,7 +96,7 @@ describe("Secrets", function() {
{ userId: "@alice:example.com", deviceId: "Osborne2" }, { userId: "@alice:example.com", deviceId: "Osborne2" },
{ {
cryptoCallbacks: { cryptoCallbacks: {
getCrossSigningKey: t => signingKey, getCrossSigningKey: async t => signingKey,
getSecretStorageKey: getKey, getSecretStorageKey: getKey,
}, },
}, },
@@ -104,7 +107,8 @@ describe("Secrets", function() {
const secretStorage = alice.crypto.secretStorage; const secretStorage = alice.crypto.secretStorage;
alice.setAccountData = async function(eventType, contents, callback) { jest.spyOn(alice, 'setAccountData').mockImplementation(
async function(eventType, contents, callback) {
alice.store.storeAccountDataEvents([ alice.store.storeAccountDataEvents([
new MatrixEvent({ new MatrixEvent({
type: eventType, type: eventType,
@@ -112,9 +116,10 @@ describe("Secrets", function() {
}), }),
]); ]);
if (callback) { if (callback) {
callback(); callback(undefined, undefined);
} }
}; return {};
});
const keyAccountData = { const keyAccountData = {
algorithm: SECRET_STORAGE_ALGORITHM_V1_AES, algorithm: SECRET_STORAGE_ALGORITHM_V1_AES,
@@ -170,7 +175,7 @@ describe("Secrets", function() {
it("should encrypt with default key if keys is null", async function() { it("should encrypt with default key if keys is null", async function() {
const key = new Uint8Array(16); const key = new Uint8Array(16);
for (let i = 0; i < 16; i++) key[i] = i; for (let i = 0; i < 16; i++) key[i] = i;
const getKey = jest.fn(e => { const getKey = jest.fn().mockImplementation(async e => {
expect(Object.keys(e.keys)).toEqual([newKeyId]); expect(Object.keys(e.keys)).toEqual([newKeyId]);
return [newKeyId, key]; return [newKeyId, key];
}); });
@@ -193,11 +198,12 @@ describe("Secrets", function() {
content: contents, content: contents,
}), }),
]); ]);
return {};
}; };
resetCrossSigningKeys(alice); resetCrossSigningKeys(alice);
const { keyId: newKeyId } = await alice.addSecretStorageKey( const { keyId: newKeyId } = await alice.addSecretStorageKey(
SECRET_STORAGE_ALGORITHM_V1_AES, SECRET_STORAGE_ALGORITHM_V1_AES, { pubkey: undefined, key: undefined },
); );
// we don't await on this because it waits for the event to come down the sync // we don't await on this because it waits for the event to come down the sync
// which won't happen in the test setup // which won't happen in the test setup
@@ -306,7 +312,7 @@ describe("Secrets", function() {
it("bootstraps when no storage or cross-signing keys locally", async function() { it("bootstraps when no storage or cross-signing keys locally", async function() {
const key = new Uint8Array(16); const key = new Uint8Array(16);
for (let i = 0; i < 16; i++) key[i] = i; for (let i = 0; i < 16; i++) key[i] = i;
const getKey = jest.fn(e => { const getKey = jest.fn().mockImplementation(async e => {
return [Object.keys(e.keys)[0], key]; return [Object.keys(e.keys)[0], key];
}); });
@@ -321,8 +327,8 @@ describe("Secrets", function() {
}, },
}, },
); );
bob.uploadDeviceSigningKeys = async () => {}; bob.uploadDeviceSigningKeys = async () => ({});
bob.uploadKeySignatures = async () => {}; bob.uploadKeySignatures = jest.fn().mockResolvedValue(undefined);
bob.setAccountData = async function(eventType, contents, callback) { bob.setAccountData = async function(eventType, contents, callback) {
const event = new MatrixEvent({ const event = new MatrixEvent({
type: eventType, type: eventType,
@@ -332,10 +338,11 @@ describe("Secrets", function() {
event, event,
]); ]);
this.emit("accountData", event); this.emit("accountData", event);
return {};
}; };
await bob.bootstrapCrossSigning({ await bob.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async func => await func({}), authUploadDeviceSigningKeys: async func => { await func({}); },
}); });
await bob.bootstrapSecretStorage({ await bob.bootstrapSecretStorage({
createSecretStorageKey, createSecretStorageKey,
@@ -419,7 +426,7 @@ describe("Secrets", function() {
}); });
it("adds passphrase checking if it's lacking", async function() { it("adds passphrase checking if it's lacking", async function() {
let crossSigningKeys = { let crossSigningKeys: Record<string, Uint8Array> = {
master: XSK, master: XSK,
user_signing: USK, user_signing: USK,
self_signing: SSK, self_signing: SSK,
@@ -431,9 +438,9 @@ describe("Secrets", function() {
{ userId: "@alice:example.com", deviceId: "Osborne2" }, { userId: "@alice:example.com", deviceId: "Osborne2" },
{ {
cryptoCallbacks: { cryptoCallbacks: {
getCrossSigningKey: t => crossSigningKeys[t], getCrossSigningKey: async t => crossSigningKeys[t],
saveCrossSigningKeys: k => crossSigningKeys = k, saveCrossSigningKeys: k => crossSigningKeys = k,
getSecretStorageKey: ({ keys }, name) => { getSecretStorageKey: async ({ keys }, name) => {
for (const keyId of Object.keys(keys)) { for (const keyId of Object.keys(keys)) {
if (secretStorageKeys[keyId]) { if (secretStorageKeys[keyId]) {
return [keyId, secretStorageKeys[keyId]]; return [keyId, secretStorageKeys[keyId]];
@@ -489,6 +496,8 @@ describe("Secrets", function() {
}), }),
]); ]);
alice.crypto.deviceList.storeCrossSigningForUser("@alice:example.com", { alice.crypto.deviceList.storeCrossSigningForUser("@alice:example.com", {
firstUse: false,
crossSigningVerifiedBefore: false,
keys: { keys: {
master: { master: {
user_id: "@alice:example.com", user_id: "@alice:example.com",
@@ -529,14 +538,15 @@ describe("Secrets", function() {
}); });
alice.store.storeAccountDataEvents([event]); alice.store.storeAccountDataEvents([event]);
this.emit("accountData", event); this.emit("accountData", event);
return {};
}; };
await alice.bootstrapSecretStorage(); await alice.bootstrapSecretStorage({});
expect(alice.getAccountData("m.secret_storage.default_key").getContent()) expect(alice.getAccountData("m.secret_storage.default_key").getContent())
.toEqual({ key: "key_id" }); .toEqual({ key: "key_id" });
const keyInfo = alice.getAccountData("m.secret_storage.key.key_id") const keyInfo = alice.getAccountData("m.secret_storage.key.key_id")
.getContent(); .getContent() as ISecretStorageKeyInfo;
expect(keyInfo.algorithm) expect(keyInfo.algorithm)
.toEqual("m.secret_storage.v1.aes-hmac-sha2"); .toEqual("m.secret_storage.v1.aes-hmac-sha2");
expect(keyInfo.passphrase).toEqual({ expect(keyInfo.passphrase).toEqual({
@@ -551,7 +561,7 @@ describe("Secrets", function() {
alice.stopClient(); alice.stopClient();
}); });
it("fixes backup keys in the wrong format", async function() { it("fixes backup keys in the wrong format", async function() {
let crossSigningKeys = { let crossSigningKeys: Record<string, Uint8Array> = {
master: XSK, master: XSK,
user_signing: USK, user_signing: USK,
self_signing: SSK, self_signing: SSK,
@@ -563,9 +573,9 @@ describe("Secrets", function() {
{ userId: "@alice:example.com", deviceId: "Osborne2" }, { userId: "@alice:example.com", deviceId: "Osborne2" },
{ {
cryptoCallbacks: { cryptoCallbacks: {
getCrossSigningKey: t => crossSigningKeys[t], getCrossSigningKey: async t => crossSigningKeys[t],
saveCrossSigningKeys: k => crossSigningKeys = k, saveCrossSigningKeys: k => crossSigningKeys = k,
getSecretStorageKey: ({ keys }, name) => { getSecretStorageKey: async ({ keys }, name) => {
for (const keyId of Object.keys(keys)) { for (const keyId of Object.keys(keys)) {
if (secretStorageKeys[keyId]) { if (secretStorageKeys[keyId]) {
return [keyId, secretStorageKeys[keyId]]; return [keyId, secretStorageKeys[keyId]];
@@ -630,6 +640,8 @@ describe("Secrets", function() {
}), }),
]); ]);
alice.crypto.deviceList.storeCrossSigningForUser("@alice:example.com", { alice.crypto.deviceList.storeCrossSigningForUser("@alice:example.com", {
firstUse: false,
crossSigningVerifiedBefore: false,
keys: { keys: {
master: { master: {
user_id: "@alice:example.com", user_id: "@alice:example.com",
@@ -670,9 +682,10 @@ describe("Secrets", function() {
}); });
alice.store.storeAccountDataEvents([event]); alice.store.storeAccountDataEvents([event]);
this.emit("accountData", event); this.emit("accountData", event);
return {};
}; };
await alice.bootstrapSecretStorage(); await alice.bootstrapSecretStorage({});
const backupKey = alice.getAccountData("m.megolm_backup.v1") const backupKey = alice.getAccountData("m.megolm_backup.v1")
.getContent(); .getContent();