You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Enable noImplicitAny (#2895)
* Stash noImplicitAny work * Enable noImplicitAny * Update olm * Fun * Fix msgid stuff * Fix tests * Attempt to fix Browserify
This commit is contained in:
committed by
GitHub
parent
6f81371e61
commit
8d018f9c2d
@@ -3,7 +3,7 @@ import '../olm-loader';
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
import type { PkDecryption, PkSigning } from "@matrix-org/olm";
|
||||
import { MatrixClient } from "../../src/client";
|
||||
import { IClaimOTKsResult, MatrixClient } from "../../src/client";
|
||||
import { Crypto } from "../../src/crypto";
|
||||
import { MemoryCryptoStore } from "../../src/crypto/store/memory-crypto-store";
|
||||
import { MockStorageApi } from "../MockStorageApi";
|
||||
@@ -23,16 +23,16 @@ import { IRoomEncryption, RoomList } from "../../src/crypto/RoomList";
|
||||
|
||||
const Olm = global.Olm;
|
||||
|
||||
function awaitEvent(emitter, event) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function awaitEvent(emitter: EventEmitter, event: string): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
emitter.once(event, (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function keyshareEventForEvent(client, event, index): Promise<MatrixEvent> {
|
||||
const roomId = event.getRoomId();
|
||||
async function keyshareEventForEvent(client: MatrixClient, event: MatrixEvent, index?: number): Promise<MatrixEvent> {
|
||||
const roomId = event.getRoomId()!;
|
||||
const eventContent = event.getWireContent();
|
||||
const key = await client.crypto!.olmDevice.getInboundGroupSessionKey(
|
||||
roomId,
|
||||
@@ -42,16 +42,16 @@ async function keyshareEventForEvent(client, event, index): Promise<MatrixEvent>
|
||||
);
|
||||
const ksEvent = new MatrixEvent({
|
||||
type: "m.forwarded_room_key",
|
||||
sender: client.getUserId(),
|
||||
sender: client.getUserId()!,
|
||||
content: {
|
||||
"algorithm": olmlib.MEGOLM_ALGORITHM,
|
||||
"room_id": roomId,
|
||||
"sender_key": eventContent.sender_key,
|
||||
"sender_claimed_ed25519_key": key.sender_claimed_ed25519_key,
|
||||
"sender_claimed_ed25519_key": key?.sender_claimed_ed25519_key,
|
||||
"session_id": eventContent.session_id,
|
||||
"session_key": key.key,
|
||||
"chain_index": key.chain_index,
|
||||
"forwarding_curve25519_key_chain": key.forwarding_curve_key_chain,
|
||||
"session_key": key?.key,
|
||||
"chain_index": key?.chain_index,
|
||||
"forwarding_curve25519_key_chain": key?.forwarding_curve25519_key_chain,
|
||||
"org.matrix.msc3061.shared_history": true,
|
||||
},
|
||||
});
|
||||
@@ -172,7 +172,8 @@ describe("Crypto", function() {
|
||||
});
|
||||
|
||||
describe('Session management', function() {
|
||||
const otkResponse = {
|
||||
const otkResponse: IClaimOTKsResult = {
|
||||
failures: {},
|
||||
one_time_keys: {
|
||||
'@alice:home.server': {
|
||||
aliceDevice: {
|
||||
@@ -188,11 +189,12 @@ describe("Crypto", function() {
|
||||
},
|
||||
},
|
||||
};
|
||||
let crypto;
|
||||
let mockBaseApis;
|
||||
let mockRoomList;
|
||||
|
||||
let fakeEmitter;
|
||||
let crypto: Crypto;
|
||||
let mockBaseApis: MatrixClient;
|
||||
let mockRoomList: RoomList;
|
||||
|
||||
let fakeEmitter: EventEmitter;
|
||||
|
||||
beforeEach(async function() {
|
||||
const mockStorage = new MockStorageApi() as unknown as Storage;
|
||||
@@ -219,8 +221,8 @@ describe("Crypto", function() {
|
||||
sendToDevice: jest.fn(),
|
||||
getKeyBackupVersion: jest.fn(),
|
||||
isGuest: jest.fn(),
|
||||
};
|
||||
mockRoomList = {};
|
||||
} as unknown as MatrixClient;
|
||||
mockRoomList = {} as unknown as RoomList;
|
||||
|
||||
fakeEmitter = new EventEmitter();
|
||||
|
||||
@@ -233,7 +235,7 @@ describe("Crypto", function() {
|
||||
mockRoomList,
|
||||
[],
|
||||
);
|
||||
crypto.registerEventHandlers(fakeEmitter);
|
||||
crypto.registerEventHandlers(fakeEmitter as any);
|
||||
await crypto.init();
|
||||
});
|
||||
|
||||
@@ -245,7 +247,7 @@ describe("Crypto", function() {
|
||||
const prom = new Promise<void>((resolve) => {
|
||||
mockBaseApis.claimOneTimeKeys = function() {
|
||||
resolve();
|
||||
return otkResponse;
|
||||
return Promise.resolve(otkResponse);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -989,7 +991,7 @@ describe("Crypto", function() {
|
||||
ensureOlmSessionsForDevices.mockResolvedValue({});
|
||||
encryptMessageForDevice = jest.spyOn(olmlib, "encryptMessageForDevice");
|
||||
encryptMessageForDevice.mockImplementation(async (...[result,,,,,, payload]) => {
|
||||
result.plaintext = JSON.stringify(payload);
|
||||
result.plaintext = { type: 0, body: JSON.stringify(payload) };
|
||||
});
|
||||
|
||||
client = new TestClient("@alice:example.org", "aliceweb");
|
||||
@@ -998,7 +1000,7 @@ describe("Crypto", function() {
|
||||
encryptedPayload = {
|
||||
algorithm: "m.olm.v1.curve25519-aes-sha2",
|
||||
sender_key: client.client.crypto!.olmDevice.deviceCurve25519Key,
|
||||
ciphertext: { plaintext: JSON.stringify(payload) },
|
||||
ciphertext: { plaintext: { type: 0, body: JSON.stringify(payload) } },
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1046,7 +1048,7 @@ describe("Crypto", function() {
|
||||
encryptMessageForDevice.mockImplementation(async (...[result,,,, userId, device, payload]) => {
|
||||
// Refuse to encrypt to Carol's desktop device
|
||||
if (userId === "@carol:example.org" && device.deviceId === "caroldesktop") return;
|
||||
result.plaintext = JSON.stringify(payload);
|
||||
result.plaintext = { type: 0, body: JSON.stringify(payload) };
|
||||
});
|
||||
|
||||
client.httpBackend
|
||||
|
@@ -232,7 +232,7 @@ describe.each([
|
||||
return store;
|
||||
}],
|
||||
])("CrossSigning > createCryptoStoreCacheCallbacks [%s]", function(name, dbFactory) {
|
||||
let store;
|
||||
let store: IndexedDBCryptoStore;
|
||||
|
||||
beforeAll(() => {
|
||||
store = dbFactory();
|
||||
|
@@ -22,6 +22,7 @@ import { MemoryCryptoStore } from "../../../src/crypto/store/memory-crypto-store
|
||||
import { DeviceList } from "../../../src/crypto/DeviceList";
|
||||
import { IDownloadKeyResult, MatrixClient } from "../../../src";
|
||||
import { OlmDevice } from "../../../src/crypto/OlmDevice";
|
||||
import { CryptoStore } from "../../../src/crypto/store/base";
|
||||
|
||||
const signedDeviceList: IDownloadKeyResult = {
|
||||
"failures": {},
|
||||
@@ -88,8 +89,8 @@ const signedDeviceList2: IDownloadKeyResult = {
|
||||
};
|
||||
|
||||
describe('DeviceList', function() {
|
||||
let downloadSpy;
|
||||
let cryptoStore;
|
||||
let downloadSpy: jest.Mock;
|
||||
let cryptoStore: CryptoStore;
|
||||
let deviceLists: DeviceList[] = [];
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -112,7 +113,7 @@ describe('DeviceList', function() {
|
||||
deviceId: 'HGKAWHRVJQ',
|
||||
} as unknown as MatrixClient;
|
||||
const mockOlm = {
|
||||
verifySignature: function(key, message, signature) {},
|
||||
verifySignature: function(key: string, message: string, signature: string) {},
|
||||
} as unknown as OlmDevice;
|
||||
const dl = new DeviceList(baseApis, cryptoStore, mockOlm, keyDownloadChunkSize);
|
||||
deviceLists.push(dl);
|
||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
import { mocked, MockedObject } from 'jest-mock';
|
||||
|
||||
import '../../../olm-loader';
|
||||
import type { OutboundGroupSession } from "@matrix-org/olm";
|
||||
import * as algorithms from "../../../../src/crypto/algorithms";
|
||||
import { MemoryCryptoStore } from "../../../../src/crypto/store/memory-crypto-store";
|
||||
import * as testUtils from "../../../test-utils/test-utils";
|
||||
@@ -31,6 +32,7 @@ import { TypedEventEmitter } from '../../../../src/models/typed-event-emitter';
|
||||
import { ClientEvent, MatrixClient, RoomMember } from '../../../../src';
|
||||
import { DeviceInfo, IDevice } from '../../../../src/crypto/deviceinfo';
|
||||
import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning';
|
||||
import { MegolmEncryption as MegolmEncryptionClass } from "../../../../src/crypto/algorithms/megolm";
|
||||
|
||||
const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2')!;
|
||||
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES.get('m.megolm.v1.aes-sha2')!;
|
||||
@@ -87,7 +89,7 @@ describe("MegolmDecryption", function() {
|
||||
});
|
||||
|
||||
describe('receives some keys:', function() {
|
||||
let groupSession;
|
||||
let groupSession: OutboundGroupSession;
|
||||
beforeEach(async function() {
|
||||
groupSession = new global.Olm.OutboundGroupSession();
|
||||
groupSession.create();
|
||||
@@ -298,10 +300,10 @@ describe("MegolmDecryption", function() {
|
||||
describe("session reuse and key reshares", () => {
|
||||
const rotationPeriodMs = 999 * 24 * 60 * 60 * 1000; // 999 days, so we don't have to deal with it
|
||||
|
||||
let megolmEncryption;
|
||||
let aliceDeviceInfo;
|
||||
let mockRoom;
|
||||
let olmDevice;
|
||||
let megolmEncryption: MegolmEncryptionClass;
|
||||
let aliceDeviceInfo: DeviceInfo;
|
||||
let mockRoom: Room;
|
||||
let olmDevice: OlmDevice;
|
||||
|
||||
beforeEach(async () => {
|
||||
// @ts-ignore assigning to readonly prop
|
||||
@@ -342,7 +344,7 @@ describe("MegolmDecryption", function() {
|
||||
'YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE',
|
||||
),
|
||||
getFingerprint: jest.fn().mockReturnValue(''),
|
||||
};
|
||||
} as unknown as DeviceInfo;
|
||||
|
||||
mockCrypto.downloadKeys.mockReturnValue(Promise.resolve({
|
||||
'@alice:home.server': {
|
||||
@@ -365,7 +367,7 @@ describe("MegolmDecryption", function() {
|
||||
algorithm: 'm.megolm.v1.aes-sha2',
|
||||
rotation_period_ms: rotationPeriodMs,
|
||||
},
|
||||
});
|
||||
}) as MegolmEncryptionClass;
|
||||
|
||||
// Splice the real method onto the mock object as megolm uses this method
|
||||
// on the crypto class in order to encrypt / start sessions
|
||||
@@ -381,7 +383,7 @@ describe("MegolmDecryption", function() {
|
||||
[{ userId: "@alice:home.server" }],
|
||||
),
|
||||
getBlacklistUnverifiedDevices: jest.fn().mockReturnValue(false),
|
||||
};
|
||||
} as unknown as Room;
|
||||
});
|
||||
|
||||
it("should use larger otkTimeout when preparing to encrypt room", async () => {
|
||||
@@ -397,11 +399,14 @@ describe("MegolmDecryption", function() {
|
||||
});
|
||||
|
||||
it("should generate a new session if this one needs rotation", async () => {
|
||||
// @ts-ignore - private method access
|
||||
const session = await megolmEncryption.prepareNewSession(false);
|
||||
session.creationTime -= rotationPeriodMs + 10000; // a smidge over the rotation time
|
||||
// Inject expired session which needs rotation
|
||||
// @ts-ignore - private field access
|
||||
megolmEncryption.setupPromise = Promise.resolve(session);
|
||||
|
||||
// @ts-ignore - private method access
|
||||
const prepareNewSessionSpy = jest.spyOn(megolmEncryption, "prepareNewSession");
|
||||
await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
|
||||
body: "Some text",
|
||||
@@ -446,8 +451,8 @@ describe("MegolmDecryption", function() {
|
||||
});
|
||||
|
||||
mockBaseApis.sendToDevice.mockClear();
|
||||
await megolmEncryption.reshareKeyWithDevice(
|
||||
olmDevice.deviceCurve25519Key,
|
||||
await megolmEncryption.reshareKeyWithDevice!(
|
||||
olmDevice.deviceCurve25519Key!,
|
||||
ct1.session_id,
|
||||
'@alice:home.server',
|
||||
aliceDeviceInfo,
|
||||
@@ -466,8 +471,8 @@ describe("MegolmDecryption", function() {
|
||||
);
|
||||
|
||||
mockBaseApis.queueToDevice.mockClear();
|
||||
await megolmEncryption.reshareKeyWithDevice(
|
||||
olmDevice.deviceCurve25519Key,
|
||||
await megolmEncryption.reshareKeyWithDevice!(
|
||||
olmDevice.deviceCurve25519Key!,
|
||||
ct1.session_id,
|
||||
'@alice:home.server',
|
||||
aliceDeviceInfo,
|
||||
|
@@ -31,17 +31,21 @@ function makeOlmDevice() {
|
||||
return olmDevice;
|
||||
}
|
||||
|
||||
async function setupSession(initiator, opponent) {
|
||||
async function setupSession(initiator: OlmDevice, opponent: OlmDevice) {
|
||||
await opponent.generateOneTimeKeys(1);
|
||||
const keys = await opponent.getOneTimeKeys();
|
||||
const firstKey = Object.values(keys['curve25519'])[0];
|
||||
|
||||
const sid = await initiator.createOutboundSession(
|
||||
opponent.deviceCurve25519Key, firstKey,
|
||||
);
|
||||
const sid = await initiator.createOutboundSession(opponent.deviceCurve25519Key!, firstKey);
|
||||
return sid;
|
||||
}
|
||||
|
||||
function alwaysSucceed<T>(promise: Promise<T>): Promise<T | void> {
|
||||
// swallow any exception thrown by a promise, so that
|
||||
// Promise.all doesn't abort
|
||||
return promise.catch(() => {});
|
||||
}
|
||||
|
||||
describe("OlmDevice", function() {
|
||||
if (!global.Olm) {
|
||||
logger.warn('Not running megolm unit tests: libolm not present');
|
||||
@@ -159,11 +163,6 @@ describe("OlmDevice", function() {
|
||||
}, "ABCDEFG"),
|
||||
],
|
||||
};
|
||||
function alwaysSucceed(promise) {
|
||||
// swallow any exception thrown by a promise, so that
|
||||
// Promise.all doesn't abort
|
||||
return promise.catch(() => {});
|
||||
}
|
||||
|
||||
// start two tasks that try to ensure that there's an olm session
|
||||
const promises = Promise.all([
|
||||
@@ -235,12 +234,6 @@ describe("OlmDevice", function() {
|
||||
],
|
||||
};
|
||||
|
||||
function alwaysSucceed(promise) {
|
||||
// swallow any exception thrown by a promise, so that
|
||||
// Promise.all doesn't abort
|
||||
return promise.catch(() => {});
|
||||
}
|
||||
|
||||
const task1 = alwaysSucceed(olmlib.ensureOlmSessionsForDevices(
|
||||
aliceOlmDevice, baseApis, devicesByUserAB,
|
||||
));
|
||||
|
@@ -15,8 +15,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MockedObject } from "jest-mock";
|
||||
|
||||
import '../../olm-loader';
|
||||
import { logger } from "../../../src/logger";
|
||||
import * as olmlib from "../../../src/crypto/olmlib";
|
||||
@@ -30,7 +28,10 @@ import { Crypto } from "../../../src/crypto";
|
||||
import { resetCrossSigningKeys } from "./crypto-utils";
|
||||
import { BackupManager } from "../../../src/crypto/backup";
|
||||
import { StubStore } from "../../../src/store/stub";
|
||||
import { MatrixScheduler } from '../../../src';
|
||||
import { IndexedDBCryptoStore, MatrixScheduler } from '../../../src';
|
||||
import { CryptoStore } from "../../../src/crypto/store/base";
|
||||
import { MegolmDecryption as MegolmDecryptionClass } from "../../../src/crypto/algorithms/megolm";
|
||||
import { IKeyBackupInfo } from "../../../src/crypto/keybackup";
|
||||
|
||||
const Olm = global.Olm;
|
||||
|
||||
@@ -102,29 +103,36 @@ const CURVE25519_BACKUP_INFO = {
|
||||
},
|
||||
};
|
||||
|
||||
const AES256_BACKUP_INFO = {
|
||||
const AES256_BACKUP_INFO: IKeyBackupInfo = {
|
||||
algorithm: "org.matrix.msc3270.v1.aes-hmac-sha2",
|
||||
version: '1',
|
||||
auth_data: {
|
||||
// FIXME: add iv and mac
|
||||
},
|
||||
auth_data: {} as IKeyBackupInfo["auth_data"],
|
||||
};
|
||||
|
||||
const keys = {};
|
||||
const keys: Record<string, Uint8Array> = {};
|
||||
|
||||
function getCrossSigningKey(type) {
|
||||
return keys[type];
|
||||
function getCrossSigningKey(type: string) {
|
||||
return Promise.resolve(keys[type]);
|
||||
}
|
||||
|
||||
function saveCrossSigningKeys(k) {
|
||||
function saveCrossSigningKeys(k: Record<string, Uint8Array>) {
|
||||
Object.assign(keys, k);
|
||||
}
|
||||
|
||||
function makeTestClient(cryptoStore) {
|
||||
const scheduler = [
|
||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||
function makeTestScheduler(): MatrixScheduler {
|
||||
return ([
|
||||
"getQueueForEvent",
|
||||
"queueEvent",
|
||||
"removeEventFromQueue",
|
||||
"setProcessFunction",
|
||||
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {}) as MockedObject<MatrixScheduler>;
|
||||
] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as MatrixScheduler);
|
||||
}
|
||||
|
||||
function makeTestClient(cryptoStore: CryptoStore) {
|
||||
const scheduler = makeTestScheduler();
|
||||
const store = new StubStore();
|
||||
|
||||
return new MatrixClient({
|
||||
@@ -151,36 +159,33 @@ describe("MegolmBackup", function() {
|
||||
return Olm.init();
|
||||
});
|
||||
|
||||
let olmDevice;
|
||||
let mockOlmLib;
|
||||
let mockCrypto;
|
||||
let cryptoStore;
|
||||
let megolmDecryption;
|
||||
let olmDevice: OlmDevice;
|
||||
let mockOlmLib: typeof olmlib;
|
||||
let mockCrypto: Crypto;
|
||||
let cryptoStore: CryptoStore;
|
||||
let megolmDecryption: MegolmDecryptionClass;
|
||||
beforeEach(async function() {
|
||||
mockCrypto = testUtils.mock(Crypto, 'Crypto');
|
||||
// @ts-ignore making mock
|
||||
mockCrypto.backupManager = testUtils.mock(BackupManager, "BackupManager");
|
||||
mockCrypto.backupKey = new Olm.PkEncryption();
|
||||
mockCrypto.backupKey.set_recipient_key(
|
||||
"hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo",
|
||||
);
|
||||
mockCrypto.backupInfo = CURVE25519_BACKUP_INFO;
|
||||
mockCrypto.backupManager.backupInfo = CURVE25519_BACKUP_INFO;
|
||||
|
||||
cryptoStore = new MemoryCryptoStore();
|
||||
|
||||
olmDevice = new OlmDevice(cryptoStore);
|
||||
|
||||
// we stub out the olm encryption bits
|
||||
mockOlmLib = {};
|
||||
mockOlmLib = {} as unknown as typeof olmlib;
|
||||
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();
|
||||
mockOlmLib.encryptMessageForDevice =
|
||||
jest.fn().mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
describe("backup", function() {
|
||||
let mockBaseApis;
|
||||
let mockBaseApis: MatrixClient;
|
||||
|
||||
beforeEach(function() {
|
||||
mockBaseApis = {};
|
||||
mockBaseApis = {} as unknown as MatrixClient;
|
||||
|
||||
megolmDecryption = new MegolmDecryption({
|
||||
userId: '@user:id',
|
||||
@@ -188,8 +193,9 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: mockBaseApis,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
// clobber the setTimeout function to run 100x faster.
|
||||
@@ -239,6 +245,7 @@ describe("MegolmBackup", function() {
|
||||
};
|
||||
mockCrypto.cancelRoomKeyRequest = function() {};
|
||||
|
||||
// @ts-ignore readonly field write
|
||||
mockCrypto.backupManager = {
|
||||
backupGroupSession: jest.fn(),
|
||||
};
|
||||
@@ -264,21 +271,22 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: client,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
return client.initCrypto()
|
||||
.then(() => {
|
||||
return cryptoStore.doTxn(
|
||||
"readwrite",
|
||||
[cryptoStore.STORE_SESSION],
|
||||
[IndexedDBCryptoStore.STORE_SESSIONS],
|
||||
(txn) => {
|
||||
cryptoStore.addEndToEndInboundGroupSession(
|
||||
"F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI",
|
||||
groupSession.session_id(),
|
||||
{
|
||||
forwardingCurve25519KeyChain: undefined,
|
||||
forwardingCurve25519KeyChain: undefined!,
|
||||
keysClaimed: {
|
||||
ed25519: "SENDER_ED25519",
|
||||
},
|
||||
@@ -298,25 +306,25 @@ describe("MegolmBackup", function() {
|
||||
});
|
||||
let numCalls = 0;
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
client.http.authedRequest = function<T>(
|
||||
client.http.authedRequest = function(
|
||||
method, path, queryParams, data, opts,
|
||||
): Promise<T> {
|
||||
): any {
|
||||
++numCalls;
|
||||
expect(numCalls).toBeLessThanOrEqual(1);
|
||||
if (numCalls >= 2) {
|
||||
// exit out of retry loop if there's something wrong
|
||||
reject(new Error("authedRequest called too many timmes"));
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
}
|
||||
expect(method).toBe("PUT");
|
||||
expect(path).toBe("/room_keys/keys");
|
||||
expect(queryParams.version).toBe('1');
|
||||
expect(queryParams?.version).toBe('1');
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toBeDefined();
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toHaveProperty(
|
||||
groupSession.session_id(),
|
||||
);
|
||||
resolve();
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
};
|
||||
client.crypto!.backupManager.backupGroupSession(
|
||||
"F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI",
|
||||
@@ -343,8 +351,9 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: client,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
return client.initCrypto()
|
||||
@@ -354,13 +363,13 @@ describe("MegolmBackup", function() {
|
||||
.then(() => {
|
||||
return cryptoStore.doTxn(
|
||||
"readwrite",
|
||||
[cryptoStore.STORE_SESSION],
|
||||
[IndexedDBCryptoStore.STORE_SESSIONS],
|
||||
(txn) => {
|
||||
cryptoStore.addEndToEndInboundGroupSession(
|
||||
"F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI",
|
||||
groupSession.session_id(),
|
||||
{
|
||||
forwardingCurve25519KeyChain: undefined,
|
||||
forwardingCurve25519KeyChain: undefined!,
|
||||
keysClaimed: {
|
||||
ed25519: "SENDER_ED25519",
|
||||
},
|
||||
@@ -381,25 +390,25 @@ describe("MegolmBackup", function() {
|
||||
});
|
||||
let numCalls = 0;
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
client.http.authedRequest = function<T>(
|
||||
client.http.authedRequest = function(
|
||||
method, path, queryParams, data, opts,
|
||||
): Promise<T> {
|
||||
): any {
|
||||
++numCalls;
|
||||
expect(numCalls).toBeLessThanOrEqual(1);
|
||||
if (numCalls >= 2) {
|
||||
// exit out of retry loop if there's something wrong
|
||||
reject(new Error("authedRequest called too many timmes"));
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
}
|
||||
expect(method).toBe("PUT");
|
||||
expect(path).toBe("/room_keys/keys");
|
||||
expect(queryParams.version).toBe('1');
|
||||
expect(queryParams?.version).toBe('1');
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toBeDefined();
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toHaveProperty(
|
||||
groupSession.session_id(),
|
||||
);
|
||||
resolve();
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
};
|
||||
client.crypto!.backupManager.backupGroupSession(
|
||||
"F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI",
|
||||
@@ -426,8 +435,9 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: client,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
await client.initCrypto();
|
||||
@@ -437,10 +447,10 @@ describe("MegolmBackup", function() {
|
||||
let numCalls = 0;
|
||||
await Promise.all([
|
||||
new Promise<void>((resolve, reject) => {
|
||||
let backupInfo;
|
||||
let backupInfo: Record<string, any> | BodyInit | undefined;
|
||||
client.http.authedRequest = function(
|
||||
method, path, queryParams, data, opts,
|
||||
) {
|
||||
): any {
|
||||
++numCalls;
|
||||
expect(numCalls).toBeLessThanOrEqual(2);
|
||||
if (numCalls === 1) {
|
||||
@@ -486,10 +496,7 @@ describe("MegolmBackup", function() {
|
||||
const ibGroupSession = new Olm.InboundGroupSession();
|
||||
ibGroupSession.create(groupSession.session_key());
|
||||
|
||||
const scheduler = [
|
||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||
"setProcessFunction",
|
||||
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {}) as MockedObject<MatrixScheduler>;
|
||||
const scheduler = makeTestScheduler();
|
||||
const store = new StubStore();
|
||||
const client = new MatrixClient({
|
||||
baseUrl: "https://my.home.server",
|
||||
@@ -509,20 +516,21 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: client,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
await client.initCrypto();
|
||||
await cryptoStore.doTxn(
|
||||
"readwrite",
|
||||
[cryptoStore.STORE_SESSION],
|
||||
[IndexedDBCryptoStore.STORE_SESSIONS],
|
||||
(txn) => {
|
||||
cryptoStore.addEndToEndInboundGroupSession(
|
||||
"F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI",
|
||||
groupSession.session_id(),
|
||||
{
|
||||
forwardingCurve25519KeyChain: undefined,
|
||||
forwardingCurve25519KeyChain: undefined!,
|
||||
keysClaimed: {
|
||||
ed25519: "SENDER_ED25519",
|
||||
},
|
||||
@@ -542,26 +550,26 @@ describe("MegolmBackup", function() {
|
||||
let numCalls = 0;
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
client.http.authedRequest = function<T>(
|
||||
client.http.authedRequest = function(
|
||||
method, path, queryParams, data, opts,
|
||||
): Promise<T> {
|
||||
): any {
|
||||
++numCalls;
|
||||
expect(numCalls).toBeLessThanOrEqual(2);
|
||||
if (numCalls >= 3) {
|
||||
// exit out of retry loop if there's something wrong
|
||||
reject(new Error("authedRequest called too many timmes"));
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
}
|
||||
expect(method).toBe("PUT");
|
||||
expect(path).toBe("/room_keys/keys");
|
||||
expect(queryParams.version).toBe('1');
|
||||
expect(queryParams?.version).toBe('1');
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toBeDefined();
|
||||
expect((data as Record<string, any>).rooms[ROOM_ID].sessions).toHaveProperty(
|
||||
groupSession.session_id(),
|
||||
);
|
||||
if (numCalls > 1) {
|
||||
resolve();
|
||||
return Promise.resolve({} as T);
|
||||
return Promise.resolve({});
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new Error("this is an expected failure"),
|
||||
@@ -579,7 +587,7 @@ describe("MegolmBackup", function() {
|
||||
});
|
||||
|
||||
describe("restore", function() {
|
||||
let client;
|
||||
let client: MatrixClient;
|
||||
|
||||
beforeEach(function() {
|
||||
client = makeTestClient(cryptoStore);
|
||||
@@ -590,8 +598,9 @@ describe("MegolmBackup", function() {
|
||||
olmDevice: olmDevice,
|
||||
baseApis: client,
|
||||
roomId: ROOM_ID,
|
||||
});
|
||||
}) as MegolmDecryptionClass;
|
||||
|
||||
// @ts-ignore private field access
|
||||
megolmDecryption.olmlib = mockOlmLib;
|
||||
|
||||
return client.initCrypto();
|
||||
@@ -603,7 +612,7 @@ describe("MegolmBackup", function() {
|
||||
|
||||
it('can restore from backup (Curve25519 version)', function() {
|
||||
client.http.authedRequest = function() {
|
||||
return Promise.resolve(CURVE25519_KEY_BACKUP_DATA);
|
||||
return Promise.resolve<any>(CURVE25519_KEY_BACKUP_DATA);
|
||||
};
|
||||
return client.restoreKeyBackupWithRecoveryKey(
|
||||
"EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d",
|
||||
@@ -620,7 +629,7 @@ describe("MegolmBackup", function() {
|
||||
|
||||
it('can restore from backup (AES-256 version)', function() {
|
||||
client.http.authedRequest = function() {
|
||||
return Promise.resolve(AES256_KEY_BACKUP_DATA);
|
||||
return Promise.resolve<any>(AES256_KEY_BACKUP_DATA);
|
||||
};
|
||||
return client.restoreKeyBackupWithRecoveryKey(
|
||||
"EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d",
|
||||
@@ -637,7 +646,7 @@ describe("MegolmBackup", function() {
|
||||
|
||||
it('can restore backup by room (Curve25519 version)', function() {
|
||||
client.http.authedRequest = function() {
|
||||
return Promise.resolve({
|
||||
return Promise.resolve<any>({
|
||||
rooms: {
|
||||
[ROOM_ID]: {
|
||||
sessions: {
|
||||
@@ -649,7 +658,7 @@ describe("MegolmBackup", function() {
|
||||
};
|
||||
return client.restoreKeyBackupWithRecoveryKey(
|
||||
"EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d",
|
||||
null, null, CURVE25519_BACKUP_INFO,
|
||||
null!, null!, CURVE25519_BACKUP_INFO,
|
||||
).then(() => {
|
||||
return megolmDecryption.decryptEvent(ENCRYPTED_EVENT);
|
||||
}).then((res) => {
|
||||
@@ -659,18 +668,18 @@ describe("MegolmBackup", function() {
|
||||
|
||||
it('has working cache functions', async function() {
|
||||
const key = Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
await client.crypto.storeSessionBackupPrivateKey(key);
|
||||
const result = await client.crypto.getSessionBackupPrivateKey();
|
||||
expect(new Uint8Array(result)).toEqual(key);
|
||||
await client.crypto!.storeSessionBackupPrivateKey(key);
|
||||
const result = await client.crypto!.getSessionBackupPrivateKey();
|
||||
expect(new Uint8Array(result!)).toEqual(key);
|
||||
});
|
||||
|
||||
it('caches session backup keys as it encounters them', async function() {
|
||||
const cachedNull = await client.crypto.getSessionBackupPrivateKey();
|
||||
const cachedNull = await client.crypto!.getSessionBackupPrivateKey();
|
||||
expect(cachedNull).toBeNull();
|
||||
client.http.authedRequest = function() {
|
||||
return Promise.resolve(CURVE25519_KEY_BACKUP_DATA);
|
||||
return Promise.resolve<any>(CURVE25519_KEY_BACKUP_DATA);
|
||||
};
|
||||
await new Promise((resolve) => {
|
||||
await new Promise<void>((resolve) => {
|
||||
client.restoreKeyBackupWithRecoveryKey(
|
||||
"EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d",
|
||||
ROOM_ID,
|
||||
@@ -679,7 +688,7 @@ describe("MegolmBackup", function() {
|
||||
{ cacheCompleteCallback: resolve },
|
||||
);
|
||||
});
|
||||
const cachedKey = await client.crypto.getSessionBackupPrivateKey();
|
||||
const cachedKey = await client.crypto!.getSessionBackupPrivateKey();
|
||||
expect(cachedKey).not.toBeNull();
|
||||
});
|
||||
|
||||
@@ -688,7 +697,7 @@ describe("MegolmBackup", function() {
|
||||
algorithm: "this.algorithm.does.not.exist",
|
||||
});
|
||||
client.http.authedRequest = function() {
|
||||
return Promise.resolve(CURVE25519_KEY_BACKUP_DATA);
|
||||
return Promise.resolve<any>(CURVE25519_KEY_BACKUP_DATA);
|
||||
};
|
||||
|
||||
await expect(client.restoreKeyBackupWithRecoveryKey(
|
||||
@@ -702,10 +711,7 @@ describe("MegolmBackup", function() {
|
||||
|
||||
describe("flagAllGroupSessionsForBackup", () => {
|
||||
it("should return number of sesions needing backup", async () => {
|
||||
const scheduler = [
|
||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||
"setProcessFunction",
|
||||
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {}) as MockedObject<MatrixScheduler>;
|
||||
const scheduler = makeTestScheduler();
|
||||
const store = new StubStore();
|
||||
const client = new MatrixClient({
|
||||
baseUrl: "https://my.home.server",
|
||||
|
@@ -18,23 +18,24 @@ limitations under the License.
|
||||
import '../../olm-loader';
|
||||
import anotherjson from 'another-json';
|
||||
import { PkSigning } from '@matrix-org/olm';
|
||||
import HttpBackend from "matrix-mock-request";
|
||||
|
||||
import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import { MatrixError } from '../../../src/http-api';
|
||||
import { logger } from '../../../src/logger';
|
||||
import { ICrossSigningKey, ICreateClientOpts, ISignedKey } from '../../../src/client';
|
||||
import { CryptoEvent } from '../../../src/crypto';
|
||||
import { CryptoEvent, IBootstrapCrossSigningOpts } from '../../../src/crypto';
|
||||
import { IDevice } from '../../../src/crypto/deviceinfo';
|
||||
import { TestClient } from '../../TestClient';
|
||||
import { resetCrossSigningKeys } from "./crypto-utils";
|
||||
|
||||
const PUSH_RULES_RESPONSE = {
|
||||
const PUSH_RULES_RESPONSE: Response = {
|
||||
method: "GET",
|
||||
path: "/pushrules/",
|
||||
data: {},
|
||||
};
|
||||
|
||||
const filterResponse = function(userId) {
|
||||
const filterResponse = function(userId: string): Response {
|
||||
const filterPath = "/user/" + encodeURIComponent(userId) + "/filter";
|
||||
return {
|
||||
method: "POST",
|
||||
@@ -43,7 +44,13 @@ const filterResponse = function(userId) {
|
||||
};
|
||||
};
|
||||
|
||||
function setHttpResponses(httpBackend, responses) {
|
||||
interface Response {
|
||||
method: 'GET' | 'PUT' | 'POST' | 'DELETE';
|
||||
path: string;
|
||||
data: object;
|
||||
}
|
||||
|
||||
function setHttpResponses(httpBackend: HttpBackend, responses: Response[]) {
|
||||
responses.forEach(response => {
|
||||
httpBackend
|
||||
.when(response.method, response.path)
|
||||
@@ -54,13 +61,13 @@ function setHttpResponses(httpBackend, responses) {
|
||||
async function makeTestClient(
|
||||
userInfo: { userId: string, deviceId: string},
|
||||
options: Partial<ICreateClientOpts> = {},
|
||||
keys = {},
|
||||
keys: Record<string, Uint8Array> = {},
|
||||
) {
|
||||
function getCrossSigningKey(type) {
|
||||
return keys[type];
|
||||
function getCrossSigningKey(type: string) {
|
||||
return keys[type] ?? null;
|
||||
}
|
||||
|
||||
function saveCrossSigningKeys(k) {
|
||||
function saveCrossSigningKeys(k: Record<string, Uint8Array>) {
|
||||
Object.assign(keys, k);
|
||||
}
|
||||
|
||||
@@ -142,7 +149,9 @@ describe("Cross Signing", function() {
|
||||
alice.uploadKeySignatures = async () => ({ failures: {} });
|
||||
alice.setAccountData = async () => ({});
|
||||
alice.getAccountDataFromServer = async <T extends {[k: string]: any}>(): Promise<T | null> => ({} as T);
|
||||
const authUploadDeviceSigningKeys = async func => await func({});
|
||||
const authUploadDeviceSigningKeys: IBootstrapCrossSigningOpts["authUploadDeviceSigningKeys"] = async func => {
|
||||
await func({});
|
||||
};
|
||||
|
||||
// Try bootstrap, expecting `authUploadDeviceSigningKeys` to pass
|
||||
// through failure, stopping before actually applying changes.
|
||||
@@ -275,7 +284,7 @@ describe("Cross Signing", function() {
|
||||
);
|
||||
|
||||
// feed sync result that includes master key, ssk, device key
|
||||
const responses = [
|
||||
const responses: Response[] = [
|
||||
PUSH_RULES_RESPONSE,
|
||||
{
|
||||
method: "POST",
|
||||
@@ -464,7 +473,7 @@ describe("Cross Signing", function() {
|
||||
});
|
||||
|
||||
it.skip("should trust signatures received from other devices", async function() {
|
||||
const aliceKeys: Record<string, PkSigning> = {};
|
||||
const aliceKeys: Record<string, Uint8Array> = {};
|
||||
const { client: alice, httpBackend } = await makeTestClient(
|
||||
{ userId: "@alice:example.com", deviceId: "Osborne2" },
|
||||
undefined,
|
||||
@@ -494,8 +503,7 @@ describe("Cross Signing", function() {
|
||||
});
|
||||
|
||||
// @ts-ignore private property
|
||||
const deviceInfo = alice.crypto!.deviceList.devices["@alice:example.com"]
|
||||
.Osborne2;
|
||||
const deviceInfo = alice.crypto!.deviceList.devices["@alice:example.com"].Osborne2;
|
||||
const aliceDevice = {
|
||||
user_id: "@alice:example.com",
|
||||
device_id: "Osborne2",
|
||||
@@ -549,7 +557,7 @@ describe("Cross Signing", function() {
|
||||
// - ssk
|
||||
// - master key signed by her usk (pretend that it was signed by another
|
||||
// of Alice's devices)
|
||||
const responses = [
|
||||
const responses: Response[] = [
|
||||
PUSH_RULES_RESPONSE,
|
||||
{
|
||||
method: "POST",
|
||||
@@ -853,7 +861,7 @@ describe("Cross Signing", function() {
|
||||
});
|
||||
|
||||
it("should offer to upgrade device verifications to cross-signing", async function() {
|
||||
let upgradeResolveFunc;
|
||||
let upgradeResolveFunc: Function;
|
||||
|
||||
const { client: alice } = await makeTestClient(
|
||||
{ userId: "@alice:example.com", deviceId: "Osborne2" },
|
||||
|
@@ -1,14 +1,16 @@
|
||||
import { IRecoveryKey } from '../../../src/crypto/api';
|
||||
import { CrossSigningLevel } from '../../../src/crypto/CrossSigning';
|
||||
import { IndexedDBCryptoStore } from '../../../src/crypto/store/indexeddb-crypto-store';
|
||||
import { MatrixClient } from "../../../src";
|
||||
import { CryptoEvent } from "../../../src/crypto";
|
||||
|
||||
// needs to be phased out and replaced with bootstrapSecretStorage,
|
||||
// but that is doing too much extra stuff for it to be an easy transition.
|
||||
export async function resetCrossSigningKeys(
|
||||
client,
|
||||
client: MatrixClient,
|
||||
{ level }: { level?: CrossSigningLevel} = {},
|
||||
): Promise<void> {
|
||||
const crypto = client.crypto;
|
||||
const crypto = client.crypto!;
|
||||
|
||||
const oldKeys = Object.assign({}, crypto.crossSigningInfo.keys);
|
||||
try {
|
||||
@@ -28,7 +30,8 @@ export async function resetCrossSigningKeys(
|
||||
crypto.crossSigningInfo.keys = oldKeys;
|
||||
throw e;
|
||||
}
|
||||
crypto.emit("crossSigning.keysChanged", {});
|
||||
crypto.emit(CryptoEvent.KeysChanged, {});
|
||||
// @ts-ignore
|
||||
await crypto.afterCrossSigningLocalKeyChange();
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
|
||||
import '../../olm-loader';
|
||||
import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import { IObject } from "../../../src/crypto/olmlib";
|
||||
import { SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/crypto/SecretStorage";
|
||||
import { MatrixEvent } from "../../../src/models/event";
|
||||
import { TestClient } from '../../TestClient';
|
||||
@@ -23,9 +24,11 @@ import { makeTestClients } from './verification/util';
|
||||
import { encryptAES } from "../../../src/crypto/aes";
|
||||
import { createSecretStorageKey, resetCrossSigningKeys } from "./crypto-utils";
|
||||
import { logger } from '../../../src/logger';
|
||||
import { ClientEvent, ICreateClientOpts } from '../../../src/client';
|
||||
import { ClientEvent, ICreateClientOpts, ICrossSigningKey, MatrixClient } from '../../../src/client';
|
||||
import { ISecretStorageKeyInfo } from '../../../src/crypto/api';
|
||||
import { DeviceInfo } from '../../../src/crypto/deviceinfo';
|
||||
import { ISignatures } from "../../../src/@types/signed";
|
||||
import { ICurve25519AuthData } from "../../../src/crypto/keybackup";
|
||||
|
||||
async function makeTestClient(userInfo: { userId: string, deviceId: string}, options: Partial<ICreateClientOpts> = {}) {
|
||||
const client = (new TestClient(
|
||||
@@ -48,9 +51,15 @@ async function makeTestClient(userInfo: { userId: string, deviceId: string}, opt
|
||||
|
||||
// Wrapper around pkSign to return a signed object. pkSign returns the
|
||||
// signature, rather than the signed object.
|
||||
function sign(obj, key, userId) {
|
||||
function sign<T extends IObject | ICurve25519AuthData>(obj: T, key: Uint8Array, userId: string): T & {
|
||||
signatures: ISignatures;
|
||||
unsigned?: object;
|
||||
} {
|
||||
olmlib.pkSign(obj, key, userId, '');
|
||||
return obj;
|
||||
return obj as T & {
|
||||
signatures: ISignatures;
|
||||
unsigned?: object;
|
||||
};
|
||||
}
|
||||
|
||||
describe("Secrets", function() {
|
||||
@@ -169,12 +178,12 @@ describe("Secrets", function() {
|
||||
return [newKeyId, key];
|
||||
});
|
||||
|
||||
let keys = {};
|
||||
let keys: Record<string, Uint8Array> = {};
|
||||
const alice = await makeTestClient(
|
||||
{ userId: "@alice:example.com", deviceId: "Osborne2" },
|
||||
{
|
||||
cryptoCallbacks: {
|
||||
getCrossSigningKey: t => keys[t],
|
||||
getCrossSigningKey: t => Promise.resolve(keys[t]),
|
||||
saveCrossSigningKeys: k => keys = k,
|
||||
getSecretStorageKey: getKey,
|
||||
},
|
||||
@@ -227,7 +236,7 @@ describe("Secrets", function() {
|
||||
cryptoCallbacks: {
|
||||
onSecretRequested: (userId, deviceId, requestId, secretName, deviceTrust) => {
|
||||
expect(secretName).toBe("foo");
|
||||
return "bar";
|
||||
return Promise.resolve("bar");
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -354,7 +363,7 @@ describe("Secrets", function() {
|
||||
const storagePublicKey = decryption.generate_key();
|
||||
const storagePrivateKey = decryption.get_private_key();
|
||||
|
||||
const bob = await makeTestClient(
|
||||
const bob: MatrixClient = await makeTestClient(
|
||||
{
|
||||
userId: "@bob:example.com",
|
||||
deviceId: "bob1",
|
||||
@@ -364,15 +373,15 @@ describe("Secrets", function() {
|
||||
getSecretStorageKey: async request => {
|
||||
const defaultKeyId = await bob.getDefaultSecretStorageKeyId();
|
||||
expect(Object.keys(request.keys)).toEqual([defaultKeyId]);
|
||||
return [defaultKeyId, storagePrivateKey];
|
||||
return [defaultKeyId!, storagePrivateKey];
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
bob.uploadDeviceSigningKeys = async () => {};
|
||||
bob.uploadKeySignatures = async () => {};
|
||||
bob.setAccountData = async function(eventType, contents, callback) {
|
||||
bob.uploadDeviceSigningKeys = async () => ({});
|
||||
bob.uploadKeySignatures = async () => ({ failures: {} });
|
||||
bob.setAccountData = async function(eventType, contents) {
|
||||
const event = new MatrixEvent({
|
||||
type: eventType,
|
||||
content: contents,
|
||||
@@ -380,16 +389,19 @@ describe("Secrets", function() {
|
||||
this.store.storeAccountDataEvents([
|
||||
event,
|
||||
]);
|
||||
this.emit("accountData", event);
|
||||
this.emit(ClientEvent.AccountData, event);
|
||||
return {};
|
||||
};
|
||||
bob.crypto.backupManager.checkKeyBackup = async () => {};
|
||||
bob.crypto!.backupManager.checkKeyBackup = async () => null;
|
||||
|
||||
const crossSigning = bob.crypto.crossSigningInfo;
|
||||
const secretStorage = bob.crypto.secretStorage;
|
||||
const crossSigning = bob.crypto!.crossSigningInfo;
|
||||
const secretStorage = bob.crypto!.secretStorage;
|
||||
|
||||
// Set up cross-signing keys from scratch with specific storage key
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
authUploadDeviceSigningKeys: async func => {
|
||||
await func({});
|
||||
},
|
||||
});
|
||||
await bob.bootstrapSecretStorage({
|
||||
createSecretStorageKey: async () => ({
|
||||
@@ -400,13 +412,15 @@ describe("Secrets", function() {
|
||||
});
|
||||
|
||||
// Clear local cross-signing keys and read from secret storage
|
||||
bob.crypto.deviceList.storeCrossSigningForUser(
|
||||
bob.crypto!.deviceList.storeCrossSigningForUser(
|
||||
"@bob:example.com",
|
||||
crossSigning.toStorage(),
|
||||
);
|
||||
crossSigning.keys = {};
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
authUploadDeviceSigningKeys: async func => {
|
||||
await func({});
|
||||
},
|
||||
});
|
||||
|
||||
expect(crossSigning.getId()).toBeTruthy();
|
||||
@@ -422,7 +436,7 @@ describe("Secrets", function() {
|
||||
user_signing: USK,
|
||||
self_signing: SSK,
|
||||
};
|
||||
const secretStorageKeys = {
|
||||
const secretStorageKeys: Record<string, Uint8Array> = {
|
||||
key_id: SSSSKey,
|
||||
};
|
||||
const alice = await makeTestClient(
|
||||
@@ -498,14 +512,14 @@ describe("Secrets", function() {
|
||||
[`ed25519:${XSPubKey}`]: XSPubKey,
|
||||
},
|
||||
},
|
||||
self_signing: sign({
|
||||
self_signing: sign<ICrossSigningKey>({
|
||||
user_id: "@alice:example.com",
|
||||
usage: ["self_signing"],
|
||||
keys: {
|
||||
[`ed25519:${SSPubKey}`]: SSPubKey,
|
||||
},
|
||||
}, XSK, "@alice:example.com"),
|
||||
user_signing: sign({
|
||||
user_signing: sign<ICrossSigningKey>({
|
||||
user_id: "@alice:example.com",
|
||||
usage: ["user_signing"],
|
||||
keys: {
|
||||
@@ -557,7 +571,7 @@ describe("Secrets", function() {
|
||||
user_signing: USK,
|
||||
self_signing: SSK,
|
||||
};
|
||||
const secretStorageKeys = {
|
||||
const secretStorageKeys: Record<string, Uint8Array> = {
|
||||
key_id: SSSSKey,
|
||||
};
|
||||
const alice = await makeTestClient(
|
||||
@@ -642,14 +656,14 @@ describe("Secrets", function() {
|
||||
[`ed25519:${XSPubKey}`]: XSPubKey,
|
||||
},
|
||||
},
|
||||
self_signing: sign({
|
||||
self_signing: sign<ICrossSigningKey>({
|
||||
user_id: "@alice:example.com",
|
||||
usage: ["self_signing"],
|
||||
keys: {
|
||||
[`ed25519:${SSPubKey}`]: SSPubKey,
|
||||
},
|
||||
}, XSK, "@alice:example.com"),
|
||||
user_signing: sign({
|
||||
user_signing: sign<ICrossSigningKey>({
|
||||
user_id: "@alice:example.com",
|
||||
usage: ["user_signing"],
|
||||
keys: {
|
||||
|
@@ -18,12 +18,12 @@ import "../../../olm-loader";
|
||||
import { makeTestClients } from './util';
|
||||
import { MatrixEvent } from "../../../../src/models/event";
|
||||
import { ISasEvent, SAS, SasEvent } from "../../../../src/crypto/verification/SAS";
|
||||
import { DeviceInfo } from "../../../../src/crypto/deviceinfo";
|
||||
import { DeviceInfo, IDevice } from "../../../../src/crypto/deviceinfo";
|
||||
import { CryptoEvent, verificationMethods } from "../../../../src/crypto";
|
||||
import * as olmlib from "../../../../src/crypto/olmlib";
|
||||
import { logger } from "../../../../src/logger";
|
||||
import { resetCrossSigningKeys } from "../crypto-utils";
|
||||
import { VerificationBase as Verification, VerificationBase } from "../../../../src/crypto/verification/Base";
|
||||
import { VerificationBase } from "../../../../src/crypto/verification/Base";
|
||||
import { IVerificationChannel } from "../../../../src/crypto/verification/request/Channel";
|
||||
import { MatrixClient } from "../../../../src";
|
||||
import { VerificationRequest } from "../../../../src/crypto/verification/request/VerificationRequest";
|
||||
@@ -31,8 +31,8 @@ import { TestClient } from "../../../TestClient";
|
||||
|
||||
const Olm = global.Olm;
|
||||
|
||||
let ALICE_DEVICES;
|
||||
let BOB_DEVICES;
|
||||
let ALICE_DEVICES: Record<string, IDevice>;
|
||||
let BOB_DEVICES: Record<string, IDevice>;
|
||||
|
||||
describe("SAS verification", function() {
|
||||
if (!global.Olm) {
|
||||
@@ -75,7 +75,7 @@ describe("SAS verification", function() {
|
||||
let bob: TestClient;
|
||||
let aliceSasEvent: ISasEvent | null;
|
||||
let bobSasEvent: ISasEvent | null;
|
||||
let aliceVerifier: Verification<any, any>;
|
||||
let aliceVerifier: SAS;
|
||||
let bobPromise: Promise<VerificationBase<any, any>>;
|
||||
let clearTestClientTimeouts: () => void;
|
||||
|
||||
@@ -95,25 +95,25 @@ describe("SAS verification", function() {
|
||||
|
||||
ALICE_DEVICES = {
|
||||
Osborne2: {
|
||||
user_id: "@alice:example.com",
|
||||
device_id: "Osborne2",
|
||||
algorithms: [olmlib.OLM_ALGORITHM, olmlib.MEGOLM_ALGORITHM],
|
||||
keys: {
|
||||
"ed25519:Osborne2": aliceDevice.deviceEd25519Key,
|
||||
"curve25519:Osborne2": aliceDevice.deviceCurve25519Key,
|
||||
"ed25519:Osborne2": aliceDevice.deviceEd25519Key!,
|
||||
"curve25519:Osborne2": aliceDevice.deviceCurve25519Key!,
|
||||
},
|
||||
verified: DeviceInfo.DeviceVerification.UNVERIFIED,
|
||||
known: false,
|
||||
},
|
||||
};
|
||||
|
||||
BOB_DEVICES = {
|
||||
Dynabook: {
|
||||
user_id: "@bob:example.com",
|
||||
device_id: "Dynabook",
|
||||
algorithms: [olmlib.OLM_ALGORITHM, olmlib.MEGOLM_ALGORITHM],
|
||||
keys: {
|
||||
"ed25519:Dynabook": bobDevice.deviceEd25519Key,
|
||||
"curve25519:Dynabook": bobDevice.deviceCurve25519Key,
|
||||
"ed25519:Dynabook": bobDevice.deviceEd25519Key!,
|
||||
"curve25519:Dynabook": bobDevice.deviceCurve25519Key!,
|
||||
},
|
||||
verified: DeviceInfo.DeviceVerification.UNVERIFIED,
|
||||
known: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ describe("SAS verification", function() {
|
||||
|
||||
bobPromise = new Promise<VerificationBase<any, any>>((resolve, reject) => {
|
||||
bob.client.on(CryptoEvent.VerificationRequest, request => {
|
||||
request.verifier!.on("show_sas", (e) => {
|
||||
(<SAS>request.verifier!).on(SasEvent.ShowSas, (e) => {
|
||||
if (!e.sas.emoji || !e.sas.decimal) {
|
||||
e.cancel();
|
||||
} else if (!aliceSasEvent) {
|
||||
@@ -158,7 +158,7 @@ describe("SAS verification", function() {
|
||||
|
||||
aliceVerifier = alice.client.beginKeyVerification(
|
||||
verificationMethods.SAS, bob.client.getUserId()!, bob.deviceId!,
|
||||
);
|
||||
) as SAS;
|
||||
aliceVerifier.on(SasEvent.ShowSas, (e) => {
|
||||
if (!e.sas.emoji || !e.sas.decimal) {
|
||||
e.cancel();
|
||||
@@ -413,7 +413,7 @@ describe("SAS verification", function() {
|
||||
|
||||
const bobPromise = new Promise<VerificationBase<any, any>>((resolve, reject) => {
|
||||
bob.client.on(CryptoEvent.VerificationRequest, request => {
|
||||
request.verifier!.on("show_sas", (e) => {
|
||||
(<SAS>request.verifier!).on(SasEvent.ShowSas, (e) => {
|
||||
e.mismatch();
|
||||
});
|
||||
resolve(request.verifier!);
|
||||
@@ -443,13 +443,13 @@ describe("SAS verification", function() {
|
||||
});
|
||||
|
||||
describe("verification in DM", function() {
|
||||
let alice;
|
||||
let bob;
|
||||
let aliceSasEvent;
|
||||
let bobSasEvent;
|
||||
let aliceVerifier;
|
||||
let bobPromise;
|
||||
let clearTestClientTimeouts;
|
||||
let alice: TestClient;
|
||||
let bob: TestClient;
|
||||
let aliceSasEvent: ISasEvent | null;
|
||||
let bobSasEvent: ISasEvent | null;
|
||||
let aliceVerifier: SAS;
|
||||
let bobPromise: Promise<void>;
|
||||
let clearTestClientTimeouts: Function;
|
||||
|
||||
beforeEach(async function() {
|
||||
[[alice, bob], clearTestClientTimeouts] = await makeTestClients(
|
||||
@@ -477,7 +477,7 @@ describe("SAS verification", function() {
|
||||
);
|
||||
};
|
||||
alice.client.downloadKeys = () => {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
};
|
||||
|
||||
bob.client.crypto!.setDeviceVerification = jest.fn();
|
||||
@@ -495,16 +495,16 @@ describe("SAS verification", function() {
|
||||
return "bob+base64+ed25519+key";
|
||||
};
|
||||
bob.client.downloadKeys = () => {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
};
|
||||
|
||||
aliceSasEvent = null;
|
||||
bobSasEvent = null;
|
||||
|
||||
bobPromise = new Promise<void>((resolve, reject) => {
|
||||
bob.client.on("crypto.verification.request", async (request) => {
|
||||
const verifier = request.beginKeyVerification(SAS.NAME);
|
||||
verifier.on("show_sas", (e) => {
|
||||
bob.client.on(CryptoEvent.VerificationRequest, async (request) => {
|
||||
const verifier = request.beginKeyVerification(SAS.NAME) as SAS;
|
||||
verifier.on(SasEvent.ShowSas, (e) => {
|
||||
if (!e.sas.emoji || !e.sas.decimal) {
|
||||
e.cancel();
|
||||
} else if (!aliceSasEvent) {
|
||||
@@ -525,12 +525,10 @@ describe("SAS verification", function() {
|
||||
});
|
||||
});
|
||||
|
||||
const aliceRequest = await alice.client.requestVerificationDM(
|
||||
bob.client.getUserId(), "!room_id",
|
||||
);
|
||||
const aliceRequest = await alice.client.requestVerificationDM(bob.client.getUserId()!, "!room_id");
|
||||
await aliceRequest.waitFor(r => r.started);
|
||||
aliceVerifier = aliceRequest.verifier;
|
||||
aliceVerifier.on("show_sas", (e) => {
|
||||
aliceVerifier = aliceRequest.verifier! as SAS;
|
||||
aliceVerifier.on(SasEvent.ShowSas, (e) => {
|
||||
if (!e.sas.emoji || !e.sas.decimal) {
|
||||
e.cancel();
|
||||
} else if (!bobSasEvent) {
|
||||
|
@@ -125,7 +125,7 @@ describe("self-verifications", () => {
|
||||
expect(restoreKeyBackupWithCache).toHaveBeenCalled();
|
||||
|
||||
expect(result).toBeInstanceOf(Array);
|
||||
expect(result[0][0]).toBe(testKeyPub);
|
||||
expect(result[1][0]).toBe(testKeyPub);
|
||||
expect(result![0][0]).toBe(testKeyPub);
|
||||
expect(result![1][0]).toBe(testKeyPub);
|
||||
});
|
||||
});
|
||||
|
@@ -16,13 +16,21 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { TestClient } from '../../../TestClient';
|
||||
import { MatrixEvent } from "../../../../src/models/event";
|
||||
import { IContent, MatrixEvent } from "../../../../src/models/event";
|
||||
import { IRoomTimelineData } from "../../../../src/models/event-timeline-set";
|
||||
import { Room, RoomEvent } from "../../../../src/models/room";
|
||||
import { logger } from '../../../../src/logger';
|
||||
import { MatrixClient, ClientEvent } from '../../../../src/client';
|
||||
import { MatrixClient, ClientEvent, ICreateClientOpts } from '../../../../src/client';
|
||||
|
||||
export async function makeTestClients(userInfos, options): Promise<[TestClient[], () => void]> {
|
||||
interface UserInfo {
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
}
|
||||
|
||||
export async function makeTestClients(
|
||||
userInfos: UserInfo[],
|
||||
options: Partial<ICreateClientOpts>,
|
||||
): Promise<[TestClient[], () => void]> {
|
||||
const clients: TestClient[] = [];
|
||||
const timeouts: ReturnType<typeof setTimeout>[] = [];
|
||||
const clientMap: Record<string, Record<string, MatrixClient>> = {};
|
||||
@@ -51,7 +59,7 @@ export async function makeTestClients(userInfos, options): Promise<[TestClient[]
|
||||
}
|
||||
return {};
|
||||
};
|
||||
const makeSendEvent = (matrixClient: MatrixClient) => (room, type, content) => {
|
||||
const makeSendEvent = (matrixClient: MatrixClient) => (room: string, type: string, content: IContent) => {
|
||||
// make up a unique ID as the event ID
|
||||
const eventId = "$" + matrixClient.makeTxnId();
|
||||
const rawEvent = {
|
||||
@@ -88,11 +96,12 @@ export async function makeTestClients(userInfos, options): Promise<[TestClient[]
|
||||
};
|
||||
|
||||
for (const userInfo of userInfos) {
|
||||
let keys = {};
|
||||
let keys: Record<string, Uint8Array> = {};
|
||||
if (!options) options = {};
|
||||
if (!options.cryptoCallbacks) options.cryptoCallbacks = {};
|
||||
if (!options.cryptoCallbacks.saveCrossSigningKeys) {
|
||||
options.cryptoCallbacks.saveCrossSigningKeys = k => { keys = k; };
|
||||
// @ts-ignore tsc getting confused by overloads
|
||||
options.cryptoCallbacks.getCrossSigningKey = typ => keys[typ];
|
||||
}
|
||||
const testClient = new TestClient(
|
||||
@@ -104,6 +113,7 @@ export async function makeTestClients(userInfos, options): Promise<[TestClient[]
|
||||
}
|
||||
clientMap[userInfo.userId][userInfo.deviceId] = testClient.client;
|
||||
testClient.client.sendToDevice = makeSendToDevice(testClient.client);
|
||||
// @ts-ignore tsc getting confused by overloads
|
||||
testClient.client.sendEvent = makeSendEvent(testClient.client);
|
||||
clients.push(testClient);
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ import { VerificationRequest, READY_TYPE, START_TYPE, DONE_TYPE } from
|
||||
import { InRoomChannel } from "../../../../src/crypto/verification/request/InRoomChannel";
|
||||
import { ToDeviceChannel } from
|
||||
"../../../../src/crypto/verification/request/ToDeviceChannel";
|
||||
import { MatrixEvent } from "../../../../src/models/event";
|
||||
import { IContent, MatrixEvent } from "../../../../src/models/event";
|
||||
import { MatrixClient } from "../../../../src/client";
|
||||
import { IVerificationChannel } from "../../../../src/crypto/verification/request/Channel";
|
||||
import { VerificationBase } from "../../../../src/crypto/verification/Base";
|
||||
@@ -30,12 +30,12 @@ type MockClient = MatrixClient & {
|
||||
function makeMockClient(userId: string, deviceId: string): MockClient {
|
||||
let counter = 1;
|
||||
let events: MatrixEvent[] = [];
|
||||
const deviceEvents = {};
|
||||
const deviceEvents: Record<string, Record<string, MatrixEvent[]>> = {};
|
||||
return {
|
||||
getUserId() { return userId; },
|
||||
getDeviceId() { return deviceId; },
|
||||
|
||||
sendEvent(roomId, type, content) {
|
||||
sendEvent(roomId: string, type: string, content: IContent) {
|
||||
counter = counter + 1;
|
||||
const eventId = `$${userId}-${deviceId}-${counter}`;
|
||||
events.push(new MatrixEvent({
|
||||
@@ -49,7 +49,7 @@ function makeMockClient(userId: string, deviceId: string): MockClient {
|
||||
return Promise.resolve({ event_id: eventId });
|
||||
},
|
||||
|
||||
sendToDevice(type, msgMap) {
|
||||
sendToDevice(type: string, msgMap: Record<string, Record<string, IContent>>) {
|
||||
for (const userId of Object.keys(msgMap)) {
|
||||
const deviceMap = msgMap[userId];
|
||||
for (const deviceId of Object.keys(deviceMap)) {
|
||||
@@ -111,7 +111,7 @@ class MockVerifier extends VerificationBase<'', any> {
|
||||
}
|
||||
}
|
||||
|
||||
async handleEvent(event) {
|
||||
async handleEvent(event: MatrixEvent) {
|
||||
if (event.getType() === DONE_TYPE && !this._startEvent) {
|
||||
await this._channel.send(DONE_TYPE, {});
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class MockVerifier extends VerificationBase<'', any> {
|
||||
}
|
||||
}
|
||||
|
||||
function makeRemoteEcho(event) {
|
||||
function makeRemoteEcho(event: MatrixEvent) {
|
||||
return new MatrixEvent(Object.assign({}, event.event, {
|
||||
unsigned: {
|
||||
transaction_id: "abc",
|
||||
|
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import { logger } from "../../src/logger";
|
||||
import { MatrixClient, ClientEvent } from "../../src/client";
|
||||
import { ClientEvent, ITurnServerResponse, MatrixClient, Store } from "../../src/client";
|
||||
import { Filter } from "../../src/filter";
|
||||
import { DEFAULT_TREE_POWER_LEVELS_TEMPLATE } from "../../src/models/MSC3089TreeSpace";
|
||||
import {
|
||||
@@ -36,7 +36,16 @@ import { ReceiptType } from "../../src/@types/read_receipts";
|
||||
import * as testUtils from "../test-utils/test-utils";
|
||||
import { makeBeaconInfoContent } from "../../src/content-helpers";
|
||||
import { M_BEACON_INFO } from "../../src/@types/beacon";
|
||||
import { ContentHelpers, EventTimeline, MatrixError, Room } from "../../src";
|
||||
import {
|
||||
ContentHelpers,
|
||||
EventTimeline, ICreateRoomOpts,
|
||||
IRequestOpts,
|
||||
MatrixError,
|
||||
MatrixHttpApi,
|
||||
MatrixScheduler,
|
||||
Method,
|
||||
Room,
|
||||
} from "../../src";
|
||||
import { supportsMatrixCall } from "../../src/webrtc/call";
|
||||
import { makeBeaconEvent } from "../test-utils/beacon";
|
||||
import {
|
||||
@@ -44,6 +53,9 @@ import {
|
||||
POLICIES_ACCOUNT_EVENT_TYPE,
|
||||
PolicyScope,
|
||||
} from "../../src/models/invites-ignorer";
|
||||
import { IOlmDevice } from "../../src/crypto/algorithms/megolm";
|
||||
import { QueryDict } from "../../src/utils";
|
||||
import { SyncState } from "../../src/sync";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
@@ -52,17 +64,36 @@ jest.mock("../../src/webrtc/call", () => ({
|
||||
supportsMatrixCall: jest.fn(() => false),
|
||||
}));
|
||||
|
||||
type HttpLookup = {
|
||||
method: string;
|
||||
path: string;
|
||||
data?: Record<string, any>;
|
||||
error?: object;
|
||||
expectBody?: Record<string, any>;
|
||||
expectQueryParams?: QueryDict;
|
||||
thenCall?: Function;
|
||||
};
|
||||
|
||||
interface Options extends ICreateRoomOpts {
|
||||
_roomId?: string;
|
||||
}
|
||||
|
||||
type WrappedRoom = Room & {
|
||||
_options: Options;
|
||||
_state: Map<string, any>;
|
||||
};
|
||||
|
||||
describe("MatrixClient", function() {
|
||||
const userId = "@alice:bar";
|
||||
const identityServerUrl = "https://identity.server";
|
||||
const identityServerDomain = "identity.server";
|
||||
let client;
|
||||
let store;
|
||||
let scheduler;
|
||||
let client: MatrixClient;
|
||||
let store: Store;
|
||||
let scheduler: MatrixScheduler;
|
||||
|
||||
const KEEP_ALIVE_PATH = "/_matrix/client/versions";
|
||||
|
||||
const PUSH_RULES_RESPONSE = {
|
||||
const PUSH_RULES_RESPONSE: HttpLookup = {
|
||||
method: "GET",
|
||||
path: "/pushrules/",
|
||||
data: {},
|
||||
@@ -70,7 +101,7 @@ describe("MatrixClient", function() {
|
||||
|
||||
const FILTER_PATH = "/user/" + encodeURIComponent(userId) + "/filter";
|
||||
|
||||
const FILTER_RESPONSE = {
|
||||
const FILTER_RESPONSE: HttpLookup = {
|
||||
method: "POST",
|
||||
path: FILTER_PATH,
|
||||
data: { filter_id: "f1lt3r" },
|
||||
@@ -82,29 +113,21 @@ describe("MatrixClient", function() {
|
||||
rooms: {},
|
||||
};
|
||||
|
||||
const SYNC_RESPONSE = {
|
||||
const SYNC_RESPONSE: HttpLookup = {
|
||||
method: "GET",
|
||||
path: "/sync",
|
||||
data: SYNC_DATA,
|
||||
};
|
||||
|
||||
// items are popped off when processed and block if no items left.
|
||||
let httpLookups: {
|
||||
method: string;
|
||||
path: string;
|
||||
data?: object;
|
||||
error?: object;
|
||||
expectBody?: object;
|
||||
expectQueryParams?: object;
|
||||
thenCall?: Function;
|
||||
}[] = [];
|
||||
let httpLookups: HttpLookup[] = [];
|
||||
let acceptKeepalives: boolean;
|
||||
let pendingLookup: {
|
||||
promise: Promise<any>;
|
||||
method: string;
|
||||
path: string;
|
||||
} | null = null;
|
||||
function httpReq(method, path, qp, data, prefix) {
|
||||
function httpReq(method: Method, path: string, qp?: QueryDict, data?: BodyInit, opts?: IRequestOpts) {
|
||||
if (path === KEEP_ALIVE_PATH && acceptKeepalives) {
|
||||
return Promise.resolve({
|
||||
unstable_features: {
|
||||
@@ -145,7 +168,7 @@ describe("MatrixClient", function() {
|
||||
}
|
||||
if (next.expectQueryParams) {
|
||||
Object.keys(next.expectQueryParams).forEach(function(k) {
|
||||
expect(qp[k]).toEqual(next.expectQueryParams![k]);
|
||||
expect(qp?.[k]).toEqual(next.expectQueryParams![k]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -184,24 +207,38 @@ describe("MatrixClient", function() {
|
||||
userId: userId,
|
||||
});
|
||||
// FIXME: We shouldn't be yanking http like this.
|
||||
client.http = [
|
||||
"authedRequest", "getContentUri", "request", "uploadContent",
|
||||
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||
client.http.authedRequest.mockImplementation(httpReq);
|
||||
client.http.request.mockImplementation(httpReq);
|
||||
client.http = ([
|
||||
"authedRequest",
|
||||
"getContentUri",
|
||||
"request",
|
||||
"uploadContent",
|
||||
] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as MatrixHttpApi<any>);
|
||||
mocked(client.http.authedRequest).mockImplementation(httpReq);
|
||||
mocked(client.http.request).mockImplementation(httpReq);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
scheduler = [
|
||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||
scheduler = ([
|
||||
"getQueueForEvent",
|
||||
"queueEvent",
|
||||
"removeEventFromQueue",
|
||||
"setProcessFunction",
|
||||
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||
store = [
|
||||
] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as MatrixScheduler);
|
||||
store = ([
|
||||
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
||||
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom", "storeUser",
|
||||
"getFilterIdByName", "setFilterIdByName", "getFilter", "storeFilter",
|
||||
"getSyncAccumulator", "startup", "deleteAllData",
|
||||
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||
"startup", "deleteAllData",
|
||||
] as const).reduce((r, k) => {
|
||||
r[k] = jest.fn();
|
||||
return r;
|
||||
}, {} as Store);
|
||||
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||
@@ -225,7 +262,7 @@ describe("MatrixClient", function() {
|
||||
// means they may call /events and then fail an expect() which will fail
|
||||
// a DIFFERENT test (pollution between tests!) - we return unresolved
|
||||
// promises to stop the client from continuing to run.
|
||||
client.http.authedRequest.mockImplementation(function() {
|
||||
mocked(client.http.authedRequest).mockImplementation(function() {
|
||||
return new Promise(() => {});
|
||||
});
|
||||
client.stopClient();
|
||||
@@ -289,7 +326,7 @@ describe("MatrixClient", function() {
|
||||
const txnId = client.makeTxnId();
|
||||
|
||||
const room = new Room(roomId, client, userId);
|
||||
store.getRoom.mockReturnValue(room);
|
||||
mocked(store.getRoom).mockReturnValue(room);
|
||||
|
||||
const rootEvent = new MatrixEvent({ event_id: threadId });
|
||||
room.createThread(threadId, rootEvent, [rootEvent], false);
|
||||
@@ -329,7 +366,7 @@ describe("MatrixClient", function() {
|
||||
};
|
||||
|
||||
const room = new Room(roomId, client, userId);
|
||||
store.getRoom.mockReturnValue(room);
|
||||
mocked(store.getRoom).mockReturnValue(room);
|
||||
|
||||
const rootEvent = new MatrixEvent({ event_id: threadId });
|
||||
room.createThread(threadId, rootEvent, [rootEvent], false);
|
||||
@@ -359,7 +396,7 @@ describe("MatrixClient", function() {
|
||||
const userId = "@test:example.org";
|
||||
const roomId = "!room:example.org";
|
||||
const roomName = "Test Tree";
|
||||
const mockRoom = {};
|
||||
const mockRoom = {} as unknown as Room;
|
||||
const fn = jest.fn().mockImplementation((opts) => {
|
||||
expect(opts).toMatchObject({
|
||||
name: roomName,
|
||||
@@ -431,23 +468,23 @@ describe("MatrixClient", function() {
|
||||
throw new Error("Unexpected event type or state key");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
} as Room["currentState"],
|
||||
} as unknown as Room;
|
||||
client.getRoom = (getRoomId) => {
|
||||
expect(getRoomId).toEqual(roomId);
|
||||
return mockRoom;
|
||||
};
|
||||
const tree = client.unstableGetFileTreeSpace(roomId);
|
||||
expect(tree).toBeDefined();
|
||||
expect(tree.roomId).toEqual(roomId);
|
||||
expect(tree.room).toBe(mockRoom);
|
||||
expect(tree!.roomId).toEqual(roomId);
|
||||
expect(tree!.room).toBe(mockRoom);
|
||||
});
|
||||
|
||||
it("should not get (unstable) file trees if not joined", async () => {
|
||||
const roomId = "!room:example.org";
|
||||
const mockRoom = {
|
||||
getMyMembership: () => "leave", // "not join"
|
||||
};
|
||||
} as unknown as Room;
|
||||
client.getRoom = (getRoomId) => {
|
||||
expect(getRoomId).toEqual(roomId);
|
||||
return mockRoom;
|
||||
@@ -491,8 +528,8 @@ describe("MatrixClient", function() {
|
||||
throw new Error("Unexpected event type or state key");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
} as Room["currentState"],
|
||||
} as unknown as Room;
|
||||
client.getRoom = (getRoomId) => {
|
||||
expect(getRoomId).toEqual(roomId);
|
||||
return mockRoom;
|
||||
@@ -525,8 +562,8 @@ describe("MatrixClient", function() {
|
||||
throw new Error("Unexpected event type or state key");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
} as Room["currentState"],
|
||||
} as unknown as Room;
|
||||
client.getRoom = (getRoomId) => {
|
||||
expect(getRoomId).toEqual(roomId);
|
||||
return mockRoom;
|
||||
@@ -541,15 +578,15 @@ describe("MatrixClient", function() {
|
||||
SYNC_RESPONSE,
|
||||
];
|
||||
const filterId = "ehfewf";
|
||||
store.getFilterIdByName.mockReturnValue(filterId);
|
||||
mocked(store.getFilterIdByName).mockReturnValue(filterId);
|
||||
const filter = new Filter("0", filterId);
|
||||
filter.setDefinition({ "room": { "timeline": { "limit": 8 } } });
|
||||
store.getFilter.mockReturnValue(filter);
|
||||
mocked(store.getFilter).mockReturnValue(filter);
|
||||
const syncPromise = new Promise<void>((resolve, reject) => {
|
||||
client.on("sync", function syncListener(state) {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
if (state === "SYNCING") {
|
||||
expect(httpLookups.length).toEqual(0);
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
resolve();
|
||||
} else if (state === "ERROR") {
|
||||
reject(new Error("sync error"));
|
||||
@@ -567,10 +604,10 @@ describe("MatrixClient", function() {
|
||||
|
||||
it("should return the same sync state as emitted sync events", async function() {
|
||||
const syncingPromise = new Promise<void>((resolve) => {
|
||||
client.on("sync", function syncListener(state) {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
expect(state).toEqual(client.getSyncState());
|
||||
if (state === "SYNCING") {
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
@@ -586,7 +623,7 @@ describe("MatrixClient", function() {
|
||||
it("should use an existing filter if id is present in localStorage", function() {
|
||||
});
|
||||
it("should handle localStorage filterId missing from the server", function(done) {
|
||||
function getFilterName(userId, suffix?: string) {
|
||||
function getFilterName(userId: string, suffix?: string) {
|
||||
// scope this on the user ID because people may login on many accounts
|
||||
// and they all need to be stored!
|
||||
return "FILTER_SYNC_" + userId + (suffix ? "_" + suffix : "");
|
||||
@@ -605,14 +642,14 @@ describe("MatrixClient", function() {
|
||||
},
|
||||
});
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
store.getFilterIdByName.mockReturnValue(invalidFilterId);
|
||||
mocked(store.getFilterIdByName).mockReturnValue(invalidFilterId);
|
||||
|
||||
const filterName = getFilterName(client.credentials.userId);
|
||||
const filterName = getFilterName(client.credentials.userId!);
|
||||
client.store.setFilterIdByName(filterName, invalidFilterId);
|
||||
const filter = new Filter(client.credentials.userId);
|
||||
|
||||
client.getOrCreateFilter(filterName, filter).then(function(filterId) {
|
||||
expect(filterId).toEqual(FILTER_RESPONSE.data.filter_id);
|
||||
expect(filterId).toEqual(FILTER_RESPONSE.data?.filter_id);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -634,13 +671,13 @@ describe("MatrixClient", function() {
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
|
||||
client.on("sync", function syncListener(state) {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
if (state === "ERROR" && httpLookups.length > 0) {
|
||||
expect(httpLookups.length).toEqual(2);
|
||||
expect(client.retryImmediately()).toBe(true);
|
||||
jest.advanceTimersByTime(1);
|
||||
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
done();
|
||||
} else {
|
||||
// unexpected state transition!
|
||||
@@ -658,7 +695,7 @@ describe("MatrixClient", function() {
|
||||
method: "GET", path: "/sync", data: SYNC_DATA,
|
||||
});
|
||||
|
||||
client.on("sync", function syncListener(state) {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
if (state === "ERROR" && httpLookups.length > 0) {
|
||||
expect(httpLookups.length).toEqual(1);
|
||||
expect(client.retryImmediately()).toBe(
|
||||
@@ -668,7 +705,7 @@ describe("MatrixClient", function() {
|
||||
} else if (state === "RECONNECTING" && httpLookups.length > 0) {
|
||||
jest.advanceTimersByTime(10000);
|
||||
} else if (state === "SYNCING" && httpLookups.length === 0) {
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -684,13 +721,13 @@ describe("MatrixClient", function() {
|
||||
httpLookups.push(FILTER_RESPONSE);
|
||||
httpLookups.push(SYNC_RESPONSE);
|
||||
|
||||
client.on("sync", function syncListener(state) {
|
||||
client.on(ClientEvent.Sync, function syncListener(state) {
|
||||
if (state === "ERROR" && httpLookups.length > 0) {
|
||||
expect(httpLookups.length).toEqual(3);
|
||||
expect(client.retryImmediately()).toBe(true);
|
||||
jest.advanceTimersByTime(1);
|
||||
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
done();
|
||||
} else {
|
||||
// unexpected state transition!
|
||||
@@ -702,8 +739,8 @@ describe("MatrixClient", function() {
|
||||
});
|
||||
|
||||
describe("emitted sync events", function() {
|
||||
function syncChecker(expectedStates, done) {
|
||||
return function syncListener(state, old) {
|
||||
function syncChecker(expectedStates: [string, string | null][], done: Function) {
|
||||
return function syncListener(state: SyncState, old: SyncState | null) {
|
||||
const expected = expectedStates.shift();
|
||||
logger.log(
|
||||
"'sync' curr=%s old=%s EXPECT=%s", state, old, expected,
|
||||
@@ -715,7 +752,7 @@ describe("MatrixClient", function() {
|
||||
expect(state).toEqual(expected[0]);
|
||||
expect(old).toEqual(expected[1]);
|
||||
if (expectedStates.length === 0) {
|
||||
client.removeListener("sync", syncListener);
|
||||
client.removeListener(ClientEvent.Sync, syncListener);
|
||||
done();
|
||||
}
|
||||
// standard retry time is 5 to 10 seconds
|
||||
@@ -726,7 +763,7 @@ describe("MatrixClient", function() {
|
||||
it("should transition null -> PREPARED after the first /sync", function(done) {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -738,7 +775,7 @@ describe("MatrixClient", function() {
|
||||
method: "POST", path: FILTER_PATH, error: { errcode: "NOPE_NOPE_NOPE" },
|
||||
});
|
||||
expectedStates.push(["ERROR", null]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -768,7 +805,7 @@ describe("MatrixClient", function() {
|
||||
expectedStates.push(["RECONNECTING", null]);
|
||||
expectedStates.push(["ERROR", "RECONNECTING"]);
|
||||
expectedStates.push(["CATCHUP", "ERROR"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -776,7 +813,7 @@ describe("MatrixClient", function() {
|
||||
const expectedStates: [string, string | null][] = [];
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
expectedStates.push(["SYNCING", "PREPARED"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -795,7 +832,7 @@ describe("MatrixClient", function() {
|
||||
expectedStates.push(["SYNCING", "PREPARED"]);
|
||||
expectedStates.push(["RECONNECTING", "SYNCING"]);
|
||||
expectedStates.push(["ERROR", "RECONNECTING"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -809,7 +846,7 @@ describe("MatrixClient", function() {
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
expectedStates.push(["SYNCING", "PREPARED"]);
|
||||
expectedStates.push(["ERROR", "SYNCING"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -821,7 +858,7 @@ describe("MatrixClient", function() {
|
||||
expectedStates.push(["PREPARED", null]);
|
||||
expectedStates.push(["SYNCING", "PREPARED"]);
|
||||
expectedStates.push(["SYNCING", "SYNCING"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
|
||||
@@ -845,7 +882,7 @@ describe("MatrixClient", function() {
|
||||
expectedStates.push(["RECONNECTING", "SYNCING"]);
|
||||
expectedStates.push(["ERROR", "RECONNECTING"]);
|
||||
expectedStates.push(["ERROR", "ERROR"]);
|
||||
client.on("sync", syncChecker(expectedStates, done));
|
||||
client.on(ClientEvent.Sync, syncChecker(expectedStates, done));
|
||||
client.startClient();
|
||||
});
|
||||
});
|
||||
@@ -914,14 +951,14 @@ describe("MatrixClient", function() {
|
||||
throw new Error("Unexpected event type or state key");
|
||||
}
|
||||
},
|
||||
},
|
||||
} as Room["currentState"],
|
||||
getThread: jest.fn(),
|
||||
addPendingEvent: jest.fn(),
|
||||
updatePendingEvent: jest.fn(),
|
||||
reEmitter: {
|
||||
reEmit: jest.fn(),
|
||||
},
|
||||
};
|
||||
} as unknown as Room;
|
||||
|
||||
beforeEach(() => {
|
||||
client.getRoom = (getRoomId) => {
|
||||
@@ -987,7 +1024,7 @@ describe("MatrixClient", function() {
|
||||
|
||||
const mockRoom = {
|
||||
getMyMembership: () => "join",
|
||||
updatePendingEvent: (event, status) => event.setStatus(status),
|
||||
updatePendingEvent: (event: MatrixEvent, status: EventStatus) => event.setStatus(status),
|
||||
currentState: {
|
||||
getStateEvents: (eventType, stateKey) => {
|
||||
if (eventType === EventType.RoomCreate) {
|
||||
@@ -1004,15 +1041,14 @@ describe("MatrixClient", function() {
|
||||
throw new Error("Unexpected event type or state key");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
} as Room["currentState"],
|
||||
} as unknown as Room;
|
||||
|
||||
let event;
|
||||
let event: MatrixEvent;
|
||||
beforeEach(async () => {
|
||||
event = new MatrixEvent({
|
||||
event_id: "~" + roomId + ":" + txnId,
|
||||
user_id: client.credentials.userId,
|
||||
sender: client.credentials.userId,
|
||||
sender: client.credentials.userId!,
|
||||
room_id: roomId,
|
||||
origin_server_ts: new Date().getTime(),
|
||||
});
|
||||
@@ -1023,25 +1059,26 @@ describe("MatrixClient", function() {
|
||||
return mockRoom;
|
||||
};
|
||||
client.crypto = { // mock crypto
|
||||
encryptEvent: (event, room) => new Promise(() => {}),
|
||||
encryptEvent: () => new Promise(() => {}),
|
||||
stop: jest.fn(),
|
||||
};
|
||||
} as unknown as Crypto;
|
||||
});
|
||||
|
||||
function assertCancelled() {
|
||||
expect(event.status).toBe(EventStatus.CANCELLED);
|
||||
expect(client.scheduler.removeEventFromQueue(event)).toBeFalsy();
|
||||
expect(client.scheduler?.removeEventFromQueue(event)).toBeFalsy();
|
||||
expect(httpLookups.filter(h => h.path.includes("/send/")).length).toBe(0);
|
||||
}
|
||||
|
||||
it("should cancel an event which is queued", () => {
|
||||
event.setStatus(EventStatus.QUEUED);
|
||||
client.scheduler.queueEvent(event);
|
||||
client.scheduler?.queueEvent(event);
|
||||
client.cancelPendingEvent(event);
|
||||
assertCancelled();
|
||||
});
|
||||
|
||||
it("should cancel an event which is encrypting", async () => {
|
||||
// @ts-ignore protected method access
|
||||
client.encryptAndSendEvent(null, event);
|
||||
await testUtils.emitPromise(event, "Event.status");
|
||||
client.cancelPendingEvent(event);
|
||||
@@ -1103,7 +1140,7 @@ describe("MatrixClient", function() {
|
||||
const room = {
|
||||
hasPendingEvent: jest.fn().mockReturnValue(false),
|
||||
addLocalEchoReceipt: jest.fn(),
|
||||
};
|
||||
} as unknown as Room;
|
||||
const rrEvent = new MatrixEvent({ event_id: "read_event_id" });
|
||||
const rpEvent = new MatrixEvent({ event_id: "read_private_event_id" });
|
||||
client.getRoom = () => room;
|
||||
@@ -1142,7 +1179,7 @@ describe("MatrixClient", function() {
|
||||
const content = makeBeaconInfoContent(100, true);
|
||||
|
||||
beforeEach(() => {
|
||||
client.http.authedRequest.mockClear().mockResolvedValue({});
|
||||
mocked(client.http.authedRequest).mockClear().mockResolvedValue({});
|
||||
});
|
||||
|
||||
it("creates new beacon info", async () => {
|
||||
@@ -1150,7 +1187,7 @@ describe("MatrixClient", function() {
|
||||
|
||||
// event type combined
|
||||
const expectedEventType = M_BEACON_INFO.name;
|
||||
const [method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0];
|
||||
const [method, path, queryParams, requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(method).toBe('PUT');
|
||||
expect(path).toEqual(
|
||||
`/rooms/${encodeURIComponent(roomId)}/state/` +
|
||||
@@ -1164,7 +1201,7 @@ describe("MatrixClient", function() {
|
||||
await client.unstable_setLiveBeacon(roomId, content);
|
||||
|
||||
// event type combined
|
||||
const [, path, , requestContent] = client.http.authedRequest.mock.calls[0];
|
||||
const [, path, , requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(path).toEqual(
|
||||
`/rooms/${encodeURIComponent(roomId)}/state/` +
|
||||
`${encodeURIComponent(M_BEACON_INFO.name)}/${encodeURIComponent(userId)}`,
|
||||
@@ -1242,7 +1279,7 @@ describe("MatrixClient", function() {
|
||||
const newPassword = 'newpassword';
|
||||
|
||||
const passwordTest = (expectedRequestContent: any) => {
|
||||
const [method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0];
|
||||
const [method, path, queryParams, requestContent] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(method).toBe('POST');
|
||||
expect(path).toEqual('/account/password');
|
||||
expect(queryParams).toBeFalsy();
|
||||
@@ -1250,7 +1287,7 @@ describe("MatrixClient", function() {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
client.http.authedRequest.mockClear().mockResolvedValue({});
|
||||
mocked(client.http.authedRequest).mockClear().mockResolvedValue({});
|
||||
});
|
||||
|
||||
it("no logout_devices specified", async () => {
|
||||
@@ -1289,13 +1326,13 @@ describe("MatrixClient", function() {
|
||||
const response = {
|
||||
aliases: ["#woop:example.org", "#another:example.org"],
|
||||
};
|
||||
client.http.authedRequest.mockClear().mockResolvedValue(response);
|
||||
mocked(client.http.authedRequest).mockClear().mockResolvedValue(response);
|
||||
|
||||
const roomId = "!whatever:example.org";
|
||||
const result = await client.getLocalAliases(roomId);
|
||||
|
||||
// Current version of the endpoint we support is v3
|
||||
const [method, path, queryParams, data, opts] = client.http.authedRequest.mock.calls[0];
|
||||
const [method, path, queryParams, data, opts] = mocked(client.http.authedRequest).mock.calls[0];
|
||||
expect(data).toBeFalsy();
|
||||
expect(method).toBe('GET');
|
||||
expect(path).toEqual(`/rooms/${encodeURIComponent(roomId)}/aliases`);
|
||||
@@ -1352,11 +1389,11 @@ describe("MatrixClient", function() {
|
||||
],
|
||||
username: "1443779631:@user:example.com",
|
||||
password: "JlKfBy1QwLrO20385QyAtEyIv0=",
|
||||
};
|
||||
} as unknown as ITurnServerResponse;
|
||||
jest.spyOn(client, "turnServer").mockResolvedValue(turnServer);
|
||||
|
||||
const events: any[][] = [];
|
||||
const onTurnServers = (...args) => events.push(args);
|
||||
const onTurnServers = (...args: any[]) => events.push(args);
|
||||
client.on(ClientEvent.TurnServers, onTurnServers);
|
||||
expect(await client.checkTurnServers()).toBe(true);
|
||||
client.off(ClientEvent.TurnServers, onTurnServers);
|
||||
@@ -1372,7 +1409,7 @@ describe("MatrixClient", function() {
|
||||
jest.spyOn(client, "turnServer").mockRejectedValue(error);
|
||||
|
||||
const events: any[][] = [];
|
||||
const onTurnServersError = (...args) => events.push(args);
|
||||
const onTurnServersError = (...args: any[]) => events.push(args);
|
||||
client.on(ClientEvent.TurnServersError, onTurnServersError);
|
||||
expect(await client.checkTurnServers()).toBe(false);
|
||||
client.off(ClientEvent.TurnServersError, onTurnServersError);
|
||||
@@ -1384,7 +1421,7 @@ describe("MatrixClient", function() {
|
||||
jest.spyOn(client, "turnServer").mockRejectedValue(error);
|
||||
|
||||
const events: any[][] = [];
|
||||
const onTurnServersError = (...args) => events.push(args);
|
||||
const onTurnServersError = (...args: any[]) => events.push(args);
|
||||
client.on(ClientEvent.TurnServersError, onTurnServersError);
|
||||
expect(await client.checkTurnServers()).toBe(false);
|
||||
client.off(ClientEvent.TurnServersError, onTurnServersError);
|
||||
@@ -1400,7 +1437,7 @@ describe("MatrixClient", function() {
|
||||
|
||||
it("is an alias for the crypto method", async () => {
|
||||
client.crypto = testUtils.mock(Crypto, "Crypto");
|
||||
const deviceInfos = [];
|
||||
const deviceInfos: IOlmDevice[] = [];
|
||||
const payload = {};
|
||||
await client.encryptAndSendToDevices(deviceInfos, payload);
|
||||
expect(client.crypto.encryptAndSendToDevices).toHaveBeenLastCalledWith(deviceInfos, payload);
|
||||
@@ -1413,7 +1450,7 @@ describe("MatrixClient", function() {
|
||||
const dataStore = new Map();
|
||||
client.setAccountData = function(eventType, content) {
|
||||
dataStore.set(eventType, content);
|
||||
return Promise.resolve();
|
||||
return Promise.resolve({});
|
||||
};
|
||||
client.getAccountData = function(eventType) {
|
||||
const data = dataStore.get(eventType);
|
||||
@@ -1424,9 +1461,9 @@ describe("MatrixClient", function() {
|
||||
|
||||
// Mockup `createRoom`/`getRoom`/`joinRoom`, including state.
|
||||
const rooms = new Map();
|
||||
client.createRoom = function(options = {}) {
|
||||
client.createRoom = function(options: Options = {}) {
|
||||
const roomId = options["_roomId"] || `!room-${rooms.size}:example.org`;
|
||||
const state = new Map();
|
||||
const state = new Map<string, any>();
|
||||
const room = {
|
||||
roomId,
|
||||
_options: options,
|
||||
@@ -1444,24 +1481,24 @@ describe("MatrixClient", function() {
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
} as EventTimeline;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
} as unknown as WrappedRoom;
|
||||
rooms.set(roomId, room);
|
||||
return Promise.resolve({ room_id: roomId });
|
||||
};
|
||||
client.getRoom = function(roomId) {
|
||||
return rooms.get(roomId);
|
||||
};
|
||||
client.joinRoom = function(roomId) {
|
||||
return this.getRoom(roomId) || this.createRoom({ _roomId: roomId });
|
||||
client.joinRoom = async function(roomId) {
|
||||
return this.getRoom(roomId)! || this.createRoom({ _roomId: roomId } as ICreateRoomOpts);
|
||||
};
|
||||
|
||||
// Mockup state events
|
||||
client.sendStateEvent = function(roomId, type, content) {
|
||||
const room = this.getRoom(roomId);
|
||||
const room = this.getRoom(roomId) as WrappedRoom;
|
||||
const state: Map<string, any> = room._state;
|
||||
let store = state.get(type);
|
||||
if (!store) {
|
||||
@@ -1480,14 +1517,15 @@ describe("MatrixClient", function() {
|
||||
return content;
|
||||
},
|
||||
};
|
||||
return { event_id: eventId };
|
||||
return Promise.resolve({ event_id: eventId });
|
||||
};
|
||||
client.redactEvent = function(roomId, eventId) {
|
||||
const room = this.getRoom(roomId);
|
||||
const room = this.getRoom(roomId) as WrappedRoom;
|
||||
const state: Map<string, any> = room._state;
|
||||
for (const store of state.values()) {
|
||||
delete store[eventId];
|
||||
delete store[eventId!];
|
||||
}
|
||||
return Promise.resolve({ event_id: "$" + eventId + "-" + Math.random() });
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1523,7 +1561,7 @@ describe("MatrixClient", function() {
|
||||
roomId: "!snafu:somewhere.org",
|
||||
});
|
||||
expect(ruleMatch).toBeTruthy();
|
||||
expect(ruleMatch.getContent()).toMatchObject({
|
||||
expect(ruleMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: "just a test",
|
||||
});
|
||||
@@ -1552,7 +1590,7 @@ describe("MatrixClient", function() {
|
||||
roomId: "!snafu:somewhere.org",
|
||||
});
|
||||
expect(ruleSenderMatch).toBeTruthy();
|
||||
expect(ruleSenderMatch.getContent()).toMatchObject({
|
||||
expect(ruleSenderMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: REASON,
|
||||
});
|
||||
@@ -1562,7 +1600,7 @@ describe("MatrixClient", function() {
|
||||
roomId: "!snafu:example.org",
|
||||
});
|
||||
expect(ruleRoomMatch).toBeTruthy();
|
||||
expect(ruleRoomMatch.getContent()).toMatchObject({
|
||||
expect(ruleRoomMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: REASON,
|
||||
});
|
||||
@@ -1587,7 +1625,7 @@ describe("MatrixClient", function() {
|
||||
roomId: BAD_ROOM_ID,
|
||||
});
|
||||
expect(ruleSenderMatch).toBeTruthy();
|
||||
expect(ruleSenderMatch.getContent()).toMatchObject({
|
||||
expect(ruleSenderMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: REASON,
|
||||
});
|
||||
@@ -1621,7 +1659,7 @@ describe("MatrixClient", function() {
|
||||
roomId: "!snafu:somewhere.org",
|
||||
});
|
||||
expect(ruleMatch).toBeTruthy();
|
||||
expect(ruleMatch.getContent()).toMatchObject({
|
||||
expect(ruleMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: "just a test",
|
||||
});
|
||||
@@ -1649,13 +1687,13 @@ describe("MatrixClient", function() {
|
||||
roomId: "!snafu:somewhere.org",
|
||||
});
|
||||
expect(ruleMatch).toBeTruthy();
|
||||
expect(ruleMatch.getContent()).toMatchObject({
|
||||
expect(ruleMatch!.getContent()).toMatchObject({
|
||||
recommendation: "m.ban",
|
||||
reason: "just a test",
|
||||
});
|
||||
|
||||
// After removing the invite, we shouldn't reject it anymore.
|
||||
await client.ignoredInvites.removeRule(ruleMatch);
|
||||
await client.ignoredInvites.removeRule(ruleMatch as MatrixEvent);
|
||||
const ruleMatch2 = await client.ignoredInvites.getRuleForInvite({
|
||||
sender: "@foobar:example.org",
|
||||
roomId: "!snafu:somewhere.org",
|
||||
@@ -1669,10 +1707,10 @@ describe("MatrixClient", function() {
|
||||
// Make sure that everything is initialized.
|
||||
await client.ignoredInvites.getOrCreateSourceRooms();
|
||||
await client.joinRoom(NEW_SOURCE_ROOM_ID);
|
||||
const newSourceRoom = client.getRoom(NEW_SOURCE_ROOM_ID);
|
||||
const newSourceRoom = client.getRoom(NEW_SOURCE_ROOM_ID) as WrappedRoom;
|
||||
|
||||
// Fetch the list of sources and check that we do not have the new room yet.
|
||||
const policies = await client.getAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name).getContent();
|
||||
const policies = await client.getAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name)!.getContent();
|
||||
expect(policies).toBeTruthy();
|
||||
const ignoreInvites = policies[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name];
|
||||
expect(ignoreInvites).toBeTruthy();
|
||||
@@ -1686,7 +1724,7 @@ describe("MatrixClient", function() {
|
||||
expect(added2).toBe(false);
|
||||
|
||||
// Fetch the list of sources and check that we have added the new room.
|
||||
const policies2 = await client.getAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name).getContent();
|
||||
const policies2 = await client.getAccountData(POLICIES_ACCOUNT_EVENT_TYPE.name)!.getContent();
|
||||
expect(policies2).toBeTruthy();
|
||||
const ignoreInvites2 = policies2[IGNORE_INVITES_ACCOUNT_EVENT_KEY.name];
|
||||
expect(ignoreInvites2).toBeTruthy();
|
||||
@@ -1698,7 +1736,7 @@ describe("MatrixClient", function() {
|
||||
|
||||
// Check where it shows up.
|
||||
const targetRoomId = ignoreInvites2.target;
|
||||
const targetRoom = client.getRoom(targetRoomId);
|
||||
const targetRoom = client.getRoom(targetRoomId) as WrappedRoom;
|
||||
expect(targetRoom._state.get(PolicyScope.User)[eventId]).toBeTruthy();
|
||||
expect(newSourceRoom._state.get(PolicyScope.User)?.[eventId]).toBeFalsy();
|
||||
});
|
||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixClient } from "../../../src";
|
||||
import { IContent, MatrixClient } from "../../../src";
|
||||
import { Room } from "../../../src/models/room";
|
||||
import { MatrixEvent } from "../../../src/models/event";
|
||||
import { EventType, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from "../../../src/@types/event";
|
||||
@@ -33,7 +33,7 @@ describe("MSC3089TreeSpace", () => {
|
||||
const roomId = "!tree:localhost";
|
||||
const targetUser = "@target:example.org";
|
||||
|
||||
let powerLevels;
|
||||
let powerLevels: MatrixEvent;
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Use utility functions to create test rooms and clients
|
||||
@@ -480,7 +480,7 @@ describe("MSC3089TreeSpace", () => {
|
||||
const staticDomain = "static.example.org";
|
||||
|
||||
function addSubspace(roomId: string, createTs?: number, order?: string) {
|
||||
const content = {
|
||||
const content: IContent = {
|
||||
via: [staticDomain],
|
||||
};
|
||||
if (order) content['order'] = order;
|
||||
|
@@ -121,7 +121,7 @@ describe('MatrixEvent', () => {
|
||||
});
|
||||
|
||||
describe(".attemptDecryption", () => {
|
||||
let encryptedEvent;
|
||||
let encryptedEvent: MatrixEvent;
|
||||
const eventId = 'test_encrypted_event';
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -155,7 +155,7 @@ describe('MatrixEvent', () => {
|
||||
},
|
||||
});
|
||||
}),
|
||||
};
|
||||
} as unknown as Crypto;
|
||||
|
||||
await encryptedEvent.attemptDecryption(crypto);
|
||||
|
||||
|
@@ -39,7 +39,7 @@ let threadEvent: MatrixEvent;
|
||||
const ROOM_ID = "!roomId:example.org";
|
||||
let THREAD_ID: string;
|
||||
|
||||
function mkPushAction(notify, highlight): IActionsObject {
|
||||
function mkPushAction(notify: boolean, highlight: boolean): IActionsObject {
|
||||
return {
|
||||
notify,
|
||||
tweaks: {
|
||||
|
@@ -70,7 +70,7 @@ const roomEvent = utils.mkEvent({
|
||||
},
|
||||
});
|
||||
|
||||
function mockServerSideSupport(client, serverSideSupport: ServerSupport) {
|
||||
function mockServerSideSupport(client: MatrixClient, serverSideSupport: ServerSupport) {
|
||||
client.canSupport.set(Feature.ThreadUnreadNotifications, serverSideSupport);
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ let wallTime = 1234567890;
|
||||
jest.useFakeTimers().setSystemTime(wallTime);
|
||||
|
||||
describe("realtime-callbacks", function() {
|
||||
function tick(millis) {
|
||||
function tick(millis: number): void {
|
||||
wallTime += millis;
|
||||
jest.advanceTimersByTime(millis);
|
||||
}
|
||||
|
@@ -87,7 +87,7 @@ describe("Rendezvous", function() {
|
||||
});
|
||||
|
||||
let httpBackend: MockHttpBackend;
|
||||
let fetchFn: typeof global.fetchFn;
|
||||
let fetchFn: typeof global.fetch;
|
||||
let transports: DummyTransport<any, MSC3903ECDHPayload>[];
|
||||
|
||||
beforeEach(function() {
|
||||
|
@@ -373,37 +373,36 @@ describe("RoomMember", function() {
|
||||
expect(member.events.member).toEqual(joinEvent);
|
||||
});
|
||||
|
||||
it("should set 'name' based on user_id, displayname and room state",
|
||||
function() {
|
||||
const roomState = {
|
||||
getStateEvents: function(type) {
|
||||
if (type !== "m.room.member") {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
utils.mkMembership({
|
||||
event: true, mship: "join", room: roomId,
|
||||
user: userB,
|
||||
}),
|
||||
utils.mkMembership({
|
||||
event: true, mship: "join", room: roomId,
|
||||
user: userC, name: "Alice",
|
||||
}),
|
||||
joinEvent,
|
||||
];
|
||||
},
|
||||
getUserIdsWithDisplayName: function(displayName) {
|
||||
return [userA, userC];
|
||||
},
|
||||
} as unknown as RoomState;
|
||||
expect(member.name).toEqual(userA); // default = user_id
|
||||
member.setMembershipEvent(joinEvent);
|
||||
expect(member.name).toEqual("Alice"); // prefer displayname
|
||||
member.setMembershipEvent(joinEvent, roomState);
|
||||
expect(member.name).not.toEqual("Alice"); // it should disambig.
|
||||
// user_id should be there somewhere
|
||||
expect(member.name.indexOf(userA)).not.toEqual(-1);
|
||||
});
|
||||
it("should set 'name' based on user_id, displayname and room state", function() {
|
||||
const roomState = {
|
||||
getStateEvents: function(type: string) {
|
||||
if (type !== "m.room.member") {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
utils.mkMembership({
|
||||
event: true, mship: "join", room: roomId,
|
||||
user: userB,
|
||||
}),
|
||||
utils.mkMembership({
|
||||
event: true, mship: "join", room: roomId,
|
||||
user: userC, name: "Alice",
|
||||
}),
|
||||
joinEvent,
|
||||
];
|
||||
},
|
||||
getUserIdsWithDisplayName: function(displayName: string) {
|
||||
return [userA, userC];
|
||||
},
|
||||
} as unknown as RoomState;
|
||||
expect(member.name).toEqual(userA); // default = user_id
|
||||
member.setMembershipEvent(joinEvent);
|
||||
expect(member.name).toEqual("Alice"); // prefer displayname
|
||||
member.setMembershipEvent(joinEvent, roomState);
|
||||
expect(member.name).not.toEqual("Alice"); // it should disambig.
|
||||
// user_id should be there somewhere
|
||||
expect(member.name.indexOf(userA)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("should emit 'RoomMember.membership' if the membership changes", function() {
|
||||
let emitCount = 0;
|
||||
@@ -455,7 +454,7 @@ describe("RoomMember", function() {
|
||||
});
|
||||
|
||||
const roomState = {
|
||||
getStateEvents: function(type) {
|
||||
getStateEvents: function(type: string) {
|
||||
if (type !== "m.room.member") {
|
||||
return [];
|
||||
}
|
||||
@@ -467,7 +466,7 @@ describe("RoomMember", function() {
|
||||
joinEvent,
|
||||
];
|
||||
},
|
||||
getUserIdsWithDisplayName: function(displayName) {
|
||||
getUserIdsWithDisplayName: function(displayName: string) {
|
||||
return [userA, userC];
|
||||
},
|
||||
} as unknown as RoomState;
|
||||
|
@@ -19,27 +19,32 @@ limitations under the License.
|
||||
* @module client
|
||||
*/
|
||||
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import * as utils from "../test-utils/test-utils";
|
||||
import { emitPromise } from "../test-utils/test-utils";
|
||||
import {
|
||||
Direction,
|
||||
DuplicateStrategy,
|
||||
EventStatus,
|
||||
EventTimelineSet,
|
||||
EventType, IStateEventWithRoomId,
|
||||
EventType, IContent,
|
||||
IStateEventWithRoomId,
|
||||
JoinRule,
|
||||
MatrixEvent,
|
||||
MatrixEventEvent,
|
||||
PendingEventOrdering,
|
||||
RelationType,
|
||||
RoomEvent,
|
||||
RoomMember,
|
||||
} from "../../src";
|
||||
import { EventTimeline } from "../../src/models/event-timeline";
|
||||
import { NotificationCountType, Room } from "../../src/models/room";
|
||||
import { RoomState } from "../../src/models/room-state";
|
||||
import { UNSTABLE_ELEMENT_FUNCTIONAL_USERS } from "../../src/@types/event";
|
||||
import { TestClient } from "../TestClient";
|
||||
import { emitPromise } from "../test-utils/test-utils";
|
||||
import { ReceiptType, WrappedReceipt } from "../../src/@types/read_receipts";
|
||||
import { FeatureSupport, Thread, ThreadEvent, THREAD_RELATION_TYPE } from "../../src/models/thread";
|
||||
import { FeatureSupport, Thread, THREAD_RELATION_TYPE, ThreadEvent } from "../../src/models/thread";
|
||||
import { Crypto } from "../../src/crypto";
|
||||
|
||||
describe("Room", function() {
|
||||
@@ -48,7 +53,7 @@ describe("Room", function() {
|
||||
const userB = "@bertha:bar";
|
||||
const userC = "@clarissa:bar";
|
||||
const userD = "@dorothy:bar";
|
||||
let room;
|
||||
let room: Room;
|
||||
|
||||
const mkMessage = () => utils.mkMessage({
|
||||
event: true,
|
||||
@@ -131,13 +136,16 @@ describe("Room", function() {
|
||||
beforeEach(function() {
|
||||
room = new Room(roomId, new TestClient(userA, "device").client, userA);
|
||||
// mock RoomStates
|
||||
// @ts-ignore
|
||||
room.oldState = room.getLiveTimeline().startState = utils.mock(RoomState, "oldState");
|
||||
// @ts-ignore
|
||||
room.currentState = room.getLiveTimeline().endState = utils.mock(RoomState, "currentState");
|
||||
});
|
||||
|
||||
describe('getCreator', () => {
|
||||
it("should return the creator from m.room.create", function() {
|
||||
room.currentState.getStateEvents.mockImplementation(function(type, key) {
|
||||
// @ts-ignore - mocked doesn't handle overloads sanely
|
||||
mocked(room.currentState.getStateEvents).mockImplementation(function(type, key) {
|
||||
if (type === EventType.RoomCreate && key === "") {
|
||||
return utils.mkEvent({
|
||||
event: true,
|
||||
@@ -160,7 +168,8 @@ describe("Room", function() {
|
||||
const hsUrl = "https://my.home.server";
|
||||
|
||||
it("should return the URL from m.room.avatar preferentially", function() {
|
||||
room.currentState.getStateEvents.mockImplementation(function(type, key) {
|
||||
// @ts-ignore - mocked doesn't handle overloads sanely
|
||||
mocked(room.currentState.getStateEvents).mockImplementation(function(type, key) {
|
||||
if (type === EventType.RoomAvatar && key === "") {
|
||||
return utils.mkEvent({
|
||||
event: true,
|
||||
@@ -174,10 +183,10 @@ describe("Room", function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
const url = room.getAvatarUrl(hsUrl);
|
||||
const url = room.getAvatarUrl(hsUrl, 100, 100, "scale");
|
||||
// we don't care about how the mxc->http conversion is done, other
|
||||
// than it contains the mxc body.
|
||||
expect(url.indexOf("flibble/wibble")).not.toEqual(-1);
|
||||
expect(url?.indexOf("flibble/wibble")).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("should return nothing if there is no m.room.avatar and allowDefault=false",
|
||||
@@ -189,12 +198,12 @@ describe("Room", function() {
|
||||
|
||||
describe("getMember", function() {
|
||||
beforeEach(function() {
|
||||
room.currentState.getMember.mockImplementation(function(userId) {
|
||||
mocked(room.currentState.getMember).mockImplementation(function(userId) {
|
||||
return {
|
||||
"@alice:bar": {
|
||||
userId: userA,
|
||||
roomId: roomId,
|
||||
},
|
||||
} as unknown as RoomMember,
|
||||
}[userId] || null;
|
||||
});
|
||||
});
|
||||
@@ -222,11 +231,13 @@ describe("Room", function() {
|
||||
it("Make sure legacy overload passing options directly as parameters still works", () => {
|
||||
expect(() => room.addLiveEvents(events, DuplicateStrategy.Replace, false)).not.toThrow();
|
||||
expect(() => room.addLiveEvents(events, DuplicateStrategy.Ignore, true)).not.toThrow();
|
||||
// @ts-ignore
|
||||
expect(() => room.addLiveEvents(events, "shouldfailbecauseinvalidduplicatestrategy", false)).toThrow();
|
||||
});
|
||||
|
||||
it("should throw if duplicateStrategy isn't 'replace' or 'ignore'", function() {
|
||||
expect(function() {
|
||||
// @ts-ignore
|
||||
room.addLiveEvents(events, {
|
||||
duplicateStrategy: "foo",
|
||||
});
|
||||
@@ -255,6 +266,7 @@ describe("Room", function() {
|
||||
dupe.event.event_id = events[0].getId();
|
||||
room.addLiveEvents(events);
|
||||
expect(room.timeline[0]).toEqual(events[0]);
|
||||
// @ts-ignore
|
||||
room.addLiveEvents([dupe], {
|
||||
duplicateStrategy: "ignore",
|
||||
});
|
||||
@@ -263,7 +275,7 @@ describe("Room", function() {
|
||||
|
||||
it("should emit 'Room.timeline' events", function() {
|
||||
let callCount = 0;
|
||||
room.on("Room.timeline", function(event, emitRoom, toStart) {
|
||||
room.on(RoomEvent.Timeline, function(event, emitRoom, toStart) {
|
||||
callCount += 1;
|
||||
expect(room.timeline.length).toEqual(callCount);
|
||||
expect(event).toEqual(events[callCount - 1]);
|
||||
@@ -306,8 +318,8 @@ describe("Room", function() {
|
||||
userId: userA,
|
||||
membership: "join",
|
||||
name: "Alice",
|
||||
};
|
||||
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||
} as unknown as RoomMember;
|
||||
mocked(room.currentState.getSentinelMember).mockImplementation(function(uid) {
|
||||
if (uid === userA) {
|
||||
return sentinel;
|
||||
}
|
||||
@@ -331,27 +343,25 @@ describe("Room", function() {
|
||||
const remoteEventId = remoteEvent.getId();
|
||||
|
||||
let callCount = 0;
|
||||
room.on("Room.localEchoUpdated",
|
||||
function(event, emitRoom, oldEventId, oldStatus) {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expect(event.getId()).toEqual(localEventId);
|
||||
expect(event.status).toEqual(EventStatus.SENDING);
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toBeUndefined();
|
||||
expect(oldStatus).toBeUndefined();
|
||||
break;
|
||||
case 1:
|
||||
expect(event.getId()).toEqual(remoteEventId);
|
||||
expect(event.status).toBeNull();
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toEqual(localEventId);
|
||||
expect(oldStatus).toBe(EventStatus.SENDING);
|
||||
break;
|
||||
}
|
||||
callCount += 1;
|
||||
},
|
||||
);
|
||||
room.on(RoomEvent.LocalEchoUpdated, (event, emitRoom, oldEventId, oldStatus) => {
|
||||
switch (callCount) {
|
||||
case 0:
|
||||
expect(event.getId()).toEqual(localEventId);
|
||||
expect(event.status).toEqual(EventStatus.SENDING);
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toBeUndefined();
|
||||
expect(oldStatus).toBeUndefined();
|
||||
break;
|
||||
case 1:
|
||||
expect(event.getId()).toEqual(remoteEventId);
|
||||
expect(event.status).toBeNull();
|
||||
expect(emitRoom).toEqual(room);
|
||||
expect(oldEventId).toEqual(localEventId);
|
||||
expect(oldStatus).toBe(EventStatus.SENDING);
|
||||
break;
|
||||
}
|
||||
callCount += 1;
|
||||
});
|
||||
|
||||
// first add the local echo
|
||||
room.addPendingEvent(localEvent, "TXN_ID");
|
||||
@@ -367,7 +377,7 @@ describe("Room", function() {
|
||||
it("should be able to update local echo without a txn ID (/send then /sync)", function() {
|
||||
const eventJson = utils.mkMessage({
|
||||
room: roomId, user: userA, event: false,
|
||||
}) as object;
|
||||
});
|
||||
delete eventJson["txn_id"];
|
||||
delete eventJson["event_id"];
|
||||
const localEvent = new MatrixEvent(Object.assign({ event_id: "$temp" }, eventJson));
|
||||
@@ -398,7 +408,7 @@ describe("Room", function() {
|
||||
it("should be able to update local echo without a txn ID (/sync then /send)", function() {
|
||||
const eventJson = utils.mkMessage({
|
||||
room: roomId, user: userA, event: false,
|
||||
}) as object;
|
||||
});
|
||||
delete eventJson["txn_id"];
|
||||
delete eventJson["event_id"];
|
||||
const txnId = "My_txn_id";
|
||||
@@ -483,7 +493,7 @@ describe("Room", function() {
|
||||
it("should emit 'Room.timeline' events when added to the start",
|
||||
function() {
|
||||
let callCount = 0;
|
||||
room.on("Room.timeline", function(event, emitRoom, toStart) {
|
||||
room.on(RoomEvent.Timeline, function(event, emitRoom, toStart) {
|
||||
callCount += 1;
|
||||
expect(room.timeline.length).toEqual(callCount);
|
||||
expect(event).toEqual(events[callCount - 1]);
|
||||
@@ -501,19 +511,19 @@ describe("Room", function() {
|
||||
userId: userA,
|
||||
membership: "join",
|
||||
name: "Alice",
|
||||
};
|
||||
} as unknown as RoomMember;
|
||||
const oldSentinel = {
|
||||
userId: userA,
|
||||
membership: "join",
|
||||
name: "Old Alice",
|
||||
};
|
||||
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||
} as unknown as RoomMember;
|
||||
mocked(room.currentState.getSentinelMember).mockImplementation(function(uid) {
|
||||
if (uid === userA) {
|
||||
return sentinel;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
room.oldState.getSentinelMember.mockImplementation(function(uid) {
|
||||
mocked(room.oldState.getSentinelMember).mockImplementation(function(uid) {
|
||||
if (uid === userA) {
|
||||
return oldSentinel;
|
||||
}
|
||||
@@ -539,19 +549,19 @@ describe("Room", function() {
|
||||
userId: userA,
|
||||
membership: "join",
|
||||
name: "Alice",
|
||||
};
|
||||
} as unknown as RoomMember;
|
||||
const oldSentinel = {
|
||||
userId: userA,
|
||||
membership: "join",
|
||||
name: "Old Alice",
|
||||
};
|
||||
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||
} as unknown as RoomMember;
|
||||
mocked(room.currentState.getSentinelMember).mockImplementation(function(uid) {
|
||||
if (uid === userA) {
|
||||
return sentinel;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
room.oldState.getSentinelMember.mockImplementation(function(uid) {
|
||||
mocked(room.oldState.getSentinelMember).mockImplementation(function(uid) {
|
||||
if (uid === userA) {
|
||||
return oldSentinel;
|
||||
}
|
||||
@@ -599,7 +609,7 @@ describe("Room", function() {
|
||||
});
|
||||
});
|
||||
|
||||
const resetTimelineTests = function(timelineSupport) {
|
||||
const resetTimelineTests = function(timelineSupport: boolean) {
|
||||
let events: MatrixEvent[];
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -630,8 +640,8 @@ describe("Room", function() {
|
||||
const oldState = room.getLiveTimeline().getState(EventTimeline.BACKWARDS);
|
||||
const newState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
||||
expect(room.getLiveTimeline().getEvents().length).toEqual(1);
|
||||
expect(oldState.getStateEvents(EventType.RoomName, "")).toEqual(events[1]);
|
||||
expect(newState.getStateEvents(EventType.RoomName, "")).toEqual(events[2]);
|
||||
expect(oldState?.getStateEvents(EventType.RoomName, "")).toEqual(events[1]);
|
||||
expect(newState?.getStateEvents(EventType.RoomName, "")).toEqual(events[2]);
|
||||
});
|
||||
|
||||
it("should reset the legacy timeline fields", function() {
|
||||
@@ -669,17 +679,14 @@ describe("Room", function() {
|
||||
expect(currentStateUpdateEmitCount).toEqual(timelineSupport ? 1 : 0);
|
||||
});
|
||||
|
||||
it("should emit Room.timelineReset event and set the correct " +
|
||||
"pagination token", function() {
|
||||
it("should emit Room.timelineReset event and set the correct pagination token", function() {
|
||||
let callCount = 0;
|
||||
room.on("Room.timelineReset", function(emitRoom) {
|
||||
room.on(RoomEvent.TimelineReset, function(emitRoom) {
|
||||
callCount += 1;
|
||||
expect(emitRoom).toEqual(room);
|
||||
|
||||
// make sure that the pagination token has been set before the
|
||||
// event is emitted.
|
||||
const tok = emitRoom.getLiveTimeline()
|
||||
.getPaginationToken(EventTimeline.BACKWARDS);
|
||||
// make sure that the pagination token has been set before the event is emitted.
|
||||
const tok = emitRoom?.getLiveTimeline().getPaginationToken(EventTimeline.BACKWARDS);
|
||||
|
||||
expect(tok).toEqual("pagToken");
|
||||
});
|
||||
@@ -693,7 +700,7 @@ describe("Room", function() {
|
||||
const firstLiveTimeline = room.getLiveTimeline();
|
||||
room.resetLiveTimeline('sometoken', 'someothertoken');
|
||||
|
||||
const tl = room.getTimelineForEvent(events[0].getId());
|
||||
const tl = room.getTimelineForEvent(events[0].getId()!);
|
||||
expect(tl).toBe(timelineSupport ? firstLiveTimeline : null);
|
||||
});
|
||||
};
|
||||
@@ -721,30 +728,25 @@ describe("Room", function() {
|
||||
it("should handle events in the same timeline", function() {
|
||||
room.addLiveEvents(events);
|
||||
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!,
|
||||
events[1].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!, events[1].getId()!))
|
||||
.toBeLessThan(0);
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[2].getId()!,
|
||||
events[1].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[2].getId()!, events[1].getId()!))
|
||||
.toBeGreaterThan(0);
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!,
|
||||
events[1].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!, events[1].getId()!))
|
||||
.toEqual(0);
|
||||
});
|
||||
|
||||
it("should handle events in adjacent timelines", function() {
|
||||
const oldTimeline = room.addTimeline();
|
||||
oldTimeline.setNeighbouringTimeline(room.getLiveTimeline(), 'f');
|
||||
room.getLiveTimeline().setNeighbouringTimeline(oldTimeline, 'b');
|
||||
oldTimeline.setNeighbouringTimeline(room.getLiveTimeline(), Direction.Forward);
|
||||
room.getLiveTimeline().setNeighbouringTimeline(oldTimeline, Direction.Backward);
|
||||
|
||||
room.addEventsToTimeline([events[0]], false, oldTimeline);
|
||||
room.addLiveEvents([events[1]]);
|
||||
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!,
|
||||
events[1].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!, events[1].getId()!))
|
||||
.toBeLessThan(0);
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!,
|
||||
events[0].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!, events[0].getId()!))
|
||||
.toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -754,11 +756,9 @@ describe("Room", function() {
|
||||
room.addEventsToTimeline([events[0]], false, oldTimeline);
|
||||
room.addLiveEvents([events[1]]);
|
||||
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!,
|
||||
events[1].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[0].getId()!, events[1].getId()!))
|
||||
.toBe(null);
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!,
|
||||
events[0].getId()))
|
||||
expect(room.getUnfilteredTimelineSet().compareEventOrdering(events[1].getId()!, events[0].getId()!))
|
||||
.toBe(null);
|
||||
});
|
||||
|
||||
@@ -769,21 +769,21 @@ describe("Room", function() {
|
||||
.compareEventOrdering(events[0].getId()!, "xxx"))
|
||||
.toBe(null);
|
||||
expect(room.getUnfilteredTimelineSet()
|
||||
.compareEventOrdering("xxx", events[0].getId()))
|
||||
.compareEventOrdering("xxx", events[0].getId()!))
|
||||
.toBe(null);
|
||||
expect(room.getUnfilteredTimelineSet()
|
||||
.compareEventOrdering(events[0].getId()!, events[0].getId()))
|
||||
.compareEventOrdering(events[0].getId()!, events[0].getId()!))
|
||||
.toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getJoinedMembers", function() {
|
||||
it("should return members whose membership is 'join'", function() {
|
||||
room.currentState.getMembers.mockImplementation(function() {
|
||||
mocked(room.currentState.getMembers).mockImplementation(function() {
|
||||
return [
|
||||
{ userId: "@alice:bar", membership: "join" },
|
||||
{ userId: "@bob:bar", membership: "invite" },
|
||||
{ userId: "@cleo:bar", membership: "leave" },
|
||||
{ userId: "@alice:bar", membership: "join" } as unknown as RoomMember,
|
||||
{ userId: "@bob:bar", membership: "invite" } as unknown as RoomMember,
|
||||
{ userId: "@cleo:bar", membership: "leave" } as unknown as RoomMember,
|
||||
];
|
||||
});
|
||||
const res = room.getJoinedMembers();
|
||||
@@ -792,9 +792,9 @@ describe("Room", function() {
|
||||
});
|
||||
|
||||
it("should return an empty list if no membership is 'join'", function() {
|
||||
room.currentState.getMembers.mockImplementation(function() {
|
||||
mocked(room.currentState.getMembers).mockImplementation(function() {
|
||||
return [
|
||||
{ userId: "@bob:bar", membership: "invite" },
|
||||
{ userId: "@bob:bar", membership: "invite" } as unknown as RoomMember,
|
||||
];
|
||||
});
|
||||
const res = room.getJoinedMembers();
|
||||
@@ -805,41 +805,41 @@ describe("Room", function() {
|
||||
describe("hasMembershipState", function() {
|
||||
it("should return true for a matching userId and membership",
|
||||
function() {
|
||||
room.currentState.getMember.mockImplementation(function(userId) {
|
||||
mocked(room.currentState.getMember).mockImplementation(function(userId) {
|
||||
return {
|
||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||
"@bob:bar": { userId: "@bob:bar", membership: "invite" },
|
||||
}[userId];
|
||||
}[userId] as unknown as RoomMember;
|
||||
});
|
||||
expect(room.hasMembershipState("@bob:bar", "invite")).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if match membership but no match userId",
|
||||
function() {
|
||||
room.currentState.getMember.mockImplementation(function(userId) {
|
||||
mocked(room.currentState.getMember).mockImplementation(function(userId) {
|
||||
return {
|
||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||
}[userId];
|
||||
}[userId] as unknown as RoomMember;
|
||||
});
|
||||
expect(room.hasMembershipState("@bob:bar", "join")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false if match userId but no match membership",
|
||||
function() {
|
||||
room.currentState.getMember.mockImplementation(function(userId) {
|
||||
mocked(room.currentState.getMember).mockImplementation(function(userId) {
|
||||
return {
|
||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||
}[userId];
|
||||
}[userId] as unknown as RoomMember;
|
||||
});
|
||||
expect(room.hasMembershipState("@alice:bar", "ban")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false if no match membership or userId",
|
||||
function() {
|
||||
room.currentState.getMember.mockImplementation(function(userId) {
|
||||
mocked(room.currentState.getMember).mockImplementation(function(userId) {
|
||||
return {
|
||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||
}[userId];
|
||||
}[userId] as unknown as RoomMember;
|
||||
});
|
||||
expect(room.hasMembershipState("@bob:bar", "invite")).toBe(false);
|
||||
});
|
||||
@@ -1193,8 +1193,8 @@ describe("Room", function() {
|
||||
event: true,
|
||||
});
|
||||
|
||||
function mkReceipt(roomId: string, records) {
|
||||
const content = {};
|
||||
function mkReceipt(roomId: string, records: Array<ReturnType<typeof mkRecord>>) {
|
||||
const content: IContent = {};
|
||||
records.forEach(function(r) {
|
||||
if (!content[r.eventId]) {
|
||||
content[r.eventId] = {};
|
||||
@@ -1241,7 +1241,7 @@ describe("Room", function() {
|
||||
it("should emit an event when a receipt is added",
|
||||
function() {
|
||||
const listener = jest.fn();
|
||||
room.on("Room.receipt", listener);
|
||||
room.on(RoomEvent.Receipt, listener);
|
||||
|
||||
const ts = 13787898424;
|
||||
|
||||
@@ -1448,7 +1448,7 @@ describe("Room", function() {
|
||||
});
|
||||
|
||||
describe("tags", function() {
|
||||
function mkTags(roomId, tags) {
|
||||
function mkTags(roomId: string, tags: object) {
|
||||
const content = { "tags": tags };
|
||||
return new MatrixEvent({
|
||||
content: content,
|
||||
@@ -1470,7 +1470,7 @@ describe("Room", function() {
|
||||
"received on the event stream",
|
||||
function() {
|
||||
const listener = jest.fn();
|
||||
room.on("Room.tags", listener);
|
||||
room.on(RoomEvent.Tags, listener);
|
||||
|
||||
const tags = { "m.foo": { "order": 0.5 } };
|
||||
const event = mkTags(roomId, tags);
|
||||
@@ -1642,11 +1642,14 @@ describe("Room", function() {
|
||||
});
|
||||
|
||||
describe("loadMembersIfNeeded", function() {
|
||||
function createClientMock(serverResponse, storageResponse: MatrixEvent[] | Error | null = null) {
|
||||
function createClientMock(
|
||||
serverResponse: Error | MatrixEvent[],
|
||||
storageResponse: MatrixEvent[] | Error | null = null,
|
||||
) {
|
||||
return {
|
||||
getEventMapper: function() {
|
||||
// events should already be MatrixEvents
|
||||
return function(event) {return event;};
|
||||
return function(event: MatrixEvent) {return event;};
|
||||
},
|
||||
isCryptoEnabled() {
|
||||
return true;
|
||||
@@ -1671,7 +1674,7 @@ describe("Room", function() {
|
||||
return Promise.resolve(this.storageResponse);
|
||||
}
|
||||
},
|
||||
setOutOfBandMembers: function(roomId, memberEvents) {
|
||||
setOutOfBandMembers: function(roomId: string, memberEvents: IStateEventWithRoomId[]) {
|
||||
this.storedMembers = memberEvents;
|
||||
return Promise.resolve();
|
||||
},
|
||||
@@ -2170,7 +2173,7 @@ describe("Room", function() {
|
||||
},
|
||||
});
|
||||
|
||||
room.createThread("$000", undefined, [eventWithoutARootEvent]);
|
||||
room.createThread("$000", undefined, [eventWithoutARootEvent], false);
|
||||
|
||||
const rootEvent = new MatrixEvent({
|
||||
event_id: "$666",
|
||||
@@ -2188,7 +2191,7 @@ describe("Room", function() {
|
||||
},
|
||||
});
|
||||
|
||||
expect(() => room.createThread(rootEvent.getId()!, rootEvent, [])).not.toThrow();
|
||||
expect(() => room.createThread(rootEvent.getId()!, rootEvent, [], false)).not.toThrow();
|
||||
});
|
||||
|
||||
it("creating thread from edited event should not conflate old versions of the event", () => {
|
||||
@@ -2406,8 +2409,6 @@ describe("Room", function() {
|
||||
Thread.setServerSideListSupport(FeatureSupport.Stable);
|
||||
|
||||
room.client.createThreadListMessagesRequest = () => Promise.resolve({
|
||||
start: null,
|
||||
end: null,
|
||||
chunk: [],
|
||||
state: [],
|
||||
});
|
||||
@@ -2761,7 +2762,7 @@ describe("Room", function() {
|
||||
});
|
||||
|
||||
describe("thread notifications", () => {
|
||||
let room;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
const client = new TestClient(userA).client;
|
||||
|
@@ -1,18 +1,19 @@
|
||||
// This file had a function whose name is all caps, which displeases eslint
|
||||
/* eslint new-cap: "off" */
|
||||
|
||||
import { defer } from '../../src/utils';
|
||||
import { defer, IDeferred } from '../../src/utils';
|
||||
import { MatrixError } from "../../src/http-api";
|
||||
import { MatrixScheduler } from "../../src/scheduler";
|
||||
import * as utils from "../test-utils/test-utils";
|
||||
import { MatrixEvent } from "../../src";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe("MatrixScheduler", function() {
|
||||
let scheduler;
|
||||
let retryFn;
|
||||
let queueFn;
|
||||
let deferred;
|
||||
let scheduler: MatrixScheduler<Record<string, boolean>>;
|
||||
let retryFn: Function | null;
|
||||
let queueFn: ((event: MatrixEvent) => string | null) | null;
|
||||
let deferred: IDeferred<Record<string, boolean>>;
|
||||
const roomId = "!foo:bar";
|
||||
const eventA = utils.mkMessage({
|
||||
user: "@alice:bar", room: roomId, event: true,
|
||||
@@ -65,8 +66,8 @@ describe("MatrixScheduler", function() {
|
||||
deferB.resolve({ b: true });
|
||||
deferA.resolve({ a: true });
|
||||
const [a, b] = await abPromise;
|
||||
expect(a.a).toEqual(true);
|
||||
expect(b.b).toEqual(true);
|
||||
expect(a!.a).toEqual(true);
|
||||
expect(b!.b).toEqual(true);
|
||||
});
|
||||
|
||||
it("should invoke the retryFn on failure and wait the amount of time specified",
|
||||
@@ -92,6 +93,7 @@ describe("MatrixScheduler", function() {
|
||||
return new Promise(() => {});
|
||||
}
|
||||
expect(procCount).toBeLessThan(3);
|
||||
return new Promise(() => {});
|
||||
});
|
||||
|
||||
scheduler.queueEvent(eventA);
|
||||
@@ -119,8 +121,8 @@ describe("MatrixScheduler", function() {
|
||||
return "yep";
|
||||
};
|
||||
|
||||
const deferA = defer();
|
||||
const deferB = defer();
|
||||
const deferA = defer<Record<string, boolean>>();
|
||||
const deferB = defer<Record<string, boolean>>();
|
||||
let procCount = 0;
|
||||
scheduler.setProcessFunction(function(ev) {
|
||||
procCount += 1;
|
||||
@@ -132,6 +134,7 @@ describe("MatrixScheduler", function() {
|
||||
return deferB.promise;
|
||||
}
|
||||
expect(procCount).toBeLessThan(3);
|
||||
return new Promise<Record<string, boolean>>(() => {});
|
||||
});
|
||||
|
||||
const globalA = scheduler.queueEvent(eventA);
|
||||
@@ -159,7 +162,7 @@ describe("MatrixScheduler", function() {
|
||||
const eventC = utils.mkMessage({ user: "@a:bar", room: roomId, event: true });
|
||||
const eventD = utils.mkMessage({ user: "@b:bar", room: roomId, event: true });
|
||||
|
||||
const buckets = {};
|
||||
const buckets: Record<string, string> = {};
|
||||
buckets[eventA.getId()!] = "queue_A";
|
||||
buckets[eventD.getId()!] = "queue_A";
|
||||
buckets[eventB.getId()!] = "queue_B";
|
||||
@@ -169,13 +172,13 @@ describe("MatrixScheduler", function() {
|
||||
return 0;
|
||||
};
|
||||
queueFn = function(event) {
|
||||
return buckets[event.getId()];
|
||||
return buckets[event.getId()!];
|
||||
};
|
||||
|
||||
const expectOrder = [
|
||||
eventA.getId(), eventB.getId(), eventD.getId(),
|
||||
];
|
||||
const deferA = defer<void>();
|
||||
const deferA = defer<Record<string, boolean>>();
|
||||
scheduler.setProcessFunction(function(event) {
|
||||
const id = expectOrder.shift();
|
||||
expect(id).toEqual(event.getId());
|
||||
@@ -191,7 +194,7 @@ describe("MatrixScheduler", function() {
|
||||
|
||||
// wait a bit then resolve A and we should get D (not C) next.
|
||||
setTimeout(function() {
|
||||
deferA.resolve();
|
||||
deferA.resolve({});
|
||||
}, 1000);
|
||||
jest.advanceTimersByTime(1000);
|
||||
});
|
||||
@@ -210,7 +213,7 @@ describe("MatrixScheduler", function() {
|
||||
};
|
||||
const prom = scheduler.queueEvent(eventA);
|
||||
expect(prom).toBeTruthy();
|
||||
expect(prom.then).toBeTruthy();
|
||||
expect(prom!.then).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -237,15 +240,15 @@ describe("MatrixScheduler", function() {
|
||||
scheduler.queueEvent(eventA);
|
||||
scheduler.queueEvent(eventB);
|
||||
const queue = scheduler.getQueueForEvent(eventA);
|
||||
expect(queue.length).toEqual(2);
|
||||
expect(queue).toHaveLength(2);
|
||||
expect(queue).toEqual([eventA, eventB]);
|
||||
// modify the queue
|
||||
const eventC = utils.mkMessage(
|
||||
{ user: "@a:bar", room: roomId, event: true },
|
||||
);
|
||||
queue.push(eventC);
|
||||
queue!.push(eventC);
|
||||
const queueAgain = scheduler.getQueueForEvent(eventA);
|
||||
expect(queueAgain.length).toEqual(2);
|
||||
expect(queueAgain).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("should return a list of events in the queue and modifications to" +
|
||||
@@ -255,10 +258,10 @@ describe("MatrixScheduler", function() {
|
||||
};
|
||||
scheduler.queueEvent(eventA);
|
||||
scheduler.queueEvent(eventB);
|
||||
const queue = scheduler.getQueueForEvent(eventA);
|
||||
queue[1].event.content.body = "foo";
|
||||
const queueAgain = scheduler.getQueueForEvent(eventA);
|
||||
expect(queueAgain[1].event.content.body).toEqual("foo");
|
||||
const queue = scheduler.getQueueForEvent(eventA)!;
|
||||
queue[1].event.content!.body = "foo";
|
||||
const queueAgain = scheduler.getQueueForEvent(eventA)!;
|
||||
expect(queueAgain[1].event.content?.body).toEqual("foo");
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -16,7 +16,8 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReceiptType } from "../../src/@types/read_receipts";
|
||||
import { SyncAccumulator } from "../../src/sync-accumulator";
|
||||
import { IJoinedRoom, ISyncResponse, SyncAccumulator } from "../../src/sync-accumulator";
|
||||
import { IRoomSummary } from "../../src";
|
||||
|
||||
// The event body & unsigned object get frozen to assert that they don't get altered
|
||||
// by the impl
|
||||
@@ -55,10 +56,10 @@ const RES_WITH_AGE = {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ISyncResponse;
|
||||
|
||||
describe("SyncAccumulator", function() {
|
||||
let sa;
|
||||
let sa: SyncAccumulator;
|
||||
|
||||
beforeEach(function() {
|
||||
sa = new SyncAccumulator({
|
||||
@@ -98,7 +99,7 @@ describe("SyncAccumulator", function() {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ISyncResponse;
|
||||
sa.accumulate(res);
|
||||
const output = sa.getJSON();
|
||||
expect(output.nextBatch).toEqual(res.next_batch);
|
||||
@@ -223,7 +224,6 @@ describe("SyncAccumulator", function() {
|
||||
content: {
|
||||
user_ids: ["@alice:localhost"],
|
||||
},
|
||||
room_id: "!foo:bar",
|
||||
}],
|
||||
},
|
||||
});
|
||||
@@ -281,12 +281,12 @@ describe("SyncAccumulator", function() {
|
||||
account_data: {
|
||||
events: [acc1],
|
||||
},
|
||||
});
|
||||
} as unknown as ISyncResponse);
|
||||
sa.accumulate({
|
||||
account_data: {
|
||||
events: [acc2],
|
||||
},
|
||||
});
|
||||
} as unknown as ISyncResponse);
|
||||
expect(
|
||||
sa.getJSON().accountData.length,
|
||||
).toEqual(1);
|
||||
@@ -422,7 +422,7 @@ describe("SyncAccumulator", function() {
|
||||
});
|
||||
|
||||
describe("summary field", function() {
|
||||
function createSyncResponseWithSummary(summary) {
|
||||
function createSyncResponseWithSummary(summary: IRoomSummary): ISyncResponse {
|
||||
return {
|
||||
next_batch: "abc",
|
||||
rooms: {
|
||||
@@ -444,7 +444,7 @@ describe("SyncAccumulator", function() {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ISyncResponse;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
@@ -487,8 +487,8 @@ describe("SyncAccumulator", function() {
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(startingTs + delta);
|
||||
|
||||
const output = sa.getJSON();
|
||||
expect(output.roomsData.join["!foo:bar"].timeline.events[0].unsigned.age).toEqual(
|
||||
RES_WITH_AGE.rooms.join["!foo:bar"].timeline.events[0].unsigned.age + delta,
|
||||
expect(output.roomsData.join["!foo:bar"].timeline.events[0].unsigned?.age).toEqual(
|
||||
RES_WITH_AGE.rooms.join["!foo:bar"].timeline.events[0].unsigned!.age! + delta,
|
||||
);
|
||||
expect(Object.keys(output.roomsData.join["!foo:bar"].timeline.events[0])).toEqual(
|
||||
Object.keys(RES_WITH_AGE.rooms.join["!foo:bar"].timeline.events[0]),
|
||||
@@ -507,12 +507,12 @@ describe("SyncAccumulator", function() {
|
||||
sa.accumulate(RES_WITH_AGE);
|
||||
const output = sa.getJSON();
|
||||
expect(output.roomsData.join["!foo:bar"]
|
||||
.unread_thread_notifications["$143273582443PhrSn:example.org"]).not.toBeUndefined();
|
||||
.unread_thread_notifications!["$143273582443PhrSn:example.org"]).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function syncSkeleton(joinObj) {
|
||||
function syncSkeleton(joinObj: Partial<IJoinedRoom>): ISyncResponse {
|
||||
joinObj = joinObj || {};
|
||||
return {
|
||||
next_batch: "abc",
|
||||
@@ -521,11 +521,12 @@ function syncSkeleton(joinObj) {
|
||||
"!foo:bar": joinObj,
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ISyncResponse;
|
||||
}
|
||||
|
||||
function msg(localpart, text) {
|
||||
function msg(localpart: string, text: string) {
|
||||
return {
|
||||
event_id: "$" + Math.random(),
|
||||
content: {
|
||||
body: text,
|
||||
},
|
||||
@@ -535,8 +536,9 @@ function msg(localpart, text) {
|
||||
};
|
||||
}
|
||||
|
||||
function member(localpart, membership) {
|
||||
function member(localpart: string, membership: string) {
|
||||
return {
|
||||
event_id: "$" + Math.random(),
|
||||
content: {
|
||||
membership: membership,
|
||||
},
|
||||
|
@@ -455,7 +455,11 @@ describe("utils", function() {
|
||||
|
||||
describe("recursivelyAssign", () => {
|
||||
it("doesn't override with null/undefined", () => {
|
||||
const result = utils.recursivelyAssign(
|
||||
const result = utils.recursivelyAssign<{
|
||||
string: string;
|
||||
object: object;
|
||||
float: number;
|
||||
}, {}>(
|
||||
{
|
||||
string: "Hello world",
|
||||
object: {},
|
||||
@@ -475,7 +479,11 @@ describe("utils", function() {
|
||||
});
|
||||
|
||||
it("assigns recursively", () => {
|
||||
const result = utils.recursivelyAssign(
|
||||
const result = utils.recursivelyAssign<{
|
||||
number: number;
|
||||
object: object;
|
||||
thing: string | object;
|
||||
}, {}>(
|
||||
{
|
||||
number: 42,
|
||||
object: {
|
||||
|
@@ -933,7 +933,7 @@ describe('Call', function() {
|
||||
await fakeIncomingCall(client, call, "1");
|
||||
});
|
||||
|
||||
const untilEventSent = async (...args) => {
|
||||
const untilEventSent = async (...args: any[]) => {
|
||||
const maxTries = 20;
|
||||
|
||||
for (let tries = 0; tries < maxTries; ++tries) {
|
||||
@@ -971,7 +971,7 @@ describe('Call', function() {
|
||||
});
|
||||
|
||||
describe("ICE candidate sending", () => {
|
||||
let mockPeerConn;
|
||||
let mockPeerConn: MockRTCPeerConnection;
|
||||
const fakeCandidateString = "here is a fake candidate!";
|
||||
const fakeCandidateEvent = {
|
||||
candidate: {
|
||||
@@ -1086,7 +1086,7 @@ describe('Call', function() {
|
||||
});
|
||||
|
||||
describe("Screen sharing", () => {
|
||||
const waitNegotiateFunc = resolve => {
|
||||
const waitNegotiateFunc = (resolve: Function): void => {
|
||||
mockSendEvent.mockImplementationOnce(() => {
|
||||
// Note that the peer connection here is a dummy one and always returns
|
||||
// dummy SDP, so there's not much point returning the content: the SDP will
|
||||
|
Reference in New Issue
Block a user