diff --git a/spec/unit/matrixrtc/RTCEncryptionManager.spec.ts b/spec/unit/matrixrtc/RTCEncryptionManager.spec.ts index de88d47f60..1614ec1e87 100644 --- a/spec/unit/matrixrtc/RTCEncryptionManager.spec.ts +++ b/spec/unit/matrixrtc/RTCEncryptionManager.spec.ts @@ -22,9 +22,7 @@ import { type ToDeviceKeyTransport } from "../../../src/matrixrtc/ToDeviceKeyTra import { KeyTransportEvents, type KeyTransportEventsHandlerMap } from "../../../src/matrixrtc/IKeyTransport.ts"; import { membershipTemplate, mockCallMembership } from "./mocks.ts"; import { decodeBase64, TypedEventEmitter } from "../../../src"; -import { RoomAndToDeviceTransport } from "../../../src/matrixrtc/RoomAndToDeviceKeyTransport.ts"; -import { type RoomKeyTransport } from "../../../src/matrixrtc/RoomKeyTransport.ts"; -import { logger, type Logger } from "../../../src/logger.ts"; +import { logger } from "../../../src/logger.ts"; import { getParticipantId } from "../../../src/matrixrtc/utils.ts"; describe("RTCEncryptionManager", () => { @@ -782,86 +780,6 @@ describe("RTCEncryptionManager", () => { ); }); - it("Should re-distribute key on transport switch", async () => { - const toDeviceEmitter = new TypedEventEmitter(); - const mockToDeviceTransport = { - start: jest.fn(), - stop: jest.fn(), - sendKey: jest.fn().mockResolvedValue(undefined), - on: toDeviceEmitter.on.bind(toDeviceEmitter), - off: toDeviceEmitter.off.bind(toDeviceEmitter), - emit: toDeviceEmitter.emit.bind(toDeviceEmitter), - setParentLogger: jest.fn(), - } as unknown as Mocked; - - const roomEmitter = new TypedEventEmitter(); - const mockRoomTransport = { - start: jest.fn(), - stop: jest.fn(), - sendKey: jest.fn().mockResolvedValue(undefined), - on: roomEmitter.on.bind(roomEmitter), - off: roomEmitter.off.bind(roomEmitter), - emit: roomEmitter.emit.bind(roomEmitter), - setParentLogger: jest.fn(), - } as unknown as Mocked; - - const mockLogger = { - debug: jest.fn(), - warn: jest.fn(), - } as unknown as Mocked; - - const transport = new RoomAndToDeviceTransport(mockToDeviceTransport, mockRoomTransport, { - getChild: jest.fn().mockReturnValue(mockLogger), - } as unknown as Mocked); - - encryptionManager = new RTCEncryptionManager( - "@alice:example.org", - "DEVICE01", - getMembershipMock, - transport, - statistics, - onEncryptionKeysChanged, - ); - - const members = [ - aCallMembership("@bob:example.org", "BOBDEVICE"), - aCallMembership("@bob:example.org", "BOBDEVICE2"), - aCallMembership("@carl:example.org", "CARLDEVICE"), - ]; - getMembershipMock.mockReturnValue(members); - - // Let's join - encryptionManager.join(undefined); - encryptionManager.onMembershipsUpdate(); - await jest.advanceTimersByTimeAsync(10); - - // Should have sent the key to the toDevice transport - expect(mockToDeviceTransport.sendKey).toHaveBeenCalledTimes(1); - expect(mockRoomTransport.sendKey).not.toHaveBeenCalled(); - - // Simulate receiving a key by room transport - roomEmitter.emit( - KeyTransportEvents.ReceivedKeys, - "@bob:example.org", - "BOBDEVICE", - "AAAAAAAAAAA", - 0 /* KeyId */, - 0 /* Timestamp */, - ); - - await jest.runOnlyPendingTimersAsync(); - - // The key should have been re-distributed to the room transport - expect(mockRoomTransport.sendKey).toHaveBeenCalled(); - expect(mockToDeviceTransport.sendKey).toHaveBeenCalledWith( - expect.any(String), - // It is the first key re-distributed - 0, - // to all the members - members.map((m) => ({ userId: m.sender, deviceId: m.deviceId, membershipTs: m.createdTs() })), - ); - }); - function aCallMembership(userId: string, deviceId: string, ts: number = 1000): CallMembership { return mockCallMembership( { ...membershipTemplate, user_id: userId, device_id: deviceId, created_ts: ts }, diff --git a/spec/unit/matrixrtc/RoomAndToDeviceTransport.spec.ts b/spec/unit/matrixrtc/RoomAndToDeviceTransport.spec.ts deleted file mode 100644 index bd618fede3..0000000000 --- a/spec/unit/matrixrtc/RoomAndToDeviceTransport.spec.ts +++ /dev/null @@ -1,187 +0,0 @@ -/* -Copyright 2025 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { type Mocked } from "jest-mock"; - -import { makeKey, makeMockEvent, makeMockRoom } from "./mocks"; -import { EventType, type IRoomTimelineData, type Room, RoomEvent, type MatrixClient } from "../../../src"; -import { ToDeviceKeyTransport } from "../../../src/matrixrtc/ToDeviceKeyTransport.ts"; -import { - getMockClientWithEventEmitter, - mockClientMethodsEvents, - mockClientMethodsUser, -} from "../../test-utils/client.ts"; -import { type ParticipantDeviceInfo, type Statistics } from "../../../src/matrixrtc"; -import { KeyTransportEvents } from "../../../src/matrixrtc/IKeyTransport.ts"; -import { type Logger } from "../../../src/logger.ts"; -import { RoomAndToDeviceEvents, RoomAndToDeviceTransport } from "../../../src/matrixrtc/RoomAndToDeviceKeyTransport.ts"; -import { RoomKeyTransport } from "../../../src/matrixrtc/RoomKeyTransport.ts"; - -describe("RoomAndToDeviceTransport", () => { - const roomId = "!room:id"; - - let mockClient: Mocked; - let statistics: Statistics; - let mockLogger: Mocked; - let transport: RoomAndToDeviceTransport; - let mockRoom: Room; - let sendEventMock: jest.Mock; - let roomKeyTransport: RoomKeyTransport; - let toDeviceKeyTransport: ToDeviceKeyTransport; - let toDeviceSendKeySpy: jest.SpyInstance; - let roomSendKeySpy: jest.SpyInstance; - beforeEach(() => { - sendEventMock = jest.fn(); - mockClient = getMockClientWithEventEmitter({ - encryptAndSendToDevice: jest.fn(), - getDeviceId: jest.fn().mockReturnValue("MYDEVICE"), - ...mockClientMethodsEvents(), - ...mockClientMethodsUser("@alice:example.org"), - sendEvent: sendEventMock, - }); - mockRoom = makeMockRoom([]); - mockLogger = { - debug: jest.fn(), - warn: jest.fn(), - getChild: jest.fn(), - } as unknown as Mocked; - mockLogger.getChild.mockReturnValue(mockLogger); - statistics = { - counters: { - roomEventEncryptionKeysSent: 0, - roomEventEncryptionKeysReceived: 0, - }, - totals: { - roomEventEncryptionKeysReceivedTotalAge: 0, - }, - }; - roomKeyTransport = new RoomKeyTransport(mockRoom, mockClient, statistics); - toDeviceKeyTransport = new ToDeviceKeyTransport( - "@alice:example.org", - "MYDEVICE", - mockRoom.roomId, - mockClient, - statistics, - ); - transport = new RoomAndToDeviceTransport(toDeviceKeyTransport, roomKeyTransport, mockLogger); - toDeviceSendKeySpy = jest.spyOn(toDeviceKeyTransport, "sendKey"); - roomSendKeySpy = jest.spyOn(roomKeyTransport, "sendKey"); - }); - - it("should enable to device transport when starting", () => { - transport.start(); - expect(transport.enabled.room).toBeFalsy(); - expect(transport.enabled.toDevice).toBeTruthy(); - }); - it("only sends to device keys when sending a key", async () => { - transport.start(); - await transport.sendKey("1235", 0, [ - { userId: "@alice:example.org", deviceId: "ALICEDEVICE", membershipTs: 1234 }, - ]); - expect(toDeviceSendKeySpy).toHaveBeenCalledTimes(1); - expect(roomSendKeySpy).toHaveBeenCalledTimes(0); - expect(transport.enabled.room).toBeFalsy(); - expect(transport.enabled.toDevice).toBeTruthy(); - }); - - it("enables room transport and disables to device transport when receiving a room key", async () => { - transport.start(); - const onNewKeyFromTransport = jest.fn(); - const onTransportEnabled = jest.fn(); - transport.on(KeyTransportEvents.ReceivedKeys, onNewKeyFromTransport); - transport.on(RoomAndToDeviceEvents.EnabledTransportsChanged, onTransportEnabled); - mockRoom.emit( - RoomEvent.Timeline, - makeMockEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", roomId, { - call_id: "", - keys: [makeKey(0, "testKey")], - sent_ts: Date.now(), - device_id: "AAAAAAA", - }), - undefined, - undefined, - false, - {} as IRoomTimelineData, - ); - await jest.advanceTimersByTimeAsync(1); - expect(transport.enabled.room).toBeTruthy(); - expect(transport.enabled.toDevice).toBeFalsy(); - - await transport.sendKey("1235", 0, [ - { userId: "@alice:example.org", deviceId: "AlICEDEV", membershipTs: 1234 }, - ]); - expect(sendEventMock).toHaveBeenCalledTimes(1); - expect(roomSendKeySpy).toHaveBeenCalledTimes(1); - expect(toDeviceSendKeySpy).toHaveBeenCalledTimes(0); - expect(onTransportEnabled).toHaveBeenCalledWith({ toDevice: false, room: true }); - }); - - it("enables room transport and disables to device transport on widget driver error", async () => { - mockClient.encryptAndSendToDevice.mockRejectedValue({ - message: - "unknown variant `send_to_device`, expected one of `supported_api_versions`, `content_loaded`, `get_openid`, `org.matrix.msc2876.read_events`, `send_event`, `org.matrix.msc4157.update_delayed_event` at line 1 column 22", - }); - - transport.start(); - const membership: ParticipantDeviceInfo = { - userId: "@alice:example.org", - deviceId: "ALICEDEVICE", - membershipTs: 1234, - }; - const onTransportEnabled = jest.fn(); - transport.on(RoomAndToDeviceEvents.EnabledTransportsChanged, onTransportEnabled); - - // We start with toDevice transport enabled - expect(transport.enabled.room).toBeFalsy(); - expect(transport.enabled.toDevice).toBeTruthy(); - - await transport.sendKey("1235", 0, [membership]); - - // We switched transport, now room transport is enabled - expect(onTransportEnabled).toHaveBeenCalledWith({ toDevice: false, room: true }); - expect(transport.enabled.room).toBeTruthy(); - expect(transport.enabled.toDevice).toBeFalsy(); - - // sanity check that we called the failang to device send key. - expect(toDeviceKeyTransport.sendKey).toHaveBeenCalledWith("1235", 0, [membership]); - expect(toDeviceKeyTransport.sendKey).toHaveBeenCalledTimes(1); - // We re-sent the key via the room transport - expect(roomKeyTransport.sendKey).toHaveBeenCalledWith("1235", 0, [membership]); - expect(roomKeyTransport.sendKey).toHaveBeenCalledTimes(1); - - mockClient.encryptAndSendToDevice.mockRestore(); - }); - - it("does log that it did nothing when disabled", () => { - transport.start(); - const onNewKeyFromTransport = jest.fn(); - const onTransportEnabled = jest.fn(); - transport.on(KeyTransportEvents.ReceivedKeys, onNewKeyFromTransport); - transport.on(RoomAndToDeviceEvents.EnabledTransportsChanged, onTransportEnabled); - - transport.setEnabled({ toDevice: false, room: false }); - const dateNow = Date.now(); - roomKeyTransport.emit(KeyTransportEvents.ReceivedKeys, "user", "device", "roomKey", 0, dateNow); - toDeviceKeyTransport.emit(KeyTransportEvents.ReceivedKeys, "user", "device", "toDeviceKey", 0, Date.now()); - - expect(mockLogger.debug).toHaveBeenCalledWith("To Device transport is disabled, ignoring received keys"); - // for room key transport we will never get a disabled message because its will always just turn on - expect(onTransportEnabled).toHaveBeenNthCalledWith(1, { toDevice: false, room: false }); - expect(onTransportEnabled).toHaveBeenNthCalledWith(2, { toDevice: false, room: true }); - expect(onNewKeyFromTransport).toHaveBeenCalledTimes(1); - expect(onNewKeyFromTransport).toHaveBeenCalledWith("user", "device", "roomKey", 0, dateNow); - }); -}); diff --git a/src/matrixrtc/EncryptionManager.ts b/src/matrixrtc/EncryptionManager.ts index 056f30d83b..14990b726c 100644 --- a/src/matrixrtc/EncryptionManager.ts +++ b/src/matrixrtc/EncryptionManager.ts @@ -7,11 +7,6 @@ import { type CallMembership } from "./CallMembership.ts"; import { type KeyTransportEventListener, KeyTransportEvents, type IKeyTransport } from "./IKeyTransport.ts"; import { isMyMembership, type ParticipantId, type Statistics } from "./types.ts"; import { getParticipantId } from "./utils.ts"; -import { - type EnabledTransports, - RoomAndToDeviceEvents, - RoomAndToDeviceTransport, -} from "./RoomAndToDeviceKeyTransport.ts"; /** * This interface is for testing and for making it possible to interchange the encryption manager. @@ -119,10 +114,7 @@ export class EncryptionManager implements IEncryptionManager { this.manageMediaKeys = this.joinConfig?.manageMediaKeys ?? this.manageMediaKeys; this.transport.on(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived); - // Deprecate RoomKeyTransport: this can get removed. - if (this.transport instanceof RoomAndToDeviceTransport) { - this.transport.on(RoomAndToDeviceEvents.EnabledTransportsChanged, this.onTransportChanged); - } + this.transport.start(); if (this.joinConfig?.manageMediaKeys) { this.makeNewSenderKey(); @@ -315,10 +307,6 @@ export class EncryptionManager implements IEncryptionManager { } }; - private onTransportChanged: (enabled: EnabledTransports) => void = () => { - this.requestSendCurrentKey(); - }; - public onNewKeyReceived: KeyTransportEventListener = (userId, deviceId, keyBase64Encoded, index, timestamp) => { this.logger.debug(`Received key over key transport ${userId}:${deviceId} at index ${index}`); this.setEncryptionKey(userId, deviceId, index, keyBase64Encoded, timestamp); diff --git a/src/matrixrtc/MatrixRTCSession.ts b/src/matrixrtc/MatrixRTCSession.ts index b8c5c29403..2c4ed58603 100644 --- a/src/matrixrtc/MatrixRTCSession.ts +++ b/src/matrixrtc/MatrixRTCSession.ts @@ -35,20 +35,15 @@ import { type IRTCNotificationContent, type ICallNotifyContent, } from "./types.ts"; -import { RoomKeyTransport } from "./RoomKeyTransport.ts"; import { MembershipManagerEvent, type MembershipManagerEventHandlerMap, type IMembershipManager, } from "./IMembershipManager.ts"; import { RTCEncryptionManager } from "./RTCEncryptionManager.ts"; -import { - RoomAndToDeviceEvents, - type RoomAndToDeviceEventsHandlerMap, - RoomAndToDeviceTransport, -} from "./RoomAndToDeviceKeyTransport.ts"; -import { TypedReEmitter } from "../ReEmitter.ts"; import { ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts"; +import { RoomKeyTransport } from "./RoomKeyTransport.ts"; +import { TypedReEmitter } from "../ReEmitter.ts"; /** * Events emitted by MatrixRTCSession @@ -229,8 +224,8 @@ export type JoinSessionConfig = SessionConfig & MembershipConfig & EncryptionCon * This class doesn't deal with media at all, just membership & properties of a session. */ export class MatrixRTCSession extends TypedEventEmitter< - MatrixRTCSessionEvent | RoomAndToDeviceEvents | MembershipManagerEvent, - MatrixRTCSessionEventHandlerMap & RoomAndToDeviceEventsHandlerMap & MembershipManagerEventHandlerMap + MatrixRTCSessionEvent | MembershipManagerEvent, + MatrixRTCSessionEventHandlerMap & MembershipManagerEventHandlerMap > { private membershipManager?: IMembershipManager; private encryptionManager?: IEncryptionManager; @@ -473,8 +468,8 @@ export class MatrixRTCSession extends TypedEventEmitter< roomState?.off(RoomStateEvent.Members, this.onRoomMemberUpdate); } private reEmitter = new TypedReEmitter< - MatrixRTCSessionEvent | RoomAndToDeviceEvents | MembershipManagerEvent, - MatrixRTCSessionEventHandlerMap & RoomAndToDeviceEventsHandlerMap & MembershipManagerEventHandlerMap + MatrixRTCSessionEvent | MembershipManagerEvent, + MatrixRTCSessionEventHandlerMap & MembershipManagerEventHandlerMap >(this); /** @@ -518,13 +513,7 @@ export class MatrixRTCSession extends TypedEventEmitter< this.logger.info("Using to-device with room fallback transport for encryption keys"); const [uId, dId] = [this.client.getUserId()!, this.client.getDeviceId()!]; const [room, client, statistics] = [this.roomSubset, this.client, this.statistics]; - // Deprecate RoomKeyTransport: only ToDeviceKeyTransport is needed once deprecated - const roomKeyTransport = new RoomKeyTransport(room, client, statistics); - const toDeviceTransport = new ToDeviceKeyTransport(uId, dId, room.roomId, client, statistics); - transport = new RoomAndToDeviceTransport(toDeviceTransport, roomKeyTransport, this.logger); - - // Expose the changes so the ui can display the currently used transport. - this.reEmitter.reEmit(transport, [RoomAndToDeviceEvents.EnabledTransportsChanged]); + const transport = new ToDeviceKeyTransport(uId, dId, room.roomId, client, statistics); this.encryptionManager = new RTCEncryptionManager( this.client.getUserId()!, this.client.getDeviceId()!, diff --git a/src/matrixrtc/RTCEncryptionManager.ts b/src/matrixrtc/RTCEncryptionManager.ts index 0fc6b8799b..fc8820c384 100644 --- a/src/matrixrtc/RTCEncryptionManager.ts +++ b/src/matrixrtc/RTCEncryptionManager.ts @@ -29,11 +29,6 @@ import type { Statistics, } from "./types.ts"; import { getParticipantId, OutdatedKeyFilter } from "./utils.ts"; -import { - type EnabledTransports, - RoomAndToDeviceEvents, - RoomAndToDeviceTransport, -} from "./RoomAndToDeviceKeyTransport.ts"; /** * RTCEncryptionManager is used to manage the encryption keys for a call. @@ -137,10 +132,6 @@ export class RTCEncryptionManager implements IEncryptionManager { this.useKeyDelay = joinConfig?.useKeyDelay ?? 1000; this.keyRotationGracePeriodMs = joinConfig?.keyRotationGracePeriodMs ?? 10_000; this.transport.on(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived); - // Deprecate RoomKeyTransport: this can get removed. - if (this.transport instanceof RoomAndToDeviceTransport) { - this.transport.on(RoomAndToDeviceEvents.EnabledTransportsChanged, this.onTransportChanged); - } this.transport.start(); } @@ -151,29 +142,6 @@ export class RTCEncryptionManager implements IEncryptionManager { this.participantKeyRings.clear(); } - // Temporary for backwards compatibility - // TODO: Remove this in the future - private onTransportChanged: (enabled: EnabledTransports) => void = () => { - this.logger?.info("Transport change detected, restarting key distribution"); - if (this.currentKeyDistributionPromise) { - this.currentKeyDistributionPromise - .then(() => { - if (this.outboundSession) { - this.outboundSession.sharedWith = []; - this.ensureKeyDistribution(); - } - }) - .catch((e) => { - this.logger?.error("Failed to restart key distribution", e); - }); - } else { - if (this.outboundSession) { - this.outboundSession.sharedWith = []; - this.ensureKeyDistribution(); - } - } - }; - /** * Will ensure that a new key is distributed and used to encrypt our media. * If there is already a key distribution in progress, it will schedule a new distribution round just after the current one is completed. diff --git a/src/matrixrtc/RoomAndToDeviceKeyTransport.ts b/src/matrixrtc/RoomAndToDeviceKeyTransport.ts deleted file mode 100644 index becca2742c..0000000000 --- a/src/matrixrtc/RoomAndToDeviceKeyTransport.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2025 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { logger as rootLogger, type Logger } from "../logger.ts"; -import { KeyTransportEvents, type KeyTransportEventsHandlerMap, type IKeyTransport } from "./IKeyTransport.ts"; -import type { RoomKeyTransport } from "./RoomKeyTransport.ts"; -import { NotSupportedError, type ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts"; -import { TypedEventEmitter } from "../models/typed-event-emitter.ts"; -import { type ParticipantDeviceInfo } from "./types.ts"; - -// Deprecate RoomAndToDeviceTransport: This whole class is only a stop gap until we remove RoomKeyTransport. -export interface EnabledTransports { - toDevice: boolean; - room: boolean; -} - -export enum RoomAndToDeviceEvents { - EnabledTransportsChanged = "enabled_transports_changed", -} -export type RoomAndToDeviceEventsHandlerMap = { - [RoomAndToDeviceEvents.EnabledTransportsChanged]: (enabledTransports: EnabledTransports) => void; -}; -/** - * A custom transport that subscribes to room key events (via `RoomKeyTransport`) and to device key events (via: `ToDeviceKeyTransport`) - * The public setEnabled method allows to turn one or the other on or off on the fly. - * It will emit `RoomAndToDeviceEvents.EnabledTransportsChanged` if the enabled transport changes to allow comminitcating this to - * the user in the ui. - * - * Since it will always subscribe to both (room and to device) but only emit for the enabled ones, it can detect - * if a room key event was received and autoenable it. - */ -export class RoomAndToDeviceTransport - extends TypedEventEmitter< - KeyTransportEvents | RoomAndToDeviceEvents, - KeyTransportEventsHandlerMap & RoomAndToDeviceEventsHandlerMap - > - implements IKeyTransport -{ - private readonly logger: Logger; - private _enabled: EnabledTransports = { toDevice: true, room: false }; - public constructor( - private toDeviceTransport: ToDeviceKeyTransport, - private roomKeyTransport: RoomKeyTransport, - parentLogger?: Logger, - ) { - super(); - this.logger = (parentLogger ?? rootLogger).getChild(`[RoomAndToDeviceTransport]`); - // update parent loggers for the sub transports so filtering for `RoomAndToDeviceTransport` contains their logs too - this.toDeviceTransport.setParentLogger(this.logger); - this.roomKeyTransport.setParentLogger(this.logger); - - this.roomKeyTransport.on(KeyTransportEvents.ReceivedKeys, (...props) => { - // Turn on the room transport if we receive a roomKey from another participant - // and disable the toDevice transport. - if (!this._enabled.room) { - this.logger.debug("Received room key, enabling room key transport, disabling toDevice transport"); - this.setEnabled({ toDevice: false, room: true }); - } - this.emit(KeyTransportEvents.ReceivedKeys, ...props); - }); - this.toDeviceTransport.on(KeyTransportEvents.ReceivedKeys, (...props) => { - if (this._enabled.toDevice) { - this.emit(KeyTransportEvents.ReceivedKeys, ...props); - } else { - this.logger.debug("To Device transport is disabled, ignoring received keys"); - } - }); - } - - /** Set which transport type should be used to send and receive keys.*/ - public setEnabled(enabled: { toDevice: boolean; room: boolean }): void { - if (this.enabled.toDevice !== enabled.toDevice || this.enabled.room !== enabled.room) { - this._enabled = enabled; - this.emit(RoomAndToDeviceEvents.EnabledTransportsChanged, enabled); - } - } - - /** The currently enabled transports that are used to send and receive keys.*/ - public get enabled(): EnabledTransports { - return this._enabled; - } - - public start(): void { - // always start the underlying transport since we need to enable room transport - // when someone else sends us a room key. (we need to listen to roomKeyTransport) - this.roomKeyTransport.start(); - this.toDeviceTransport.start(); - } - - public stop(): void { - // always stop since it is always running - this.roomKeyTransport.stop(); - this.toDeviceTransport.stop(); - } - - public async sendKey(keyBase64Encoded: string, index: number, members: ParticipantDeviceInfo[]): Promise { - this.logger.debug( - `Sending key with index ${index} to call members (count=${members.length}) via:` + - (this._enabled.room ? "room transport" : "") + - (this._enabled.room && this._enabled.toDevice ? "and" : "") + - (this._enabled.toDevice ? "to device transport" : ""), - ); - if (this._enabled.room) await this.roomKeyTransport.sendKey(keyBase64Encoded, index, members); - if (this._enabled.toDevice) { - try { - await this.toDeviceTransport.sendKey(keyBase64Encoded, index, members); - } catch (error) { - if (error instanceof NotSupportedError && !this._enabled.room) { - this.logger.warn( - "To device is not supported enabling room key transport, disabling toDevice transport", - ); - this.setEnabled({ toDevice: false, room: true }); - await this.sendKey(keyBase64Encoded, index, members); - } - } - } - } -}