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

Element-R: pass device list change notifications into rust crypto-sdk (#3254)

This commit is contained in:
Florian Duros
2023-04-11 15:42:19 +02:00
committed by GitHub
parent 70e34ffb76
commit f71d86f005
7 changed files with 39 additions and 28 deletions

View File

@@ -662,13 +662,17 @@ describe("SlidingSyncSdk", () => {
}); });
it("can update device lists", () => { it("can update device lists", () => {
client!.crypto!.processDeviceLists = jest.fn();
ext.onResponse({ ext.onResponse({
device_lists: { device_lists: {
changed: ["@alice:localhost"], changed: ["@alice:localhost"],
left: ["@bob:localhost"], left: ["@bob:localhost"],
}, },
}); });
// TODO: more assertions? expect(client!.crypto!.processDeviceLists).toHaveBeenCalledWith({
changed: ["@alice:localhost"],
left: ["@bob:localhost"],
});
}); });
it("can update OTK counts and unused fallback keys", () => { it("can update OTK counts and unused fallback keys", () => {

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import type { IToDeviceEvent } from "../sync-accumulator"; import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator";
import { MatrixEvent } from "../models/event"; import { MatrixEvent } from "../models/event";
import { Room } from "../models/room"; import { Room } from "../models/room";
import { CryptoApi } from "../crypto-api"; import { CryptoApi } from "../crypto-api";
@@ -113,6 +113,14 @@ export interface SyncCryptoCallbacks {
*/ */
processKeyCounts(oneTimeKeysCounts?: Record<string, number>, unusedFallbackKeys?: string[]): Promise<void>; processKeyCounts(oneTimeKeysCounts?: Record<string, number>, unusedFallbackKeys?: string[]): Promise<void>;
/**
* Handle the notification from /sync that device lists have
* been changed.
*
* @param deviceLists - device_lists field from /sync
*/
processDeviceLists(deviceLists: IDeviceLists): Promise<void>;
/** /**
* Called by the /sync loop whenever an m.room.encryption event is received. * Called by the /sync loop whenever an m.room.encryption event is received.
* *

View File

@@ -71,7 +71,7 @@ import { CryptoStore } from "./store/base";
import { IVerificationChannel } from "./verification/request/Channel"; import { IVerificationChannel } from "./verification/request/Channel";
import { TypedEventEmitter } from "../models/typed-event-emitter"; import { TypedEventEmitter } from "../models/typed-event-emitter";
import { IContent } from "../models/event"; import { IContent } from "../models/event";
import { ISyncResponse, IToDeviceEvent } from "../sync-accumulator"; import { IDeviceLists, ISyncResponse, IToDeviceEvent } from "../sync-accumulator";
import { ISignatures } from "../@types/signed"; import { ISignatures } from "../@types/signed";
import { IMessage } from "./algorithms/olm"; import { IMessage } from "./algorithms/olm";
import { CryptoBackend, OnSyncCompletedData } from "../common-crypto/CryptoBackend"; import { CryptoBackend, OnSyncCompletedData } from "../common-crypto/CryptoBackend";
@@ -2893,21 +2893,12 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
} }
/** /**
* Handle the notification from /sync or /keys/changes that device lists have * Handle the notification from /sync that device lists have
* been changed. * been changed.
* *
* @param syncData - Object containing sync tokens associated with this sync * @param deviceLists - device_lists field from /sync
* @param syncDeviceLists - device_lists field from /sync, or response from
* /keys/changes
*/ */
public async handleDeviceListChanges( public async processDeviceLists(deviceLists: IDeviceLists): Promise<void> {
syncData: ISyncStateData,
syncDeviceLists: Required<ISyncResponse>["device_lists"],
): Promise<void> {
// Initial syncs don't have device change lists. We'll either get the complete list
// of changes for the interval or will have invalidated everything in willProcessSync
if (!syncData.oldSyncToken) return;
// Here, we're relying on the fact that we only ever save the sync data after // Here, we're relying on the fact that we only ever save the sync data after
// sucessfully saving the device list data, so we're guaranteed that the device // sucessfully saving the device list data, so we're guaranteed that the device
// list store is at least as fresh as the sync token from the sync store, ie. // list store is at least as fresh as the sync token from the sync store, ie.
@@ -2916,7 +2907,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
// If we didn't make this assumption, we'd have to use the /keys/changes API // If we didn't make this assumption, we'd have to use the /keys/changes API
// to get key changes between the sync token in the device list and the 'old' // to get key changes between the sync token in the device list and the 'old'
// sync token used here to make sure we didn't miss any. // sync token used here to make sure we didn't miss any.
await this.evalDeviceListChanges(syncDeviceLists); await this.evalDeviceListChanges(deviceLists);
} }
/** /**

View File

@@ -17,7 +17,7 @@ limitations under the License.
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js"; import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js";
import type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto"; import type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto";
import type { IToDeviceEvent } from "../sync-accumulator"; import type { IDeviceLists, IToDeviceEvent } from "../sync-accumulator";
import type { IEncryptedEventInfo } from "../crypto/api"; import type { IEncryptedEventInfo } from "../crypto/api";
import { MatrixEvent } from "../models/event"; import { MatrixEvent } from "../models/event";
import { Room } from "../models/room"; import { Room } from "../models/room";
@@ -176,20 +176,23 @@ export class RustCrypto implements CryptoBackend {
* @param events - the received to-device messages * @param events - the received to-device messages
* @param oneTimeKeysCounts - the received one time key counts * @param oneTimeKeysCounts - the received one time key counts
* @param unusedFallbackKeys - the received unused fallback keys * @param unusedFallbackKeys - the received unused fallback keys
* @param devices - the received device list updates
* @returns A list of preprocessed to-device messages. * @returns A list of preprocessed to-device messages.
*/ */
private async receiveSyncChanges({ private async receiveSyncChanges({
events, events,
oneTimeKeysCounts = new Map<string, number>(), oneTimeKeysCounts = new Map<string, number>(),
unusedFallbackKeys = new Set<string>(), unusedFallbackKeys = new Set<string>(),
devices = new RustSdkCryptoJs.DeviceLists(),
}: { }: {
events?: IToDeviceEvent[]; events?: IToDeviceEvent[];
oneTimeKeysCounts?: Map<string, number>; oneTimeKeysCounts?: Map<string, number>;
unusedFallbackKeys?: Set<string>; unusedFallbackKeys?: Set<string>;
devices?: RustSdkCryptoJs.DeviceLists;
}): Promise<IToDeviceEvent[]> { }): Promise<IToDeviceEvent[]> {
const result = await this.olmMachine.receiveSyncChanges( const result = await this.olmMachine.receiveSyncChanges(
events ? JSON.stringify(events) : "[]", events ? JSON.stringify(events) : "[]",
new RustSdkCryptoJs.DeviceLists(), devices,
oneTimeKeysCounts, oneTimeKeysCounts,
unusedFallbackKeys, unusedFallbackKeys,
); );
@@ -229,6 +232,16 @@ export class RustCrypto implements CryptoBackend {
} }
} }
/** called by the sync loop to process the notification that device lists have
* been changed.
*
* @param deviceLists - device_lists field from /sync
*/
public async processDeviceLists(deviceLists: IDeviceLists): Promise<void> {
const devices = new RustSdkCryptoJs.DeviceLists(deviceLists.changed, deviceLists.left);
await this.receiveSyncChanges({ devices });
}
/** called by the sync loop on m.room.encrypted events /** called by the sync loop on m.room.encrypted events
* *
* @param room - in which the event was received * @param room - in which the event was received

View File

@@ -85,13 +85,8 @@ class ExtensionE2EE implements Extension<ExtensionE2EERequest, ExtensionE2EEResp
public async onResponse(data: ExtensionE2EEResponse): Promise<void> { public async onResponse(data: ExtensionE2EEResponse): Promise<void> {
// Handle device list updates // Handle device list updates
if (data["device_lists"]) { if (data.device_lists) {
await this.crypto.handleDeviceListChanges( await this.crypto.processDeviceLists(data.device_lists);
{
oldSyncToken: "yep", // XXX need to do this so the device list changes get processed :(
},
data["device_lists"],
);
} }
// Handle one_time_keys_count and unused_fallback_key_types // Handle one_time_keys_count and unused_fallback_key_types

View File

@@ -132,7 +132,7 @@ interface IToDevice {
events: IToDeviceEvent[]; events: IToDeviceEvent[];
} }
interface IDeviceLists { export interface IDeviceLists {
changed?: string[]; changed?: string[];
left?: string[]; left?: string[];
} }

View File

@@ -1515,8 +1515,8 @@ export class SyncApi {
// Handle device list updates // Handle device list updates
if (data.device_lists) { if (data.device_lists) {
if (this.syncOpts.crypto) { if (this.syncOpts.cryptoCallbacks) {
await this.syncOpts.crypto.handleDeviceListChanges(syncEventData, data.device_lists); await this.syncOpts.cryptoCallbacks.processDeviceLists(data.device_lists);
} else { } else {
// FIXME if we *don't* have a crypto module, we still need to // FIXME if we *don't* have a crypto module, we still need to
// invalidate the device lists. But that would require a // invalidate the device lists. But that would require a