Skip to content

Commit

Permalink
Merge branch 'robertlong/group-call' into matroska
Browse files Browse the repository at this point in the history
  • Loading branch information
robintown committed Aug 5, 2022
2 parents afd8b55 + 471f174 commit d4024d5
Show file tree
Hide file tree
Showing 27 changed files with 1,365 additions and 318 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
Changes in [19.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v19.2.0) (2022-08-02)
==================================================================================================

## 🦖 Deprecations
* Remove unstable support for `m.room_key.withheld` ([\#2512](https://github.com/matrix-org/matrix-js-sdk/pull/2512)). Fixes #2233.

## ✨ Features
* Sliding sync: add missing filters from latest MSC ([\#2555](https://github.com/matrix-org/matrix-js-sdk/pull/2555)).
* Use stable prefixes for MSC3827 ([\#2537](https://github.com/matrix-org/matrix-js-sdk/pull/2537)).
* Add support for MSC3575: Sliding Sync ([\#2242](https://github.com/matrix-org/matrix-js-sdk/pull/2242)).

## 🐛 Bug Fixes
* Correct the units in TURN servers expiry documentation ([\#2520](https://github.com/matrix-org/matrix-js-sdk/pull/2520)).
* Re-insert room IDs when decrypting bundled redaction events returned by `/sync` ([\#2531](https://github.com/matrix-org/matrix-js-sdk/pull/2531)). Contributed by @duxovni.

Changes in [19.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v19.1.0) (2022-07-26)
==================================================================================================

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "19.1.0",
"version": "19.2.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=12.9.0"
Expand Down Expand Up @@ -105,7 +105,7 @@
"jest-localstorage-mock": "^2.4.6",
"jest-sonar-reporter": "^2.0.0",
"jsdoc": "^3.6.6",
"matrix-mock-request": "^2.1.0",
"matrix-mock-request": "^2.1.2",
"rimraf": "^3.0.2",
"terser": "^5.5.1",
"tsify": "^5.0.2",
Expand Down
130 changes: 119 additions & 11 deletions spec/unit/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import '../olm-loader';
// eslint-disable-next-line no-restricted-imports
import { EventEmitter } from "events";

import { MatrixClient } from "../../src/client";
import { Crypto } from "../../src/crypto";
import { MemoryCryptoStore } from "../../src/crypto/store/memory-crypto-store";
import { MockStorageApi } from "../MockStorageApi";
Expand Down Expand Up @@ -64,6 +65,10 @@ describe("Crypto", function() {
return Olm.init();
});

afterEach(() => {
jest.useRealTimers();
});

it("Crypto exposes the correct olm library version", function() {
expect(Crypto.getOlmVersion()[0]).toEqual(3);
});
Expand Down Expand Up @@ -225,8 +230,8 @@ describe("Crypto", function() {
});

describe('Key requests', function() {
let aliceClient;
let bobClient;
let aliceClient: MatrixClient;
let bobClient: MatrixClient;

beforeEach(async function() {
aliceClient = (new TestClient(
Expand Down Expand Up @@ -313,7 +318,7 @@ describe("Crypto", function() {
expect(events[0].getContent().msgtype).toBe("m.bad.encrypted");
expect(events[1].getContent().msgtype).not.toBe("m.bad.encrypted");

const cryptoStore = bobClient.cryptoStore;
const cryptoStore = bobClient.crypto.cryptoStore;
const eventContent = events[0].getWireContent();
const senderKey = eventContent.sender_key;
const sessionId = eventContent.session_id;
Expand Down Expand Up @@ -383,9 +388,9 @@ describe("Crypto", function() {

const ksEvent = await keyshareEventForEvent(aliceClient, event, 1);
ksEvent.getContent().sender_key = undefined; // test
bobClient.crypto.addInboundGroupSession = jest.fn();
bobClient.crypto.olmDevice.addInboundGroupSession = jest.fn();
await bobDecryptor.onRoomKeyEvent(ksEvent);
expect(bobClient.crypto.addInboundGroupSession).not.toHaveBeenCalled();
expect(bobClient.crypto.olmDevice.addInboundGroupSession).not.toHaveBeenCalled();
});

it("creates a new keyshare request if we request a keyshare", async function() {
Expand All @@ -401,7 +406,7 @@ describe("Crypto", function() {
},
});
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
const cryptoStore = aliceClient.cryptoStore;
const cryptoStore = aliceClient.crypto.cryptoStore;
const roomKeyRequestBody = {
algorithm: olmlib.MEGOLM_ALGORITHM,
room_id: "!someroom",
Expand All @@ -425,7 +430,8 @@ describe("Crypto", function() {
},
});
// replace Alice's sendToDevice function with a mock
aliceClient.sendToDevice = jest.fn().mockResolvedValue(undefined);
const aliceSendToDevice = jest.fn().mockResolvedValue(undefined);
aliceClient.sendToDevice = aliceSendToDevice;
aliceClient.startClient();

// make a room key request, and record the transaction ID for the
Expand All @@ -434,11 +440,12 @@ describe("Crypto", function() {
// key requests get queued until the sync has finished, but we don't
// let the client set up enough for that to happen, so gut-wrench a bit
// to force it to send now.
// @ts-ignore
aliceClient.crypto.outgoingRoomKeyRequestManager.sendQueuedRequests();
jest.runAllTimers();
await Promise.resolve();
expect(aliceClient.sendToDevice).toBeCalledTimes(1);
const txnId = aliceClient.sendToDevice.mock.calls[0][2];
expect(aliceSendToDevice).toBeCalledTimes(1);
const txnId = aliceSendToDevice.mock.calls[0][2];

// give the room key request manager time to update the state
// of the request
Expand All @@ -451,8 +458,8 @@ describe("Crypto", function() {
// cancelAndResend will call sendToDevice twice:
// the first call to sendToDevice will be the cancellation
// the second call to sendToDevice will be the key request
expect(aliceClient.sendToDevice).toBeCalledTimes(3);
expect(aliceClient.sendToDevice.mock.calls[2][2]).not.toBe(txnId);
expect(aliceSendToDevice).toBeCalledTimes(3);
expect(aliceSendToDevice.mock.calls[2][2]).not.toBe(txnId);
});
});

Expand Down Expand Up @@ -480,4 +487,105 @@ describe("Crypto", function() {
client.stopClient();
});
});

describe("encryptAndSendToDevices", () => {
let client: TestClient;
let ensureOlmSessionsForDevices: jest.SpiedFunction<typeof olmlib.ensureOlmSessionsForDevices>;
let encryptMessageForDevice: jest.SpiedFunction<typeof olmlib.encryptMessageForDevice>;
const payload = { hello: "world" };
let encryptedPayload: object;

beforeEach(async () => {
ensureOlmSessionsForDevices = jest.spyOn(olmlib, "ensureOlmSessionsForDevices");
ensureOlmSessionsForDevices.mockResolvedValue({});
encryptMessageForDevice = jest.spyOn(olmlib, "encryptMessageForDevice");
encryptMessageForDevice.mockImplementation(async (...[result,,,,,, payload]) => {
result.plaintext = JSON.stringify(payload);
});

client = new TestClient("@alice:example.org", "aliceweb");
await client.client.initCrypto();

encryptedPayload = {
algorithm: "m.olm.v1.curve25519-aes-sha2",
sender_key: client.client.crypto.olmDevice.deviceCurve25519Key,
ciphertext: { plaintext: JSON.stringify(payload) },
};
});

afterEach(async () => {
ensureOlmSessionsForDevices.mockRestore();
encryptMessageForDevice.mockRestore();
await client.stop();
});

it("encrypts and sends to devices", async () => {
client.httpBackend
.when("PUT", "/sendToDevice/m.room.encrypted", {
messages: {
"@bob:example.org": {
bobweb: encryptedPayload,
bobmobile: encryptedPayload,
},
"@carol:example.org": {
caroldesktop: encryptedPayload,
},
},
})
.respond(200, {});

await Promise.all([
client.client.encryptAndSendToDevices(
[
{ userId: "@bob:example.org", deviceInfo: new DeviceInfo("bobweb") },
{ userId: "@bob:example.org", deviceInfo: new DeviceInfo("bobmobile") },
{ userId: "@carol:example.org", deviceInfo: new DeviceInfo("caroldesktop") },
],
payload,
),
client.httpBackend.flushAllExpected(),
]);
});

it("sends nothing to devices that couldn't be encrypted to", async () => {
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);
});

client.httpBackend
.when("PUT", "/sendToDevice/m.room.encrypted", {
// Carol is nowhere to be seen
messages: { "@bob:example.org": { bobweb: encryptedPayload } },
})
.respond(200, {});

await Promise.all([
client.client.encryptAndSendToDevices(
[
{ userId: "@bob:example.org", deviceInfo: new DeviceInfo("bobweb") },
{ userId: "@carol:example.org", deviceInfo: new DeviceInfo("caroldesktop") },
],
payload,
),
client.httpBackend.flushAllExpected(),
]);
});

it("no-ops if no devices can be encrypted to", async () => {
// Refuse to encrypt to anybody
encryptMessageForDevice.mockResolvedValue(undefined);

// Get the room keys version request out of the way
client.httpBackend.when("GET", "/room_keys/version").respond(404, {});
await client.httpBackend.flush("/room_keys/version", 1);

await client.client.encryptAndSendToDevices(
[{ userId: "@bob:example.org", deviceInfo: new DeviceInfo("bobweb") }],
payload,
);
client.httpBackend.verifyNoOutstandingRequests();
});
});
});
Loading

0 comments on commit d4024d5

Please sign in to comment.