matrix-js-sdk 41.5.0 → 41.6.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 +7 -0
- package/lib/ReEmitter.js +1 -1
- package/lib/ReEmitter.js.map +1 -1
- package/lib/ToDeviceMessageQueue.js +2 -2
- package/lib/ToDeviceMessageQueue.js.map +1 -1
- package/lib/autodiscovery.js +0 -1
- package/lib/autodiscovery.js.map +1 -1
- package/lib/client.js +112 -165
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/CryptoBackend.js +0 -2
- package/lib/common-crypto/CryptoBackend.js.map +1 -1
- package/lib/content-helpers.js +3 -5
- package/lib/content-helpers.js.map +1 -1
- package/lib/content-repo.js +7 -1
- package/lib/content-repo.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js +9 -11
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store.js +0 -2
- package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +11 -9
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto/store/memory-crypto-store.js +11 -9
- package/lib/crypto/store/memory-crypto-store.js.map +1 -1
- package/lib/crypto-api/index.js +58 -58
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/embedded.js +29 -45
- package/lib/embedded.js.map +1 -1
- package/lib/extensible_events_v1/MessageEvent.js +15 -15
- package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollEndEvent.js +8 -8
- package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollResponseEvent.js +0 -1
- package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollStartEvent.js +28 -28
- package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
- package/lib/feature.js +5 -1
- package/lib/feature.js.map +1 -1
- package/lib/filter-component.js +4 -1
- package/lib/filter-component.js.map +1 -1
- package/lib/filter.js +1 -3
- package/lib/filter.js.map +1 -1
- package/lib/http-api/errors.js +20 -16
- package/lib/http-api/errors.js.map +1 -1
- package/lib/http-api/fetch.js +4 -6
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/http-api/refresh.js +10 -12
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/interactive-auth.js +1 -11
- package/lib/interactive-auth.js.map +1 -1
- package/lib/logger.js +0 -2
- package/lib/logger.js.map +1 -1
- package/lib/matrixrtc/CallMembership.js +43 -57
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +19 -24
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +2 -3
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +23 -30
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManagerActionScheduler.js +1 -2
- package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.js +8 -11
- package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
- package/lib/matrixrtc/ToDeviceKeyTransport.js +4 -4
- package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
- package/lib/matrixrtc/utils.js +7 -1
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/MSC3089TreeSpace.js +5 -7
- package/lib/models/MSC3089TreeSpace.js.map +1 -1
- package/lib/models/beacon.js +5 -11
- package/lib/models/beacon.js.map +1 -1
- package/lib/models/device.js +0 -7
- package/lib/models/device.js.map +1 -1
- package/lib/models/event-context.js +1 -2
- package/lib/models/event-context.js.map +1 -1
- package/lib/models/event-timeline-set.js +16 -26
- package/lib/models/event-timeline-set.js.map +1 -1
- package/lib/models/event-timeline.js +8 -15
- package/lib/models/event-timeline.js.map +1 -1
- package/lib/models/event.js +20 -37
- package/lib/models/event.js.map +1 -1
- package/lib/models/invites-ignorer.js +8 -12
- package/lib/models/invites-ignorer.js.map +1 -1
- package/lib/models/poll.js +7 -13
- package/lib/models/poll.js.map +1 -1
- package/lib/models/read-receipt.js +8 -4
- package/lib/models/read-receipt.js.map +1 -1
- package/lib/models/related-relations.js +0 -2
- package/lib/models/related-relations.js.map +1 -1
- package/lib/models/relations-container.js +4 -6
- package/lib/models/relations-container.js.map +1 -1
- package/lib/models/relations.js +7 -10
- package/lib/models/relations.js.map +1 -1
- package/lib/models/room-member.js +2 -24
- package/lib/models/room-member.js.map +1 -1
- package/lib/models/room-receipts.js +25 -22
- package/lib/models/room-receipts.js.map +1 -1
- package/lib/models/room-state.js +2 -2
- package/lib/models/room-state.js.map +1 -1
- package/lib/models/room-sticky-events.js +20 -5
- package/lib/models/room-sticky-events.js.map +1 -1
- package/lib/models/room.js +82 -105
- package/lib/models/room.js.map +1 -1
- package/lib/models/thread.js +12 -57
- package/lib/models/thread.js.map +1 -1
- package/lib/models/user.js +1 -20
- package/lib/models/user.js.map +1 -1
- package/lib/oidc/authorize.js +23 -32
- package/lib/oidc/authorize.js.map +1 -1
- package/lib/oidc/tokenRefresher.js +8 -11
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/pushprocessor.js +8 -5
- package/lib/pushprocessor.js.map +1 -1
- package/lib/receipt-accumulator.js +12 -3
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
- package/lib/rendezvous/MSC4108SignInWithQR.js +10 -23
- package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
- package/lib/rendezvous/channels/MSC4108SecureChannel.js +5 -10
- package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js +5 -15
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
- package/lib/room-hierarchy.js +7 -12
- package/lib/room-hierarchy.js.map +1 -1
- package/lib/rust-crypto/DehydratedDeviceManager.js +2 -3
- package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
- package/lib/rust-crypto/KeyClaimManager.js +1 -2
- package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +11 -4
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestsManager.js +12 -12
- package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +3 -5
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
- package/lib/rust-crypto/RoomEncryptor.js +6 -6
- package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
- package/lib/rust-crypto/backup.js +22 -16
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/rust-crypto/device-converter.js +13 -4
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/index.js +1 -3
- package/lib/rust-crypto/index.js.map +1 -1
- package/lib/rust-crypto/libolm_migration.js +13 -15
- package/lib/rust-crypto/libolm_migration.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +52 -59
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/rust-crypto/verification.js +10 -10
- package/lib/rust-crypto/verification.js.map +1 -1
- package/lib/scheduler.js +2 -2
- package/lib/scheduler.js.map +1 -1
- package/lib/secret-storage.js +16 -10
- package/lib/secret-storage.js.map +1 -1
- package/lib/serverCapabilities.js +2 -5
- package/lib/serverCapabilities.js.map +1 -1
- package/lib/sliding-sync-sdk.js +4 -9
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.js +4 -9
- package/lib/sliding-sync.js.map +1 -1
- package/lib/store/indexeddb-local-backend.js +13 -8
- package/lib/store/indexeddb-local-backend.js.map +1 -1
- package/lib/store/indexeddb-remote-backend.js +6 -7
- package/lib/store/indexeddb-remote-backend.js.map +1 -1
- package/lib/store/indexeddb-store-worker.js +1 -2
- package/lib/store/indexeddb-store-worker.js.map +1 -1
- package/lib/store/indexeddb.js +4 -2
- package/lib/store/indexeddb.js.map +1 -1
- package/lib/store/memory.js +0 -4
- package/lib/store/memory.js.map +1 -1
- package/lib/sync-accumulator.js +2 -4
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/sync.js +36 -43
- package/lib/sync.js.map +1 -1
- package/lib/timeline-window.js +2 -6
- package/lib/timeline-window.js.map +1 -1
- package/lib/utils/decryptAESSecretStorageItem.js +5 -1
- package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/encryptAESSecretStorageItem.js +5 -1
- package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils.js +35 -20
- package/lib/utils.js.map +1 -1
- package/lib/webrtc/call.js +13 -45
- package/lib/webrtc/call.js.map +1 -1
- package/lib/webrtc/callEventHandler.js +0 -5
- package/lib/webrtc/callEventHandler.js.map +1 -1
- package/lib/webrtc/callFeed.js +0 -15
- package/lib/webrtc/callFeed.js.map +1 -1
- package/lib/webrtc/groupCall.js +82 -89
- package/lib/webrtc/groupCall.js.map +1 -1
- package/lib/webrtc/groupCallEventHandler.js +6 -7
- package/lib/webrtc/groupCallEventHandler.js.map +1 -1
- package/lib/webrtc/mediaHandler.js +8 -15
- package/lib/webrtc/mediaHandler.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportGatherer.js +2 -5
- package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js +5 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
- package/lib/webrtc/stats/groupCallStats.js +3 -4
- package/lib/webrtc/stats/groupCallStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStats.js +3 -3
- package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +1 -1
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
- package/package.json +3 -3
- package/src/rendezvous/MSC4108SignInWithQR.ts +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RTCEncryptionManager.js","names":["getEncryptionKeyMapKey","decodeBase64","encodeBase64","KeyTransportEvents","sleep","OutdatedKeyFilter","computeRtcIdentityRaw","RTCEncryptionManager","constructor","ownMembership","getMemberships","transport","onEncryptionKeysChanged","parentLogger","rtcBackendIdProvider","_defineProperty","Map","undefined","membership","keyBase64Encoded","index","timestamp","_this$logger2","manageMediaKeys","_this$logger","logger","warn","concat","userId","deviceId","debug","keyBin","candidateInboundSession","key","keyIndex","creationTS","outdated","keyBuffer","isOutdated","addKeyToParticipant","_this$logger3","info","getChild","rtcIdentityProvider","getOwnRtcBackendIdentity","_this","_asyncToGenerator","ownRtcBackendIdentityCache","useHashedRtcBackendIdentity","_this$logger4","memberId","getEncryptionKeys","participantKeyRings","checkKeysWithoutMatchingRTCMembership","keyInfoTemp","keysWithoutMatchingRTCMembership","forEach","keyInfo","knownRtcMembership","fullMembership","find","member","_this$logger5","push","addKeyToParticipantWithBackendIdentity","rtcBackendIdentity","mapKey","has","set","get","join","joinConfig","_joinConfig$manageMed","_joinConfig$unstableS","_joinConfig$useKeyDel","_joinConfig$keyRotati","_this$logger6","unstableSendStickyEvents","useKeyDelay","keyRotationGracePeriodMs","on","ReceivedKeys","onNewKeyReceived","start","leave","off","stop","clear","ensureKeyDistribution","currentKeyDistributionPromise","_this$logger7","rolloutOutboundKey","then","_this$logger8","needToEnsureKeyAgain","_this$logger9","_this$logger0","onMembershipsUpdate","_this$logger1","oldMemberships","arguments","length","trace","_this2","_this2$outboundSessio","_this2$outboundSessio2","isFirstKey","outboundSession","firstKey","generateRandomKey","Date","now","sharedWith","keyId","toShareWith","filter","sender","map","membershipTs","createdTs","alreadySharedWith","x","some","o","anyLeft","anyJoined","toDistributeTo","outboundKey","hasKeyChanged","newOutboundKey","createNewOutboundSession","keyAge","_this2$logger","_this2$logger2","_this2$logger3","_this2$logger4","sendKey","m","_this2$logger5","_this2$logger6","err","_this2$logger7","error","_this$logger10","nextKeyIndex","Uint8Array","globalThis","crypto","getRandomValues"],"sources":["../../src/matrixrtc/RTCEncryptionManager.ts"],"sourcesContent":["/*\nCopyright 2025-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*/\n\nimport {\n type CallMembershipIdentityParts,\n getEncryptionKeyMapKey,\n type IEncryptionManager,\n} from \"./EncryptionManager.ts\";\nimport { type EncryptionConfig, type MembershipConfig } from \"./MatrixRTCSession.ts\";\nimport type { CallMembership } from \"./CallMembership.ts\";\nimport { decodeBase64, encodeBase64 } from \"../base64.ts\";\nimport { type IKeyTransport, type KeyTransportEventListener, KeyTransportEvents } from \"./IKeyTransport.ts\";\nimport { type Logger } from \"../logger.ts\";\nimport { sleep } from \"../utils.ts\";\nimport {\n type EncryptionKeyMapKey,\n type InboundEncryptionSession,\n type OutboundEncryptionSession,\n type ParticipantDeviceInfo,\n} from \"./types.ts\";\nimport { OutdatedKeyFilter } from \"./utils.ts\";\nimport { computeRtcIdentityRaw } from \"./membershipData/rtc.ts\";\n\n/**\n * RTCEncryptionManager is used to manage the encryption keys for a call.\n *\n * It is responsible for distributing the keys to the other participants and rotating the keys if needed.\n *\n * This manager when used with to-device transport will share the existing key only to new joiners, and rotate\n * if there is a leaver.\n *\n * XXX In the future we want to distribute a ratcheted key not the current one for new joiners.\n */\nexport class RTCEncryptionManager implements IEncryptionManager {\n // This is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n private manageMediaKeys = false;\n\n private useHashedRtcBackendIdentity = false;\n private ownRtcBackendIdentityCache: string | undefined;\n\n /**\n * Store the key rings for each participant.\n * The encryption manager stores the keys because the application layer might not be ready yet to handle the keys.\n * The keys are stored and can be retrieved later when the application layer is ready {@link RTCEncryptionManager#getEncryptionKeys}.\n */\n private readonly participantKeyRings = new Map<\n EncryptionKeyMapKey,\n Array<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n rtcBackendIdentity: string;\n }>\n >();\n\n // The current per-sender media key for this device\n private outboundSession: OutboundEncryptionSession | null = null;\n\n /**\n * Ensures that there is only one distribute operation at a time for that call.\n */\n private currentKeyDistributionPromise: Promise<void> | null = null;\n\n /**\n * The time to wait before using the outbound session after it has been distributed.\n * This is to ensure that the key is delivered to all participants before it is used.\n * When creating the first key, this is set to 0 so that the key can be used immediately.\n */\n private useKeyDelay = 5000;\n\n /**\n * We want to avoid rolling out a new outbound key when the previous one was created less than `keyRotationGracePeriodMs` milliseconds ago.\n * This is to avoid expensive key rotations when users quickly join the call in a row.\n *\n * This must be higher than `useKeyDelay` to have an effect.\n * If it is lower, the current key will always be older than the grace period.\n * @private\n */\n private keyRotationGracePeriodMs = 10_000;\n\n /**\n * If a new key distribution is being requested while one is going on, we will set this flag to true.\n * This will ensure that a new round is started after the current one.\n * @private\n */\n private needToEnsureKeyAgain = false;\n\n /**\n * There is a possibility that keys arrive in the wrong order.\n * For example, after a quick join/leave/join, there will be 2 keys of index 0 distributed, and\n * if they are received in the wrong order, the stream won't be decryptable.\n * For that reason we keep a small buffer of keys for a limited time to disambiguate.\n * @private\n */\n private keyBuffer = new OutdatedKeyFilter();\n\n private logger: Logger | undefined = undefined;\n\n private readonly rtcIdentityProvider: (userId: string, deviceId: string, memberId: string) => Promise<string>;\n\n /**\n *\n * @param ownMembership - our own membership info\n * @param getMemberships - function to get current memberships\n * @param transport - key transport (room or to-device)\n * @param statistics - statistics collector\n * @param onEncryptionKeysChanged - callback to notify the media layer of new keys\n * @param parentLogger - optional parent logger\n * @param rtcBackendIdProvider - A function to compute the rtc backend identity, exposed for testing purposes\n */\n public constructor(\n private readonly ownMembership: CallMembershipIdentityParts,\n private getMemberships: () => CallMembership[],\n private transport: IKeyTransport,\n // Callback to notify the media layer of new keys\n private onEncryptionKeysChanged: (\n keyBin: Uint8Array<ArrayBuffer>,\n encryptionKeyIndex: number,\n membership: CallMembershipIdentityParts,\n rtcBackendIdentity: string,\n ) => void,\n parentLogger?: Logger,\n rtcBackendIdProvider?: (userId: string, deviceId: string, memberId: string) => Promise<string>,\n ) {\n this.logger = parentLogger?.getChild(`[EncryptionManager]`);\n this.rtcIdentityProvider = rtcBackendIdProvider ?? computeRtcIdentityRaw;\n }\n\n private async getOwnRtcBackendIdentity(): Promise<string> {\n if (this.ownRtcBackendIdentityCache) return this.ownRtcBackendIdentityCache;\n\n if (this.useHashedRtcBackendIdentity) {\n const { userId, deviceId, memberId } = this.ownMembership;\n this.logger?.info(\n // If we see this log multiple times, we need to reconsider the precompute call of getOwnRtcBackendIdentity\n `Computing RTC backend identity for ${userId}:${deviceId}:${memberId} (SHOULD ONLY BE CALLED ONCE)`,\n );\n this.ownRtcBackendIdentityCache = await this.rtcIdentityProvider(userId, deviceId, memberId);\n } else {\n this.ownRtcBackendIdentityCache = `${this.ownMembership.userId}:${this.ownMembership.deviceId}`;\n }\n return this.ownRtcBackendIdentityCache;\n }\n\n public getEncryptionKeys(): ReadonlyMap<\n EncryptionKeyMapKey,\n ReadonlyArray<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n rtcBackendIdentity: string;\n }>\n > {\n return new Map(this.participantKeyRings);\n }\n\n private keysWithoutMatchingRTCMembership: Array<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n }> = [];\n\n private checkKeysWithoutMatchingRTCMembership(): void {\n const keyInfoTemp = this.keysWithoutMatchingRTCMembership;\n this.keysWithoutMatchingRTCMembership = [];\n keyInfoTemp.forEach((keyInfo) => {\n this.addKeyToParticipant(keyInfo.key, keyInfo.keyIndex, keyInfo.membership);\n });\n }\n\n private addKeyToParticipant(\n key: Uint8Array<ArrayBuffer>,\n keyIndex: number,\n membership: CallMembershipIdentityParts,\n ): void {\n const knownRtcMembership = this.getMemberships();\n const fullMembership = knownRtcMembership.find(\n (member) => member.userId === membership.userId && member.deviceId === membership.deviceId,\n );\n if (!fullMembership) {\n this.logger?.info(\n `No matching RTC membership for key from ${membership.userId}:${membership.deviceId}, delaying key addition`,\n );\n this.keysWithoutMatchingRTCMembership.push({ key, keyIndex, membership });\n return;\n }\n this.addKeyToParticipantWithBackendIdentity(key, keyIndex, membership, fullMembership.rtcBackendIdentity);\n }\n\n private addKeyToParticipantWithBackendIdentity(\n key: Uint8Array<ArrayBuffer>,\n keyIndex: number,\n membership: CallMembershipIdentityParts,\n rtcBackendIdentity: string,\n ): void {\n const mapKey = getEncryptionKeyMapKey(membership);\n if (!this.participantKeyRings.has(mapKey)) {\n this.participantKeyRings.set(mapKey, []);\n }\n this.participantKeyRings.get(mapKey)!.push({ key, keyIndex, membership, rtcBackendIdentity });\n this.onEncryptionKeysChanged(key, keyIndex, membership, rtcBackendIdentity);\n }\n\n public join(joinConfig: (EncryptionConfig & MembershipConfig) | undefined): void {\n this.manageMediaKeys = joinConfig?.manageMediaKeys ?? true; // default to true\n this.useHashedRtcBackendIdentity = joinConfig?.unstableSendStickyEvents ?? false;\n this.useKeyDelay = joinConfig?.useKeyDelay ?? 1000;\n this.keyRotationGracePeriodMs = joinConfig?.keyRotationGracePeriodMs ?? 10_000;\n\n this.transport.on(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived);\n void this.getOwnRtcBackendIdentity(); // precompute own identity\n\n this.logger?.info(`Joining room`);\n this.transport.start();\n }\n\n public leave(): void {\n this.transport.off(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived);\n this.transport.stop();\n this.participantKeyRings.clear();\n }\n\n /**\n * Will ensure that a new key is distributed and used to encrypt our media.\n * If there is already a key distribution in progress, it will schedule a new distribution round just after the current one is completed.\n * If this function is called repeatedly while a distribution is in progress,\n * the calls will be coalesced to a single new distribution (that will start just after the current one has completed).\n */\n private ensureKeyDistribution(): void {\n // `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n if (!this.manageMediaKeys) return;\n if (this.currentKeyDistributionPromise == null) {\n this.logger?.debug(`No active rollout, start a new one`);\n // start a rollout\n this.currentKeyDistributionPromise = this.rolloutOutboundKey().then(() => {\n this.logger?.debug(`Rollout completed`);\n this.currentKeyDistributionPromise = null;\n if (this.needToEnsureKeyAgain) {\n this.logger?.debug(`New Rollout needed`);\n this.needToEnsureKeyAgain = false;\n // rollout a new one\n this.ensureKeyDistribution();\n }\n });\n } else {\n // There is a rollout in progress, but a key rotation is requested (could be caused by a ownMembership change)\n // Remember that a new rotation is needed after the current one.\n this.logger?.debug(`Rollout in progress, a new rollout will be started after the current one`);\n this.needToEnsureKeyAgain = true;\n }\n }\n\n public onNewKeyReceived: KeyTransportEventListener = (membership, keyBase64Encoded, index, timestamp) => {\n // `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n if (!this.manageMediaKeys) {\n this.logger?.warn(\n `Received key over transport ${membership.userId}:${membership.deviceId} at index ${index} but media keys are disabled`,\n );\n return;\n }\n this.logger?.debug(`Received key over transport ${membership.userId}:${membership.deviceId} at index ${index}`);\n\n // We received a new key, notify the video layer of this new key so that it can decrypt the frames properly.\n const keyBin = decodeBase64(keyBase64Encoded);\n const candidateInboundSession: InboundEncryptionSession = {\n key: keyBin,\n membership,\n keyIndex: index,\n creationTS: timestamp,\n };\n\n const outdated = this.keyBuffer.isOutdated(membership, candidateInboundSession);\n if (!outdated) {\n this.addKeyToParticipant(\n candidateInboundSession.key,\n candidateInboundSession.keyIndex,\n candidateInboundSession.membership,\n );\n } else {\n this.logger?.info(\n `Received an out of order key for ${membership.userId}:${membership.deviceId}, dropping it`,\n );\n }\n };\n\n /**\n * Called when the ownMembership of the call changes.\n * This encryption manager is very basic, it will rotate the key everytime this is called.\n * @param oldMemberships - This parameter is not used here, but it is kept for compatibility with the interface.\n */\n public onMembershipsUpdate(oldMemberships: CallMembership[] = []): void {\n this.logger?.trace(`onMembershipsUpdate`);\n\n // Ensure the key is distributed. This will be no-op if the key is already being distributed to everyone.\n // If there is an ongoing distribution, it will be completed before a new one is started.\n this.ensureKeyDistribution();\n // ensure key emission to the rtc backend\n this.checkKeysWithoutMatchingRTCMembership();\n }\n\n private async rolloutOutboundKey(): Promise<void> {\n const isFirstKey = this.outboundSession == null;\n if (isFirstKey) {\n // create the first key\n const firstKey = {\n key: this.generateRandomKey(),\n creationTS: Date.now(),\n sharedWith: [],\n keyId: 0,\n };\n this.outboundSession = firstKey;\n this.addKeyToParticipantWithBackendIdentity(\n firstKey.key,\n firstKey.keyId,\n this.ownMembership,\n await this.getOwnRtcBackendIdentity(),\n );\n }\n // get current memberships\n const toShareWith: ParticipantDeviceInfo[] = this.getMemberships()\n .filter((membership) => {\n return membership.sender != undefined;\n })\n .map((membership) => {\n return {\n userId: membership.sender!,\n deviceId: membership.deviceId,\n membershipTs: membership.createdTs(),\n };\n });\n\n let alreadySharedWith = this.outboundSession?.sharedWith ?? [];\n\n // Some users might have rotate their ownMembership event (formally called fingerprint) meaning they might have\n // clear their key. Reset the `alreadySharedWith` flag for them.\n alreadySharedWith = alreadySharedWith.filter(\n (x) =>\n // If there was a member with same userId and deviceId but different membershipTs, we need to clear it\n !toShareWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs != o.membershipTs,\n ),\n );\n\n const anyLeft = alreadySharedWith.filter(\n (x) =>\n !toShareWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs == o.membershipTs,\n ),\n );\n const anyJoined = toShareWith.filter(\n (x) =>\n !alreadySharedWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs == o.membershipTs,\n ),\n );\n\n let toDistributeTo: ParticipantDeviceInfo[] = [];\n let outboundKey: OutboundEncryptionSession;\n let hasKeyChanged = false;\n if (anyLeft.length > 0) {\n // We need to rotate the key\n const newOutboundKey = this.createNewOutboundSession();\n hasKeyChanged = true;\n toDistributeTo = toShareWith;\n outboundKey = newOutboundKey;\n } else if (anyJoined.length > 0) {\n const now = Date.now();\n const keyAge = now - this.outboundSession!.creationTS;\n // If the current key is recently created (less than `keyRotationGracePeriodMs`), we can keep it and just distribute it to the new joiners.\n if (keyAge < this.keyRotationGracePeriodMs) {\n // keep the same key\n // XXX In the future we want to distribute a ratcheted key, not the current one\n this.logger?.debug(`New joiners detected, but the key is recent enough (age:${keyAge}), keeping it`);\n toDistributeTo = anyJoined;\n outboundKey = this.outboundSession!;\n } else {\n // We need to rotate the key\n this.logger?.debug(`New joiners detected, rotating the key`);\n const newOutboundKey = this.createNewOutboundSession();\n hasKeyChanged = true;\n toDistributeTo = toShareWith;\n outboundKey = newOutboundKey;\n }\n } else {\n // no changes\n return;\n }\n\n try {\n this.logger?.trace(`Sending key...`);\n await this.transport.sendKey(encodeBase64(outboundKey.key), outboundKey.keyId, toDistributeTo);\n outboundKey.sharedWith.push(...toDistributeTo);\n this.logger?.trace(\n `key index:${outboundKey.keyId} sent to ${outboundKey.sharedWith.map((m) => `${m.userId}:${m.deviceId}`).join(\",\")}`,\n );\n if (hasKeyChanged) {\n // Delay a bit before using this key\n // It is recommended not to start using a key immediately but instead wait for a short time to make sure it is delivered.\n this.logger?.trace(`Delay Rollout for key:${outboundKey.keyId}...`);\n await sleep(this.useKeyDelay);\n this.logger?.trace(`...Delayed rollout of index:${outboundKey.keyId} `);\n this.addKeyToParticipantWithBackendIdentity(\n outboundKey.key,\n outboundKey.keyId,\n this.ownMembership,\n await this.getOwnRtcBackendIdentity(),\n );\n }\n } catch (err) {\n this.logger?.error(`Failed to rollout key`, err);\n }\n }\n\n private createNewOutboundSession(): OutboundEncryptionSession {\n const newOutboundKey: OutboundEncryptionSession = {\n key: this.generateRandomKey(),\n creationTS: Date.now(),\n sharedWith: [],\n keyId: this.nextKeyIndex(),\n };\n\n this.logger?.info(`creating new outbound key index:${newOutboundKey.keyId}`);\n // Set this new key as the current one\n this.outboundSession = newOutboundKey;\n return newOutboundKey;\n }\n\n private nextKeyIndex(): number {\n if (this.outboundSession) {\n return (this.outboundSession!.keyId + 1) % 256;\n }\n return 0;\n }\n\n private generateRandomKey(): Uint8Array<ArrayBuffer> {\n const key = new Uint8Array(16);\n globalThis.crypto.getRandomValues(key);\n return key;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"RTCEncryptionManager.js","names":["getEncryptionKeyMapKey","decodeBase64","encodeBase64","KeyTransportEvents","sleep","OutdatedKeyFilter","computeRtcIdentityRaw","RTCEncryptionManager","constructor","ownMembership","getMemberships","transport","onEncryptionKeysChanged","parentLogger","rtcBackendIdProvider","_defineProperty","Map","undefined","membership","keyBase64Encoded","index","timestamp","_this$logger2","manageMediaKeys","_this$logger","logger","warn","concat","userId","deviceId","debug","keyBin","candidateInboundSession","key","keyIndex","creationTS","outdated","keyBuffer","isOutdated","addKeyToParticipant","_this$logger3","info","getChild","rtcIdentityProvider","getOwnRtcBackendIdentity","_this","_asyncToGenerator","ownRtcBackendIdentityCache","useHashedRtcBackendIdentity","_this$logger4","_this$ownMembership","memberId","getEncryptionKeys","participantKeyRings","checkKeysWithoutMatchingRTCMembership","keyInfoTemp","keysWithoutMatchingRTCMembership","forEach","keyInfo","knownRtcMembership","fullMembership","find","member","_this$logger5","push","addKeyToParticipantWithBackendIdentity","rtcBackendIdentity","mapKey","has","set","get","join","joinConfig","_joinConfig$manageMed","_joinConfig$unstableS","_joinConfig$useKeyDel","_joinConfig$keyRotati","_this$logger6","unstableSendStickyEvents","useKeyDelay","keyRotationGracePeriodMs","on","ReceivedKeys","onNewKeyReceived","start","leave","off","stop","clear","ensureKeyDistribution","currentKeyDistributionPromise","_this$logger7","rolloutOutboundKey","then","_this$logger8","needToEnsureKeyAgain","_this$logger9","_this$logger0","onMembershipsUpdate","_this$logger1","oldMemberships","arguments","length","trace","_this2","_this2$outboundSessio","_this2$outboundSessio2","isFirstKey","outboundSession","firstKey","generateRandomKey","Date","now","sharedWith","keyId","toShareWith","filter","sender","map","membershipTs","createdTs","alreadySharedWith","x","some","o","anyLeft","anyJoined","toDistributeTo","outboundKey","hasKeyChanged","newOutboundKey","createNewOutboundSession","keyAge","_this2$logger","_this2$logger2","_this2$logger3","_this2$logger4","sendKey","m","_this2$logger5","_this2$logger6","err","_this2$logger7","error","_this$logger10","nextKeyIndex","Uint8Array","globalThis","crypto","getRandomValues"],"sources":["../../src/matrixrtc/RTCEncryptionManager.ts"],"sourcesContent":["/*\nCopyright 2025-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*/\n\nimport {\n type CallMembershipIdentityParts,\n getEncryptionKeyMapKey,\n type IEncryptionManager,\n} from \"./EncryptionManager.ts\";\nimport { type EncryptionConfig, type MembershipConfig } from \"./MatrixRTCSession.ts\";\nimport type { CallMembership } from \"./CallMembership.ts\";\nimport { decodeBase64, encodeBase64 } from \"../base64.ts\";\nimport { type IKeyTransport, type KeyTransportEventListener, KeyTransportEvents } from \"./IKeyTransport.ts\";\nimport { type Logger } from \"../logger.ts\";\nimport { sleep } from \"../utils.ts\";\nimport {\n type EncryptionKeyMapKey,\n type InboundEncryptionSession,\n type OutboundEncryptionSession,\n type ParticipantDeviceInfo,\n} from \"./types.ts\";\nimport { OutdatedKeyFilter } from \"./utils.ts\";\nimport { computeRtcIdentityRaw } from \"./membershipData/rtc.ts\";\n\n/**\n * RTCEncryptionManager is used to manage the encryption keys for a call.\n *\n * It is responsible for distributing the keys to the other participants and rotating the keys if needed.\n *\n * This manager when used with to-device transport will share the existing key only to new joiners, and rotate\n * if there is a leaver.\n *\n * XXX In the future we want to distribute a ratcheted key not the current one for new joiners.\n */\nexport class RTCEncryptionManager implements IEncryptionManager {\n // This is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n private manageMediaKeys = false;\n\n private useHashedRtcBackendIdentity = false;\n private ownRtcBackendIdentityCache: string | undefined;\n\n /**\n * Store the key rings for each participant.\n * The encryption manager stores the keys because the application layer might not be ready yet to handle the keys.\n * The keys are stored and can be retrieved later when the application layer is ready {@link RTCEncryptionManager#getEncryptionKeys}.\n */\n private readonly participantKeyRings = new Map<\n EncryptionKeyMapKey,\n Array<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n rtcBackendIdentity: string;\n }>\n >();\n\n // The current per-sender media key for this device\n private outboundSession: OutboundEncryptionSession | null = null;\n\n /**\n * Ensures that there is only one distribute operation at a time for that call.\n */\n private currentKeyDistributionPromise: Promise<void> | null = null;\n\n /**\n * The time to wait before using the outbound session after it has been distributed.\n * This is to ensure that the key is delivered to all participants before it is used.\n * When creating the first key, this is set to 0 so that the key can be used immediately.\n */\n private useKeyDelay = 5000;\n\n /**\n * We want to avoid rolling out a new outbound key when the previous one was created less than `keyRotationGracePeriodMs` milliseconds ago.\n * This is to avoid expensive key rotations when users quickly join the call in a row.\n *\n * This must be higher than `useKeyDelay` to have an effect.\n * If it is lower, the current key will always be older than the grace period.\n * @private\n */\n private keyRotationGracePeriodMs = 10_000;\n\n /**\n * If a new key distribution is being requested while one is going on, we will set this flag to true.\n * This will ensure that a new round is started after the current one.\n * @private\n */\n private needToEnsureKeyAgain = false;\n\n /**\n * There is a possibility that keys arrive in the wrong order.\n * For example, after a quick join/leave/join, there will be 2 keys of index 0 distributed, and\n * if they are received in the wrong order, the stream won't be decryptable.\n * For that reason we keep a small buffer of keys for a limited time to disambiguate.\n * @private\n */\n private keyBuffer = new OutdatedKeyFilter();\n\n private logger: Logger | undefined = undefined;\n\n private readonly rtcIdentityProvider: (userId: string, deviceId: string, memberId: string) => Promise<string>;\n\n /**\n *\n * @param ownMembership - our own membership info\n * @param getMemberships - function to get current memberships\n * @param transport - key transport (room or to-device)\n * @param statistics - statistics collector\n * @param onEncryptionKeysChanged - callback to notify the media layer of new keys\n * @param parentLogger - optional parent logger\n * @param rtcBackendIdProvider - A function to compute the rtc backend identity, exposed for testing purposes\n */\n public constructor(\n private readonly ownMembership: CallMembershipIdentityParts,\n private getMemberships: () => CallMembership[],\n private transport: IKeyTransport,\n // Callback to notify the media layer of new keys\n private onEncryptionKeysChanged: (\n keyBin: Uint8Array<ArrayBuffer>,\n encryptionKeyIndex: number,\n membership: CallMembershipIdentityParts,\n rtcBackendIdentity: string,\n ) => void,\n parentLogger?: Logger,\n rtcBackendIdProvider?: (userId: string, deviceId: string, memberId: string) => Promise<string>,\n ) {\n this.logger = parentLogger?.getChild(`[EncryptionManager]`);\n this.rtcIdentityProvider = rtcBackendIdProvider ?? computeRtcIdentityRaw;\n }\n\n private async getOwnRtcBackendIdentity(): Promise<string> {\n if (this.ownRtcBackendIdentityCache) return this.ownRtcBackendIdentityCache;\n\n if (this.useHashedRtcBackendIdentity) {\n const { userId, deviceId, memberId } = this.ownMembership;\n this.logger?.info(\n // If we see this log multiple times, we need to reconsider the precompute call of getOwnRtcBackendIdentity\n `Computing RTC backend identity for ${userId}:${deviceId}:${memberId} (SHOULD ONLY BE CALLED ONCE)`,\n );\n this.ownRtcBackendIdentityCache = await this.rtcIdentityProvider(userId, deviceId, memberId);\n } else {\n this.ownRtcBackendIdentityCache = `${this.ownMembership.userId}:${this.ownMembership.deviceId}`;\n }\n return this.ownRtcBackendIdentityCache;\n }\n\n public getEncryptionKeys(): ReadonlyMap<\n EncryptionKeyMapKey,\n ReadonlyArray<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n rtcBackendIdentity: string;\n }>\n > {\n return new Map(this.participantKeyRings);\n }\n\n private keysWithoutMatchingRTCMembership: Array<{\n key: Uint8Array<ArrayBuffer>;\n keyIndex: number;\n membership: CallMembershipIdentityParts;\n }> = [];\n\n private checkKeysWithoutMatchingRTCMembership(): void {\n const keyInfoTemp = this.keysWithoutMatchingRTCMembership;\n this.keysWithoutMatchingRTCMembership = [];\n keyInfoTemp.forEach((keyInfo) => {\n this.addKeyToParticipant(keyInfo.key, keyInfo.keyIndex, keyInfo.membership);\n });\n }\n\n private addKeyToParticipant(\n key: Uint8Array<ArrayBuffer>,\n keyIndex: number,\n membership: CallMembershipIdentityParts,\n ): void {\n const knownRtcMembership = this.getMemberships();\n const fullMembership = knownRtcMembership.find(\n (member) => member.userId === membership.userId && member.deviceId === membership.deviceId,\n );\n if (!fullMembership) {\n this.logger?.info(\n `No matching RTC membership for key from ${membership.userId}:${membership.deviceId}, delaying key addition`,\n );\n this.keysWithoutMatchingRTCMembership.push({ key, keyIndex, membership });\n return;\n }\n this.addKeyToParticipantWithBackendIdentity(key, keyIndex, membership, fullMembership.rtcBackendIdentity);\n }\n\n private addKeyToParticipantWithBackendIdentity(\n key: Uint8Array<ArrayBuffer>,\n keyIndex: number,\n membership: CallMembershipIdentityParts,\n rtcBackendIdentity: string,\n ): void {\n const mapKey = getEncryptionKeyMapKey(membership);\n if (!this.participantKeyRings.has(mapKey)) {\n this.participantKeyRings.set(mapKey, []);\n }\n this.participantKeyRings.get(mapKey)!.push({ key, keyIndex, membership, rtcBackendIdentity });\n this.onEncryptionKeysChanged(key, keyIndex, membership, rtcBackendIdentity);\n }\n\n public join(joinConfig: (EncryptionConfig & MembershipConfig) | undefined): void {\n this.manageMediaKeys = joinConfig?.manageMediaKeys ?? true; // default to true\n this.useHashedRtcBackendIdentity = joinConfig?.unstableSendStickyEvents ?? false;\n this.useKeyDelay = joinConfig?.useKeyDelay ?? 1000;\n this.keyRotationGracePeriodMs = joinConfig?.keyRotationGracePeriodMs ?? 10_000;\n\n this.transport.on(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived);\n void this.getOwnRtcBackendIdentity(); // precompute own identity\n\n this.logger?.info(`Joining room`);\n this.transport.start();\n }\n\n public leave(): void {\n this.transport.off(KeyTransportEvents.ReceivedKeys, this.onNewKeyReceived);\n this.transport.stop();\n this.participantKeyRings.clear();\n }\n\n /**\n * Will ensure that a new key is distributed and used to encrypt our media.\n * If there is already a key distribution in progress, it will schedule a new distribution round just after the current one is completed.\n * If this function is called repeatedly while a distribution is in progress,\n * the calls will be coalesced to a single new distribution (that will start just after the current one has completed).\n */\n private ensureKeyDistribution(): void {\n // `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n if (!this.manageMediaKeys) return;\n if (this.currentKeyDistributionPromise == null) {\n this.logger?.debug(`No active rollout, start a new one`);\n // start a rollout\n this.currentKeyDistributionPromise = this.rolloutOutboundKey().then(() => {\n this.logger?.debug(`Rollout completed`);\n this.currentKeyDistributionPromise = null;\n if (this.needToEnsureKeyAgain) {\n this.logger?.debug(`New Rollout needed`);\n this.needToEnsureKeyAgain = false;\n // rollout a new one\n this.ensureKeyDistribution();\n }\n });\n } else {\n // There is a rollout in progress, but a key rotation is requested (could be caused by a ownMembership change)\n // Remember that a new rotation is needed after the current one.\n this.logger?.debug(`Rollout in progress, a new rollout will be started after the current one`);\n this.needToEnsureKeyAgain = true;\n }\n }\n\n public onNewKeyReceived: KeyTransportEventListener = (membership, keyBase64Encoded, index, timestamp) => {\n // `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead\n // to create a NoOpEncryptionManager that does nothing and use it for the session.\n // This will be done when removing the legacy EncryptionManager.\n if (!this.manageMediaKeys) {\n this.logger?.warn(\n `Received key over transport ${membership.userId}:${membership.deviceId} at index ${index} but media keys are disabled`,\n );\n return;\n }\n this.logger?.debug(`Received key over transport ${membership.userId}:${membership.deviceId} at index ${index}`);\n\n // We received a new key, notify the video layer of this new key so that it can decrypt the frames properly.\n const keyBin = decodeBase64(keyBase64Encoded);\n const candidateInboundSession: InboundEncryptionSession = {\n key: keyBin,\n membership,\n keyIndex: index,\n creationTS: timestamp,\n };\n\n const outdated = this.keyBuffer.isOutdated(membership, candidateInboundSession);\n if (!outdated) {\n this.addKeyToParticipant(\n candidateInboundSession.key,\n candidateInboundSession.keyIndex,\n candidateInboundSession.membership,\n );\n } else {\n this.logger?.info(\n `Received an out of order key for ${membership.userId}:${membership.deviceId}, dropping it`,\n );\n }\n };\n\n /**\n * Called when the ownMembership of the call changes.\n * This encryption manager is very basic, it will rotate the key everytime this is called.\n * @param oldMemberships - This parameter is not used here, but it is kept for compatibility with the interface.\n */\n public onMembershipsUpdate(oldMemberships: CallMembership[] = []): void {\n this.logger?.trace(`onMembershipsUpdate`);\n\n // Ensure the key is distributed. This will be no-op if the key is already being distributed to everyone.\n // If there is an ongoing distribution, it will be completed before a new one is started.\n this.ensureKeyDistribution();\n // ensure key emission to the rtc backend\n this.checkKeysWithoutMatchingRTCMembership();\n }\n\n private async rolloutOutboundKey(): Promise<void> {\n const isFirstKey = this.outboundSession == null;\n if (isFirstKey) {\n // create the first key\n const firstKey = {\n key: this.generateRandomKey(),\n creationTS: Date.now(),\n sharedWith: [],\n keyId: 0,\n };\n this.outboundSession = firstKey;\n this.addKeyToParticipantWithBackendIdentity(\n firstKey.key,\n firstKey.keyId,\n this.ownMembership,\n await this.getOwnRtcBackendIdentity(),\n );\n }\n // get current memberships\n const toShareWith: ParticipantDeviceInfo[] = this.getMemberships()\n .filter((membership) => {\n return membership.sender != undefined;\n })\n .map((membership) => {\n return {\n userId: membership.sender!,\n deviceId: membership.deviceId,\n membershipTs: membership.createdTs(),\n };\n });\n\n let alreadySharedWith = this.outboundSession?.sharedWith ?? [];\n\n // Some users might have rotate their ownMembership event (formally called fingerprint) meaning they might have\n // clear their key. Reset the `alreadySharedWith` flag for them.\n alreadySharedWith = alreadySharedWith.filter(\n (x) =>\n // If there was a member with same userId and deviceId but different membershipTs, we need to clear it\n !toShareWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs != o.membershipTs,\n ),\n );\n\n const anyLeft = alreadySharedWith.filter(\n (x) =>\n !toShareWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs == o.membershipTs,\n ),\n );\n const anyJoined = toShareWith.filter(\n (x) =>\n !alreadySharedWith.some(\n (o) => x.userId == o.userId && x.deviceId == o.deviceId && x.membershipTs == o.membershipTs,\n ),\n );\n\n let toDistributeTo: ParticipantDeviceInfo[] = [];\n let outboundKey: OutboundEncryptionSession;\n let hasKeyChanged = false;\n if (anyLeft.length > 0) {\n // We need to rotate the key\n const newOutboundKey = this.createNewOutboundSession();\n hasKeyChanged = true;\n toDistributeTo = toShareWith;\n outboundKey = newOutboundKey;\n } else if (anyJoined.length > 0) {\n const now = Date.now();\n const keyAge = now - this.outboundSession!.creationTS;\n // If the current key is recently created (less than `keyRotationGracePeriodMs`), we can keep it and just distribute it to the new joiners.\n if (keyAge < this.keyRotationGracePeriodMs) {\n // keep the same key\n // XXX In the future we want to distribute a ratcheted key, not the current one\n this.logger?.debug(`New joiners detected, but the key is recent enough (age:${keyAge}), keeping it`);\n toDistributeTo = anyJoined;\n outboundKey = this.outboundSession!;\n } else {\n // We need to rotate the key\n this.logger?.debug(`New joiners detected, rotating the key`);\n const newOutboundKey = this.createNewOutboundSession();\n hasKeyChanged = true;\n toDistributeTo = toShareWith;\n outboundKey = newOutboundKey;\n }\n } else {\n // no changes\n return;\n }\n\n try {\n this.logger?.trace(`Sending key...`);\n await this.transport.sendKey(encodeBase64(outboundKey.key), outboundKey.keyId, toDistributeTo);\n outboundKey.sharedWith.push(...toDistributeTo);\n this.logger?.trace(\n `key index:${outboundKey.keyId} sent to ${outboundKey.sharedWith.map((m) => `${m.userId}:${m.deviceId}`).join(\",\")}`,\n );\n if (hasKeyChanged) {\n // Delay a bit before using this key\n // It is recommended not to start using a key immediately but instead wait for a short time to make sure it is delivered.\n this.logger?.trace(`Delay Rollout for key:${outboundKey.keyId}...`);\n await sleep(this.useKeyDelay);\n this.logger?.trace(`...Delayed rollout of index:${outboundKey.keyId} `);\n this.addKeyToParticipantWithBackendIdentity(\n outboundKey.key,\n outboundKey.keyId,\n this.ownMembership,\n await this.getOwnRtcBackendIdentity(),\n );\n }\n } catch (err) {\n this.logger?.error(`Failed to rollout key`, err);\n }\n }\n\n private createNewOutboundSession(): OutboundEncryptionSession {\n const newOutboundKey: OutboundEncryptionSession = {\n key: this.generateRandomKey(),\n creationTS: Date.now(),\n sharedWith: [],\n keyId: this.nextKeyIndex(),\n };\n\n this.logger?.info(`creating new outbound key index:${newOutboundKey.keyId}`);\n // Set this new key as the current one\n this.outboundSession = newOutboundKey;\n return newOutboundKey;\n }\n\n private nextKeyIndex(): number {\n if (this.outboundSession) {\n return (this.outboundSession!.keyId + 1) % 256;\n }\n return 0;\n }\n\n private generateRandomKey(): Uint8Array<ArrayBuffer> {\n const key = new Uint8Array(16);\n globalThis.crypto.getRandomValues(key);\n return key;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -39,10 +39,6 @@ export class ToDeviceKeyTransport extends TypedEventEmitter {
|
|
|
39
39
|
}
|
|
40
40
|
constructor(membership, roomId, client, statistics, parentLogger) {
|
|
41
41
|
super();
|
|
42
|
-
this.membership = membership;
|
|
43
|
-
this.roomId = roomId;
|
|
44
|
-
this.client = client;
|
|
45
|
-
this.statistics = statistics;
|
|
46
42
|
_defineProperty(this, "logger", rootLogger);
|
|
47
43
|
_defineProperty(this, "onToDeviceEvent", event => {
|
|
48
44
|
if (event.getType() !== EventType.CallEncryptionKeysPrefix) {
|
|
@@ -63,6 +59,10 @@ export class ToDeviceKeyTransport extends TypedEventEmitter {
|
|
|
63
59
|
if (!event.getSender()) return;
|
|
64
60
|
this.receiveCallKeyEvent(event.getSender(), content);
|
|
65
61
|
});
|
|
62
|
+
this.membership = membership;
|
|
63
|
+
this.roomId = roomId;
|
|
64
|
+
this.client = client;
|
|
65
|
+
this.statistics = statistics;
|
|
66
66
|
this.setParentLogger(parentLogger !== null && parentLogger !== void 0 ? parentLogger : rootLogger);
|
|
67
67
|
}
|
|
68
68
|
start() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToDeviceKeyTransport.js","names":["TypedEventEmitter","KeyTransportEvents","logger","rootLogger","ClientEvent","EventType","NotSupportedError","Error","constructor","message","name","ToDeviceKeyTransport","setParentLogger","parentLogger","getChild","membership","roomId","client","statistics","_defineProperty","event","getType","CallEncryptionKeysPrefix","content","getValidEventContent","getSender","receiveCallKeyEvent","start","on","ToDeviceEvent","onToDeviceEvent","stop","off","sendKey","keyBase64Encoded","index","members","_this","_asyncToGenerator","keys","key","room_id","member","claimed_device_id","deviceId","id","memberId","session","call_id","application","scope","sent_ts","Date","now","targets","map","userId","filter","length","encryptAndSendToDevice","catch","error","msg","includes","counters","roomEventEncryptionKeysSent","warn","fromUser","_content$member$id","roomEventEncryptionKeysReceived","age","totals","roomEventEncryptionKeysReceivedTotalAge","hardcodedMemberIdAlternative","concat","emit","ReceivedKeys","getContent"],"sources":["../../src/matrixrtc/ToDeviceKeyTransport.ts"],"sourcesContent":["/*\nCopyright 2025 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*/\n\nimport { type WidgetApiResponseError } from \"matrix-widget-api\";\n\nimport { TypedEventEmitter } from \"../models/typed-event-emitter.ts\";\nimport { type IKeyTransport, KeyTransportEvents, type KeyTransportEventsHandlerMap } from \"./IKeyTransport.ts\";\nimport { type Logger, logger as rootLogger } from \"../logger.ts\";\nimport { type EncryptionKeysToDeviceEventContent, type ParticipantDeviceInfo, type Statistics } from \"./types.ts\";\nimport { ClientEvent, type MatrixClient } from \"../client.ts\";\nimport type { MatrixEvent } from \"../models/event.ts\";\nimport { EventType } from \"../@types/event.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\n\nexport class NotSupportedError extends Error {\n public constructor(message?: string) {\n super(message);\n }\n public get name(): string {\n return \"NotSupportedError\";\n }\n}\n/**\n * ToDeviceKeyTransport is used to send MatrixRTC keys to other devices using the\n * to-device CS-API.\n */\nexport class ToDeviceKeyTransport\n extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>\n implements IKeyTransport\n{\n private logger: Logger = rootLogger;\n\n public setParentLogger(parentLogger: Logger): void {\n this.logger = parentLogger.getChild(`[ToDeviceKeyTransport]`);\n }\n\n public constructor(\n private membership: CallMembershipIdentityParts,\n private roomId: string,\n private client: Pick<MatrixClient, \"encryptAndSendToDevice\" | \"on\" | \"off\">,\n private statistics: Statistics,\n parentLogger?: Logger,\n ) {\n super();\n this.setParentLogger(parentLogger ?? rootLogger);\n }\n\n public start(): void {\n this.client.on(ClientEvent.ToDeviceEvent, this.onToDeviceEvent);\n }\n\n public stop(): void {\n this.client.off(ClientEvent.ToDeviceEvent, this.onToDeviceEvent);\n }\n\n public async sendKey(keyBase64Encoded: string, index: number, members: ParticipantDeviceInfo[]): Promise<void> {\n const content: EncryptionKeysToDeviceEventContent = {\n keys: {\n index: index,\n key: keyBase64Encoded,\n },\n room_id: this.roomId,\n member: {\n claimed_device_id: this.membership.deviceId,\n id: this.membership.memberId,\n },\n session: {\n call_id: \"\",\n application: \"m.call\",\n scope: \"m.room\",\n },\n sent_ts: Date.now(),\n };\n\n const targets = members\n .map((member) => {\n return {\n userId: member.userId!,\n deviceId: member.deviceId!,\n };\n })\n // filter out me\n .filter(\n (member) => !(member.userId == this.membership.userId && member.deviceId == this.membership.deviceId),\n );\n\n if (targets.length > 0) {\n await this.client\n .encryptAndSendToDevice(EventType.CallEncryptionKeysPrefix, targets, content)\n .catch((error: WidgetApiResponseError) => {\n const msg: string = error.message;\n // This is not ideal. We would want to have a custom error type for unsupported actions.\n // This is not part of the widget API spec. Since as of now there are only two implementations:\n // Rust SDK + JS-SDK, and the JS-SDK does support to-device sending, we can assume that\n // this is a widget driver issue error message.\n if (\n (msg.includes(\"unknown variant\") && msg.includes(\"send_to_device\")) ||\n msg.includes(\"not supported\")\n ) {\n throw new NotSupportedError(\"The widget driver does not support to-device encryption\");\n }\n });\n this.statistics.counters.roomEventEncryptionKeysSent += 1;\n } else {\n this.logger.warn(\"No targets found for sending key\");\n }\n }\n\n private receiveCallKeyEvent(fromUser: string, content: EncryptionKeysToDeviceEventContent): void {\n // The event has already been validated at this point.\n\n this.statistics.counters.roomEventEncryptionKeysReceived += 1;\n\n // What is this, and why is it needed?\n // Also to device events do not have an origin server ts\n const now = Date.now();\n const age = now - (typeof content.sent_ts === \"number\" ? content.sent_ts : now);\n this.statistics.totals.roomEventEncryptionKeysReceivedTotalAge += age;\n\n const hardcodedMemberIdAlternative = `${fromUser}:${content.member.claimed_device_id}`;\n\n this.emit(\n KeyTransportEvents.ReceivedKeys,\n // TODO userId this is claimed information, deviceId is claimed information\n {\n userId: fromUser,\n deviceId: content.member.claimed_device_id!,\n memberId: content.member.id ?? hardcodedMemberIdAlternative,\n },\n content.keys.key,\n content.keys.index,\n now,\n );\n }\n\n private onToDeviceEvent = (event: MatrixEvent): void => {\n if (event.getType() !== EventType.CallEncryptionKeysPrefix) {\n // Ignore this is not a call encryption event\n return;\n }\n\n // TODO: Not possible to check if the event is encrypted or not\n // see https://github.com/matrix-org/matrix-rust-sdk/issues/4883\n // if (evnt.getWireType() != EventType.RoomMessageEncrypted) {\n // // WARN: The call keys were sent in clear. Ignore them\n // logger.warn(`Call encryption keys sent in clear from: ${event.getSender()}`);\n // return;\n // }\n\n const content = this.getValidEventContent(event);\n if (!content) return;\n\n if (!event.getSender()) return;\n\n this.receiveCallKeyEvent(event.getSender()!, content);\n };\n\n private getValidEventContent(event: MatrixEvent): EncryptionKeysToDeviceEventContent | undefined {\n const content = event.getContent();\n const roomId = content.room_id;\n if (!roomId) {\n // Invalid event\n this.logger.warn(\"Malformed Event: invalid call encryption keys event, no roomId\");\n return;\n }\n if (roomId !== this.roomId) {\n this.logger.warn(\"Malformed Event: Mismatch roomId\");\n return;\n }\n\n if (!content.keys || !content.keys.key || typeof content.keys.index !== \"number\") {\n this.logger.warn(\"Malformed Event: Missing keys field\");\n return;\n }\n\n if (!content.member || !content.member.claimed_device_id) {\n this.logger.warn(\"Malformed Event: Missing claimed_device_id\");\n return;\n }\n\n // TODO check for session related fields once the to-device encryption uses the new format.\n return content as EncryptionKeysToDeviceEventContent;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ToDeviceKeyTransport.js","names":["TypedEventEmitter","KeyTransportEvents","logger","rootLogger","ClientEvent","EventType","NotSupportedError","Error","constructor","message","name","ToDeviceKeyTransport","setParentLogger","parentLogger","getChild","membership","roomId","client","statistics","_defineProperty","event","getType","CallEncryptionKeysPrefix","content","getValidEventContent","getSender","receiveCallKeyEvent","start","on","ToDeviceEvent","onToDeviceEvent","stop","off","sendKey","keyBase64Encoded","index","members","_this","_asyncToGenerator","keys","key","room_id","member","claimed_device_id","deviceId","id","memberId","session","call_id","application","scope","sent_ts","Date","now","targets","map","userId","filter","length","encryptAndSendToDevice","catch","error","msg","includes","counters","roomEventEncryptionKeysSent","warn","fromUser","_content$member$id","roomEventEncryptionKeysReceived","age","totals","roomEventEncryptionKeysReceivedTotalAge","hardcodedMemberIdAlternative","concat","emit","ReceivedKeys","getContent"],"sources":["../../src/matrixrtc/ToDeviceKeyTransport.ts"],"sourcesContent":["/*\nCopyright 2025 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*/\n\nimport { type WidgetApiResponseError } from \"matrix-widget-api\";\n\nimport { TypedEventEmitter } from \"../models/typed-event-emitter.ts\";\nimport { type IKeyTransport, KeyTransportEvents, type KeyTransportEventsHandlerMap } from \"./IKeyTransport.ts\";\nimport { type Logger, logger as rootLogger } from \"../logger.ts\";\nimport { type EncryptionKeysToDeviceEventContent, type ParticipantDeviceInfo, type Statistics } from \"./types.ts\";\nimport { ClientEvent, type MatrixClient } from \"../client.ts\";\nimport type { MatrixEvent } from \"../models/event.ts\";\nimport { EventType } from \"../@types/event.ts\";\nimport { type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\n\nexport class NotSupportedError extends Error {\n public constructor(message?: string) {\n super(message);\n }\n public get name(): string {\n return \"NotSupportedError\";\n }\n}\n/**\n * ToDeviceKeyTransport is used to send MatrixRTC keys to other devices using the\n * to-device CS-API.\n */\nexport class ToDeviceKeyTransport\n extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>\n implements IKeyTransport\n{\n private logger: Logger = rootLogger;\n\n public setParentLogger(parentLogger: Logger): void {\n this.logger = parentLogger.getChild(`[ToDeviceKeyTransport]`);\n }\n\n public constructor(\n private membership: CallMembershipIdentityParts,\n private roomId: string,\n private client: Pick<MatrixClient, \"encryptAndSendToDevice\" | \"on\" | \"off\">,\n private statistics: Statistics,\n parentLogger?: Logger,\n ) {\n super();\n this.setParentLogger(parentLogger ?? rootLogger);\n }\n\n public start(): void {\n this.client.on(ClientEvent.ToDeviceEvent, this.onToDeviceEvent);\n }\n\n public stop(): void {\n this.client.off(ClientEvent.ToDeviceEvent, this.onToDeviceEvent);\n }\n\n public async sendKey(keyBase64Encoded: string, index: number, members: ParticipantDeviceInfo[]): Promise<void> {\n const content: EncryptionKeysToDeviceEventContent = {\n keys: {\n index: index,\n key: keyBase64Encoded,\n },\n room_id: this.roomId,\n member: {\n claimed_device_id: this.membership.deviceId,\n id: this.membership.memberId,\n },\n session: {\n call_id: \"\",\n application: \"m.call\",\n scope: \"m.room\",\n },\n sent_ts: Date.now(),\n };\n\n const targets = members\n .map((member) => {\n return {\n userId: member.userId!,\n deviceId: member.deviceId!,\n };\n })\n // filter out me\n .filter(\n (member) => !(member.userId == this.membership.userId && member.deviceId == this.membership.deviceId),\n );\n\n if (targets.length > 0) {\n await this.client\n .encryptAndSendToDevice(EventType.CallEncryptionKeysPrefix, targets, content)\n .catch((error: WidgetApiResponseError) => {\n const msg: string = error.message;\n // This is not ideal. We would want to have a custom error type for unsupported actions.\n // This is not part of the widget API spec. Since as of now there are only two implementations:\n // Rust SDK + JS-SDK, and the JS-SDK does support to-device sending, we can assume that\n // this is a widget driver issue error message.\n if (\n (msg.includes(\"unknown variant\") && msg.includes(\"send_to_device\")) ||\n msg.includes(\"not supported\")\n ) {\n throw new NotSupportedError(\"The widget driver does not support to-device encryption\");\n }\n });\n this.statistics.counters.roomEventEncryptionKeysSent += 1;\n } else {\n this.logger.warn(\"No targets found for sending key\");\n }\n }\n\n private receiveCallKeyEvent(fromUser: string, content: EncryptionKeysToDeviceEventContent): void {\n // The event has already been validated at this point.\n\n this.statistics.counters.roomEventEncryptionKeysReceived += 1;\n\n // What is this, and why is it needed?\n // Also to device events do not have an origin server ts\n const now = Date.now();\n const age = now - (typeof content.sent_ts === \"number\" ? content.sent_ts : now);\n this.statistics.totals.roomEventEncryptionKeysReceivedTotalAge += age;\n\n const hardcodedMemberIdAlternative = `${fromUser}:${content.member.claimed_device_id}`;\n\n this.emit(\n KeyTransportEvents.ReceivedKeys,\n // TODO userId this is claimed information, deviceId is claimed information\n {\n userId: fromUser,\n deviceId: content.member.claimed_device_id!,\n memberId: content.member.id ?? hardcodedMemberIdAlternative,\n },\n content.keys.key,\n content.keys.index,\n now,\n );\n }\n\n private onToDeviceEvent = (event: MatrixEvent): void => {\n if (event.getType() !== EventType.CallEncryptionKeysPrefix) {\n // Ignore this is not a call encryption event\n return;\n }\n\n // TODO: Not possible to check if the event is encrypted or not\n // see https://github.com/matrix-org/matrix-rust-sdk/issues/4883\n // if (evnt.getWireType() != EventType.RoomMessageEncrypted) {\n // // WARN: The call keys were sent in clear. Ignore them\n // logger.warn(`Call encryption keys sent in clear from: ${event.getSender()}`);\n // return;\n // }\n\n const content = this.getValidEventContent(event);\n if (!content) return;\n\n if (!event.getSender()) return;\n\n this.receiveCallKeyEvent(event.getSender()!, content);\n };\n\n private getValidEventContent(event: MatrixEvent): EncryptionKeysToDeviceEventContent | undefined {\n const content = event.getContent();\n const roomId = content.room_id;\n if (!roomId) {\n // Invalid event\n this.logger.warn(\"Malformed Event: invalid call encryption keys event, no roomId\");\n return;\n }\n if (roomId !== this.roomId) {\n this.logger.warn(\"Malformed Event: Mismatch roomId\");\n return;\n }\n\n if (!content.keys || !content.keys.key || typeof content.keys.index !== \"number\") {\n this.logger.warn(\"Malformed Event: Missing keys field\");\n return;\n }\n\n if (!content.member || !content.member.claimed_device_id) {\n this.logger.warn(\"Malformed Event: Missing claimed_device_id\");\n return;\n }\n\n // TODO check for session related fields once the to-device encryption uses the new format.\n return content as EncryptionKeysToDeviceEventContent;\n }\n}\n"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA,SAASA,iBAAiB,QAAQ,kCAAkC;AACpE,SAA6BC,kBAAkB,QAA2C,oBAAoB;AAC9G,SAAsBC,MAAM,IAAIC,UAAU,QAAQ,cAAc;AAEhE,SAASC,WAAW,QAA2B,cAAc;AAE7D,SAASC,SAAS,QAAQ,oBAAoB;AAG9C,OAAO,MAAMC,iBAAiB,SAASC,KAAK,CAAC;EAClCC,WAAWA,CAACC,OAAgB,EAAE;IACjC,KAAK,CAACA,OAAO,CAAC;EAClB;EACA,IAAWC,IAAIA,CAAA,EAAW;IACtB,OAAO,mBAAmB;EAC9B;AACJ;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,oBAAoB,SACrBX,iBAAiB,CAE7B;EAGWY,eAAeA,CAACC,YAAoB,EAAQ;IAC/C,IAAI,CAACX,MAAM,GAAGW,YAAY,CAACC,QAAQ,yBAAyB,CAAC;EACjE;EAEON,WAAWA,CACNO,UAAuC,EACvCC,MAAc,EACdC,MAAmE,EACnEC,UAAsB,EAC9BL,YAAqB,EACvB;IACE,KAAK,CAAC,CAAC;IAACM,eAAA,iBAbahB,UAAU;IAAAgB,eAAA,0BAyGRC,KAAkB,IAAW;MACpD,IAAIA,KAAK,CAACC,OAAO,CAAC,CAAC,KAAKhB,SAAS,CAACiB,wBAAwB,EAAE;QACxD;QACA;MACJ;;MAEA;MACA;MACA;MACA;MACA;MACA;MACA;;MAEA,IAAMC,OAAO,GAAG,IAAI,CAACC,oBAAoB,CAACJ,KAAK,CAAC;MAChD,IAAI,CAACG,OAAO,EAAE;MAEd,IAAI,CAACH,KAAK,CAACK,SAAS,CAAC,CAAC,EAAE;MAExB,IAAI,CAACC,mBAAmB,CAACN,KAAK,CAACK,SAAS,CAAC,CAAC,EAAGF,OAAO,CAAC;IACzD,CAAC;IAAA,KAtHWR,UAAuC,GAAvCA,UAAuC;IAAA,KACvCC,MAAc,GAAdA,MAAc;IAAA,KACdC,MAAmE,GAAnEA,MAAmE;IAAA,KACnEC,UAAsB,GAAtBA,UAAsB;IAI9B,IAAI,CAACN,eAAe,CAACC,YAAY,aAAZA,YAAY,cAAZA,YAAY,GAAIV,UAAU,CAAC;EACpD;EAEOwB,KAAKA,CAAA,EAAS;IACjB,IAAI,CAACV,MAAM,CAACW,EAAE,CAACxB,WAAW,CAACyB,aAAa,EAAE,IAAI,CAACC,eAAe,CAAC;EACnE;EAEOC,IAAIA,CAAA,EAAS;IAChB,IAAI,CAACd,MAAM,CAACe,GAAG,CAAC5B,WAAW,CAACyB,aAAa,EAAE,IAAI,CAACC,eAAe,CAAC;EACpE;EAEaG,OAAOA,CAACC,gBAAwB,EAAEC,KAAa,EAAEC,OAAgC,EAAiB;IAAA,IAAAC,KAAA;IAAA,OAAAC,iBAAA;MAC3G,IAAMf,OAA2C,GAAG;QAChDgB,IAAI,EAAE;UACFJ,KAAK,EAAEA,KAAK;UACZK,GAAG,EAAEN;QACT,CAAC;QACDO,OAAO,EAAEJ,KAAI,CAACrB,MAAM;QACpB0B,MAAM,EAAE;UACJC,iBAAiB,EAAEN,KAAI,CAACtB,UAAU,CAAC6B,QAAQ;UAC3CC,EAAE,EAAER,KAAI,CAACtB,UAAU,CAAC+B;QACxB,CAAC;QACDC,OAAO,EAAE;UACLC,OAAO,EAAE,EAAE;UACXC,WAAW,EAAE,QAAQ;UACrBC,KAAK,EAAE;QACX,CAAC;QACDC,OAAO,EAAEC,IAAI,CAACC,GAAG,CAAC;MACtB,CAAC;MAED,IAAMC,OAAO,GAAGlB,OAAO,CAClBmB,GAAG,CAAEb,MAAM,IAAK;QACb,OAAO;UACHc,MAAM,EAAEd,MAAM,CAACc,MAAO;UACtBZ,QAAQ,EAAEF,MAAM,CAACE;QACrB,CAAC;MACL,CAAC;MACD;MAAA,CACCa,MAAM,CACFf,MAAM,IAAK,EAAEA,MAAM,CAACc,MAAM,IAAInB,KAAI,CAACtB,UAAU,CAACyC,MAAM,IAAId,MAAM,CAACE,QAAQ,IAAIP,KAAI,CAACtB,UAAU,CAAC6B,QAAQ,CACxG,CAAC;MAEL,IAAIU,OAAO,CAACI,MAAM,GAAG,CAAC,EAAE;QACpB,MAAMrB,KAAI,CAACpB,MAAM,CACZ0C,sBAAsB,CAACtD,SAAS,CAACiB,wBAAwB,EAAEgC,OAAO,EAAE/B,OAAO,CAAC,CAC5EqC,KAAK,CAAEC,KAA6B,IAAK;UACtC,IAAMC,GAAW,GAAGD,KAAK,CAACpD,OAAO;UACjC;UACA;UACA;UACA;UACA,IACKqD,GAAG,CAACC,QAAQ,CAAC,iBAAiB,CAAC,IAAID,GAAG,CAACC,QAAQ,CAAC,gBAAgB,CAAC,IAClED,GAAG,CAACC,QAAQ,CAAC,eAAe,CAAC,EAC/B;YACE,MAAM,IAAIzD,iBAAiB,CAAC,yDAAyD,CAAC;UAC1F;QACJ,CAAC,CAAC;QACN+B,KAAI,CAACnB,UAAU,CAAC8C,QAAQ,CAACC,2BAA2B,IAAI,CAAC;MAC7D,CAAC,MAAM;QACH5B,KAAI,CAACnC,MAAM,CAACgE,IAAI,CAAC,kCAAkC,CAAC;MACxD;IAAC;EACL;EAEQxC,mBAAmBA,CAACyC,QAAgB,EAAE5C,OAA2C,EAAQ;IAAA,IAAA6C,kBAAA;IAC7F;;IAEA,IAAI,CAAClD,UAAU,CAAC8C,QAAQ,CAACK,+BAA+B,IAAI,CAAC;;IAE7D;IACA;IACA,IAAMhB,GAAG,GAAGD,IAAI,CAACC,GAAG,CAAC,CAAC;IACtB,IAAMiB,GAAG,GAAGjB,GAAG,IAAI,OAAO9B,OAAO,CAAC4B,OAAO,KAAK,QAAQ,GAAG5B,OAAO,CAAC4B,OAAO,GAAGE,GAAG,CAAC;IAC/E,IAAI,CAACnC,UAAU,CAACqD,MAAM,CAACC,uCAAuC,IAAIF,GAAG;IAErE,IAAMG,4BAA4B,MAAAC,MAAA,CAAMP,QAAQ,OAAAO,MAAA,CAAInD,OAAO,CAACmB,MAAM,CAACC,iBAAiB,CAAE;IAEtF,IAAI,CAACgC,IAAI,CACL1E,kBAAkB,CAAC2E,YAAY;IAC/B;IACA;MACIpB,MAAM,EAAEW,QAAQ;MAChBvB,QAAQ,EAAErB,OAAO,CAACmB,MAAM,CAACC,iBAAkB;MAC3CG,QAAQ,GAAAsB,kBAAA,GAAE7C,OAAO,CAACmB,MAAM,CAACG,EAAE,cAAAuB,kBAAA,cAAAA,kBAAA,GAAIK;IACnC,CAAC,EACDlD,OAAO,CAACgB,IAAI,CAACC,GAAG,EAChBjB,OAAO,CAACgB,IAAI,CAACJ,KAAK,EAClBkB,GACJ,CAAC;EACL;EAwBQ7B,oBAAoBA,CAACJ,KAAkB,EAAkD;IAC7F,IAAMG,OAAO,GAAGH,KAAK,CAACyD,UAAU,CAAC,CAAC;IAClC,IAAM7D,MAAM,GAAGO,OAAO,CAACkB,OAAO;IAC9B,IAAI,CAACzB,MAAM,EAAE;MACT;MACA,IAAI,CAACd,MAAM,CAACgE,IAAI,CAAC,gEAAgE,CAAC;MAClF;IACJ;IACA,IAAIlD,MAAM,KAAK,IAAI,CAACA,MAAM,EAAE;MACxB,IAAI,CAACd,MAAM,CAACgE,IAAI,CAAC,kCAAkC,CAAC;MACpD;IACJ;IAEA,IAAI,CAAC3C,OAAO,CAACgB,IAAI,IAAI,CAAChB,OAAO,CAACgB,IAAI,CAACC,GAAG,IAAI,OAAOjB,OAAO,CAACgB,IAAI,CAACJ,KAAK,KAAK,QAAQ,EAAE;MAC9E,IAAI,CAACjC,MAAM,CAACgE,IAAI,CAAC,qCAAqC,CAAC;MACvD;IACJ;IAEA,IAAI,CAAC3C,OAAO,CAACmB,MAAM,IAAI,CAACnB,OAAO,CAACmB,MAAM,CAACC,iBAAiB,EAAE;MACtD,IAAI,CAACzC,MAAM,CAACgE,IAAI,CAAC,4CAA4C,CAAC;MAC9D;IACJ;;IAEA;IACA,OAAO3C,OAAO;EAClB;AACJ","ignoreList":[]}
|
package/lib/matrixrtc/utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import _toArray from "@babel/runtime/helpers/toArray";
|
|
1
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
2
4
|
/*
|
|
3
5
|
Copyright 2025-2026 The Matrix.org Foundation C.I.C.
|
|
4
6
|
|
|
@@ -53,7 +55,11 @@ export class OutdatedKeyFilter {
|
|
|
53
55
|
* @throws If the format of `slotId` is invalid.
|
|
54
56
|
*/
|
|
55
57
|
export function slotIdToDescription(slotId) {
|
|
56
|
-
var
|
|
58
|
+
var _slotId$split = slotId.split("#"),
|
|
59
|
+
_slotId$split2 = _toArray(_slotId$split),
|
|
60
|
+
application = _slotId$split2[0],
|
|
61
|
+
id = _slotId$split2[1],
|
|
62
|
+
unexpectedAdditionalValues = _arrayLikeToArray(_slotId$split2).slice(2);
|
|
57
63
|
if (unexpectedAdditionalValues.length) {
|
|
58
64
|
throw Error("MatrixRTC Slot IDs *must* only contain two components seperated by one '#'. Additional '#' characters detected.");
|
|
59
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["getEncryptionKeyMapKey","OutdatedKeyFilter","constructor","_defineProperty","Map","isOutdated","membership","item","_this$tsBuffer$get","mapKey","tsBuffer","has","set","latestTimestamp","get","keyIndex","creationTS","slotIdToDescription","slotId","application","id","unexpectedAdditionalValues","
|
|
1
|
+
{"version":3,"file":"utils.js","names":["getEncryptionKeyMapKey","OutdatedKeyFilter","constructor","_defineProperty","Map","isOutdated","membership","item","_this$tsBuffer$get","mapKey","tsBuffer","has","set","latestTimestamp","get","keyIndex","creationTS","slotIdToDescription","slotId","_slotId$split","split","_slotId$split2","_toArray","application","id","unexpectedAdditionalValues","_arrayLikeToArray","slice","length","Error","computeSlotId","slotDescription","concat"],"sources":["../../src/matrixrtc/utils.ts"],"sourcesContent":["/*\nCopyright 2025-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*/\n\nimport { getEncryptionKeyMapKey, type CallMembershipIdentityParts } from \"./EncryptionManager.ts\";\nimport type { InboundEncryptionSession, EncryptionKeyMapKey, SlotDescription } from \"./types.ts\";\n\n/**\n * Detects when a key for a given index is outdated.\n */\nexport class OutdatedKeyFilter {\n // Map of participantId -> keyIndex -> timestamp\n private tsBuffer: Map<EncryptionKeyMapKey, Map<number, number>> = new Map();\n\n public constructor() {}\n\n /**\n * Check if there is a recent key with the same keyId (index) and then use the creationTS to decide what to\n * do with the key. If the key received is older than the one already in the buffer, it is ignored.\n * @param participantId\n * @param item\n */\n public isOutdated(membership: CallMembershipIdentityParts, item: InboundEncryptionSession): boolean {\n const mapKey = getEncryptionKeyMapKey(membership);\n if (!this.tsBuffer.has(mapKey)) {\n this.tsBuffer.set(mapKey, new Map<number, number>());\n }\n\n const latestTimestamp = this.tsBuffer.get(mapKey)?.get(item.keyIndex);\n if (latestTimestamp && latestTimestamp > item.creationTS) {\n // The existing key is more recent, ignore this one\n return true;\n }\n this.tsBuffer.get(mapKey)!.set(item.keyIndex, item.creationTS);\n return false;\n }\n}\n\n/**\n * Converts a slot ID into it's component application and ID portions.\n * @param slotId e.g. `m.call#call_id`\n * @throws If the format of `slotId` is invalid.\n */\nexport function slotIdToDescription(slotId: string): SlotDescription {\n const [application, id, ...unexpectedAdditionalValues] = slotId.split(\"#\");\n if (unexpectedAdditionalValues.length) {\n throw Error(\n \"MatrixRTC Slot IDs *must* only contain two components seperated by one '#'. Additional '#' characters detected.\",\n );\n }\n return { application, id };\n}\n\n/**\n * Converts a SlotDescription into it's slot ID format.\n */\nexport function computeSlotId(slotDescription: SlotDescription): string {\n return `${slotDescription.application}#${slotDescription.id}`;\n}\n"],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,sBAAsB,QAA0C,wBAAwB;AAGjG;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,CAAC;EAIpBC,WAAWA,CAAA,EAAG;IAHrB;IAAAC,eAAA,mBACkE,IAAIC,GAAG,CAAC,CAAC;EAErD;;EAEtB;AACJ;AACA;AACA;AACA;AACA;EACWC,UAAUA,CAACC,UAAuC,EAAEC,IAA8B,EAAW;IAAA,IAAAC,kBAAA;IAChG,IAAMC,MAAM,GAAGT,sBAAsB,CAACM,UAAU,CAAC;IACjD,IAAI,CAAC,IAAI,CAACI,QAAQ,CAACC,GAAG,CAACF,MAAM,CAAC,EAAE;MAC5B,IAAI,CAACC,QAAQ,CAACE,GAAG,CAACH,MAAM,EAAE,IAAIL,GAAG,CAAiB,CAAC,CAAC;IACxD;IAEA,IAAMS,eAAe,IAAAL,kBAAA,GAAG,IAAI,CAACE,QAAQ,CAACI,GAAG,CAACL,MAAM,CAAC,cAAAD,kBAAA,uBAAzBA,kBAAA,CAA2BM,GAAG,CAACP,IAAI,CAACQ,QAAQ,CAAC;IACrE,IAAIF,eAAe,IAAIA,eAAe,GAAGN,IAAI,CAACS,UAAU,EAAE;MACtD;MACA,OAAO,IAAI;IACf;IACA,IAAI,CAACN,QAAQ,CAACI,GAAG,CAACL,MAAM,CAAC,CAAEG,GAAG,CAACL,IAAI,CAACQ,QAAQ,EAAER,IAAI,CAACS,UAAU,CAAC;IAC9D,OAAO,KAAK;EAChB;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAACC,MAAc,EAAmB;EACjE,IAAAC,aAAA,GAAyDD,MAAM,CAACE,KAAK,CAAC,GAAG,CAAC;IAAAC,cAAA,GAAAC,QAAA,CAAAH,aAAA;IAAnEI,WAAW,GAAAF,cAAA;IAAEG,EAAE,GAAAH,cAAA;IAAKI,0BAA0B,GAAAC,iBAAA,CAAAL,cAAA,EAAAM,KAAA;EACrD,IAAIF,0BAA0B,CAACG,MAAM,EAAE;IACnC,MAAMC,KAAK,CACP,iHACJ,CAAC;EACL;EACA,OAAO;IAAEN,WAAW;IAAEC;EAAG,CAAC;AAC9B;;AAEA;AACA;AACA;AACA,OAAO,SAASM,aAAaA,CAACC,eAAgC,EAAU;EACpE,UAAAC,MAAA,CAAUD,eAAe,CAACR,WAAW,OAAAS,MAAA,CAAID,eAAe,CAACP,EAAE;AAC/D","ignoreList":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
3
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
4
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
5
|
/*
|
|
@@ -74,7 +74,6 @@ export class MSC3089TreeSpace {
|
|
|
74
74
|
constructor(client, roomId) {
|
|
75
75
|
this.client = client;
|
|
76
76
|
this.roomId = roomId;
|
|
77
|
-
_defineProperty(this, "room", void 0);
|
|
78
77
|
this.room = this.client.getRoom(this.roomId);
|
|
79
78
|
if (!this.room) throw new Error("Unknown room");
|
|
80
79
|
}
|
|
@@ -460,11 +459,10 @@ export class MSC3089TreeSpace {
|
|
|
460
459
|
createFile(name, encryptedContents, info, additionalContent) {
|
|
461
460
|
var _this8 = this;
|
|
462
461
|
return _asyncToGenerator(function* () {
|
|
463
|
-
var {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
});
|
|
462
|
+
var _yield$_this8$client$ = yield _this8.client.uploadContent(encryptedContents, {
|
|
463
|
+
includeFilename: false
|
|
464
|
+
}),
|
|
465
|
+
mxc = _yield$_this8$client$.content_uri;
|
|
468
466
|
info.url = mxc;
|
|
469
467
|
var fileContent = {
|
|
470
468
|
msgtype: MsgType.File,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MSC3089TreeSpace.js","names":["EventType","MsgType","UNSTABLE_MSC3089_BRANCH","UNSTABLE_MSC3089_LEAF","logger","averageBetweenStrings","DEFAULT_ALPHABET","lexicographicCompare","nextString","prevString","simpleRetryOperation","MSC3089Branch","MatrixError","KnownMembership","DEFAULT_TREE_POWER_LEVELS_TEMPLATE","invite","kick","ban","redact","state_default","events_default","users_default","events","RoomPowerLevels","RoomHistoryVisibility","RoomTombstone","RoomEncryption","RoomName","RoomMessage","RoomMessageEncrypted","Sticker","users","TreePermissions","MSC3089TreeSpace","constructor","client","roomId","_defineProperty","room","getRoom","Error","id","isTopLevel","parentEvents","currentState","getStateEvents","SpaceParent","length","every","e","_e$getContent","getContent","setName","name","_this","_asyncToGenerator","sendStateEvent","userId","_arguments","arguments","_this2","andSubspaces","undefined","promises","retryInvite","push","getDirectories","map","d","Promise","all","_this3","errcode","setPermissions","role","_this4","_pls$events","currentPls","Array","isArray","pls","viewLevel","editLevel","adminLevel","Viewer","Editor","Owner","getPermissions","_pls$events2","_pls$users","userLevel","createDirectory","_this5","directory","unstableCreateFileTree","SpaceChild","via","getDomain","trees","children","child","stateKey","getStateKey","tree","unstableGetFileTreeSpace","warn","getDirectory","find","r","delete","_this6","subdirectories","dir","kickMemberships","Invite","Knock","Join","members","RoomMember","member","isNotUs","getUserId","includes","membership","leave","getOrderedChildren","ordered","c","order","filter","sort","a","b","_roomA$currentState$g","_roomA$currentState$g2","_roomB$currentState$g","_roomB$currentState$g2","roomA","roomB","createTsA","RoomCreate","getTs","createTsB","getParentRoom","parents","parent","parentRoom","getOrder","findIndex","setOrder","index","_this7","_currentChild$getCont2","Math","max","min","currentIndex","movingUp","prev","next","newOrder","ensureBeforeIsSane","startOrder","endOrder","lastOrder","i","target","_currentChild$getCont","currentChild","content","_objectSpread","createFile","encryptedContents","info","additionalContent","_this8","content_uri","mxc","uploadContent","includeFilename","url","fileContent","msgtype","File","body","file","res","sendMessage","active","getFile","fileEventId","branch","listFiles","listAllFiles","isActive","_this$room$currentSta","branches"],"sources":["../../src/models/MSC3089TreeSpace.ts"],"sourcesContent":["/*\nCopyright 2021 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*/\n\nimport { type MatrixClient } from \"../client.ts\";\nimport { EventType, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from \"../@types/event.ts\";\nimport { type Room } from \"./room.ts\";\nimport { logger } from \"../logger.ts\";\nimport { type IContent, type MatrixEvent } from \"./event.ts\";\nimport {\n averageBetweenStrings,\n DEFAULT_ALPHABET,\n lexicographicCompare,\n nextString,\n prevString,\n simpleRetryOperation,\n} from \"../utils.ts\";\nimport { MSC3089Branch } from \"./MSC3089Branch.ts\";\nimport { type ISendEventResponse } from \"../@types/requests.ts\";\nimport { type FileType, MatrixError } from \"../http-api/index.ts\";\nimport { KnownMembership } from \"../@types/membership.ts\";\nimport { type RoomPowerLevelsEventContent, type SpaceChildEventContent } from \"../@types/state_events.ts\";\nimport type { EncryptedFile, FileContent } from \"../@types/media.ts\";\nimport { type EmptyObject } from \"../@types/common.ts\";\n\n/**\n * The recommended defaults for a tree space's power levels. Note that this\n * is UNSTABLE and subject to breaking changes without notice.\n */\nexport const DEFAULT_TREE_POWER_LEVELS_TEMPLATE = {\n // Owner\n invite: 100,\n kick: 100,\n ban: 100,\n\n // Editor\n redact: 50,\n state_default: 50,\n events_default: 50,\n\n // Viewer\n users_default: 0,\n\n // Mixed\n events: {\n [EventType.RoomPowerLevels]: 100,\n [EventType.RoomHistoryVisibility]: 100,\n [EventType.RoomTombstone]: 100,\n [EventType.RoomEncryption]: 100,\n [EventType.RoomName]: 50,\n [EventType.RoomMessage]: 50,\n [EventType.RoomMessageEncrypted]: 50,\n [EventType.Sticker]: 50,\n },\n\n users: {}, // defined by calling code\n};\n\n/**\n * Ease-of-use representation for power levels represented as simple roles.\n * Note that this is UNSTABLE and subject to breaking changes without notice.\n */\nexport enum TreePermissions {\n Viewer = \"viewer\", // Default\n Editor = \"editor\", // \"Moderator\" or ~PL50\n Owner = \"owner\", // \"Admin\" or PL100\n}\n\ndeclare module \"../@types/media\" {\n interface FileContent {\n [UNSTABLE_MSC3089_LEAF.name]?: EmptyObject;\n }\n}\n\n/**\n * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089)\n * file tree Space. Note that this is UNSTABLE and subject to breaking changes\n * without notice.\n */\nexport class MSC3089TreeSpace {\n public readonly room: Room;\n\n public constructor(\n private client: MatrixClient,\n public readonly roomId: string,\n ) {\n this.room = this.client.getRoom(this.roomId)!;\n\n if (!this.room) throw new Error(\"Unknown room\");\n }\n\n /**\n * Syntactic sugar for room ID of the Space.\n */\n public get id(): string {\n return this.roomId;\n }\n\n /**\n * Whether or not this is a top level space.\n */\n public get isTopLevel(): boolean {\n // XXX: This is absolutely not how you find out if the space is top level\n // but is safe for a managed usecase like we offer in the SDK.\n const parentEvents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n if (!parentEvents?.length) return true;\n return parentEvents.every((e) => !e.getContent()?.[\"via\"]);\n }\n\n /**\n * Sets the name of the tree space.\n * @param name - The new name for the space.\n * @returns Promise which resolves when complete.\n */\n public async setName(name: string): Promise<void> {\n await this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, \"\");\n }\n\n /**\n * Invites a user to the tree space. They will be given the default Viewer\n * permission level unless specified elsewhere.\n * @param userId - The user ID to invite.\n * @param andSubspaces - True (default) to invite the user to all\n * directories/subspaces too, recursively.\n * @returns Promise which resolves when complete.\n */\n public async invite(userId: string, andSubspaces = true): Promise<void> {\n const promises: Promise<void>[] = [this.retryInvite(userId)];\n if (andSubspaces) {\n promises.push(...this.getDirectories().map((d) => d.invite(userId, andSubspaces)));\n }\n await Promise.all(promises);\n }\n\n private async retryInvite(userId: string): Promise<void> {\n await simpleRetryOperation(\n () => this.client.invite(this.roomId, userId),\n (e) => {\n // We don't want to retry permission errors forever...\n if (e instanceof MatrixError && e.errcode === \"M_FORBIDDEN\") {\n return false;\n }\n return true;\n },\n );\n }\n\n /**\n * Sets the permissions of a user to the given role. Note that if setting a user\n * to Owner then they will NOT be able to be demoted. If the user does not have\n * permission to change the power level of the target, an error will be thrown.\n * @param userId - The user ID to change the role of.\n * @param role - The role to assign.\n * @returns Promise which resolves when complete.\n */\n public async setPermissions(userId: string, role: TreePermissions): Promise<void> {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent<RoomPowerLevelsEventContent>() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const users = pls[\"users\"] || {};\n switch (role) {\n case TreePermissions.Viewer:\n users[userId] = viewLevel;\n break;\n case TreePermissions.Editor:\n users[userId] = editLevel;\n break;\n case TreePermissions.Owner:\n users[userId] = adminLevel;\n break;\n default:\n throw new Error(\"Invalid role: \" + role);\n }\n pls[\"users\"] = users;\n\n await this.client.sendStateEvent(this.roomId, EventType.RoomPowerLevels, pls, \"\");\n }\n\n /**\n * Gets the current permissions of a user. Note that any users missing explicit permissions (or not\n * in the space) will be considered Viewers. Appropriate membership checks need to be performed\n * elsewhere.\n * @param userId - The user ID to check permissions of.\n * @returns The permissions for the user, defaulting to Viewer.\n */\n public getPermissions(userId: string): TreePermissions {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const userLevel = pls[\"users\"]?.[userId] || viewLevel;\n if (userLevel >= adminLevel) return TreePermissions.Owner;\n if (userLevel >= editLevel) return TreePermissions.Editor;\n return TreePermissions.Viewer;\n }\n\n /**\n * Creates a directory under this tree space, represented as another tree space.\n * @param name - The name for the directory.\n * @returns Promise which resolves to the created directory.\n */\n public async createDirectory(name: string): Promise<MSC3089TreeSpace> {\n const directory = await this.client.unstableCreateFileTree(name);\n\n await this.client.sendStateEvent(\n this.roomId,\n EventType.SpaceChild,\n {\n via: [this.client.getDomain()!],\n },\n directory.roomId,\n );\n\n await this.client.sendStateEvent(\n directory.roomId,\n EventType.SpaceParent,\n {\n via: [this.client.getDomain()!],\n },\n this.roomId,\n );\n\n return directory;\n }\n\n /**\n * Gets a list of all known immediate subdirectories to this tree space.\n * @returns The tree spaces (directories). May be empty, but not null.\n */\n public getDirectories(): MSC3089TreeSpace[] {\n const trees: MSC3089TreeSpace[] = [];\n const children = this.room.currentState.getStateEvents(EventType.SpaceChild);\n for (const child of children) {\n try {\n const stateKey = child.getStateKey();\n if (stateKey) {\n const tree = this.client.unstableGetFileTreeSpace(stateKey);\n if (tree) trees.push(tree);\n }\n } catch (e) {\n logger.warn(\"Unable to create tree space instance for listing. Are we joined?\", e);\n }\n }\n return trees;\n }\n\n /**\n * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse\n * into children and instead only look one level deep.\n * @param roomId - The room ID (directory ID) to find.\n * @returns The directory, or undefined if not found.\n */\n public getDirectory(roomId: string): MSC3089TreeSpace | undefined {\n return this.getDirectories().find((r) => r.roomId === roomId);\n }\n\n /**\n * Deletes the tree, kicking all members and deleting **all subdirectories**.\n * @returns Promise which resolves when complete.\n */\n public async delete(): Promise<void> {\n const subdirectories = this.getDirectories();\n for (const dir of subdirectories) {\n await dir.delete();\n }\n\n const kickMemberships = [KnownMembership.Invite, KnownMembership.Knock, KnownMembership.Join];\n const members = this.room.currentState.getStateEvents(EventType.RoomMember);\n for (const member of members) {\n const isNotUs = member.getStateKey() !== this.client.getUserId();\n if (isNotUs && kickMemberships.includes(member.getContent().membership! as KnownMembership)) {\n const stateKey = member.getStateKey();\n if (!stateKey) {\n throw new Error(\"State key not found for branch\");\n }\n await this.client.kick(this.roomId, stateKey, \"Room deleted\");\n }\n }\n\n await this.client.leave(this.roomId);\n }\n\n private getOrderedChildren(children: MatrixEvent[]): { roomId: string; order: string }[] {\n const ordered: { roomId: string; order: string }[] = children\n .map((c) => ({ roomId: c.getStateKey(), order: c.getContent()[\"order\"] }))\n .filter((c) => c.roomId) as { roomId: string; order: string }[];\n ordered.sort((a, b) => {\n if (a.order && !b.order) {\n return -1;\n } else if (!a.order && b.order) {\n return 1;\n } else if (!a.order && !b.order) {\n const roomA = this.client.getRoom(a.roomId);\n const roomB = this.client.getRoom(b.roomId);\n if (!roomA || !roomB) {\n // just don't bother trying to do more partial sorting\n return lexicographicCompare(a.roomId, b.roomId);\n }\n\n const createTsA = roomA.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n const createTsB = roomB.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n if (createTsA === createTsB) {\n return lexicographicCompare(a.roomId, b.roomId);\n }\n return createTsA - createTsB;\n } else {\n // both not-null orders\n return lexicographicCompare(a.order, b.order);\n }\n });\n return ordered;\n }\n\n private getParentRoom(): Room {\n const parents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n const parent = parents[0]; // XXX: Wild assumption\n if (!parent) throw new Error(\"Expected to have a parent in a non-top level space\");\n\n // XXX: We are assuming the parent is a valid tree space.\n // We probably don't need to validate the parent room state for this usecase though.\n const stateKey = parent.getStateKey();\n if (!stateKey) throw new Error(\"No state key found for parent\");\n const parentRoom = this.client.getRoom(stateKey);\n if (!parentRoom) throw new Error(\"Unable to locate room for parent\");\n\n return parentRoom;\n }\n\n /**\n * Gets the current order index for this directory. Note that if this is the top level space\n * then -1 will be returned.\n * @returns The order index of this space.\n */\n public getOrder(): number {\n if (this.isTopLevel) return -1;\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n\n return ordered.findIndex((c) => c.roomId === this.roomId);\n }\n\n /**\n * Sets the order index for this directory within its parent. Note that if this is a top level\n * space then an error will be thrown. -1 can be used to move the child to the start, and numbers\n * larger than the number of children can be used to move the child to the end.\n * @param index - The new order index for this space.\n * @returns Promise which resolves when complete.\n * @throws Throws if this is a top level space.\n */\n public async setOrder(index: number): Promise<void> {\n if (this.isTopLevel) throw new Error(\"Cannot set order of top level spaces currently\");\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n index = Math.max(Math.min(index, ordered.length - 1), 0);\n\n const currentIndex = this.getOrder();\n const movingUp = currentIndex < index;\n if (movingUp && index === ordered.length - 1) {\n index--;\n } else if (!movingUp && index === 0) {\n index++;\n }\n\n const prev = ordered[movingUp ? index : index - 1];\n const next = ordered[movingUp ? index + 1 : index];\n\n let newOrder = DEFAULT_ALPHABET[0];\n let ensureBeforeIsSane = false;\n if (!prev) {\n // Move to front\n if (next?.order) {\n newOrder = prevString(next.order);\n }\n } else if (index === ordered.length - 1) {\n // Move to back\n if (next?.order) {\n newOrder = nextString(next.order);\n }\n } else {\n // Move somewhere in the middle\n const startOrder = prev?.order;\n const endOrder = next?.order;\n if (startOrder && endOrder) {\n if (startOrder === endOrder) {\n // Error case: just move +1 to break out of awful math\n newOrder = nextString(startOrder);\n } else {\n newOrder = averageBetweenStrings(startOrder, endOrder);\n }\n } else {\n if (startOrder) {\n // We're at the end (endOrder is null, so no explicit order)\n newOrder = nextString(startOrder);\n } else if (endOrder) {\n // We're at the start (startOrder is null, so nothing before us)\n newOrder = prevString(endOrder);\n } else {\n // Both points are unknown. We're likely in a range where all the children\n // don't have particular order values, so we may need to update them too.\n // The other possibility is there's only us as a child, but we should have\n // shown up in the other states.\n ensureBeforeIsSane = true;\n }\n }\n }\n\n if (ensureBeforeIsSane) {\n // We were asked by the order algorithm to prepare the moving space for a landing\n // in the undefined order part of the order array, which means we need to update the\n // spaces that come before it with a stable order value.\n let lastOrder: string | undefined;\n for (let i = 0; i <= index; i++) {\n const target = ordered[i];\n if (i === 0) {\n lastOrder = target.order;\n }\n if (!target.order) {\n // XXX: We should be creating gaps to avoid conflicts\n lastOrder = lastOrder ? nextString(lastOrder) : DEFAULT_ALPHABET[0];\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, target.roomId);\n const content = currentChild?.getContent<SpaceChildEventContent>() ?? {\n via: [this.client.getDomain()!],\n };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n order: lastOrder,\n },\n target.roomId,\n );\n } else {\n lastOrder = target.order;\n }\n }\n if (lastOrder) {\n newOrder = nextString(lastOrder);\n }\n }\n\n // TODO: Deal with order conflicts by reordering\n\n // Now we can finally update our own order state\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, this.roomId);\n const content = currentChild?.getContent<SpaceChildEventContent>() ?? { via: [this.client.getDomain()!] };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n\n // TODO: Safely constrain to 50 character limit required by spaces.\n order: newOrder,\n },\n this.roomId,\n );\n }\n\n /**\n * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room.\n * The file contents are in a type that is compatible with MatrixClient.uploadContent().\n * @param name - The name of the file.\n * @param encryptedContents - The encrypted contents.\n * @param info - The encrypted file information.\n * @param additionalContent - Optional event content fields to include in the message.\n * @returns Promise which resolves to the file event's sent response.\n */\n public async createFile(\n name: string,\n encryptedContents: FileType,\n info: EncryptedFile,\n additionalContent?: IContent,\n ): Promise<ISendEventResponse> {\n const { content_uri: mxc } = await this.client.uploadContent(encryptedContents, {\n includeFilename: false,\n });\n info.url = mxc;\n\n const fileContent: FileContent = {\n msgtype: MsgType.File,\n body: name,\n url: mxc,\n file: info,\n };\n\n additionalContent = additionalContent ?? {};\n if (additionalContent[\"m.new_content\"]) {\n // We do the right thing according to the spec, but due to how relations are\n // handled we also end up duplicating this information to the regular `content`\n // as well.\n additionalContent[\"m.new_content\"] = fileContent;\n }\n\n const res = await this.client.sendMessage(this.roomId, {\n ...additionalContent,\n ...fileContent,\n [UNSTABLE_MSC3089_LEAF.name]: {},\n } as FileContent);\n\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n active: true,\n name: name,\n },\n res[\"event_id\"],\n );\n\n return res;\n }\n\n /**\n * Retrieves a file from the tree.\n * @param fileEventId - The event ID of the file.\n * @returns The file, or null if not found.\n */\n public getFile(fileEventId: string): MSC3089Branch | null {\n const branch = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name, fileEventId);\n return branch ? new MSC3089Branch(this.client, branch, this) : null;\n }\n\n /**\n * Gets an array of all known files for the tree.\n * @returns The known files. May be empty, but not null.\n */\n public listFiles(): MSC3089Branch[] {\n return this.listAllFiles().filter((b) => b.isActive);\n }\n\n /**\n * Gets an array of all known files for the tree, including inactive/invalid ones.\n * @returns The known files. May be empty, but not null.\n */\n public listAllFiles(): MSC3089Branch[] {\n const branches = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name) ?? [];\n return branches.map((e) => new MSC3089Branch(this.client, e, this));\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"MSC3089TreeSpace.js","names":["EventType","MsgType","UNSTABLE_MSC3089_BRANCH","UNSTABLE_MSC3089_LEAF","logger","averageBetweenStrings","DEFAULT_ALPHABET","lexicographicCompare","nextString","prevString","simpleRetryOperation","MSC3089Branch","MatrixError","KnownMembership","DEFAULT_TREE_POWER_LEVELS_TEMPLATE","invite","kick","ban","redact","state_default","events_default","users_default","events","RoomPowerLevels","RoomHistoryVisibility","RoomTombstone","RoomEncryption","RoomName","RoomMessage","RoomMessageEncrypted","Sticker","users","TreePermissions","MSC3089TreeSpace","constructor","client","roomId","room","getRoom","Error","id","isTopLevel","parentEvents","currentState","getStateEvents","SpaceParent","length","every","e","_e$getContent","getContent","setName","name","_this","_asyncToGenerator","sendStateEvent","userId","_arguments","arguments","_this2","andSubspaces","undefined","promises","retryInvite","push","getDirectories","map","d","Promise","all","_this3","errcode","setPermissions","role","_this4","_pls$events","currentPls","Array","isArray","pls","viewLevel","editLevel","adminLevel","Viewer","Editor","Owner","getPermissions","_pls$events2","_pls$users","userLevel","createDirectory","_this5","directory","unstableCreateFileTree","SpaceChild","via","getDomain","trees","children","child","stateKey","getStateKey","tree","unstableGetFileTreeSpace","warn","getDirectory","find","r","delete","_this6","subdirectories","dir","kickMemberships","Invite","Knock","Join","members","RoomMember","member","isNotUs","getUserId","includes","membership","leave","getOrderedChildren","ordered","c","order","filter","sort","a","b","_roomA$currentState$g","_roomA$currentState$g2","_roomB$currentState$g","_roomB$currentState$g2","roomA","roomB","createTsA","RoomCreate","getTs","createTsB","getParentRoom","parents","parent","parentRoom","getOrder","findIndex","setOrder","index","_this7","_currentChild$getCont2","Math","max","min","currentIndex","movingUp","prev","next","newOrder","ensureBeforeIsSane","startOrder","endOrder","lastOrder","i","target","_currentChild$getCont","currentChild","content","_objectSpread","createFile","encryptedContents","info","additionalContent","_this8","_yield$_this8$client$","uploadContent","includeFilename","mxc","content_uri","url","fileContent","msgtype","File","body","file","res","sendMessage","active","getFile","fileEventId","branch","listFiles","listAllFiles","isActive","_this$room$currentSta","branches"],"sources":["../../src/models/MSC3089TreeSpace.ts"],"sourcesContent":["/*\nCopyright 2021 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*/\n\nimport { type MatrixClient } from \"../client.ts\";\nimport { EventType, MsgType, UNSTABLE_MSC3089_BRANCH, UNSTABLE_MSC3089_LEAF } from \"../@types/event.ts\";\nimport { type Room } from \"./room.ts\";\nimport { logger } from \"../logger.ts\";\nimport { type IContent, type MatrixEvent } from \"./event.ts\";\nimport {\n averageBetweenStrings,\n DEFAULT_ALPHABET,\n lexicographicCompare,\n nextString,\n prevString,\n simpleRetryOperation,\n} from \"../utils.ts\";\nimport { MSC3089Branch } from \"./MSC3089Branch.ts\";\nimport { type ISendEventResponse } from \"../@types/requests.ts\";\nimport { type FileType, MatrixError } from \"../http-api/index.ts\";\nimport { KnownMembership } from \"../@types/membership.ts\";\nimport { type RoomPowerLevelsEventContent, type SpaceChildEventContent } from \"../@types/state_events.ts\";\nimport type { EncryptedFile, FileContent } from \"../@types/media.ts\";\nimport { type EmptyObject } from \"../@types/common.ts\";\n\n/**\n * The recommended defaults for a tree space's power levels. Note that this\n * is UNSTABLE and subject to breaking changes without notice.\n */\nexport const DEFAULT_TREE_POWER_LEVELS_TEMPLATE = {\n // Owner\n invite: 100,\n kick: 100,\n ban: 100,\n\n // Editor\n redact: 50,\n state_default: 50,\n events_default: 50,\n\n // Viewer\n users_default: 0,\n\n // Mixed\n events: {\n [EventType.RoomPowerLevels]: 100,\n [EventType.RoomHistoryVisibility]: 100,\n [EventType.RoomTombstone]: 100,\n [EventType.RoomEncryption]: 100,\n [EventType.RoomName]: 50,\n [EventType.RoomMessage]: 50,\n [EventType.RoomMessageEncrypted]: 50,\n [EventType.Sticker]: 50,\n },\n\n users: {}, // defined by calling code\n};\n\n/**\n * Ease-of-use representation for power levels represented as simple roles.\n * Note that this is UNSTABLE and subject to breaking changes without notice.\n */\nexport enum TreePermissions {\n Viewer = \"viewer\", // Default\n Editor = \"editor\", // \"Moderator\" or ~PL50\n Owner = \"owner\", // \"Admin\" or PL100\n}\n\ndeclare module \"../@types/media\" {\n interface FileContent {\n [UNSTABLE_MSC3089_LEAF.name]?: EmptyObject;\n }\n}\n\n/**\n * Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089)\n * file tree Space. Note that this is UNSTABLE and subject to breaking changes\n * without notice.\n */\nexport class MSC3089TreeSpace {\n public readonly room: Room;\n\n public constructor(\n private client: MatrixClient,\n public readonly roomId: string,\n ) {\n this.room = this.client.getRoom(this.roomId)!;\n\n if (!this.room) throw new Error(\"Unknown room\");\n }\n\n /**\n * Syntactic sugar for room ID of the Space.\n */\n public get id(): string {\n return this.roomId;\n }\n\n /**\n * Whether or not this is a top level space.\n */\n public get isTopLevel(): boolean {\n // XXX: This is absolutely not how you find out if the space is top level\n // but is safe for a managed usecase like we offer in the SDK.\n const parentEvents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n if (!parentEvents?.length) return true;\n return parentEvents.every((e) => !e.getContent()?.[\"via\"]);\n }\n\n /**\n * Sets the name of the tree space.\n * @param name - The new name for the space.\n * @returns Promise which resolves when complete.\n */\n public async setName(name: string): Promise<void> {\n await this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, \"\");\n }\n\n /**\n * Invites a user to the tree space. They will be given the default Viewer\n * permission level unless specified elsewhere.\n * @param userId - The user ID to invite.\n * @param andSubspaces - True (default) to invite the user to all\n * directories/subspaces too, recursively.\n * @returns Promise which resolves when complete.\n */\n public async invite(userId: string, andSubspaces = true): Promise<void> {\n const promises: Promise<void>[] = [this.retryInvite(userId)];\n if (andSubspaces) {\n promises.push(...this.getDirectories().map((d) => d.invite(userId, andSubspaces)));\n }\n await Promise.all(promises);\n }\n\n private async retryInvite(userId: string): Promise<void> {\n await simpleRetryOperation(\n () => this.client.invite(this.roomId, userId),\n (e) => {\n // We don't want to retry permission errors forever...\n if (e instanceof MatrixError && e.errcode === \"M_FORBIDDEN\") {\n return false;\n }\n return true;\n },\n );\n }\n\n /**\n * Sets the permissions of a user to the given role. Note that if setting a user\n * to Owner then they will NOT be able to be demoted. If the user does not have\n * permission to change the power level of the target, an error will be thrown.\n * @param userId - The user ID to change the role of.\n * @param role - The role to assign.\n * @returns Promise which resolves when complete.\n */\n public async setPermissions(userId: string, role: TreePermissions): Promise<void> {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent<RoomPowerLevelsEventContent>() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const users = pls[\"users\"] || {};\n switch (role) {\n case TreePermissions.Viewer:\n users[userId] = viewLevel;\n break;\n case TreePermissions.Editor:\n users[userId] = editLevel;\n break;\n case TreePermissions.Owner:\n users[userId] = adminLevel;\n break;\n default:\n throw new Error(\"Invalid role: \" + role);\n }\n pls[\"users\"] = users;\n\n await this.client.sendStateEvent(this.roomId, EventType.RoomPowerLevels, pls, \"\");\n }\n\n /**\n * Gets the current permissions of a user. Note that any users missing explicit permissions (or not\n * in the space) will be considered Viewers. Appropriate membership checks need to be performed\n * elsewhere.\n * @param userId - The user ID to check permissions of.\n * @returns The permissions for the user, defaulting to Viewer.\n */\n public getPermissions(userId: string): TreePermissions {\n const currentPls = this.room.currentState.getStateEvents(EventType.RoomPowerLevels, \"\");\n if (Array.isArray(currentPls)) throw new Error(\"Unexpected return type for power levels\");\n\n const pls = currentPls?.getContent() || {};\n const viewLevel = pls[\"users_default\"] || 0;\n const editLevel = pls[\"events_default\"] || 50;\n const adminLevel = pls[\"events\"]?.[EventType.RoomPowerLevels] || 100;\n\n const userLevel = pls[\"users\"]?.[userId] || viewLevel;\n if (userLevel >= adminLevel) return TreePermissions.Owner;\n if (userLevel >= editLevel) return TreePermissions.Editor;\n return TreePermissions.Viewer;\n }\n\n /**\n * Creates a directory under this tree space, represented as another tree space.\n * @param name - The name for the directory.\n * @returns Promise which resolves to the created directory.\n */\n public async createDirectory(name: string): Promise<MSC3089TreeSpace> {\n const directory = await this.client.unstableCreateFileTree(name);\n\n await this.client.sendStateEvent(\n this.roomId,\n EventType.SpaceChild,\n {\n via: [this.client.getDomain()!],\n },\n directory.roomId,\n );\n\n await this.client.sendStateEvent(\n directory.roomId,\n EventType.SpaceParent,\n {\n via: [this.client.getDomain()!],\n },\n this.roomId,\n );\n\n return directory;\n }\n\n /**\n * Gets a list of all known immediate subdirectories to this tree space.\n * @returns The tree spaces (directories). May be empty, but not null.\n */\n public getDirectories(): MSC3089TreeSpace[] {\n const trees: MSC3089TreeSpace[] = [];\n const children = this.room.currentState.getStateEvents(EventType.SpaceChild);\n for (const child of children) {\n try {\n const stateKey = child.getStateKey();\n if (stateKey) {\n const tree = this.client.unstableGetFileTreeSpace(stateKey);\n if (tree) trees.push(tree);\n }\n } catch (e) {\n logger.warn(\"Unable to create tree space instance for listing. Are we joined?\", e);\n }\n }\n return trees;\n }\n\n /**\n * Gets a subdirectory of a given ID under this tree space. Note that this will not recurse\n * into children and instead only look one level deep.\n * @param roomId - The room ID (directory ID) to find.\n * @returns The directory, or undefined if not found.\n */\n public getDirectory(roomId: string): MSC3089TreeSpace | undefined {\n return this.getDirectories().find((r) => r.roomId === roomId);\n }\n\n /**\n * Deletes the tree, kicking all members and deleting **all subdirectories**.\n * @returns Promise which resolves when complete.\n */\n public async delete(): Promise<void> {\n const subdirectories = this.getDirectories();\n for (const dir of subdirectories) {\n await dir.delete();\n }\n\n const kickMemberships = [KnownMembership.Invite, KnownMembership.Knock, KnownMembership.Join];\n const members = this.room.currentState.getStateEvents(EventType.RoomMember);\n for (const member of members) {\n const isNotUs = member.getStateKey() !== this.client.getUserId();\n if (isNotUs && kickMemberships.includes(member.getContent().membership! as KnownMembership)) {\n const stateKey = member.getStateKey();\n if (!stateKey) {\n throw new Error(\"State key not found for branch\");\n }\n await this.client.kick(this.roomId, stateKey, \"Room deleted\");\n }\n }\n\n await this.client.leave(this.roomId);\n }\n\n private getOrderedChildren(children: MatrixEvent[]): { roomId: string; order: string }[] {\n const ordered: { roomId: string; order: string }[] = children\n .map((c) => ({ roomId: c.getStateKey(), order: c.getContent()[\"order\"] }))\n .filter((c) => c.roomId) as { roomId: string; order: string }[];\n ordered.sort((a, b) => {\n if (a.order && !b.order) {\n return -1;\n } else if (!a.order && b.order) {\n return 1;\n } else if (!a.order && !b.order) {\n const roomA = this.client.getRoom(a.roomId);\n const roomB = this.client.getRoom(b.roomId);\n if (!roomA || !roomB) {\n // just don't bother trying to do more partial sorting\n return lexicographicCompare(a.roomId, b.roomId);\n }\n\n const createTsA = roomA.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n const createTsB = roomB.currentState.getStateEvents(EventType.RoomCreate, \"\")?.getTs() ?? 0;\n if (createTsA === createTsB) {\n return lexicographicCompare(a.roomId, b.roomId);\n }\n return createTsA - createTsB;\n } else {\n // both not-null orders\n return lexicographicCompare(a.order, b.order);\n }\n });\n return ordered;\n }\n\n private getParentRoom(): Room {\n const parents = this.room.currentState.getStateEvents(EventType.SpaceParent);\n const parent = parents[0]; // XXX: Wild assumption\n if (!parent) throw new Error(\"Expected to have a parent in a non-top level space\");\n\n // XXX: We are assuming the parent is a valid tree space.\n // We probably don't need to validate the parent room state for this usecase though.\n const stateKey = parent.getStateKey();\n if (!stateKey) throw new Error(\"No state key found for parent\");\n const parentRoom = this.client.getRoom(stateKey);\n if (!parentRoom) throw new Error(\"Unable to locate room for parent\");\n\n return parentRoom;\n }\n\n /**\n * Gets the current order index for this directory. Note that if this is the top level space\n * then -1 will be returned.\n * @returns The order index of this space.\n */\n public getOrder(): number {\n if (this.isTopLevel) return -1;\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n\n return ordered.findIndex((c) => c.roomId === this.roomId);\n }\n\n /**\n * Sets the order index for this directory within its parent. Note that if this is a top level\n * space then an error will be thrown. -1 can be used to move the child to the start, and numbers\n * larger than the number of children can be used to move the child to the end.\n * @param index - The new order index for this space.\n * @returns Promise which resolves when complete.\n * @throws Throws if this is a top level space.\n */\n public async setOrder(index: number): Promise<void> {\n if (this.isTopLevel) throw new Error(\"Cannot set order of top level spaces currently\");\n\n const parentRoom = this.getParentRoom();\n const children = parentRoom.currentState.getStateEvents(EventType.SpaceChild);\n const ordered = this.getOrderedChildren(children);\n index = Math.max(Math.min(index, ordered.length - 1), 0);\n\n const currentIndex = this.getOrder();\n const movingUp = currentIndex < index;\n if (movingUp && index === ordered.length - 1) {\n index--;\n } else if (!movingUp && index === 0) {\n index++;\n }\n\n const prev = ordered[movingUp ? index : index - 1];\n const next = ordered[movingUp ? index + 1 : index];\n\n let newOrder = DEFAULT_ALPHABET[0];\n let ensureBeforeIsSane = false;\n if (!prev) {\n // Move to front\n if (next?.order) {\n newOrder = prevString(next.order);\n }\n } else if (index === ordered.length - 1) {\n // Move to back\n if (next?.order) {\n newOrder = nextString(next.order);\n }\n } else {\n // Move somewhere in the middle\n const startOrder = prev?.order;\n const endOrder = next?.order;\n if (startOrder && endOrder) {\n if (startOrder === endOrder) {\n // Error case: just move +1 to break out of awful math\n newOrder = nextString(startOrder);\n } else {\n newOrder = averageBetweenStrings(startOrder, endOrder);\n }\n } else {\n if (startOrder) {\n // We're at the end (endOrder is null, so no explicit order)\n newOrder = nextString(startOrder);\n } else if (endOrder) {\n // We're at the start (startOrder is null, so nothing before us)\n newOrder = prevString(endOrder);\n } else {\n // Both points are unknown. We're likely in a range where all the children\n // don't have particular order values, so we may need to update them too.\n // The other possibility is there's only us as a child, but we should have\n // shown up in the other states.\n ensureBeforeIsSane = true;\n }\n }\n }\n\n if (ensureBeforeIsSane) {\n // We were asked by the order algorithm to prepare the moving space for a landing\n // in the undefined order part of the order array, which means we need to update the\n // spaces that come before it with a stable order value.\n let lastOrder: string | undefined;\n for (let i = 0; i <= index; i++) {\n const target = ordered[i];\n if (i === 0) {\n lastOrder = target.order;\n }\n if (!target.order) {\n // XXX: We should be creating gaps to avoid conflicts\n lastOrder = lastOrder ? nextString(lastOrder) : DEFAULT_ALPHABET[0];\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, target.roomId);\n const content = currentChild?.getContent<SpaceChildEventContent>() ?? {\n via: [this.client.getDomain()!],\n };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n order: lastOrder,\n },\n target.roomId,\n );\n } else {\n lastOrder = target.order;\n }\n }\n if (lastOrder) {\n newOrder = nextString(lastOrder);\n }\n }\n\n // TODO: Deal with order conflicts by reordering\n\n // Now we can finally update our own order state\n const currentChild = parentRoom.currentState.getStateEvents(EventType.SpaceChild, this.roomId);\n const content = currentChild?.getContent<SpaceChildEventContent>() ?? { via: [this.client.getDomain()!] };\n await this.client.sendStateEvent(\n parentRoom.roomId,\n EventType.SpaceChild,\n {\n ...content,\n\n // TODO: Safely constrain to 50 character limit required by spaces.\n order: newOrder,\n },\n this.roomId,\n );\n }\n\n /**\n * Creates (uploads) a new file to this tree. The file must have already been encrypted for the room.\n * The file contents are in a type that is compatible with MatrixClient.uploadContent().\n * @param name - The name of the file.\n * @param encryptedContents - The encrypted contents.\n * @param info - The encrypted file information.\n * @param additionalContent - Optional event content fields to include in the message.\n * @returns Promise which resolves to the file event's sent response.\n */\n public async createFile(\n name: string,\n encryptedContents: FileType,\n info: EncryptedFile,\n additionalContent?: IContent,\n ): Promise<ISendEventResponse> {\n const { content_uri: mxc } = await this.client.uploadContent(encryptedContents, {\n includeFilename: false,\n });\n info.url = mxc;\n\n const fileContent: FileContent = {\n msgtype: MsgType.File,\n body: name,\n url: mxc,\n file: info,\n };\n\n additionalContent = additionalContent ?? {};\n if (additionalContent[\"m.new_content\"]) {\n // We do the right thing according to the spec, but due to how relations are\n // handled we also end up duplicating this information to the regular `content`\n // as well.\n additionalContent[\"m.new_content\"] = fileContent;\n }\n\n const res = await this.client.sendMessage(this.roomId, {\n ...additionalContent,\n ...fileContent,\n [UNSTABLE_MSC3089_LEAF.name]: {},\n } as FileContent);\n\n await this.client.sendStateEvent(\n this.roomId,\n UNSTABLE_MSC3089_BRANCH.name,\n {\n active: true,\n name: name,\n },\n res[\"event_id\"],\n );\n\n return res;\n }\n\n /**\n * Retrieves a file from the tree.\n * @param fileEventId - The event ID of the file.\n * @returns The file, or null if not found.\n */\n public getFile(fileEventId: string): MSC3089Branch | null {\n const branch = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name, fileEventId);\n return branch ? new MSC3089Branch(this.client, branch, this) : null;\n }\n\n /**\n * Gets an array of all known files for the tree.\n * @returns The known files. May be empty, but not null.\n */\n public listFiles(): MSC3089Branch[] {\n return this.listAllFiles().filter((b) => b.isActive);\n }\n\n /**\n * Gets an array of all known files for the tree, including inactive/invalid ones.\n * @returns The known files. May be empty, but not null.\n */\n public listAllFiles(): MSC3089Branch[] {\n const branches = this.room.currentState.getStateEvents(UNSTABLE_MSC3089_BRANCH.name) ?? [];\n return branches.map((e) => new MSC3089Branch(this.client, e, this));\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
package/lib/models/beacon.js
CHANGED
|
@@ -35,20 +35,16 @@ export var getBeaconInfoIdentifier = event => "".concat(event.getRoomId(), "_").
|
|
|
35
35
|
|
|
36
36
|
// https://github.com/matrix-org/matrix-spec-proposals/pull/3672
|
|
37
37
|
export class Beacon extends TypedEventEmitter {
|
|
38
|
+
// beaconInfo is assigned by setBeaconInfo in the constructor
|
|
39
|
+
// ! to make tsc believe it is definitely assigned
|
|
40
|
+
|
|
38
41
|
constructor(rootEvent) {
|
|
39
42
|
super();
|
|
40
|
-
this.rootEvent = rootEvent;
|
|
41
|
-
_defineProperty(this, "roomId", void 0);
|
|
42
|
-
// beaconInfo is assigned by setBeaconInfo in the constructor
|
|
43
|
-
// ! to make tsc believe it is definitely assigned
|
|
44
|
-
_defineProperty(this, "_beaconInfo", void 0);
|
|
45
|
-
_defineProperty(this, "_isLive", void 0);
|
|
46
|
-
_defineProperty(this, "livenessWatchTimeout", void 0);
|
|
47
|
-
_defineProperty(this, "_latestLocationEvent", void 0);
|
|
48
43
|
_defineProperty(this, "clearLatestLocation", () => {
|
|
49
44
|
this._latestLocationEvent = undefined;
|
|
50
45
|
this.emit(BeaconEvent.LocationUpdate, this.latestLocationState);
|
|
51
46
|
});
|
|
47
|
+
this.rootEvent = rootEvent;
|
|
52
48
|
this.roomId = this.rootEvent.getRoomId();
|
|
53
49
|
this.setBeaconInfo(this.rootEvent);
|
|
54
50
|
}
|
|
@@ -137,9 +133,7 @@ export class Beacon extends TypedEventEmitter {
|
|
|
137
133
|
var content = event.getContent();
|
|
138
134
|
var parsed = parseBeaconContent(content);
|
|
139
135
|
if (!parsed.uri || !parsed.timestamp) return false; // we won't be able to process these
|
|
140
|
-
var
|
|
141
|
-
timestamp
|
|
142
|
-
} = parsed;
|
|
136
|
+
var timestamp = parsed.timestamp;
|
|
143
137
|
return this._beaconInfo.timestamp &&
|
|
144
138
|
// only include positions that were taken inside the beacon's live period
|
|
145
139
|
isTimestampInDuration(this._beaconInfo.timestamp, this._beaconInfo.timeout, timestamp) && (
|