matrix-js-sdk 41.0.0 → 41.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/lib/@types/event.d.ts +1 -1
- package/lib/@types/event.d.ts.map +1 -1
- package/lib/@types/event.js +1 -1
- package/lib/@types/event.js.map +1 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +250 -246
- package/lib/client.js.map +1 -1
- package/lib/crypto-api/index.d.ts +13 -2
- package/lib/crypto-api/index.d.ts.map +1 -1
- package/lib/crypto-api/index.js +11 -0
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/logger.d.ts +5 -5
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js.map +1 -1
- package/lib/matrixrtc/CallMembership.d.ts +49 -145
- package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
- package/lib/matrixrtc/CallMembership.js +157 -265
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/EncryptionManager.d.ts +1 -85
- package/lib/matrixrtc/EncryptionManager.d.ts.map +1 -1
- package/lib/matrixrtc/EncryptionManager.js +0 -317
- package/lib/matrixrtc/EncryptionManager.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts +18 -22
- package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +48 -76
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.d.ts +2 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +3 -2
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.d.ts +10 -4
- package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +10 -4
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.d.ts +6 -7
- package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.js +4 -7
- package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
- package/lib/matrixrtc/index.d.ts +1 -0
- package/lib/matrixrtc/index.d.ts.map +1 -1
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/common.d.ts +8 -0
- package/lib/matrixrtc/membershipData/common.d.ts.map +1 -0
- package/lib/matrixrtc/membershipData/common.js +26 -0
- package/lib/matrixrtc/membershipData/common.js.map +1 -0
- package/lib/matrixrtc/membershipData/index.d.ts +4 -0
- package/lib/matrixrtc/membershipData/index.d.ts.map +1 -0
- package/lib/matrixrtc/membershipData/index.js +20 -0
- package/lib/matrixrtc/membershipData/index.js.map +1 -0
- package/lib/matrixrtc/membershipData/rtc.d.ts +33 -0
- package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -0
- package/lib/matrixrtc/membershipData/rtc.js +137 -0
- package/lib/matrixrtc/membershipData/rtc.js.map +1 -0
- package/lib/matrixrtc/membershipData/session.d.ts +77 -0
- package/lib/matrixrtc/membershipData/session.d.ts.map +1 -0
- package/lib/matrixrtc/membershipData/session.js +62 -0
- package/lib/matrixrtc/membershipData/session.js.map +1 -0
- package/lib/matrixrtc/types.d.ts +23 -0
- package/lib/matrixrtc/types.d.ts.map +1 -1
- package/lib/matrixrtc/types.js +9 -1
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/matrixrtc/utils.d.ts +11 -1
- package/lib/matrixrtc/utils.d.ts.map +1 -1
- package/lib/matrixrtc/utils.js +24 -1
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +2 -2
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/package.json +5 -7
- package/src/@types/event.ts +2 -2
- package/src/client.ts +5 -3
- package/src/crypto-api/index.ts +17 -2
- package/src/logger.ts +5 -5
- package/src/matrixrtc/CallMembership.ts +159 -373
- package/src/matrixrtc/EncryptionManager.ts +1 -417
- package/src/matrixrtc/MatrixRTCSession.ts +82 -122
- package/src/matrixrtc/MatrixRTCSessionManager.ts +5 -3
- package/src/matrixrtc/MembershipManager.ts +14 -17
- package/src/matrixrtc/RTCEncryptionManager.ts +7 -10
- package/src/matrixrtc/index.ts +1 -0
- package/src/matrixrtc/membershipData/common.ts +27 -0
- package/src/matrixrtc/membershipData/index.ts +19 -0
- package/src/matrixrtc/membershipData/rtc.ts +156 -0
- package/src/matrixrtc/membershipData/session.ts +146 -0
- package/src/matrixrtc/types.ts +27 -1
- package/src/matrixrtc/utils.ts +24 -2
- package/src/rust-crypto/rust-crypto.ts +4 -1
- package/lib/matrixrtc/RoomKeyTransport.d.ts +0 -25
- package/lib/matrixrtc/RoomKeyTransport.d.ts.map +0 -1
- package/lib/matrixrtc/RoomKeyTransport.js +0 -152
- package/lib/matrixrtc/RoomKeyTransport.js.map +0 -1
- package/src/matrixrtc/RoomKeyTransport.ts +0 -189
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2023 -
|
|
2
|
+
Copyright 2023 - 2026 The Matrix.org Foundation C.I.C.
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -25,7 +25,7 @@ import { type ISendEventResponse } from "../@types/requests.ts";
|
|
|
25
25
|
import { CallMembership } from "./CallMembership.ts";
|
|
26
26
|
import { RoomStateEvent } from "../models/room-state.ts";
|
|
27
27
|
import { MembershipManager, StickyEventMembershipManager } from "./MembershipManager.ts";
|
|
28
|
-
import { type CallMembershipIdentityParts,
|
|
28
|
+
import { type CallMembershipIdentityParts, type IEncryptionManager } from "./EncryptionManager.ts";
|
|
29
29
|
import { logDurationSync } from "../utils.ts";
|
|
30
30
|
import type {
|
|
31
31
|
Statistics,
|
|
@@ -34,6 +34,7 @@ import type {
|
|
|
34
34
|
IRTCNotificationContent,
|
|
35
35
|
RTCCallIntent,
|
|
36
36
|
Transport,
|
|
37
|
+
SlotDescription,
|
|
37
38
|
} from "./types.ts";
|
|
38
39
|
import {
|
|
39
40
|
MembershipManagerEvent,
|
|
@@ -45,7 +46,7 @@ import { ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts";
|
|
|
45
46
|
import { TypedReEmitter } from "../ReEmitter.ts";
|
|
46
47
|
import { type IContent, type MatrixEvent } from "../models/event.ts";
|
|
47
48
|
import { RoomStickyEventsEvent, type RoomStickyEventsMap } from "../models/room-sticky-events.ts";
|
|
48
|
-
import {
|
|
49
|
+
import { computeSlotId } from "./utils.ts";
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
52
|
* Events emitted by MatrixRTCSession
|
|
@@ -96,21 +97,6 @@ export interface SessionConfig {
|
|
|
96
97
|
callIntent?: RTCCallIntent;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
/**
|
|
100
|
-
* The session description is used to identify a session. Used in the state event.
|
|
101
|
-
*/
|
|
102
|
-
export interface SlotDescription {
|
|
103
|
-
id: string;
|
|
104
|
-
application: string;
|
|
105
|
-
}
|
|
106
|
-
export function slotIdToDescription(slotId: string): SlotDescription {
|
|
107
|
-
const [application, id] = slotId.split("#");
|
|
108
|
-
return { application, id };
|
|
109
|
-
}
|
|
110
|
-
export function slotDescriptionToId(slotDescription: SlotDescription): string {
|
|
111
|
-
return `${slotDescription.application}#${slotDescription.id}`;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
100
|
// The names follow these principles:
|
|
115
101
|
// - we use the technical term delay if the option is related to delayed events.
|
|
116
102
|
// - we use delayedLeaveEvent if the option is related to the delayed leave event.
|
|
@@ -165,11 +151,6 @@ export interface MembershipConfig {
|
|
|
165
151
|
*/
|
|
166
152
|
networkErrorRetryMs?: number;
|
|
167
153
|
|
|
168
|
-
/**
|
|
169
|
-
* If true, use the new to-device transport for sending encryption keys.
|
|
170
|
-
*/
|
|
171
|
-
useExperimentalToDeviceTransport?: boolean;
|
|
172
|
-
|
|
173
154
|
/**
|
|
174
155
|
* The time (in milliseconds) after which a we consider a delayed event restart http request to have failed.
|
|
175
156
|
* Setting this to a lower value will result in more frequent retries but also a higher chance of failiour.
|
|
@@ -275,6 +256,16 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
275
256
|
|
|
276
257
|
public memberships: CallMembership[] = [];
|
|
277
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Resolves when the session has calculated the initial membership of the session.
|
|
261
|
+
*/
|
|
262
|
+
public readonly initialMembershipCalculated: Promise<void>;
|
|
263
|
+
/**
|
|
264
|
+
* Does membership need to be recalculated? This is set to false upon
|
|
265
|
+
* recalculation.
|
|
266
|
+
*/
|
|
267
|
+
private membershipNeedsRecalculation = false;
|
|
268
|
+
|
|
278
269
|
/**
|
|
279
270
|
* The statistics for this session.
|
|
280
271
|
*/
|
|
@@ -315,7 +306,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
315
306
|
* The slotId is the property that, per definition, groups memberships into one call.
|
|
316
307
|
*/
|
|
317
308
|
public get slotId(): string | undefined {
|
|
318
|
-
return
|
|
309
|
+
return computeSlotId(this.slotDescription);
|
|
319
310
|
}
|
|
320
311
|
|
|
321
312
|
/**
|
|
@@ -326,18 +317,20 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
326
317
|
*/
|
|
327
318
|
public static async sessionMembershipsForSlot(
|
|
328
319
|
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "_unstable_getStickyEvents">,
|
|
329
|
-
|
|
320
|
+
slotDescription: SlotDescription,
|
|
330
321
|
// default both true this implied we combine sticky and state events for the final call state
|
|
331
322
|
// (prefer sticky events in case of a duplicate)
|
|
332
323
|
options: SessionMembershipsForSlotOpts = DEFAULT_SESSION_MEMBERSHIPS_FOR_SLOT_OPTS,
|
|
333
324
|
): Promise<CallMembership[]> {
|
|
334
|
-
const logger = rootLogger.getChild(
|
|
325
|
+
const logger = rootLogger.getChild(
|
|
326
|
+
`[MatrixRTCSession ${room.roomId} ${slotDescription.application}#${slotDescription.id}]`,
|
|
327
|
+
);
|
|
335
328
|
const callMemberEvents = collectMembersEvents(room, options, logger);
|
|
336
329
|
|
|
337
330
|
const callMemberships = await computeBackendIdentityAndVerifyMemberEvents(
|
|
338
331
|
room,
|
|
339
332
|
callMemberEvents,
|
|
340
|
-
|
|
333
|
+
slotDescription,
|
|
341
334
|
logger,
|
|
342
335
|
);
|
|
343
336
|
|
|
@@ -389,6 +382,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
389
382
|
* @param slotDescription The slot description is a virtual address where participants are allowed to meet.
|
|
390
383
|
* This session will only manage memberships that match this slot description.Sessions are distinct if any of
|
|
391
384
|
* those properties are distinct: `roomSubset.roomId`, `slotDescription.application`, `slotDescription.id`.
|
|
385
|
+
* @param calculateMembershipsOpts - Options to configure how memberships are calculated for this session.
|
|
392
386
|
*/
|
|
393
387
|
public constructor(
|
|
394
388
|
private readonly client: Pick<
|
|
@@ -412,21 +406,27 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
412
406
|
>,
|
|
413
407
|
private roomSubset: Pick<
|
|
414
408
|
Room,
|
|
415
|
-
|
|
409
|
+
| "getLiveTimeline"
|
|
410
|
+
| "roomId"
|
|
411
|
+
| "getVersion"
|
|
412
|
+
| "hasMembershipState"
|
|
413
|
+
| "on"
|
|
414
|
+
| "off"
|
|
415
|
+
| "_unstable_getStickyEvents"
|
|
416
416
|
>,
|
|
417
417
|
|
|
418
418
|
public readonly slotDescription: SlotDescription,
|
|
419
419
|
private readonly calculateMembershipsOpts?: SessionMembershipsForSlotOpts,
|
|
420
420
|
) {
|
|
421
421
|
super();
|
|
422
|
-
this.logger = rootLogger.getChild(
|
|
422
|
+
this.logger = rootLogger.getChild(
|
|
423
|
+
`[MatrixRTCSession ${roomSubset.roomId} ${slotDescription.application}#${slotDescription.id}]`,
|
|
424
|
+
);
|
|
423
425
|
|
|
424
426
|
this.roomSubset.on(RoomStateEvent.Members, this.onRoomMemberUpdate);
|
|
425
427
|
this.roomSubset.on(RoomStickyEventsEvent.Update, this.onStickyEventUpdate);
|
|
426
428
|
|
|
427
|
-
|
|
428
|
-
// `MatrixRTCSessionEvent.MembershipsChanged` once it has completed.
|
|
429
|
-
this.ensureRecalculateSessionMembers();
|
|
429
|
+
this.initialMembershipCalculated = this.ensureRecalculateSessionMembers();
|
|
430
430
|
this.setExpiryTimer();
|
|
431
431
|
}
|
|
432
432
|
/*
|
|
@@ -500,57 +500,28 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
500
500
|
MembershipManagerEvent.DelayIdChanged,
|
|
501
501
|
]);
|
|
502
502
|
// Create Encryption manager
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
rtcBackendIdentity,
|
|
526
|
-
);
|
|
527
|
-
},
|
|
528
|
-
this.logger,
|
|
529
|
-
);
|
|
530
|
-
} else {
|
|
531
|
-
// TODO REMOVE ME!
|
|
532
|
-
transport = new RoomKeyTransport(this.roomSubset, this.client, this.statistics);
|
|
533
|
-
this.encryptionManager = new EncryptionManager(
|
|
534
|
-
ownMembershipIdentity,
|
|
535
|
-
() => this.memberships,
|
|
536
|
-
transport,
|
|
537
|
-
this.statistics,
|
|
538
|
-
(
|
|
539
|
-
keyBin: Uint8Array<ArrayBuffer>,
|
|
540
|
-
encryptionKeyIndex: number,
|
|
541
|
-
membership: CallMembershipIdentityParts,
|
|
542
|
-
rtcBackendIdentity: string,
|
|
543
|
-
) => {
|
|
544
|
-
this.emit(
|
|
545
|
-
MatrixRTCSessionEvent.EncryptionKeyChanged,
|
|
546
|
-
keyBin,
|
|
547
|
-
encryptionKeyIndex,
|
|
548
|
-
membership,
|
|
549
|
-
rtcBackendIdentity,
|
|
550
|
-
);
|
|
551
|
-
},
|
|
552
|
-
);
|
|
553
|
-
}
|
|
503
|
+
const [room, client, statistics] = [this.roomSubset, this.client, this.statistics];
|
|
504
|
+
const transport = new ToDeviceKeyTransport(ownMembershipIdentity, room.roomId, client, statistics);
|
|
505
|
+
this.encryptionManager = new RTCEncryptionManager(
|
|
506
|
+
ownMembershipIdentity,
|
|
507
|
+
() => this.memberships,
|
|
508
|
+
transport,
|
|
509
|
+
(
|
|
510
|
+
keyBin: Uint8Array<ArrayBuffer>,
|
|
511
|
+
encryptionKeyIndex: number,
|
|
512
|
+
membership: CallMembershipIdentityParts,
|
|
513
|
+
rtcBackendIdentity: string,
|
|
514
|
+
) => {
|
|
515
|
+
this.emit(
|
|
516
|
+
MatrixRTCSessionEvent.EncryptionKeyChanged,
|
|
517
|
+
keyBin,
|
|
518
|
+
encryptionKeyIndex,
|
|
519
|
+
membership,
|
|
520
|
+
rtcBackendIdentity,
|
|
521
|
+
);
|
|
522
|
+
},
|
|
523
|
+
this.logger,
|
|
524
|
+
);
|
|
554
525
|
}
|
|
555
526
|
|
|
556
527
|
this.joinConfig = joinConfig;
|
|
@@ -620,13 +591,6 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
620
591
|
return oldestMembership?.getTransport(oldestMembership);
|
|
621
592
|
}
|
|
622
593
|
|
|
623
|
-
/**
|
|
624
|
-
* The used focusActive of the oldest membership (to find out the selection type multi-sfu or oldest membership active focus)
|
|
625
|
-
* @deprecated does not work with m.rtc.member. Do not rely on it.
|
|
626
|
-
*/
|
|
627
|
-
public getActiveFocus(): Transport | undefined {
|
|
628
|
-
return this.getOldestMembership()?.getFocusActive();
|
|
629
|
-
}
|
|
630
594
|
public getOldestMembership(): CallMembership | undefined {
|
|
631
595
|
return this.memberships[0];
|
|
632
596
|
}
|
|
@@ -695,7 +659,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
695
659
|
}
|
|
696
660
|
|
|
697
661
|
if (soonestExpiry != undefined) {
|
|
698
|
-
this.expiryTimeout = setTimeout(this.ensureRecalculateSessionMembers
|
|
662
|
+
this.expiryTimeout = setTimeout(() => void this.ensureRecalculateSessionMembers(), soonestExpiry);
|
|
699
663
|
}
|
|
700
664
|
}
|
|
701
665
|
|
|
@@ -747,7 +711,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
747
711
|
* Call this when the Matrix room members have changed.
|
|
748
712
|
*/
|
|
749
713
|
private readonly onRoomMemberUpdate = (): void => {
|
|
750
|
-
this.ensureRecalculateSessionMembers();
|
|
714
|
+
void this.ensureRecalculateSessionMembers();
|
|
751
715
|
};
|
|
752
716
|
|
|
753
717
|
/**
|
|
@@ -763,7 +727,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
763
727
|
(e) => e.getType() === EventType.RTCMembership,
|
|
764
728
|
)
|
|
765
729
|
) {
|
|
766
|
-
this.ensureRecalculateSessionMembers();
|
|
730
|
+
void this.ensureRecalculateSessionMembers();
|
|
767
731
|
}
|
|
768
732
|
};
|
|
769
733
|
|
|
@@ -777,22 +741,24 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
777
741
|
};
|
|
778
742
|
|
|
779
743
|
// helper variables to make sure we do not have parallel running recalculations.
|
|
744
|
+
private recalculateSessionMembersPromise: Promise<void> = Promise.resolve();
|
|
780
745
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
this.recalculateSessionMembersDirty = false;
|
|
791
|
-
}
|
|
792
|
-
});
|
|
793
|
-
} else {
|
|
794
|
-
this.recalculateSessionMembersDirty = true;
|
|
746
|
+
/**
|
|
747
|
+
* Ensures that membership is recalculated when the state of the session may have changed.
|
|
748
|
+
* Also ensures that only one recalculation is made at a time.
|
|
749
|
+
* @returns A promise resolving when the state has been recalculated.
|
|
750
|
+
*/
|
|
751
|
+
private ensureRecalculateSessionMembers(): Promise<void> {
|
|
752
|
+
if (this.membershipNeedsRecalculation) {
|
|
753
|
+
// We have already requested recalcuation, don't attempt a new one.
|
|
754
|
+
return this.recalculateSessionMembersPromise;
|
|
795
755
|
}
|
|
756
|
+
this.membershipNeedsRecalculation = true;
|
|
757
|
+
// Chain the recalculation.
|
|
758
|
+
this.recalculateSessionMembersPromise = this.recalculateSessionMembersPromise
|
|
759
|
+
.finally()
|
|
760
|
+
.then(() => this.recalculateSessionMembers());
|
|
761
|
+
return this.recalculateSessionMembersPromise;
|
|
796
762
|
}
|
|
797
763
|
|
|
798
764
|
/**
|
|
@@ -803,11 +769,13 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
803
769
|
* This function should be called when the room members or call memberships might have changed.
|
|
804
770
|
*/
|
|
805
771
|
private readonly recalculateSessionMembers = async (): Promise<void> => {
|
|
772
|
+
// Clear the flag.
|
|
773
|
+
this.membershipNeedsRecalculation = false;
|
|
806
774
|
const oldMemberships = this.memberships;
|
|
807
775
|
|
|
808
776
|
this.memberships = await MatrixRTCSession.sessionMembershipsForSlot(
|
|
809
777
|
this.room,
|
|
810
|
-
|
|
778
|
+
this.slotDescription,
|
|
811
779
|
this.calculateMembershipsOpts,
|
|
812
780
|
);
|
|
813
781
|
|
|
@@ -857,7 +825,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
|
|
|
857
825
|
async function computeBackendIdentityAndVerifyMemberEvents(
|
|
858
826
|
room: Pick<Room, "hasMembershipState">,
|
|
859
827
|
callMemberEvents: MatrixEvent[],
|
|
860
|
-
|
|
828
|
+
slotDescription: SlotDescription,
|
|
861
829
|
logger: Logger,
|
|
862
830
|
): Promise<CallMembership[]> {
|
|
863
831
|
const callMemberships: CallMembership[] = [];
|
|
@@ -866,22 +834,14 @@ async function computeBackendIdentityAndVerifyMemberEvents(
|
|
|
866
834
|
const content = memberEvent.getContent();
|
|
867
835
|
|
|
868
836
|
// Quick filter to avoid unneeded processing of invalid events or left events.
|
|
869
|
-
// A more thorough validation will be done later with CallMembership.membershipDataFromMatrixEvent.
|
|
870
837
|
if (!quickFilterNonRelevantContents(content, logger)) {
|
|
871
838
|
continue;
|
|
872
839
|
}
|
|
873
840
|
|
|
874
841
|
try {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
const membership = new CallMembership(
|
|
878
|
-
memberEvent,
|
|
879
|
-
membershipData,
|
|
880
|
-
await CallMembership.computeRtcBackendIdentity(memberEvent, membershipData),
|
|
881
|
-
logger,
|
|
882
|
-
);
|
|
842
|
+
const membership = await CallMembership.parseFromEvent(memberEvent);
|
|
883
843
|
|
|
884
|
-
if (isValidMembership(membership, room,
|
|
844
|
+
if (isValidMembership(membership, room, slotDescription, logger)) {
|
|
885
845
|
callMemberships.push(membership);
|
|
886
846
|
}
|
|
887
847
|
} catch (e) {
|
|
@@ -914,12 +874,12 @@ function quickFilterNonRelevantContents(content: IContent, logger: Logger): bool
|
|
|
914
874
|
function isValidMembership(
|
|
915
875
|
membership: CallMembership,
|
|
916
876
|
room: Pick<Room, "hasMembershipState">,
|
|
917
|
-
|
|
877
|
+
slotDescription: SlotDescription,
|
|
918
878
|
logger: Logger,
|
|
919
879
|
): boolean {
|
|
920
|
-
if (membership.
|
|
880
|
+
if (membership.slotDescription.id !== slotDescription.id) {
|
|
921
881
|
logger.info(
|
|
922
|
-
`Ignoring membership of user ${membership.userId} for a different slot:
|
|
882
|
+
`Ignoring membership of user ${membership.userId} for a different slot. Theirs: ${JSON.stringify(membership.slotDescription)}, Expected: ${JSON.stringify(slotDescription)}`,
|
|
923
883
|
);
|
|
924
884
|
return false;
|
|
925
885
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2023 The Matrix.org Foundation C.I.C.
|
|
2
|
+
Copyright 2023-2026 The Matrix.org Foundation C.I.C.
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -20,8 +20,10 @@ import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
|
|
20
20
|
import { type Room } from "../models/room.ts";
|
|
21
21
|
import { RoomStateEvent } from "../models/room-state.ts";
|
|
22
22
|
import { type MatrixEvent } from "../models/event.ts";
|
|
23
|
-
import { MatrixRTCSession
|
|
23
|
+
import { MatrixRTCSession } from "./MatrixRTCSession.ts";
|
|
24
24
|
import { EventType } from "../@types/event.ts";
|
|
25
|
+
import { type SlotDescription } from "./types.ts";
|
|
26
|
+
import { computeSlotId } from "./utils.ts";
|
|
25
27
|
|
|
26
28
|
export enum MatrixRTCSessionManagerEvents {
|
|
27
29
|
// A member has joined the MatrixRTC session, creating an active session in a room where there wasn't previously
|
|
@@ -59,7 +61,7 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
|
|
|
59
61
|
private readonly slotDescription: SlotDescription = { application: "m.call", id: "ROOM" }, // Default to the Matrix Call application
|
|
60
62
|
) {
|
|
61
63
|
super();
|
|
62
|
-
this.logger = rootLogger.getChild(
|
|
64
|
+
this.logger = rootLogger.getChild(`[MatrixRTCSessionManager ${computeSlotId(slotDescription)}]`);
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
public start(): void {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2025 The Matrix.org Foundation C.I.C.
|
|
2
|
+
Copyright 2025-2026 The Matrix.org Foundation C.I.C.
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -22,19 +22,9 @@ import type { MatrixClient } from "../client.ts";
|
|
|
22
22
|
import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
|
|
23
23
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
|
24
24
|
import { type Room } from "../models/room.ts";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
type RtcMembershipData,
|
|
29
|
-
type SessionMembershipData,
|
|
30
|
-
} from "./CallMembership.ts";
|
|
31
|
-
import { type Transport, isMyMembership, type RTCCallIntent, Status } from "./types.ts";
|
|
32
|
-
import {
|
|
33
|
-
type SlotDescription,
|
|
34
|
-
type MembershipConfig,
|
|
35
|
-
type SessionConfig,
|
|
36
|
-
slotDescriptionToId,
|
|
37
|
-
} from "./MatrixRTCSession.ts";
|
|
25
|
+
import { type CallMembership, DEFAULT_EXPIRE_DURATION } from "./CallMembership.ts";
|
|
26
|
+
import { type Transport, isMyMembership, type RTCCallIntent, Status, type SlotDescription } from "./types.ts";
|
|
27
|
+
import { type MembershipConfig, type SessionConfig } from "./MatrixRTCSession.ts";
|
|
38
28
|
import { ActionScheduler, type ActionUpdate } from "./MembershipManagerActionScheduler.ts";
|
|
39
29
|
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
|
40
30
|
import { UnsupportedDelayedEventsEndpointError } from "../errors.ts";
|
|
@@ -43,6 +33,8 @@ import {
|
|
|
43
33
|
type IMembershipManager,
|
|
44
34
|
type MembershipManagerEventHandlerMap,
|
|
45
35
|
} from "./IMembershipManager.ts";
|
|
36
|
+
import { type RtcMembershipData, type SessionMembershipData } from "./membershipData/index.ts";
|
|
37
|
+
import { computeSlotId } from "./utils.ts";
|
|
46
38
|
import { isLivekitTransportConfig } from "./LivekitTransport.ts";
|
|
47
39
|
|
|
48
40
|
/* MembershipActionTypes:
|
|
@@ -789,13 +781,14 @@ export class MembershipManager
|
|
|
789
781
|
|
|
790
782
|
/**
|
|
791
783
|
* Constructs our own membership
|
|
784
|
+
* @returns Only returns `SessionMembershipData`
|
|
792
785
|
*/
|
|
793
786
|
protected makeMyMembership(expires: number): SessionMembershipData | RtcMembershipData {
|
|
794
787
|
const ownMembership = this.ownMembership;
|
|
795
788
|
const needsEmptyStringRoomFix =
|
|
796
789
|
this.slotDescription.application === "m.call" && this.slotDescription.id === "ROOM";
|
|
797
790
|
|
|
798
|
-
const focusObjects =
|
|
791
|
+
const focusObjects: Pick<SessionMembershipData, "foci_preferred" | "focus_active"> =
|
|
799
792
|
this.rtcTransport === undefined
|
|
800
793
|
? {
|
|
801
794
|
focus_active: { type: "livekit", focus_selection: "oldest_membership" } as const,
|
|
@@ -1099,7 +1092,11 @@ export class StickyEventMembershipManager extends MembershipManager {
|
|
|
1099
1092
|
return super.actionUpdateFromErrors(e, t, StickyEventMembershipManager.nameMap.get(m) ?? "unknown");
|
|
1100
1093
|
}
|
|
1101
1094
|
|
|
1102
|
-
|
|
1095
|
+
/**
|
|
1096
|
+
*
|
|
1097
|
+
* @returns Only returns `RtcMembershipData`
|
|
1098
|
+
*/
|
|
1099
|
+
protected makeMyMembership(): RtcMembershipData {
|
|
1103
1100
|
const ownMembership = this.ownMembership;
|
|
1104
1101
|
|
|
1105
1102
|
const livekitTransport = isLivekitTransportConfig(this.rtcTransport) ? this.rtcTransport : undefined;
|
|
@@ -1111,7 +1108,7 @@ export class StickyEventMembershipManager extends MembershipManager {
|
|
|
1111
1108
|
type: this.slotDescription.application,
|
|
1112
1109
|
...(this.callIntent ? { "m.call.intent": this.callIntent } : {}),
|
|
1113
1110
|
},
|
|
1114
|
-
slot_id:
|
|
1111
|
+
slot_id: computeSlotId(this.slotDescription),
|
|
1115
1112
|
// Make sure we do not add the alias to the transport.
|
|
1116
1113
|
// It is not needed in matrix2.0. The additional session information will be used to find the right alias on the sfu.
|
|
1117
1114
|
rtc_transports: livekitTransport
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2025 The Matrix.org Foundation C.I.C.
|
|
2
|
+
Copyright 2025-2026 The Matrix.org Foundation C.I.C.
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
type IEncryptionManager,
|
|
21
21
|
} from "./EncryptionManager.ts";
|
|
22
22
|
import { type EncryptionConfig, type MembershipConfig } from "./MatrixRTCSession.ts";
|
|
23
|
-
import { CallMembership } from "./CallMembership.ts";
|
|
23
|
+
import type { CallMembership } from "./CallMembership.ts";
|
|
24
24
|
import { decodeBase64, encodeBase64 } from "../base64.ts";
|
|
25
25
|
import { type IKeyTransport, type KeyTransportEventListener, KeyTransportEvents } from "./IKeyTransport.ts";
|
|
26
26
|
import { type Logger } from "../logger.ts";
|
|
@@ -30,9 +30,9 @@ import {
|
|
|
30
30
|
type InboundEncryptionSession,
|
|
31
31
|
type OutboundEncryptionSession,
|
|
32
32
|
type ParticipantDeviceInfo,
|
|
33
|
-
type Statistics,
|
|
34
33
|
} from "./types.ts";
|
|
35
34
|
import { OutdatedKeyFilter } from "./utils.ts";
|
|
35
|
+
import { computeRtcIdentityRaw } from "./membershipData/rtc.ts";
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* RTCEncryptionManager is used to manage the encryption keys for a call.
|
|
@@ -58,7 +58,7 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
58
58
|
* The encryption manager stores the keys because the application layer might not be ready yet to handle the keys.
|
|
59
59
|
* The keys are stored and can be retrieved later when the application layer is ready {@link RTCEncryptionManager#getEncryptionKeys}.
|
|
60
60
|
*/
|
|
61
|
-
private participantKeyRings = new Map<
|
|
61
|
+
private readonly participantKeyRings = new Map<
|
|
62
62
|
EncryptionKeyMapKey,
|
|
63
63
|
Array<{
|
|
64
64
|
key: Uint8Array<ArrayBuffer>;
|
|
@@ -111,7 +111,7 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
111
111
|
|
|
112
112
|
private logger: Logger | undefined = undefined;
|
|
113
113
|
|
|
114
|
-
private rtcIdentityProvider: (userId: string, deviceId: string, memberId: string) => Promise<string>;
|
|
114
|
+
private readonly rtcIdentityProvider: (userId: string, deviceId: string, memberId: string) => Promise<string>;
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
*
|
|
@@ -124,10 +124,9 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
124
124
|
* @param rtcBackendIdProvider - A function to compute the rtc backend identity, exposed for testing purposes
|
|
125
125
|
*/
|
|
126
126
|
public constructor(
|
|
127
|
-
private ownMembership: CallMembershipIdentityParts,
|
|
127
|
+
private readonly ownMembership: CallMembershipIdentityParts,
|
|
128
128
|
private getMemberships: () => CallMembership[],
|
|
129
129
|
private transport: IKeyTransport,
|
|
130
|
-
private statistics: Statistics,
|
|
131
130
|
// Callback to notify the media layer of new keys
|
|
132
131
|
private onEncryptionKeysChanged: (
|
|
133
132
|
keyBin: Uint8Array<ArrayBuffer>,
|
|
@@ -139,7 +138,7 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
139
138
|
rtcBackendIdProvider?: (userId: string, deviceId: string, memberId: string) => Promise<string>,
|
|
140
139
|
) {
|
|
141
140
|
this.logger = parentLogger?.getChild(`[EncryptionManager]`);
|
|
142
|
-
this.rtcIdentityProvider = rtcBackendIdProvider ??
|
|
141
|
+
this.rtcIdentityProvider = rtcBackendIdProvider ?? computeRtcIdentityRaw;
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
private async getOwnRtcBackendIdentity(): Promise<string> {
|
|
@@ -296,7 +295,6 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
296
295
|
candidateInboundSession.keyIndex,
|
|
297
296
|
candidateInboundSession.membership,
|
|
298
297
|
);
|
|
299
|
-
this.statistics.counters.roomEventEncryptionKeysReceived += 1;
|
|
300
298
|
} else {
|
|
301
299
|
this.logger?.info(
|
|
302
300
|
`Received an out of order key for ${membership.userId}:${membership.deviceId}, dropping it`,
|
|
@@ -410,7 +408,6 @@ export class RTCEncryptionManager implements IEncryptionManager {
|
|
|
410
408
|
try {
|
|
411
409
|
this.logger?.trace(`Sending key...`);
|
|
412
410
|
await this.transport.sendKey(encodeBase64(outboundKey.key), outboundKey.keyId, toDistributeTo);
|
|
413
|
-
this.statistics.counters.roomEventEncryptionKeysSent += 1;
|
|
414
411
|
outboundKey.sharedWith.push(...toDistributeTo);
|
|
415
412
|
this.logger?.trace(
|
|
416
413
|
`key index:${outboundKey.keyId} sent to ${outboundKey.sharedWith.map((m) => `${m.userId}:${m.deviceId}`).join(",")}`,
|
package/src/matrixrtc/index.ts
CHANGED
|
@@ -19,5 +19,6 @@ export * from "./LivekitTransport.ts";
|
|
|
19
19
|
export * from "./MatrixRTCSession.ts";
|
|
20
20
|
export * from "./MatrixRTCSessionManager.ts";
|
|
21
21
|
export type * from "./types.ts";
|
|
22
|
+
export { type SessionMembershipData, type RtcMembershipData } from "./membershipData/index.ts";
|
|
22
23
|
export { Status, parseCallNotificationContent, isMyMembership } from "./types.ts";
|
|
23
24
|
export { MembershipManagerEvent } from "./IMembershipManager.ts";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 The Matrix.org Foundation C.I.C.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Thrown when an event is not valid for use with MatrixRTC.
|
|
19
|
+
*/
|
|
20
|
+
export class MatrixRTCMembershipParseError extends AggregateError {
|
|
21
|
+
public constructor(
|
|
22
|
+
public readonly type: string,
|
|
23
|
+
errors: string[],
|
|
24
|
+
) {
|
|
25
|
+
super(errors, `Does not match ${type}:\n${errors.join("\n")}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 The Matrix.org Foundation C.I.C.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { type SessionMembershipData, checkSessionsMembershipData } from "./session.ts";
|
|
18
|
+
export { type RtcMembershipData, computeRtcIdentityRaw, checkRtcMembershipData } from "./rtc.ts";
|
|
19
|
+
export { MatrixRTCMembershipParseError } from "./common.ts";
|