Skip to content

Commit

Permalink
Merge branch 'matrix-org:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
finsterwalder authored Aug 29, 2023
2 parents 1872a8b + dec4650 commit a33edb2
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 30 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
Changes in [28.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v28.0.0) (2023-08-29)
==================================================================================================

## 🚨 BREAKING CHANGES
* Set minimum supported Matrix 1.1 version (drop legacy r0 versions) ([\#3007](https://github.com/matrix-org/matrix-js-sdk/pull/3007)). Fixes vector-im/element-web#16876.

## 🦖 Deprecations
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**

## ✨ Features
* ElementR: Add `CryptoApi.requestVerificationDM` ([\#3643](https://github.com/matrix-org/matrix-js-sdk/pull/3643)). Contributed by @florianduros.
* Implement `CryptoApi.checkKeyBackupAndEnable` ([\#3633](https://github.com/matrix-org/matrix-js-sdk/pull/3633)). Fixes vector-im/crypto-internal#111 and vector-im/crypto-internal#112.

## 🐛 Bug Fixes
* ElementR: Process all verification events, not just requests ([\#3650](https://github.com/matrix-org/matrix-js-sdk/pull/3650)). Contributed by @florianduros.

Changes in [27.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v27.2.0) (2023-08-15)
==================================================================================================

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "27.2.0",
"version": "28.0.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=18.0.0"
Expand Down
55 changes: 53 additions & 2 deletions spec/integ/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ import Olm from "@matrix-org/olm";
import type { IDeviceKeys } from "../../../src/@types/crypto";
import * as testUtils from "../../test-utils/test-utils";
import { CRYPTO_BACKENDS, getSyncResponse, InitCrypto, syncPromise } from "../../test-utils/test-utils";
import { TEST_ROOM_ID, TEST_ROOM_ID as ROOM_ID, TEST_USER_ID } from "../../test-utils/test-data";
import {
BOB_SIGNED_CROSS_SIGNING_KEYS_DATA,
BOB_SIGNED_TEST_DEVICE_DATA,
BOB_TEST_USER_ID,
SIGNED_CROSS_SIGNING_KEYS_DATA,
SIGNED_TEST_DEVICE_DATA,
TEST_ROOM_ID,
TEST_ROOM_ID as ROOM_ID,
TEST_USER_ID,
} from "../../test-utils/test-data";
import { TestClient } from "../../TestClient";
import { logger } from "../../../src/logger";
import {
Expand All @@ -36,6 +45,7 @@ import {
IDownloadKeyResult,
IEvent,
IndexedDBCryptoStore,
IRoomEvent,
IStartClientOpts,
MatrixClient,
MatrixEvent,
Expand All @@ -44,7 +54,6 @@ import {
Room,
RoomMember,
RoomStateEvent,
IRoomEvent,
} from "../../../src/matrix";
import { DeviceInfo } from "../../../src/crypto/deviceinfo";
import { E2EKeyReceiver, IE2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
Expand Down Expand Up @@ -2566,4 +2575,46 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
},
);
});

describe("Check if the cross signing keys are available for a user", () => {
beforeEach(async () => {
// anything that we don't have a specific matcher for silently returns a 404
fetchMock.catch(404);

keyResponder = new E2EKeyResponder(aliceClient.getHomeserverUrl());
keyResponder.addCrossSigningData(SIGNED_CROSS_SIGNING_KEYS_DATA);
keyResponder.addDeviceKeys(SIGNED_TEST_DEVICE_DATA);
keyResponder.addKeyReceiver(BOB_TEST_USER_ID, keyReceiver);
keyResponder.addCrossSigningData(BOB_SIGNED_CROSS_SIGNING_KEYS_DATA);
keyResponder.addDeviceKeys(BOB_SIGNED_TEST_DEVICE_DATA);

expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} });
await startClientAndAwaitFirstSync();
});

it("Cross signing keys are available for an untracked user with cross signing keys on the homeserver", async () => {
// Needed for old crypto, download and cache locally the cross signing keys of Bob
await aliceClient.getCrypto()?.getUserDeviceInfo([BOB_TEST_USER_ID], true);

const hasCrossSigningKeysForUser = await aliceClient
.getCrypto()!
.userHasCrossSigningKeys(BOB_TEST_USER_ID, true);
expect(hasCrossSigningKeysForUser).toBe(true);
});

it("Cross signing keys are available for a tracked user", async () => {
// Process Alice keys, old crypto has a sleep(5ms) during the process
await jest.advanceTimersByTimeAsync(5);
await flushPromises();

// Alice is the local user and should be tracked !
const hasCrossSigningKeysForUser = await aliceClient.getCrypto()!.userHasCrossSigningKeys(TEST_USER_ID);
expect(hasCrossSigningKeysForUser).toBe(true);
});

it("Cross signing keys are not available for an unknown user", async () => {
const hasCrossSigningKeysForUser = await aliceClient.getCrypto()!.userHasCrossSigningKeys("@unknown:xyz");
expect(hasCrossSigningKeysForUser).toBe(false);
});
});
});
17 changes: 17 additions & 0 deletions spec/unit/rust-crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,23 @@ describe("RustCrypto", () => {

await expect(rustCrypto.userHasCrossSigningKeys()).resolves.toBe(true);
});

it("returns true if the user is untracked, downloadUncached is set at true and the cross-signing keys are available", async () => {
fetchMock.post("path:/_matrix/client/v3/keys/query", {
device_keys: {
[testData.BOB_TEST_USER_ID]: {
[testData.BOB_TEST_DEVICE_ID]: testData.BOB_SIGNED_TEST_DEVICE_DATA,
},
},
...testData.BOB_SIGNED_CROSS_SIGNING_KEYS_DATA,
});

await expect(rustCrypto.userHasCrossSigningKeys(testData.BOB_TEST_USER_ID, true)).resolves.toBe(true);
});

it("returns false if the user is unknown", async () => {
await expect(rustCrypto.userHasCrossSigningKeys(testData.BOB_TEST_USER_ID)).resolves.toBe(false);
});
});

describe("createRecoveryKeyFromPassphrase", () => {
Expand Down
1 change: 1 addition & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* @param userId - the user ID to get the cross-signing info for.
*
* @returns the cross signing information for the user.
* @deprecated Prefer {@link CryptoApi#userHasCrossSigningKeys}
*/
public getStoredCrossSigningForUser(userId: string): CrossSigningInfo | null {
if (!this.cryptoBackend) {
Expand Down
1 change: 1 addition & 0 deletions src/common-crypto/CryptoBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export interface CryptoBackend extends SyncCryptoCallbacks, CryptoApi {
* @param userId - the user ID to get the cross-signing info for.
*
* @returns the cross signing information for the user.
* @deprecated Prefer {@link CryptoApi#userHasCrossSigningKeys}
*/
getStoredCrossSigningForUser(userId: string): CrossSigningInfo | null;

Expand Down
26 changes: 16 additions & 10 deletions src/crypto-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ export interface CryptoApi {
*/
globalBlacklistUnverifiedDevices: boolean;

/**
* Checks if the user has previously published cross-signing keys
*
* This means downloading the devicelist for the user and checking if the list includes
* the cross-signing pseudo-device.
*
* @returns true if the user has previously published cross-signing keys
*/
userHasCrossSigningKeys(): Promise<boolean>;

/**
* Perform any background tasks that can be done before a message is ready to
* send, in order to speed up sending of the message.
Expand Down Expand Up @@ -88,6 +78,22 @@ export interface CryptoApi {
*/
importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise<void>;

/**
* Check if the given user has published cross-signing keys.
*
* - If the user is tracked, a `/keys/query` request is made to update locally the cross signing keys.
* - If the user is not tracked locally and downloadUncached is set to true,
* a `/keys/query` request is made to the server to retrieve the cross signing keys.
* - Otherwise, return false
*
* @param userId - the user ID to check. Defaults to the local user.
* @param downloadUncached - If true, download the device list for users whose device list we are not
* currently tracking. Defaults to false, in which case `false` will be returned for such users.
*
* @returns true if the cross signing keys are available.
*/
userHasCrossSigningKeys(userId?: string, downloadUncached?: boolean): Promise<boolean>;

/**
* Get the device information for the given list of users.
*
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,9 +700,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
*
* @internal
*/
public async userHasCrossSigningKeys(): Promise<boolean> {
await this.downloadKeys([this.userId]);
return this.deviceList.getStoredCrossSigningForUser(this.userId) !== null;
public async userHasCrossSigningKeys(userId = this.userId): Promise<boolean> {
await this.downloadKeys([userId]);
return this.deviceList.getStoredCrossSigningForUser(userId) !== null;
}

/**
Expand Down
55 changes: 41 additions & 14 deletions src/rust-crypto/rust-crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,20 +244,6 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv

public globalBlacklistUnverifiedDevices = false;

/**
* Implementation of {@link CryptoApi.userHasCrossSigningKeys}.
*/
public async userHasCrossSigningKeys(): Promise<boolean> {
const userId = new RustSdkCryptoJs.UserId(this.userId);
/* make sure we have an *up-to-date* idea of the user's cross-signing keys. This is important, because if we
* return "false" here, we will end up generating new cross-signing keys and replacing the existing ones.
*/
const request = this.olmMachine.queryKeysForUsers([userId]);
await this.outgoingRequestProcessor.makeOutgoingRequest(request);
const userIdentity = await this.olmMachine.getIdentity(userId);
return userIdentity !== undefined;
}

public prepareToEncrypt(room: Room): void {
const encryptor = this.roomEncryptors[room.roomId];

Expand Down Expand Up @@ -289,6 +275,47 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
});
}

/**
* Implementation of {@link CryptoApi.userHasCrossSigningKeys}.
*/
public async userHasCrossSigningKeys(userId = this.userId, downloadUncached = false): Promise<boolean> {
// TODO: could probably do with a more efficient way of doing this than returning the whole set and searching
const rustTrackedUsers: Set<RustSdkCryptoJs.UserId> = await this.olmMachine.trackedUsers();
let rustTrackedUser: RustSdkCryptoJs.UserId | undefined;
for (const u of rustTrackedUsers) {
if (userId === u.toString()) {
rustTrackedUser = u;
break;
}
}

if (rustTrackedUser !== undefined) {
if (userId === this.userId) {
/* make sure we have an *up-to-date* idea of the user's cross-signing keys. This is important, because if we
* return "false" here, we will end up generating new cross-signing keys and replacing the existing ones.
*/
const request = this.olmMachine.queryKeysForUsers([rustTrackedUser]);
await this.outgoingRequestProcessor.makeOutgoingRequest(request);
}
const userIdentity = await this.olmMachine.getIdentity(rustTrackedUser);
return userIdentity !== undefined;
} else if (downloadUncached) {
// Download the cross signing keys and check if the master key is available
const keyResult = await this.downloadDeviceList(new Set([userId]));
const keys = keyResult.master_keys?.[userId];

// No master key
if (!keys) return false;

// `keys` is an object with { [`ed25519:${pubKey}`]: pubKey }
// We assume only a single key, and we want the bare form without type
// prefix, so we select the values.
return Boolean(Object.values(keys.keys)[0]);
} else {
return false;
}
}

/**
* Get the device information for the given list of users.
*
Expand Down

0 comments on commit a33edb2

Please sign in to comment.