matrix-js-sdk 42.4.0 → 43.0.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 +23 -0
- package/lib/@types/PushRules.d.ts +3 -1
- package/lib/@types/PushRules.d.ts.map +1 -1
- package/lib/@types/PushRules.js +2 -0
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/event.d.ts +1 -0
- package/lib/@types/event.d.ts.map +1 -1
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js.map +1 -1
- package/lib/client.d.ts +88 -37
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +72 -47
- package/lib/client.js.map +1 -1
- package/lib/crypto-api/index.d.ts +3 -3
- package/lib/crypto-api/index.d.ts.map +1 -1
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/embedded.d.ts +17 -1
- package/lib/embedded.d.ts.map +1 -1
- package/lib/embedded.js +46 -1
- package/lib/embedded.js.map +1 -1
- package/lib/errors.d.ts +1 -1
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +2 -2
- package/lib/errors.js.map +1 -1
- package/lib/http-api/fetch.d.ts +7 -1
- package/lib/http-api/fetch.d.ts.map +1 -1
- package/lib/http-api/fetch.js +14 -5
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/http-api/interface.d.ts +34 -8
- package/lib/http-api/interface.d.ts.map +1 -1
- package/lib/http-api/interface.js +10 -3
- package/lib/http-api/interface.js.map +1 -1
- package/lib/http-api/refresh.d.ts +30 -11
- package/lib/http-api/refresh.d.ts.map +1 -1
- package/lib/http-api/refresh.js +72 -5
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/matrix.d.ts +1 -1
- package/lib/matrix.d.ts.map +1 -1
- package/lib/matrix.js.map +1 -1
- package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
- package/lib/matrixrtc/CallMembership.js +20 -6
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/IMembershipManager.d.ts +5 -0
- package/lib/matrixrtc/IMembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/IMembershipManager.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts +27 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +58 -36
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.d.ts +76 -0
- package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +264 -47
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/index.d.ts +1 -1
- package/lib/matrixrtc/index.d.ts.map +1 -1
- package/lib/matrixrtc/index.js +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 -1
- package/lib/matrixrtc/membershipData/common.js +10 -0
- package/lib/matrixrtc/membershipData/common.js.map +1 -1
- package/lib/matrixrtc/membershipData/index.d.ts +1 -1
- package/lib/matrixrtc/membershipData/index.d.ts.map +1 -1
- package/lib/matrixrtc/membershipData/index.js +1 -1
- package/lib/matrixrtc/membershipData/index.js.map +1 -1
- package/lib/matrixrtc/types.d.ts +104 -11
- package/lib/matrixrtc/types.d.ts.map +1 -1
- package/lib/matrixrtc/types.js +263 -19
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/matrixrtc/utils.d.ts +22 -1
- package/lib/matrixrtc/utils.d.ts.map +1 -1
- package/lib/matrixrtc/utils.js +38 -0
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/room-sticky-events.d.ts +7 -0
- package/lib/models/room-sticky-events.d.ts.map +1 -1
- package/lib/models/room-sticky-events.js +27 -0
- package/lib/models/room-sticky-events.js.map +1 -1
- package/lib/models/thread.d.ts.map +1 -1
- package/lib/models/thread.js +8 -0
- package/lib/models/thread.js.map +1 -1
- package/lib/oauth/authorize.js +1 -1
- package/lib/oauth/authorize.js.map +1 -1
- package/lib/oauth/index.d.ts +3 -5
- package/lib/oauth/index.d.ts.map +1 -1
- package/lib/oauth/index.js +7 -7
- package/lib/oauth/index.js.map +1 -1
- package/lib/oauth/tokenRefresher.d.ts +10 -4
- package/lib/oauth/tokenRefresher.d.ts.map +1 -1
- package/lib/oauth/tokenRefresher.js +34 -24
- package/lib/oauth/tokenRefresher.js.map +1 -1
- package/lib/receipt-accumulator.d.ts +10 -11
- package/lib/receipt-accumulator.d.ts.map +1 -1
- package/lib/receipt-accumulator.js +26 -25
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/room-summary-api.d.ts +71 -0
- package/lib/room-summary-api.d.ts.map +1 -0
- package/lib/room-summary-api.js +82 -0
- package/lib/room-summary-api.js.map +1 -0
- package/lib/rust-crypto/backup.d.ts +7 -0
- package/lib/rust-crypto/backup.d.ts.map +1 -1
- package/lib/rust-crypto/backup.js +41 -25
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +6 -1
- package/lib/sync.js.map +1 -1
- package/package.json +6 -6
- package/src/@types/PushRules.ts +2 -0
- package/src/@types/event.ts +1 -1
- package/src/@types/matrix-sdk-crypto-wasm.d.ts +15 -12
- package/src/client.ts +105 -62
- package/src/crypto-api/index.ts +3 -3
- package/src/embedded.ts +61 -2
- package/src/errors.ts +2 -1
- package/src/http-api/fetch.ts +14 -5
- package/src/http-api/interface.ts +36 -8
- package/src/http-api/refresh.ts +101 -17
- package/src/matrix.ts +1 -1
- package/src/matrixrtc/CallMembership.ts +22 -4
- package/src/matrixrtc/IMembershipManager.ts +6 -0
- package/src/matrixrtc/MatrixRTCSession.ts +72 -49
- package/src/matrixrtc/MatrixRTCSessionManager.ts +1 -1
- package/src/matrixrtc/MembershipManager.ts +284 -61
- package/src/matrixrtc/index.ts +7 -1
- package/src/matrixrtc/membershipData/common.ts +12 -0
- package/src/matrixrtc/membershipData/index.ts +1 -1
- package/src/matrixrtc/types.ts +351 -23
- package/src/matrixrtc/utils.ts +54 -1
- package/src/models/room-sticky-events.ts +26 -1
- package/src/models/thread.ts +9 -0
- package/src/oauth/authorize.ts +1 -1
- package/src/oauth/index.ts +7 -8
- package/src/oauth/tokenRefresher.ts +15 -5
- package/src/receipt-accumulator.ts +30 -26
- package/src/room-summary-api.ts +114 -0
- package/src/rust-crypto/backup.ts +46 -33
- package/src/sync.ts +9 -1
package/lib/matrixrtc/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IMentions } from "../matrix.ts";
|
|
2
2
|
import type { RelationEvent } from "../types.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { MatrixEvent } from "../models/event.ts";
|
|
4
|
+
import type { Room } from "../models/room.ts";
|
|
5
|
+
import { CallMembership } from "./CallMembership.ts";
|
|
4
6
|
import { type CallMembershipIdentityParts } from "./EncryptionManager.ts";
|
|
5
7
|
export type EncryptionKeyMapKey = string;
|
|
6
8
|
export interface EncryptionKeyEntry {
|
|
@@ -79,32 +81,122 @@ export type RTCNotificationType = "ring" | "notification";
|
|
|
79
81
|
*/
|
|
80
82
|
export type RTCCallIntent = "audio" | "video" | string;
|
|
81
83
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* @
|
|
86
|
-
* @returns a parsed IRTCNotificationContent
|
|
84
|
+
* The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.
|
|
85
|
+
*
|
|
86
|
+
* Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.
|
|
87
|
+
* @internal
|
|
87
88
|
*/
|
|
88
|
-
export declare
|
|
89
|
+
export declare const RTC_NOTIFICATION_MAX_LIFETIME_MS: number;
|
|
90
|
+
/**
|
|
91
|
+
* The maximum amount by which a notification's `sender_ts` may lie ahead of its `origin_server_ts`
|
|
92
|
+
* before the `lifetime` is measured from `origin_server_ts` instead, as per MSC4075.
|
|
93
|
+
*
|
|
94
|
+
* Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
export declare const RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS: number;
|
|
98
|
+
/**
|
|
99
|
+
* The context that is needed to evaluate the MSC4075 rules for receiving notifications.
|
|
100
|
+
*/
|
|
101
|
+
export interface RTCNotificationValidationContext {
|
|
102
|
+
/** The room in which the notification was received. */
|
|
103
|
+
room: Pick<Room, "getLiveTimeline" | "getUnfilteredTimelineSet" | "_unstable_getStickyEvents" | "_unstable_getKeyedStickyEvent">;
|
|
104
|
+
/** The user ID of the receiving (local) user. */
|
|
105
|
+
userId: string;
|
|
106
|
+
/** The current time in milliseconds since the epoch. Defaults to `Date.now()`. */
|
|
107
|
+
now?: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Computes the absolute timestamp at which an RTC notification stops being valid, as per MSC4075.
|
|
111
|
+
*
|
|
112
|
+
* The `lifetime` is measured from `sender_ts` unless `sender_ts` lies more than 20 seconds ahead of
|
|
113
|
+
* `origin_server_ts`, in which case it is measured from `origin_server_ts` instead. Regardless of the basis,
|
|
114
|
+
* the remaining lifetime is capped at 2 minutes.
|
|
115
|
+
*
|
|
116
|
+
* @param content The notification content.
|
|
117
|
+
* @param originServerTs The `origin_server_ts` of the notification event.
|
|
118
|
+
* @param now The current time in milliseconds since the epoch. Defaults to `Date.now()`.
|
|
119
|
+
* @returns The timestamp (in milliseconds since the epoch) at which the notification expires.
|
|
120
|
+
*/
|
|
121
|
+
export declare function getCallNotificationExpiry(content: Pick<IRTCNotificationContent, "sender_ts" | "lifetime">, originServerTs: number, now?: number): number;
|
|
122
|
+
/**
|
|
123
|
+
* The subset of a notification event that {@link parseCallNotificationContent} needs.
|
|
124
|
+
*/
|
|
125
|
+
type RTCNotificationEvent = Pick<MatrixEvent, "getContent" | "getId" | "getSender" | "getTs" | "getType" | "unstableStickyInfo">;
|
|
126
|
+
/**
|
|
127
|
+
* Parses the content of a received `org.matrix.msc4075.rtc.notification` event.
|
|
128
|
+
*
|
|
129
|
+
* This checks that the content matches the schema of MSC4075, caps `lifetime` to 2 minutes and applies
|
|
130
|
+
* the rules for receiving invites from MSC4075.
|
|
131
|
+
* The notification is only considered valid if all of the following hold:
|
|
132
|
+
* - It wasn't sent by the receiving user.
|
|
133
|
+
* - It is the current entry in the room's sticky event map for its sender and slot and isn't a withdrawal.
|
|
134
|
+
* - The slot it refers to exists and is open.
|
|
135
|
+
* - Its lifetime hasn't elapsed (see {@link getCallNotificationExpiry}).
|
|
136
|
+
* - Its `m.mentions` target the receiving user, either directly or via a room mention that the sender is
|
|
137
|
+
* allowed to trigger.
|
|
138
|
+
* - The receiving user has no joined `m.rtc.member` event for the slot in the sticky event map.
|
|
139
|
+
* - Any left `m.rtc.member` event of the receiving user for the slot predates the notification.
|
|
140
|
+
* - The receiving user has no sticky decline event referencing the notification.
|
|
141
|
+
*
|
|
142
|
+
* @param event The notification event.
|
|
143
|
+
* @param context The context needed to evaluate the receiving rules.
|
|
144
|
+
* @throws if the content is malformed or the notification isn't valid.
|
|
145
|
+
* @returns A promise resolving to the parsed content.
|
|
146
|
+
*/
|
|
147
|
+
export declare function parseCallNotificationContent(event: RTCNotificationEvent, context: RTCNotificationValidationContext): Promise<IRTCNotificationContent>;
|
|
89
148
|
/**
|
|
90
149
|
* Interface for `org.matrix.msc4075.rtc.notification` events.
|
|
91
150
|
* Don't cast event content to this directly. Use `parseCallNotificationContent` instead to validate the content first.
|
|
92
151
|
*/
|
|
93
152
|
export interface IRTCNotificationContent extends RelationEvent {
|
|
94
|
-
"m.mentions"?: IMentions;
|
|
95
|
-
"notification_type": RTCNotificationType;
|
|
96
153
|
/**
|
|
97
|
-
* The
|
|
154
|
+
* The `state_key` of the `m.rtc.slot` event that the notification refers to.
|
|
155
|
+
*
|
|
156
|
+
* Notifications predating this property omit it. `parseCallNotificationContent` fills it in from the
|
|
157
|
+
* referenced membership event, so the parsed content always carries it.
|
|
158
|
+
*/
|
|
159
|
+
"slot_id": string;
|
|
160
|
+
/**
|
|
161
|
+
* The users targeted by the notification. Must either mention the room or at least one user.
|
|
162
|
+
*/
|
|
163
|
+
"m.mentions": IMentions;
|
|
164
|
+
/**
|
|
165
|
+
* @deprecated Not part of MSC4075 anymore. How to present a notification is up to the receiving client.
|
|
166
|
+
*/
|
|
167
|
+
"notification_type"?: RTCNotificationType;
|
|
168
|
+
/**
|
|
169
|
+
* @deprecated Not part of MSC4075 anymore. The initial intent of the calling user.
|
|
98
170
|
*/
|
|
99
171
|
"m.call.intent"?: RTCCallIntent;
|
|
172
|
+
/**
|
|
173
|
+
* The timestamp (in milliseconds since the epoch) at which the sending client created the event.
|
|
174
|
+
*/
|
|
100
175
|
"sender_ts": number;
|
|
176
|
+
/**
|
|
177
|
+
* The time (in milliseconds) that the notification is valid for, measured from `sender_ts`.
|
|
178
|
+
*/
|
|
101
179
|
"lifetime": number;
|
|
180
|
+
/**
|
|
181
|
+
* The sticky key as per MSC4354. Must be equal to `slot_id`.
|
|
182
|
+
*
|
|
183
|
+
* Optional because notifications predating MSC4354 omit it.
|
|
184
|
+
*/
|
|
185
|
+
"msc4354_sticky_key"?: string;
|
|
102
186
|
}
|
|
103
187
|
/**
|
|
104
188
|
* MSC4310 decline event content for `org.matrix.msc4310.rtc.decline`.
|
|
105
189
|
* Sent as a standard m.reference relation to an `org.matrix.msc4075.rtc.notification` event.
|
|
106
190
|
*/
|
|
107
191
|
export interface IRTCDeclineContent extends RelationEvent {
|
|
192
|
+
/**
|
|
193
|
+
* The sticky key as per MSC4354. Must be equal to the event ID of the notification being declined.
|
|
194
|
+
*
|
|
195
|
+
* Optional because servers without MSC4354 support can't deliver the decline as a sticky event. Such a
|
|
196
|
+
* decline still counts, but only for devices that receive it directly, since it isn't re-delivered after
|
|
197
|
+
* a gappy or initial sync.
|
|
198
|
+
*/
|
|
199
|
+
msc4354_sticky_key?: string;
|
|
108
200
|
}
|
|
109
201
|
export declare enum Status {
|
|
110
202
|
Disconnected = "Disconnected",
|
|
@@ -179,4 +271,5 @@ export interface SlotDescription {
|
|
|
179
271
|
*/
|
|
180
272
|
id: string;
|
|
181
273
|
}
|
|
274
|
+
export {};
|
|
182
275
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/types.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/types.ts"],"names":[],"mappings":"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"}
|
package/lib/matrixrtc/types.js
CHANGED
|
@@ -15,6 +15,12 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { EventTimeline } from "../models/event-timeline.js";
|
|
19
|
+
import { EventType, RelationType } from "../@types/event.js";
|
|
20
|
+
import { CallMembership } from "./CallMembership.js";
|
|
21
|
+
import { isLeftMembershipContent } from "./membershipData/index.js";
|
|
22
|
+
import { isSlotOpen, slotIdToDescription } from "./utils.js";
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* The mxID, deviceId and membership timestamp of a RTC session participant.
|
|
20
26
|
*/
|
|
@@ -45,35 +51,273 @@ limitations under the License.
|
|
|
45
51
|
*/
|
|
46
52
|
|
|
47
53
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @
|
|
52
|
-
|
|
54
|
+
* The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.
|
|
55
|
+
*
|
|
56
|
+
* Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export const RTC_NOTIFICATION_MAX_LIFETIME_MS = 2 * 60 * 1000; // 2 minutes
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The maximum amount by which a notification's `sender_ts` may lie ahead of its `origin_server_ts`
|
|
63
|
+
* before the `lifetime` is measured from `origin_server_ts` instead, as per MSC4075.
|
|
64
|
+
*
|
|
65
|
+
* Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
export const RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS = 20 * 1000; // 20 seconds
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The context that is needed to evaluate the MSC4075 rules for receiving notifications.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Computes the absolute timestamp at which an RTC notification stops being valid, as per MSC4075.
|
|
76
|
+
*
|
|
77
|
+
* The `lifetime` is measured from `sender_ts` unless `sender_ts` lies more than 20 seconds ahead of
|
|
78
|
+
* `origin_server_ts`, in which case it is measured from `origin_server_ts` instead. Regardless of the basis,
|
|
79
|
+
* the remaining lifetime is capped at 2 minutes.
|
|
80
|
+
*
|
|
81
|
+
* @param content The notification content.
|
|
82
|
+
* @param originServerTs The `origin_server_ts` of the notification event.
|
|
83
|
+
* @param now The current time in milliseconds since the epoch. Defaults to `Date.now()`.
|
|
84
|
+
* @returns The timestamp (in milliseconds since the epoch) at which the notification expires.
|
|
85
|
+
*/
|
|
86
|
+
export function getCallNotificationExpiry(content, originServerTs, now = Date.now()) {
|
|
87
|
+
const basis = content.sender_ts - originServerTs > RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS ? originServerTs : content.sender_ts;
|
|
88
|
+
return Math.min(basis + content.lifetime, now + RTC_NOTIFICATION_MAX_LIFETIME_MS);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The subset of a notification event that {@link parseCallNotificationContent} needs.
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Whether the content marks a withdrawn sticky event (MSC4354), i.e. it is empty apart from the sticky key.
|
|
97
|
+
*/
|
|
98
|
+
function isWithdrawal(content) {
|
|
99
|
+
return Object.keys(content).every(key => key === "msc4354_sticky_key");
|
|
100
|
+
}
|
|
101
|
+
function isNonNegativeInteger(value) {
|
|
102
|
+
return Number.isInteger(value) && value >= 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Looks up a legacy `m.call.member` state event by ID in the room's current state.
|
|
107
|
+
*
|
|
108
|
+
* @returns The event, or `undefined` if no current membership state event has that ID.
|
|
109
|
+
*/
|
|
110
|
+
function findMembershipStateEvent(room, eventId) {
|
|
111
|
+
const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
112
|
+
return roomState?.getStateEvents(EventType.GroupCallMemberPrefix).find(event => event.getId() === eventId);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Determines the ID of the slot that a notification invites to.
|
|
117
|
+
*
|
|
118
|
+
* Notifications predating the `slot_id` property instead carry an `m.reference` relation to the sender's
|
|
119
|
+
* membership event.
|
|
120
|
+
*
|
|
121
|
+
* @throws if the slot can't be determined.
|
|
122
|
+
* @returns A promise resolving to the slot ID.
|
|
123
|
+
*/
|
|
124
|
+
async function resolveSlotId(content, room) {
|
|
125
|
+
if (typeof content["slot_id"] === "string") {
|
|
126
|
+
// Throws if the ID is malformed, e.g. because it contains more than one "#".
|
|
127
|
+
slotIdToDescription(content["slot_id"]);
|
|
128
|
+
return content["slot_id"];
|
|
129
|
+
}
|
|
130
|
+
if (content["slot_id"] !== undefined) throw new Error("Invalid slot_id");
|
|
131
|
+
const relation = content["m.relates_to"];
|
|
132
|
+
const membershipEventId = relation?.rel_type === RelationType.Reference ? relation.event_id : undefined;
|
|
133
|
+
if (typeof membershipEventId !== "string") {
|
|
134
|
+
throw new Error("Missing slot_id and no m.reference relation to derive it from");
|
|
135
|
+
}
|
|
136
|
+
const membershipEvent = findMembershipStateEvent(room, membershipEventId);
|
|
137
|
+
if (!membershipEvent) {
|
|
138
|
+
throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a current membership`);
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
return (await CallMembership.parseFromEvent(membershipEvent)).slotId;
|
|
142
|
+
} catch (cause) {
|
|
143
|
+
throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a valid membership`, {
|
|
144
|
+
cause
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Parses the content of a received `org.matrix.msc4075.rtc.notification` event.
|
|
151
|
+
*
|
|
152
|
+
* This checks that the content matches the schema of MSC4075, caps `lifetime` to 2 minutes and applies
|
|
153
|
+
* the rules for receiving invites from MSC4075.
|
|
154
|
+
* The notification is only considered valid if all of the following hold:
|
|
155
|
+
* - It wasn't sent by the receiving user.
|
|
156
|
+
* - It is the current entry in the room's sticky event map for its sender and slot and isn't a withdrawal.
|
|
157
|
+
* - The slot it refers to exists and is open.
|
|
158
|
+
* - Its lifetime hasn't elapsed (see {@link getCallNotificationExpiry}).
|
|
159
|
+
* - Its `m.mentions` target the receiving user, either directly or via a room mention that the sender is
|
|
160
|
+
* allowed to trigger.
|
|
161
|
+
* - The receiving user has no joined `m.rtc.member` event for the slot in the sticky event map.
|
|
162
|
+
* - Any left `m.rtc.member` event of the receiving user for the slot predates the notification.
|
|
163
|
+
* - The receiving user has no sticky decline event referencing the notification.
|
|
164
|
+
*
|
|
165
|
+
* @param event The notification event.
|
|
166
|
+
* @param context The context needed to evaluate the receiving rules.
|
|
167
|
+
* @throws if the content is malformed or the notification isn't valid.
|
|
168
|
+
* @returns A promise resolving to the parsed content.
|
|
53
169
|
*/
|
|
54
|
-
export function parseCallNotificationContent(
|
|
55
|
-
if (
|
|
56
|
-
throw new Error(
|
|
170
|
+
export async function parseCallNotificationContent(event, context) {
|
|
171
|
+
if (event.getType() !== EventType.RTCNotification) {
|
|
172
|
+
throw new Error(`Event ${event.getId()} is not an ${EventType.RTCNotification} event`);
|
|
57
173
|
}
|
|
58
|
-
|
|
59
|
-
|
|
174
|
+
const content = event.getContent();
|
|
175
|
+
if (isWithdrawal(content)) {
|
|
176
|
+
throw new Error("Notification was withdrawn");
|
|
60
177
|
}
|
|
61
|
-
|
|
178
|
+
const slotId = await resolveSlotId(content, context.room);
|
|
179
|
+
// The sticky key is only validated when present. A notification predating it can still be valid, and one
|
|
180
|
+
// carrying the wrong key is filed under that key in the sticky event map, so the lookup below rejects it.
|
|
181
|
+
if (content["msc4354_sticky_key"] !== undefined && content["msc4354_sticky_key"] !== slotId) {
|
|
182
|
+
throw new Error("msc4354_sticky_key must be equal to slot_id");
|
|
183
|
+
}
|
|
184
|
+
if (!isNonNegativeInteger(content["sender_ts"])) {
|
|
62
185
|
throw new Error("Missing or invalid sender_ts");
|
|
63
186
|
}
|
|
64
|
-
if (
|
|
187
|
+
if (!isNonNegativeInteger(content["lifetime"])) {
|
|
65
188
|
throw new Error("Missing or invalid lifetime");
|
|
66
189
|
}
|
|
67
|
-
|
|
68
|
-
|
|
190
|
+
const mentions = content["m.mentions"];
|
|
191
|
+
if (typeof mentions !== "object" || mentions === null) {
|
|
192
|
+
throw new Error("Missing or malformed m.mentions");
|
|
193
|
+
}
|
|
194
|
+
if (mentions.room !== undefined && typeof mentions.room !== "boolean") {
|
|
195
|
+
throw new Error("malformed m.mentions.room");
|
|
196
|
+
}
|
|
197
|
+
if (mentions.user_ids !== undefined && (!Array.isArray(mentions.user_ids) || !mentions.user_ids.every(userId => typeof userId === "string"))) {
|
|
198
|
+
throw new Error("malformed m.mentions.user_ids");
|
|
69
199
|
}
|
|
70
|
-
if (
|
|
71
|
-
throw new Error("
|
|
200
|
+
if (mentions.room !== true && !mentions.user_ids?.length) {
|
|
201
|
+
throw new Error("m.mentions must target either the room or at least one user");
|
|
72
202
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
lifetime:
|
|
203
|
+
const parsed = _objectSpread(_objectSpread({}, content), {}, {
|
|
204
|
+
slot_id: slotId,
|
|
205
|
+
lifetime: Math.min(content["lifetime"], RTC_NOTIFICATION_MAX_LIFETIME_MS)
|
|
76
206
|
});
|
|
207
|
+
await checkCallNotificationReceivingRules(parsed, event, context);
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Applies the MSC4075 rules for receiving invites to an already schema-validated notification.
|
|
213
|
+
* @throws if any of the rules is violated.
|
|
214
|
+
*/
|
|
215
|
+
async function checkCallNotificationReceivingRules(content, event, {
|
|
216
|
+
room,
|
|
217
|
+
userId,
|
|
218
|
+
now = Date.now()
|
|
219
|
+
}) {
|
|
220
|
+
const eventId = event.getId();
|
|
221
|
+
const sender = event.getSender();
|
|
222
|
+
if (eventId === undefined || sender === undefined) {
|
|
223
|
+
throw new Error("Notification event is missing its event ID or sender");
|
|
224
|
+
}
|
|
225
|
+
const originServerTs = event.getTs();
|
|
226
|
+
const slotId = content.slot_id;
|
|
227
|
+
if (sender === userId) {
|
|
228
|
+
throw new Error("Notification was sent by the receiving user");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// A notification that wasn't delivered as a sticky event can't be superseded or withdrawn, so there is
|
|
232
|
+
// nothing to check. It isn't in the sticky event map either, which is why this can't be checked blindly.
|
|
233
|
+
if (event.unstableStickyInfo !== undefined) {
|
|
234
|
+
if (room._unstable_getKeyedStickyEvent(sender, event.getType(), slotId)?.getId() !== eventId) {
|
|
235
|
+
throw new Error("Notification is not the current sticky event for its sender and slot");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// `isSlotOpen` returns undefined when no slot event exists at all, which is just as disqualifying.
|
|
240
|
+
if (!isSlotOpen(room, slotIdToDescription(slotId))) {
|
|
241
|
+
throw new Error(`Slot ${slotId} does not exist or is closed`);
|
|
242
|
+
}
|
|
243
|
+
const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
244
|
+
if (now >= getCallNotificationExpiry(content, originServerTs, now)) {
|
|
245
|
+
throw new Error("Notification has expired");
|
|
246
|
+
}
|
|
247
|
+
const mentions = content["m.mentions"];
|
|
248
|
+
const mentionsUser = mentions.user_ids?.includes(userId) ?? false;
|
|
249
|
+
const mentionsRoom = mentions.room === true && (roomState?.mayTriggerNotifOfType("room", sender) ?? false);
|
|
250
|
+
if (!mentionsUser && !mentionsRoom) {
|
|
251
|
+
throw new Error("Notification does not mention the receiving user");
|
|
252
|
+
}
|
|
253
|
+
for (const membershipEvent of ownMembershipEvents(room, userId)) {
|
|
254
|
+
const membershipContent = membershipEvent.getContent();
|
|
255
|
+
if (isLeftMembershipContent(membershipContent)) {
|
|
256
|
+
if (membershipContent.slot_id === slotId && membershipEvent.getTs() >= originServerTs) {
|
|
257
|
+
throw new Error(`Receiving user left slot ${slotId} after the notification was sent`);
|
|
258
|
+
}
|
|
259
|
+
} else if (await isJoinedToSlot(membershipEvent, slotId, now)) {
|
|
260
|
+
throw new Error(`Receiving user is already joined to slot ${slotId}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (hasDeclined(room, userId, eventId)) {
|
|
264
|
+
throw new Error("Receiving user declined the notification");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Yields the receiving user's own MatrixRTC membership events, from both the sticky event map and the legacy
|
|
270
|
+
* member state events. Sessions that don't use sticky events keep membership in state, so both have to be
|
|
271
|
+
* consulted to tell whether the user is in a session.
|
|
272
|
+
*
|
|
273
|
+
* @yields the user's own `m.rtc.member` and `m.call.member` events.
|
|
274
|
+
*/
|
|
275
|
+
function* ownMembershipEvents(room, userId) {
|
|
276
|
+
for (const stickyEvent of room._unstable_getStickyEvents()) {
|
|
277
|
+
if (stickyEvent.getType() === EventType.RTCMembership && stickyEvent.getSender() === userId) {
|
|
278
|
+
yield stickyEvent;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
|
282
|
+
for (const stateEvent of roomState?.getStateEvents(EventType.GroupCallMemberPrefix) ?? []) {
|
|
283
|
+
if (stateEvent.getSender() === userId) yield stateEvent;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Whether the given membership event places its sender in the given slot, i.e. it is a valid, unexpired
|
|
289
|
+
* membership for that slot.
|
|
290
|
+
*/
|
|
291
|
+
async function isJoinedToSlot(membershipEvent, slotId, now) {
|
|
292
|
+
let membership;
|
|
293
|
+
try {
|
|
294
|
+
membership = await CallMembership.parseFromEvent(membershipEvent);
|
|
295
|
+
} catch {
|
|
296
|
+
// Not a membership we understand, so it doesn't place the user anywhere.
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (membership.slotId !== slotId) return false;
|
|
300
|
+
|
|
301
|
+
// Legacy memberships go stale when the client that sent them disappears without leaving. Honouring an
|
|
302
|
+
// expired one would suppress notifications for hours.
|
|
303
|
+
const expiry = membership.getAbsoluteExpiry();
|
|
304
|
+
return expiry === undefined || expiry > now;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Whether the receiving user has declined the given notification.
|
|
309
|
+
*
|
|
310
|
+
* Declines are looked up both through their `m.reference` relation and in the sticky event map. Relations
|
|
311
|
+
* cover declines that couldn't be sent as sticky events, but only see events that reached the timeline. A
|
|
312
|
+
* sticky decline delivered after a gappy or initial sync arrives via the sticky section instead, so it is
|
|
313
|
+
* only in the map.
|
|
314
|
+
*/
|
|
315
|
+
function hasDeclined(room, userId, eventId) {
|
|
316
|
+
const declines = room.getUnfilteredTimelineSet().relations.getChildEventsForEvent(eventId, RelationType.Reference, EventType.RTCDecline);
|
|
317
|
+
if (declines?.getRelations().some(decline => decline.getSender() === userId)) return true;
|
|
318
|
+
|
|
319
|
+
// Declines are keyed on the event ID of the notification they decline.
|
|
320
|
+
return room._unstable_getKeyedStickyEvent(userId, EventType.RTCDecline, eventId) !== undefined;
|
|
77
321
|
}
|
|
78
322
|
|
|
79
323
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/matrixrtc/types.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport type { IContent, IMentions } from \"../matrix.ts\";\nimport type { RelationEvent } from \"../types.ts\";\nimport type { CallMembership } from \"./CallMembership.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\n\nexport type EncryptionKeyMapKey = string;\n\nexport interface EncryptionKeyEntry {\n index: number;\n key: string;\n}\n\n/**\n * The mxID, deviceId and membership timestamp of a RTC session participant.\n */\nexport type ParticipantDeviceInfo = {\n userId: string;\n deviceId: string;\n membershipTs: number;\n};\n\n/**\n * A type representing the information needed to decrypt video streams.\n */\nexport type InboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n membership: CallMembershipIdentityParts;\n keyIndex: number;\n creationTS: number;\n};\n\n/**\n * The information about the key used to encrypt video streams.\n */\nexport type OutboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n creationTS: number;\n // The devices that this key is shared with.\n sharedWith: Array<ParticipantDeviceInfo>;\n // This is an index acting as the id of the key\n keyId: number;\n};\n\nexport interface EncryptionKeysEventContent {\n keys: EncryptionKeyEntry[];\n device_id: string;\n call_id: string;\n sent_ts?: number;\n}\n\n/**\n * THe content of a to-device event that contains encryption keys.\n */\nexport interface EncryptionKeysToDeviceEventContent {\n keys: { index: number; key: string };\n member: {\n id: string;\n // TODO Remove that it is claimed, need to get the sealed sender from decryption info\n // Or add some validation on it based on the encryption info\n claimed_device_id: string;\n };\n room_id: string;\n session: {\n application: string;\n call_id: string;\n scope: string;\n };\n // Why is this needed?\n sent_ts?: number;\n}\n/**\n * @deprecated Use `RTCNotificationType` instead.\n */\nexport type CallNotifyType = \"ring\" | \"notify\";\n/**\n * @deprecated Use `IRTCNotificationContent` instead.\n */\nexport interface ICallNotifyContent {\n \"application\": string;\n \"m.mentions\": IMentions;\n \"notify_type\": CallNotifyType;\n \"call_id\": string;\n}\n\nexport type RTCNotificationType = \"ring\" | \"notification\";\n\n/**\n * Represents the intention of the call from the perspective of the sending user.\n * May be any string, although `\"audio\"` and `\"video\"` are commonly accepted values.\n */\nexport type RTCCallIntent = \"audio\" | \"video\" | string;\n\n/**\n * This will check if the content has all the expected fields to be a valid IRTCNotificationContent.\n * It will also cap the lifetime to 90000ms (1.5 min) if a higher value is provided.\n * @param content\n * @throws if the content is invalid\n * @returns a parsed IRTCNotificationContent\n */\nexport function parseCallNotificationContent(content: IContent): IRTCNotificationContent {\n if (content[\"m.mentions\"] && typeof content[\"m.mentions\"] !== \"object\") {\n throw new Error(\"malformed m.mentions\");\n }\n if (typeof content[\"notification_type\"] !== \"string\") {\n throw new Error(\"Missing or invalid notification_type\");\n }\n if (typeof content[\"sender_ts\"] !== \"number\") {\n throw new Error(\"Missing or invalid sender_ts\");\n }\n if (typeof content[\"lifetime\"] !== \"number\") {\n throw new Error(\"Missing or invalid lifetime\");\n }\n\n if (content[\"relation\"] && content[\"relation\"][\"rel_type\"] !== \"m.reference\") {\n throw new Error(\"Invalid relation\");\n }\n if (content[\"m.call.intent\"] && typeof content[\"m.call.intent\"] !== \"string\") {\n throw new Error(\"Invalid m.call.intent\");\n }\n\n const cappedLifetime = content[\"lifetime\"] >= 90000 ? 90000 : content[\"lifetime\"];\n return { ...content, lifetime: cappedLifetime } as IRTCNotificationContent;\n}\n\n/**\n * Interface for `org.matrix.msc4075.rtc.notification` events.\n * Don't cast event content to this directly. Use `parseCallNotificationContent` instead to validate the content first.\n */\nexport interface IRTCNotificationContent extends RelationEvent {\n \"m.mentions\"?: IMentions;\n \"notification_type\": RTCNotificationType;\n /**\n * The initial intent of the calling user.\n */\n \"m.call.intent\"?: RTCCallIntent;\n \"sender_ts\": number;\n \"lifetime\": number;\n}\n\n/**\n * MSC4310 decline event content for `org.matrix.msc4310.rtc.decline`.\n * Sent as a standard m.reference relation to an `org.matrix.msc4075.rtc.notification` event.\n */\nexport interface IRTCDeclineContent extends RelationEvent {}\n\nexport enum Status {\n Disconnected = \"Disconnected\",\n Connecting = \"Connecting\",\n Connected = \"Connected\",\n Disconnecting = \"Disconnecting\",\n Unknown = \"Unknown\",\n}\n\n/**\n * A type collecting call encryption statistics for a session.\n */\nexport type Statistics = {\n counters: {\n /**\n * The number of times we have sent a room event containing encryption keys.\n */\n roomEventEncryptionKeysSent: number;\n /**\n * The number of times we have received a room event containing encryption keys.\n */\n roomEventEncryptionKeysReceived: number;\n };\n totals: {\n /**\n * The total age (in milliseconds) of all room events containing encryption keys that we have received.\n * We track the total age so that we can later calculate the average age of all keys received.\n */\n roomEventEncryptionKeysReceivedTotalAge: number;\n };\n};\n\nexport const isMyMembership = (m: CallMembership, userId: string, deviceId: string): boolean =>\n m.sender === userId && m.deviceId === deviceId;\n\n/**\n * A RTC transport is a JSON object that describes how to connect to a RTC member.\n */\nexport interface Transport {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Event content for `org.matrix.msc4143.rtc.slot` state events.\n */\nexport interface RtcSlotEventContent<T extends string = string> {\n status: \"open\" | \"closed\";\n application?: RtcSlotApplicationContent<T>;\n encryption?: RtcSlotEncryptionContent;\n}\n\n/**\n * Content of the `application` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotApplicationContent<T extends string = string> {\n type: T;\n // Other application specific keys.\n [key: string]: unknown;\n}\n\nexport const RTC_SLOT_ENCRYPTION_PER_MEMBER = \"org.matrix.msc4143.per_member\";\n\n/**\n * Content of the `encryption` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotEncryptionContent {\n type: typeof RTC_SLOT_ENCRYPTION_PER_MEMBER;\n // Other encryption-mechanism specific keys.\n [key: string]: unknown;\n}\n\n/**\n * The session description is used to identify a session. Used in the state event.\n */\nexport interface SlotDescription {\n /**\n * The application type. e.g. \"m.call\".\n */\n application: string;\n /**\n * The application-specific slot ID. e.g. \"ROOM\".\n */\n id: string;\n}\n"],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAaA;AACA;AACA;;AAOA;AACA;AACA;;AAQA;AACA;AACA;;AAiBA;AACA;AACA;;AAkBA;AACA;AACA;;AAEA;AACA;AACA;;AAUA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,4BAA4B,CAAC,OAAiB,EAA2B;EACrF,IAAI,OAAO,CAAC,YAAY,CAAC,IAAI,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ,EAAE;IACpE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;EAC3C;EACA,IAAI,OAAO,OAAO,CAAC,mBAAmB,CAAC,KAAK,QAAQ,EAAE;IAClD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC;EAC3D;EACA,IAAI,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,QAAQ,EAAE;IAC1C,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;EACnD;EACA,IAAI,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE;IACzC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC;EAClD;EAEA,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,KAAK,aAAa,EAAE;IAC1E,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC;EACvC;EACA,IAAI,OAAO,CAAC,eAAe,CAAC,IAAI,OAAO,OAAO,CAAC,eAAe,CAAC,KAAK,QAAQ,EAAE;IAC1E,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC;EAC5C;EAEA,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;EACjF,uCAAY,OAAO;IAAE,QAAQ,EAAE;EAAc;AACjD;;AAEA;AACA;AACA;AACA;;AAYA;AACA;AACA;AACA;;AAGA,WAAY,MAAM,0BAAN,MAAM;EAAN,MAAM;EAAN,MAAM;EAAN,MAAM;EAAN,MAAM;EAAN,MAAM;EAAA,OAAN,MAAM;AAAA;;AAQlB;AACA;AACA;;AAqBA,OAAO,MAAM,cAAc,GAAG,CAAC,CAAiB,EAAE,MAAc,EAAE,QAAgB,KAC9E,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;;AAElD;AACA;AACA;;AAMA;AACA;AACA;;AAOA;AACA;AACA;;AAOA,OAAO,MAAM,8BAA8B,GAAG,+BAA+B;;AAE7E;AACA;AACA;;AAOA;AACA;AACA","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/matrixrtc/types.ts"],"sourcesContent":["/*\nCopyright 2023-2026 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\nimport type { IContent, IMentions } from \"../matrix.ts\";\nimport type { RelationEvent } from \"../types.ts\";\nimport type { MatrixEvent } from \"../models/event.ts\";\nimport type { Room } from \"../models/room.ts\";\nimport { EventTimeline } from \"../models/event-timeline.ts\";\nimport { EventType, RelationType } from \"../@types/event.ts\";\nimport { CallMembership } from \"./CallMembership.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\nimport { isLeftMembershipContent } from \"./membershipData/index.ts\";\nimport { isSlotOpen, slotIdToDescription } from \"./utils.ts\";\n\nexport type EncryptionKeyMapKey = string;\n\nexport interface EncryptionKeyEntry {\n index: number;\n key: string;\n}\n\n/**\n * The mxID, deviceId and membership timestamp of a RTC session participant.\n */\nexport type ParticipantDeviceInfo = {\n userId: string;\n deviceId: string;\n membershipTs: number;\n};\n\n/**\n * A type representing the information needed to decrypt video streams.\n */\nexport type InboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n membership: CallMembershipIdentityParts;\n keyIndex: number;\n creationTS: number;\n};\n\n/**\n * The information about the key used to encrypt video streams.\n */\nexport type OutboundEncryptionSession = {\n key: Uint8Array<ArrayBuffer>;\n creationTS: number;\n // The devices that this key is shared with.\n sharedWith: Array<ParticipantDeviceInfo>;\n // This is an index acting as the id of the key\n keyId: number;\n};\n\nexport interface EncryptionKeysEventContent {\n keys: EncryptionKeyEntry[];\n device_id: string;\n call_id: string;\n sent_ts?: number;\n}\n\n/**\n * THe content of a to-device event that contains encryption keys.\n */\nexport interface EncryptionKeysToDeviceEventContent {\n keys: { index: number; key: string };\n member: {\n id: string;\n // TODO Remove that it is claimed, need to get the sealed sender from decryption info\n // Or add some validation on it based on the encryption info\n claimed_device_id: string;\n };\n room_id: string;\n session: {\n application: string;\n call_id: string;\n scope: string;\n };\n // Why is this needed?\n sent_ts?: number;\n}\n/**\n * @deprecated Use `RTCNotificationType` instead.\n */\nexport type CallNotifyType = \"ring\" | \"notify\";\n/**\n * @deprecated Use `IRTCNotificationContent` instead.\n */\nexport interface ICallNotifyContent {\n \"application\": string;\n \"m.mentions\": IMentions;\n \"notify_type\": CallNotifyType;\n \"call_id\": string;\n}\n\nexport type RTCNotificationType = \"ring\" | \"notification\";\n\n/**\n * Represents the intention of the call from the perspective of the sending user.\n * May be any string, although `\"audio\"` and `\"video\"` are commonly accepted values.\n */\nexport type RTCCallIntent = \"audio\" | \"video\" | string;\n\n/**\n * The maximum `lifetime` of an RTC notification as per MSC4075. Larger values are capped to this.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_LIFETIME_MS = 2 * 60 * 1000; // 2 minutes\n\n/**\n * The maximum amount by which a notification's `sender_ts` may lie ahead of its `origin_server_ts`\n * before the `lifetime` is measured from `origin_server_ts` instead, as per MSC4075.\n *\n * Exported for use within the js-sdk only. Not re-exported from `matrixrtc/index.ts`.\n * @internal\n */\nexport const RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS = 20 * 1000; // 20 seconds\n\n/**\n * The context that is needed to evaluate the MSC4075 rules for receiving notifications.\n */\nexport interface RTCNotificationValidationContext {\n /** The room in which the notification was received. */\n room: Pick<\n Room,\n \"getLiveTimeline\" | \"getUnfilteredTimelineSet\" | \"_unstable_getStickyEvents\" | \"_unstable_getKeyedStickyEvent\"\n >;\n /** The user ID of the receiving (local) user. */\n userId: string;\n /** The current time in milliseconds since the epoch. Defaults to `Date.now()`. */\n now?: number;\n}\n\n/**\n * Computes the absolute timestamp at which an RTC notification stops being valid, as per MSC4075.\n *\n * The `lifetime` is measured from `sender_ts` unless `sender_ts` lies more than 20 seconds ahead of\n * `origin_server_ts`, in which case it is measured from `origin_server_ts` instead. Regardless of the basis,\n * the remaining lifetime is capped at 2 minutes.\n *\n * @param content The notification content.\n * @param originServerTs The `origin_server_ts` of the notification event.\n * @param now The current time in milliseconds since the epoch. Defaults to `Date.now()`.\n * @returns The timestamp (in milliseconds since the epoch) at which the notification expires.\n */\nexport function getCallNotificationExpiry(\n content: Pick<IRTCNotificationContent, \"sender_ts\" | \"lifetime\">,\n originServerTs: number,\n now: number = Date.now(),\n): number {\n const basis =\n content.sender_ts - originServerTs > RTC_NOTIFICATION_MAX_SENDER_TS_AHEAD_MS\n ? originServerTs\n : content.sender_ts;\n return Math.min(basis + content.lifetime, now + RTC_NOTIFICATION_MAX_LIFETIME_MS);\n}\n\n/**\n * The subset of a notification event that {@link parseCallNotificationContent} needs.\n */\ntype RTCNotificationEvent = Pick<\n MatrixEvent,\n \"getContent\" | \"getId\" | \"getSender\" | \"getTs\" | \"getType\" | \"unstableStickyInfo\"\n>;\n\n/**\n * Whether the content marks a withdrawn sticky event (MSC4354), i.e. it is empty apart from the sticky key.\n */\nfunction isWithdrawal(content: IContent): boolean {\n return Object.keys(content).every((key) => key === \"msc4354_sticky_key\");\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\n/**\n * Looks up a legacy `m.call.member` state event by ID in the room's current state.\n *\n * @returns The event, or `undefined` if no current membership state event has that ID.\n */\nfunction findMembershipStateEvent(\n room: RTCNotificationValidationContext[\"room\"],\n eventId: string,\n): MatrixEvent | undefined {\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n return roomState?.getStateEvents(EventType.GroupCallMemberPrefix).find((event) => event.getId() === eventId);\n}\n\n/**\n * Determines the ID of the slot that a notification invites to.\n *\n * Notifications predating the `slot_id` property instead carry an `m.reference` relation to the sender's\n * membership event.\n *\n * @throws if the slot can't be determined.\n * @returns A promise resolving to the slot ID.\n */\nasync function resolveSlotId(content: IContent, room: RTCNotificationValidationContext[\"room\"]): Promise<string> {\n if (typeof content[\"slot_id\"] === \"string\") {\n // Throws if the ID is malformed, e.g. because it contains more than one \"#\".\n slotIdToDescription(content[\"slot_id\"]);\n return content[\"slot_id\"];\n }\n if (content[\"slot_id\"] !== undefined) throw new Error(\"Invalid slot_id\");\n\n const relation = content[\"m.relates_to\"];\n const membershipEventId = relation?.rel_type === RelationType.Reference ? relation.event_id : undefined;\n if (typeof membershipEventId !== \"string\") {\n throw new Error(\"Missing slot_id and no m.reference relation to derive it from\");\n }\n\n const membershipEvent = findMembershipStateEvent(room, membershipEventId);\n if (!membershipEvent) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a current membership`);\n }\n\n try {\n return (await CallMembership.parseFromEvent(membershipEvent)).slotId;\n } catch (cause) {\n throw new Error(`Missing slot_id and referenced event ${membershipEventId} is not a valid membership`, {\n cause,\n });\n }\n}\n\n/**\n * Parses the content of a received `org.matrix.msc4075.rtc.notification` event.\n *\n * This checks that the content matches the schema of MSC4075, caps `lifetime` to 2 minutes and applies\n * the rules for receiving invites from MSC4075.\n * The notification is only considered valid if all of the following hold:\n * - It wasn't sent by the receiving user.\n * - It is the current entry in the room's sticky event map for its sender and slot and isn't a withdrawal.\n * - The slot it refers to exists and is open.\n * - Its lifetime hasn't elapsed (see {@link getCallNotificationExpiry}).\n * - Its `m.mentions` target the receiving user, either directly or via a room mention that the sender is\n * allowed to trigger.\n * - The receiving user has no joined `m.rtc.member` event for the slot in the sticky event map.\n * - Any left `m.rtc.member` event of the receiving user for the slot predates the notification.\n * - The receiving user has no sticky decline event referencing the notification.\n *\n * @param event The notification event.\n * @param context The context needed to evaluate the receiving rules.\n * @throws if the content is malformed or the notification isn't valid.\n * @returns A promise resolving to the parsed content.\n */\nexport async function parseCallNotificationContent(\n event: RTCNotificationEvent,\n context: RTCNotificationValidationContext,\n): Promise<IRTCNotificationContent> {\n if (event.getType() !== EventType.RTCNotification) {\n throw new Error(`Event ${event.getId()} is not an ${EventType.RTCNotification} event`);\n }\n\n const content = event.getContent();\n if (isWithdrawal(content)) {\n throw new Error(\"Notification was withdrawn\");\n }\n\n const slotId = await resolveSlotId(content, context.room);\n // The sticky key is only validated when present. A notification predating it can still be valid, and one\n // carrying the wrong key is filed under that key in the sticky event map, so the lookup below rejects it.\n if (content[\"msc4354_sticky_key\"] !== undefined && content[\"msc4354_sticky_key\"] !== slotId) {\n throw new Error(\"msc4354_sticky_key must be equal to slot_id\");\n }\n if (!isNonNegativeInteger(content[\"sender_ts\"])) {\n throw new Error(\"Missing or invalid sender_ts\");\n }\n if (!isNonNegativeInteger(content[\"lifetime\"])) {\n throw new Error(\"Missing or invalid lifetime\");\n }\n\n const mentions = content[\"m.mentions\"];\n if (typeof mentions !== \"object\" || mentions === null) {\n throw new Error(\"Missing or malformed m.mentions\");\n }\n if (mentions.room !== undefined && typeof mentions.room !== \"boolean\") {\n throw new Error(\"malformed m.mentions.room\");\n }\n if (\n mentions.user_ids !== undefined &&\n (!Array.isArray(mentions.user_ids) || !mentions.user_ids.every((userId) => typeof userId === \"string\"))\n ) {\n throw new Error(\"malformed m.mentions.user_ids\");\n }\n if (mentions.room !== true && !mentions.user_ids?.length) {\n throw new Error(\"m.mentions must target either the room or at least one user\");\n }\n\n const parsed = {\n ...content,\n slot_id: slotId,\n lifetime: Math.min(content[\"lifetime\"], RTC_NOTIFICATION_MAX_LIFETIME_MS),\n } as IRTCNotificationContent;\n\n await checkCallNotificationReceivingRules(parsed, event, context);\n\n return parsed;\n}\n\n/**\n * Applies the MSC4075 rules for receiving invites to an already schema-validated notification.\n * @throws if any of the rules is violated.\n */\nasync function checkCallNotificationReceivingRules(\n content: IRTCNotificationContent,\n event: RTCNotificationEvent,\n { room, userId, now = Date.now() }: RTCNotificationValidationContext,\n): Promise<void> {\n const eventId = event.getId();\n const sender = event.getSender();\n if (eventId === undefined || sender === undefined) {\n throw new Error(\"Notification event is missing its event ID or sender\");\n }\n const originServerTs = event.getTs();\n const slotId = content.slot_id;\n\n if (sender === userId) {\n throw new Error(\"Notification was sent by the receiving user\");\n }\n\n // A notification that wasn't delivered as a sticky event can't be superseded or withdrawn, so there is\n // nothing to check. It isn't in the sticky event map either, which is why this can't be checked blindly.\n if (event.unstableStickyInfo !== undefined) {\n if (room._unstable_getKeyedStickyEvent(sender, event.getType(), slotId)?.getId() !== eventId) {\n throw new Error(\"Notification is not the current sticky event for its sender and slot\");\n }\n }\n\n // `isSlotOpen` returns undefined when no slot event exists at all, which is just as disqualifying.\n if (!isSlotOpen(room, slotIdToDescription(slotId))) {\n throw new Error(`Slot ${slotId} does not exist or is closed`);\n }\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n\n if (now >= getCallNotificationExpiry(content, originServerTs, now)) {\n throw new Error(\"Notification has expired\");\n }\n\n const mentions = content[\"m.mentions\"];\n const mentionsUser = mentions.user_ids?.includes(userId) ?? false;\n const mentionsRoom = mentions.room === true && (roomState?.mayTriggerNotifOfType(\"room\", sender) ?? false);\n if (!mentionsUser && !mentionsRoom) {\n throw new Error(\"Notification does not mention the receiving user\");\n }\n\n for (const membershipEvent of ownMembershipEvents(room, userId)) {\n const membershipContent = membershipEvent.getContent();\n if (isLeftMembershipContent(membershipContent)) {\n if (membershipContent.slot_id === slotId && membershipEvent.getTs() >= originServerTs) {\n throw new Error(`Receiving user left slot ${slotId} after the notification was sent`);\n }\n } else if (await isJoinedToSlot(membershipEvent, slotId, now)) {\n throw new Error(`Receiving user is already joined to slot ${slotId}`);\n }\n }\n\n if (hasDeclined(room, userId, eventId)) {\n throw new Error(\"Receiving user declined the notification\");\n }\n}\n\n/**\n * Yields the receiving user's own MatrixRTC membership events, from both the sticky event map and the legacy\n * member state events. Sessions that don't use sticky events keep membership in state, so both have to be\n * consulted to tell whether the user is in a session.\n *\n * @yields the user's own `m.rtc.member` and `m.call.member` events.\n */\nfunction* ownMembershipEvents(room: RTCNotificationValidationContext[\"room\"], userId: string): Iterable<MatrixEvent> {\n for (const stickyEvent of room._unstable_getStickyEvents()) {\n if (stickyEvent.getType() === EventType.RTCMembership && stickyEvent.getSender() === userId) {\n yield stickyEvent;\n }\n }\n\n const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n for (const stateEvent of roomState?.getStateEvents(EventType.GroupCallMemberPrefix) ?? []) {\n if (stateEvent.getSender() === userId) yield stateEvent;\n }\n}\n\n/**\n * Whether the given membership event places its sender in the given slot, i.e. it is a valid, unexpired\n * membership for that slot.\n */\nasync function isJoinedToSlot(membershipEvent: MatrixEvent, slotId: string, now: number): Promise<boolean> {\n let membership: CallMembership;\n try {\n membership = await CallMembership.parseFromEvent(membershipEvent);\n } catch {\n // Not a membership we understand, so it doesn't place the user anywhere.\n return false;\n }\n if (membership.slotId !== slotId) return false;\n\n // Legacy memberships go stale when the client that sent them disappears without leaving. Honouring an\n // expired one would suppress notifications for hours.\n const expiry = membership.getAbsoluteExpiry();\n return expiry === undefined || expiry > now;\n}\n\n/**\n * Whether the receiving user has declined the given notification.\n *\n * Declines are looked up both through their `m.reference` relation and in the sticky event map. Relations\n * cover declines that couldn't be sent as sticky events, but only see events that reached the timeline. A\n * sticky decline delivered after a gappy or initial sync arrives via the sticky section instead, so it is\n * only in the map.\n */\nfunction hasDeclined(room: RTCNotificationValidationContext[\"room\"], userId: string, eventId: string): boolean {\n const declines = room\n .getUnfilteredTimelineSet()\n .relations.getChildEventsForEvent(eventId, RelationType.Reference, EventType.RTCDecline);\n if (declines?.getRelations().some((decline) => decline.getSender() === userId)) return true;\n\n // Declines are keyed on the event ID of the notification they decline.\n return room._unstable_getKeyedStickyEvent(userId, EventType.RTCDecline, eventId) !== undefined;\n}\n\n/**\n * Interface for `org.matrix.msc4075.rtc.notification` events.\n * Don't cast event content to this directly. Use `parseCallNotificationContent` instead to validate the content first.\n */\nexport interface IRTCNotificationContent extends RelationEvent {\n /**\n * The `state_key` of the `m.rtc.slot` event that the notification refers to.\n *\n * Notifications predating this property omit it. `parseCallNotificationContent` fills it in from the\n * referenced membership event, so the parsed content always carries it.\n */\n \"slot_id\": string;\n /**\n * The users targeted by the notification. Must either mention the room or at least one user.\n */\n \"m.mentions\": IMentions;\n /**\n * @deprecated Not part of MSC4075 anymore. How to present a notification is up to the receiving client.\n */\n \"notification_type\"?: RTCNotificationType;\n /**\n * @deprecated Not part of MSC4075 anymore. The initial intent of the calling user.\n */\n \"m.call.intent\"?: RTCCallIntent;\n /**\n * The timestamp (in milliseconds since the epoch) at which the sending client created the event.\n */\n \"sender_ts\": number;\n /**\n * The time (in milliseconds) that the notification is valid for, measured from `sender_ts`.\n */\n \"lifetime\": number;\n /**\n * The sticky key as per MSC4354. Must be equal to `slot_id`.\n *\n * Optional because notifications predating MSC4354 omit it.\n */\n \"msc4354_sticky_key\"?: string;\n}\n\n/**\n * MSC4310 decline event content for `org.matrix.msc4310.rtc.decline`.\n * Sent as a standard m.reference relation to an `org.matrix.msc4075.rtc.notification` event.\n */\nexport interface IRTCDeclineContent extends RelationEvent {\n /**\n * The sticky key as per MSC4354. Must be equal to the event ID of the notification being declined.\n *\n * Optional because servers without MSC4354 support can't deliver the decline as a sticky event. Such a\n * decline still counts, but only for devices that receive it directly, since it isn't re-delivered after\n * a gappy or initial sync.\n */\n msc4354_sticky_key?: string;\n}\n\nexport enum Status {\n Disconnected = \"Disconnected\",\n Connecting = \"Connecting\",\n Connected = \"Connected\",\n Disconnecting = \"Disconnecting\",\n Unknown = \"Unknown\",\n}\n\n/**\n * A type collecting call encryption statistics for a session.\n */\nexport type Statistics = {\n counters: {\n /**\n * The number of times we have sent a room event containing encryption keys.\n */\n roomEventEncryptionKeysSent: number;\n /**\n * The number of times we have received a room event containing encryption keys.\n */\n roomEventEncryptionKeysReceived: number;\n };\n totals: {\n /**\n * The total age (in milliseconds) of all room events containing encryption keys that we have received.\n * We track the total age so that we can later calculate the average age of all keys received.\n */\n roomEventEncryptionKeysReceivedTotalAge: number;\n };\n};\n\nexport const isMyMembership = (m: CallMembership, userId: string, deviceId: string): boolean =>\n m.sender === userId && m.deviceId === deviceId;\n\n/**\n * A RTC transport is a JSON object that describes how to connect to a RTC member.\n */\nexport interface Transport {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Event content for `org.matrix.msc4143.rtc.slot` state events.\n */\nexport interface RtcSlotEventContent<T extends string = string> {\n status: \"open\" | \"closed\";\n application?: RtcSlotApplicationContent<T>;\n encryption?: RtcSlotEncryptionContent;\n}\n\n/**\n * Content of the `application` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotApplicationContent<T extends string = string> {\n type: T;\n // Other application specific keys.\n [key: string]: unknown;\n}\n\nexport const RTC_SLOT_ENCRYPTION_PER_MEMBER = \"org.matrix.msc4143.per_member\";\n\n/**\n * Content of the `encryption` object within `org.matrix.msc4143.rtc.slot` events.\n */\nexport interface RtcSlotEncryptionContent {\n type: typeof RTC_SLOT_ENCRYPTION_PER_MEMBER;\n // Other encryption-mechanism specific keys.\n [key: string]: unknown;\n}\n\n/**\n * The session description is used to identify a session. Used in the state event.\n */\nexport interface SlotDescription {\n /**\n * The application type. e.g. \"m.call\".\n */\n application: string;\n /**\n * The application-specific slot ID. e.g. \"ROOM\".\n */\n id: string;\n}\n"],"mappings":"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","ignoreList":[]}
|
package/lib/matrixrtc/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CallMembershipIdentityParts } from "./EncryptionManager.ts";
|
|
2
|
-
import type { InboundEncryptionSession, SlotDescription } from "./types.ts";
|
|
2
|
+
import type { InboundEncryptionSession, RtcSlotEventContent, SlotDescription } from "./types.ts";
|
|
3
|
+
import type { Room } from "../models/room.ts";
|
|
3
4
|
/**
|
|
4
5
|
* Detects when a key for a given index is outdated.
|
|
5
6
|
*/
|
|
@@ -23,4 +24,24 @@ export declare function slotIdToDescription(slotId: string): SlotDescription;
|
|
|
23
24
|
* Converts a SlotDescription into it's slot ID format.
|
|
24
25
|
*/
|
|
25
26
|
export declare function computeSlotId(slotDescription: SlotDescription): string;
|
|
27
|
+
/**
|
|
28
|
+
* Reads the slot state event's content for the given slot description.
|
|
29
|
+
*
|
|
30
|
+
* @returns The slot event's content, or `undefined` if no slot event exists for the given description.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getSlotEventContent(room: Pick<Room, "getLiveTimeline">, slotDescription: SlotDescription): RtcSlotEventContent | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the given slot is closed.
|
|
35
|
+
*
|
|
36
|
+
* @returns `true` if the slot is closed, `false` if the slot is open or `undefined`
|
|
37
|
+
* if no slot exists.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isSlotClosed(room: Pick<Room, "getLiveTimeline">, slotDescription: SlotDescription): boolean | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the given slot is open.
|
|
42
|
+
*
|
|
43
|
+
* @returns `true` if the slot is open, `false` if the slot is closed or `undefined`
|
|
44
|
+
* if no slot exists.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isSlotOpen(room: Pick<Room, "getLiveTimeline">, slotDescription: SlotDescription): boolean | undefined;
|
|
26
47
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/utils.ts"],"names":[],"mappings":"AAgBA,OAAO,EAA0B,KAAK,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,KAAK,EAAE,wBAAwB,EAAuB,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/matrixrtc/utils.ts"],"names":[],"mappings":"AAgBA,OAAO,EAA0B,KAAK,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,KAAK,EAAE,wBAAwB,EAAuB,mBAAmB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAI9C;;GAEG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAA4D;IAE5E;;;;;OAKG;IACI,UAAU,CAAC,UAAU,EAAE,2BAA2B,EAAE,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAalG;CACJ;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAQnE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,eAAe,EAAE,eAAe,GAAG,MAAM,CAEtE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAC/B,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,EACnC,eAAe,EAAE,eAAe,GACjC,mBAAmB,GAAG,SAAS,CASjC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CACxB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,EACnC,eAAe,EAAE,eAAe,GACjC,OAAO,GAAG,SAAS,CASrB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,eAAe,EAAE,eAAe,GAAG,OAAO,GAAG,SAAS,CAGrH"}
|