matrix-js-sdk 41.8.0 → 41.9.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 +11 -0
- package/README.md +1 -1
- package/lib/@types/AESEncryptedSecretStoragePayload.js +3 -1
- package/lib/@types/IIdentityServerProvider.js +3 -1
- package/lib/@types/PushRules.js +7 -7
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/auth.js +4 -4
- package/lib/@types/auth.js.map +1 -1
- package/lib/@types/beacon.js +2 -2
- package/lib/@types/beacon.js.map +1 -1
- package/lib/@types/common.js +3 -1
- package/lib/@types/crypto.js +3 -1
- package/lib/@types/event.js +20 -20
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/events.js +3 -1
- package/lib/@types/extensible_events.js +6 -6
- package/lib/@types/extensible_events.js.map +1 -1
- package/lib/@types/global.d.js.map +1 -1
- package/lib/@types/json.js +3 -1
- package/lib/@types/local_notifications.js +3 -1
- package/lib/@types/location.js +4 -4
- package/lib/@types/location.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js +3 -1
- package/lib/@types/media.js +3 -1
- package/lib/@types/membership.js +1 -1
- package/lib/@types/membership.js.map +1 -1
- package/lib/@types/partials.js +6 -6
- package/lib/@types/partials.js.map +1 -1
- package/lib/@types/polls.js +5 -5
- package/lib/@types/polls.js.map +1 -1
- package/lib/@types/read_receipts.js +2 -2
- package/lib/@types/read_receipts.js.map +1 -1
- package/lib/@types/registration.js +3 -1
- package/lib/@types/requests.js +1 -1
- package/lib/@types/requests.js.map +1 -1
- package/lib/@types/retention.js +1 -1
- package/lib/@types/retention.js.map +1 -1
- package/lib/@types/search.js +1 -1
- package/lib/@types/search.js.map +1 -1
- package/lib/@types/signed.js +3 -1
- package/lib/@types/spaces.js +3 -1
- package/lib/@types/state_events.js +3 -1
- package/lib/@types/synapse.js +3 -1
- package/lib/@types/sync.js +1 -1
- package/lib/@types/sync.js.map +1 -1
- package/lib/@types/threepids.js +1 -1
- package/lib/@types/threepids.js.map +1 -1
- package/lib/@types/topic.js +1 -1
- package/lib/@types/topic.js.map +1 -1
- package/lib/@types/uia.js +3 -1
- package/lib/NamespacedValue.js +8 -8
- package/lib/NamespacedValue.js.map +1 -1
- package/lib/ReEmitter.js +9 -16
- package/lib/ReEmitter.js.map +1 -1
- package/lib/ToDeviceMessageQueue.js +49 -57
- package/lib/ToDeviceMessageQueue.js.map +1 -1
- package/lib/autodiscovery.js +232 -247
- package/lib/autodiscovery.js.map +1 -1
- package/lib/base64.js +1 -1
- package/lib/base64.js.map +1 -1
- package/lib/browser-index.d.ts +2 -2
- package/lib/browser-index.d.ts.map +1 -1
- package/lib/browser-index.js +5 -5
- package/lib/browser-index.js.map +1 -1
- package/lib/capabilityPoller.js +19 -22
- package/lib/capabilityPoller.js.map +1 -1
- package/lib/client.d.ts +2 -8
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +2043 -2487
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/CryptoBackend.js +2 -2
- package/lib/common-crypto/CryptoBackend.js.map +1 -1
- package/lib/common-crypto/key-passphrase.js.map +1 -1
- package/lib/content-helpers.js +43 -48
- package/lib/content-helpers.js.map +1 -1
- package/lib/content-repo.js +14 -24
- package/lib/content-repo.js.map +1 -1
- package/lib/crypto/store/base.js +6 -6
- package/lib/crypto/store/base.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js +190 -238
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store.js +25 -30
- package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +113 -145
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto/store/memory-crypto-store.js +74 -105
- package/lib/crypto/store/memory-crypto-store.js.map +1 -1
- package/lib/crypto-api/CryptoEvent.js +1 -1
- package/lib/crypto-api/CryptoEvent.js.map +1 -1
- package/lib/crypto-api/CryptoEventHandlerMap.js +3 -1
- package/lib/crypto-api/index.d.ts +15 -6
- package/lib/crypto-api/index.d.ts.map +1 -1
- package/lib/crypto-api/index.js +22 -22
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/crypto-api/key-passphrase.js +15 -23
- package/lib/crypto-api/key-passphrase.js.map +1 -1
- package/lib/crypto-api/keybackup.js +3 -1
- package/lib/crypto-api/recovery-key.js +11 -12
- package/lib/crypto-api/recovery-key.js.map +1 -1
- package/lib/crypto-api/verification.js +3 -3
- package/lib/crypto-api/verification.js.map +1 -1
- package/lib/digest.js +7 -14
- package/lib/digest.js.map +1 -1
- package/lib/embedded.d.ts.map +1 -1
- package/lib/embedded.js +380 -505
- package/lib/embedded.js.map +1 -1
- package/lib/errors.js +2 -2
- package/lib/errors.js.map +1 -1
- package/lib/event-mapper.js +10 -12
- package/lib/event-mapper.js.map +1 -1
- package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
- package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
- package/lib/extensible_events_v1/MessageEvent.js +11 -13
- package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollEndEvent.js +3 -4
- package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollResponseEvent.js +5 -6
- package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollStartEvent.js +8 -10
- package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
- package/lib/extensible_events_v1/utilities.js.map +1 -1
- package/lib/feature.js +18 -31
- package/lib/feature.js.map +1 -1
- package/lib/filter-component.d.ts.map +1 -1
- package/lib/filter-component.js +20 -26
- package/lib/filter-component.js.map +1 -1
- package/lib/filter.js +14 -17
- package/lib/filter.js.map +1 -1
- package/lib/http-api/errors.js +28 -43
- package/lib/http-api/errors.js.map +1 -1
- package/lib/http-api/fetch.js +141 -159
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/http-api/index.js +17 -20
- package/lib/http-api/index.js.map +1 -1
- package/lib/http-api/interface.js +1 -1
- package/lib/http-api/interface.js.map +1 -1
- package/lib/http-api/method.js +1 -1
- package/lib/http-api/method.js.map +1 -1
- package/lib/http-api/prefix.js +3 -3
- package/lib/http-api/prefix.js.map +1 -1
- package/lib/http-api/refresh.js +74 -94
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/http-api/utils.d.ts +1 -1
- package/lib/http-api/utils.d.ts.map +1 -1
- package/lib/http-api/utils.js +34 -42
- package/lib/http-api/utils.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/indexeddb-helpers.js +3 -3
- package/lib/indexeddb-helpers.js.map +1 -1
- package/lib/indexeddb-worker.js.map +1 -1
- package/lib/interactive-auth.d.ts +5 -5
- package/lib/interactive-auth.d.ts.map +1 -1
- package/lib/interactive-auth.js +172 -204
- package/lib/interactive-auth.js.map +1 -1
- package/lib/logger.js +21 -57
- package/lib/logger.js.map +1 -1
- package/lib/matrix.js +7 -11
- package/lib/matrix.js.map +1 -1
- package/lib/matrixrtc/CallMembership.js +80 -74
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/EncryptionManager.js +1 -1
- package/lib/matrixrtc/EncryptionManager.js.map +1 -1
- package/lib/matrixrtc/IKeyTransport.js +1 -1
- package/lib/matrixrtc/IKeyTransport.js.map +1 -1
- package/lib/matrixrtc/IMembershipManager.js +1 -1
- package/lib/matrixrtc/IMembershipManager.js.map +1 -1
- package/lib/matrixrtc/LivekitTransport.d.ts +1 -1
- package/lib/matrixrtc/LivekitTransport.js +4 -4
- package/lib/matrixrtc/LivekitTransport.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +137 -187
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +36 -41
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +332 -378
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManagerActionScheduler.js +54 -63
- package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.js +119 -143
- package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
- package/lib/matrixrtc/ToDeviceKeyTransport.js +53 -58
- package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/common.js +1 -1
- package/lib/matrixrtc/membershipData/common.js.map +1 -1
- package/lib/matrixrtc/membershipData/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/rtc.js +15 -23
- package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
- package/lib/matrixrtc/membershipData/session.js +4 -5
- package/lib/matrixrtc/membershipData/session.js.map +1 -1
- package/lib/matrixrtc/types.js +4 -6
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/matrixrtc/utils.js +4 -11
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/MSC3089Branch.js +91 -116
- package/lib/models/MSC3089Branch.js.map +1 -1
- package/lib/models/MSC3089TreeSpace.js +209 -245
- package/lib/models/MSC3089TreeSpace.js.map +1 -1
- package/lib/models/ToDeviceMessage.js +3 -1
- package/lib/models/beacon.js +14 -13
- package/lib/models/beacon.js.map +1 -1
- package/lib/models/compare-event-ordering.js +13 -13
- package/lib/models/compare-event-ordering.js.map +1 -1
- package/lib/models/device.js +3 -3
- package/lib/models/device.js.map +1 -1
- package/lib/models/event-context.js +5 -8
- package/lib/models/event-context.js.map +1 -1
- package/lib/models/event-status.js +1 -1
- package/lib/models/event-status.js.map +1 -1
- package/lib/models/event-timeline-set.js +88 -94
- package/lib/models/event-timeline-set.js.map +1 -1
- package/lib/models/event-timeline.js +28 -30
- package/lib/models/event-timeline.js.map +1 -1
- package/lib/models/event.js +182 -226
- package/lib/models/event.js.map +1 -1
- package/lib/models/invites-ignorer-types.js +4 -4
- package/lib/models/invites-ignorer-types.js.map +1 -1
- package/lib/models/invites-ignorer.js +159 -179
- package/lib/models/invites-ignorer.js.map +1 -1
- package/lib/models/poll.js +71 -81
- package/lib/models/poll.js.map +1 -1
- package/lib/models/profile-keys.js +2 -2
- package/lib/models/profile-keys.js.map +1 -1
- package/lib/models/read-receipt.js +40 -56
- package/lib/models/read-receipt.js.map +1 -1
- package/lib/models/related-relations.js.map +1 -1
- package/lib/models/relations-container.js +22 -23
- package/lib/models/relations-container.js.map +1 -1
- package/lib/models/relations.js +133 -159
- package/lib/models/relations.js.map +1 -1
- package/lib/models/room-member.js +24 -29
- package/lib/models/room-member.js.map +1 -1
- package/lib/models/room-receipts.js +29 -43
- package/lib/models/room-receipts.js.map +1 -1
- package/lib/models/room-retention.js +74 -83
- package/lib/models/room-retention.js.map +1 -1
- package/lib/models/room-state.js +143 -172
- package/lib/models/room-state.js.map +1 -1
- package/lib/models/room-sticky-events.d.ts +1 -0
- package/lib/models/room-sticky-events.d.ts.map +1 -1
- package/lib/models/room-sticky-events.js +45 -65
- package/lib/models/room-sticky-events.js.map +1 -1
- package/lib/models/room-summary.js.map +1 -1
- package/lib/models/room.d.ts.map +1 -1
- package/lib/models/room.js +765 -909
- package/lib/models/room.js.map +1 -1
- package/lib/models/search-result.js +5 -5
- package/lib/models/search-result.js.map +1 -1
- package/lib/models/thread.js +225 -285
- package/lib/models/thread.js.map +1 -1
- package/lib/models/typed-event-emitter.js +7 -18
- package/lib/models/typed-event-emitter.js.map +1 -1
- package/lib/models/user.js +8 -8
- package/lib/models/user.js.map +1 -1
- package/lib/oidc/authorize.js +208 -241
- package/lib/oidc/authorize.js.map +1 -1
- package/lib/oidc/discovery.js +23 -36
- package/lib/oidc/discovery.js.map +1 -1
- package/lib/oidc/error.js +1 -1
- package/lib/oidc/error.js.map +1 -1
- package/lib/oidc/index.js +1 -0
- package/lib/oidc/index.js.map +1 -1
- package/lib/oidc/register.js +60 -66
- package/lib/oidc/register.js.map +1 -1
- package/lib/oidc/tokenRefresher.js +77 -91
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/oidc/validate.js +18 -18
- package/lib/oidc/validate.js.map +1 -1
- package/lib/pushprocessor.js +71 -82
- package/lib/pushprocessor.js.map +1 -1
- package/lib/randomstring.js +9 -9
- package/lib/randomstring.js.map +1 -1
- package/lib/realtime-callbacks.js +25 -28
- package/lib/realtime-callbacks.js.map +1 -1
- package/lib/receipt-accumulator.d.ts +2 -0
- package/lib/receipt-accumulator.d.ts.map +1 -1
- package/lib/receipt-accumulator.js +14 -22
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/rendezvous/MSC4108SignInWithQR.js +271 -302
- package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
- package/lib/rendezvous/RendezvousChannel.js +3 -1
- package/lib/rendezvous/RendezvousCode.js +3 -1
- package/lib/rendezvous/RendezvousError.js.map +1 -1
- package/lib/rendezvous/RendezvousFailureReason.js +2 -2
- package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
- package/lib/rendezvous/RendezvousIntent.js +1 -1
- package/lib/rendezvous/RendezvousIntent.js.map +1 -1
- package/lib/rendezvous/RendezvousTransport.js +3 -1
- package/lib/rendezvous/channels/MSC4108SecureChannel.js +123 -147
- package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
- package/lib/rendezvous/index.js +44 -69
- package/lib/rendezvous/index.js.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js +134 -152
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
- package/lib/retentionPolicy.js +6 -9
- package/lib/retentionPolicy.js.map +1 -1
- package/lib/room-hierarchy.js +52 -60
- package/lib/room-hierarchy.js.map +1 -1
- package/lib/rust-crypto/CrossSigningIdentity.js +94 -104
- package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
- package/lib/rust-crypto/DehydratedDeviceManager.js +157 -190
- package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
- package/lib/rust-crypto/KeyClaimManager.js +18 -22
- package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +109 -139
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestsManager.js +66 -80
- package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +196 -224
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
- package/lib/rust-crypto/RoomEncryptor.js +127 -143
- package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
- package/lib/rust-crypto/backup.js +453 -549
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/rust-crypto/constants.js +1 -1
- package/lib/rust-crypto/constants.js.map +1 -1
- package/lib/rust-crypto/device-converter.js +15 -28
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/index.js +103 -116
- package/lib/rust-crypto/index.js.map +1 -1
- package/lib/rust-crypto/libolm_migration.js +303 -365
- package/lib/rust-crypto/libolm_migration.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts +5 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +1067 -1332
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/rust-crypto/secret-storage.js +12 -25
- package/lib/rust-crypto/secret-storage.js.map +1 -1
- package/lib/rust-crypto/verification.js +137 -189
- package/lib/rust-crypto/verification.js.map +1 -1
- package/lib/scheduler.js +44 -19
- package/lib/scheduler.js.map +1 -1
- package/lib/secret-storage.js +179 -213
- package/lib/secret-storage.js.map +1 -1
- package/lib/serverCapabilities.js +6 -9
- package/lib/serverCapabilities.js.map +1 -1
- package/lib/service-types.js +1 -1
- package/lib/service-types.js.map +1 -1
- package/lib/sliding-sync-sdk.d.ts.map +1 -1
- package/lib/sliding-sync-sdk.js +368 -424
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.js +135 -171
- package/lib/sliding-sync.js.map +1 -1
- package/lib/store/index.js +3 -1
- package/lib/store/indexeddb-backend.js +3 -1
- package/lib/store/indexeddb-local-backend.js +194 -253
- package/lib/store/indexeddb-local-backend.js.map +1 -1
- package/lib/store/indexeddb-remote-backend.js +33 -63
- package/lib/store/indexeddb-remote-backend.js.map +1 -1
- package/lib/store/indexeddb-store-worker.js +22 -23
- package/lib/store/indexeddb-store-worker.js.map +1 -1
- package/lib/store/indexeddb.js +44 -71
- package/lib/store/indexeddb.js.map +1 -1
- package/lib/store/local-storage-events-emitter.js +2 -2
- package/lib/store/local-storage-events-emitter.js.map +1 -1
- package/lib/store/memory.js +34 -57
- package/lib/store/memory.js.map +1 -1
- package/lib/store/stub.js +22 -35
- package/lib/store/stub.js.map +1 -1
- package/lib/sync-accumulator.js +54 -66
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +905 -998
- package/lib/sync.js.map +1 -1
- package/lib/testing.js +63 -105
- package/lib/testing.js.map +1 -1
- package/lib/thread-utils.js +1 -4
- package/lib/thread-utils.js.map +1 -1
- package/lib/timeline-window.js +89 -102
- package/lib/timeline-window.js.map +1 -1
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/decryptAESSecretStorageItem.js +14 -25
- package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/encryptAESSecretStorageItem.js +27 -38
- package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/internal/deriveKeys.js +25 -32
- package/lib/utils/internal/deriveKeys.js.map +1 -1
- package/lib/utils/roomVersion.js +1 -1
- package/lib/utils/roomVersion.js.map +1 -1
- package/lib/utils.js +83 -135
- package/lib/utils.js.map +1 -1
- package/lib/version-support.js +3 -3
- package/lib/version-support.js.map +1 -1
- package/lib/webrtc/audioContext.js +5 -6
- package/lib/webrtc/audioContext.js.map +1 -1
- package/lib/webrtc/call.js +1081 -1250
- package/lib/webrtc/call.js.map +1 -1
- package/lib/webrtc/callEventHandler.js +202 -214
- package/lib/webrtc/callEventHandler.js.map +1 -1
- package/lib/webrtc/callEventTypes.js +2 -2
- package/lib/webrtc/callEventTypes.js.map +1 -1
- package/lib/webrtc/callFeed.js +18 -20
- package/lib/webrtc/callFeed.js.map +1 -1
- package/lib/webrtc/groupCall.js +513 -602
- package/lib/webrtc/groupCall.js.map +1 -1
- package/lib/webrtc/groupCallEventHandler.js +59 -62
- package/lib/webrtc/groupCallEventHandler.js.map +1 -1
- package/lib/webrtc/mediaHandler.js +198 -232
- package/lib/webrtc/mediaHandler.js.map +1 -1
- package/lib/webrtc/stats/callFeedStatsReporter.js +16 -20
- package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportGatherer.js +67 -75
- package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportSummary.js +3 -1
- package/lib/webrtc/stats/connectionStats.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsBuilder.js +2 -2
- package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js +20 -24
- package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
- package/lib/webrtc/stats/groupCallStats.js +6 -8
- package/lib/webrtc/stats/groupCallStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaSsrcHandler.js +7 -8
- package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackHandler.js +7 -9
- package/lib/webrtc/stats/media/mediaTrackHandler.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 +7 -7
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
- package/lib/webrtc/stats/statsReport.js +1 -1
- package/lib/webrtc/stats/statsReport.js.map +1 -1
- package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
- package/lib/webrtc/stats/summaryStatsReportGatherer.js +14 -14
- package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/trackStatsBuilder.js +32 -34
- package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/transportStats.js +3 -1
- package/lib/webrtc/stats/transportStatsBuilder.js +9 -9
- package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/valueFormatter.js +1 -1
- package/lib/webrtc/stats/valueFormatter.js.map +1 -1
- package/package.json +18 -33
- package/src/@types/global.d.ts +2 -2
- package/src/ToDeviceMessageQueue.ts +2 -2
- package/src/browser-index.ts +4 -4
- package/src/client.ts +15 -20
- package/src/crypto-api/index.ts +17 -6
- package/src/embedded.ts +4 -6
- package/src/filter-component.ts +1 -0
- package/src/http-api/utils.ts +1 -1
- package/src/interactive-auth.ts +11 -5
- package/src/matrixrtc/LivekitTransport.ts +1 -1
- package/src/matrixrtc/MatrixRTCSession.ts +1 -1
- package/src/models/MSC3089Branch.ts +1 -1
- package/src/models/room-sticky-events.ts +1 -0
- package/src/models/room.ts +9 -11
- package/src/receipt-accumulator.ts +2 -0
- package/src/rendezvous/index.ts +1 -1
- package/src/rendezvous/transports/MSC4108RendezvousSession.ts +2 -2
- package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
- package/src/rust-crypto/index.ts +6 -6
- package/src/rust-crypto/rust-crypto.ts +31 -7
- package/src/rust-crypto/verification.ts +1 -1
- package/src/sliding-sync-sdk.ts +5 -7
- package/src/store/indexeddb-local-backend.ts +3 -3
- package/src/sync.ts +6 -8
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
2
|
/*
|
|
5
3
|
Copyright 2023 - 2024 The Matrix.org Foundation C.I.C.
|
|
@@ -37,9 +35,6 @@ import { CryptoEvent, ImportRoomKeyStage } from "../crypto-api/index.js";
|
|
|
37
35
|
export class RustBackupManager extends TypedEventEmitter {
|
|
38
36
|
constructor(logger, olmMachine, http, outgoingRequestProcessor) {
|
|
39
37
|
super();
|
|
40
|
-
this.olmMachine = olmMachine;
|
|
41
|
-
this.http = http;
|
|
42
|
-
this.outgoingRequestProcessor = outgoingRequestProcessor;
|
|
43
38
|
/** Have we checked if there is a backup on the server which we can use */
|
|
44
39
|
_defineProperty(this, "checkedForBackup", false);
|
|
45
40
|
/**
|
|
@@ -57,6 +52,9 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
57
52
|
/** The logger to use */
|
|
58
53
|
_defineProperty(this, "logger", void 0);
|
|
59
54
|
_defineProperty(this, "keyBackupCheckInProgress", null);
|
|
55
|
+
this.olmMachine = olmMachine;
|
|
56
|
+
this.http = http;
|
|
57
|
+
this.outgoingRequestProcessor = outgoingRequestProcessor;
|
|
60
58
|
this.logger = logger.getChild("[RustBackupManager]");
|
|
61
59
|
}
|
|
62
60
|
|
|
@@ -72,12 +70,9 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
72
70
|
/**
|
|
73
71
|
* Get the backup version we are currently backing up to, if any
|
|
74
72
|
*/
|
|
75
|
-
getActiveBackupVersion() {
|
|
76
|
-
|
|
77
|
-
return
|
|
78
|
-
if (!(yield _this.olmMachine.isBackupEnabled())) return null;
|
|
79
|
-
return _this.activeBackupVersion;
|
|
80
|
-
})();
|
|
73
|
+
async getActiveBackupVersion() {
|
|
74
|
+
if (!(await this.olmMachine.isBackupEnabled())) return null;
|
|
75
|
+
return this.activeBackupVersion;
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
/**
|
|
@@ -88,14 +83,11 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
88
83
|
*
|
|
89
84
|
* If there was no backup on the server, `null`. If our attempt to check resulted in an error, `undefined`.
|
|
90
85
|
*/
|
|
91
|
-
getServerBackupInfo() {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
yield _this2.checkKeyBackupAndEnable(false);
|
|
97
|
-
return _this2.serverBackupInfo;
|
|
98
|
-
})();
|
|
86
|
+
async getServerBackupInfo() {
|
|
87
|
+
// Do a validity check if we haven't already done one. The check is likely to fail if we don't yet have the
|
|
88
|
+
// backup keys -- but as a side-effect, it will populate `serverBackupInfo`.
|
|
89
|
+
await this.checkKeyBackupAndEnable(false);
|
|
90
|
+
return this.serverBackupInfo;
|
|
99
91
|
}
|
|
100
92
|
|
|
101
93
|
/**
|
|
@@ -103,18 +95,15 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
103
95
|
*
|
|
104
96
|
* @param info - key backup info dict from {@link CryptoApi.getKeyBackupInfo}.
|
|
105
97
|
*/
|
|
106
|
-
isKeyBackupTrusted(info) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
trusted: signatureVerification.trusted()
|
|
116
|
-
};
|
|
117
|
-
})();
|
|
98
|
+
async isKeyBackupTrusted(info) {
|
|
99
|
+
const signatureVerification = await this.olmMachine.verifyBackup(info);
|
|
100
|
+
const backupKeys = await this.olmMachine.getBackupKeys();
|
|
101
|
+
const decryptionKey = backupKeys?.decryptionKey;
|
|
102
|
+
const backupMatchesSavedPrivateKey = !!decryptionKey && this.backupInfoMatchesBackupDecryptionKey(info, decryptionKey);
|
|
103
|
+
return {
|
|
104
|
+
matchesDecryptionKey: backupMatchesSavedPrivateKey,
|
|
105
|
+
trusted: signatureVerification.trusted()
|
|
106
|
+
};
|
|
118
107
|
}
|
|
119
108
|
|
|
120
109
|
/**
|
|
@@ -146,69 +135,62 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
146
135
|
* @param secret - The secret as received from a `m.secret.send` or `io.element.msc4385.secret.push` event for secret `m.megolm_backup.v1`.
|
|
147
136
|
* @returns true if the secret is valid and has been stored, false otherwise.
|
|
148
137
|
*/
|
|
149
|
-
handleBackupSecretReceived(secret) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
138
|
+
async handleBackupSecretReceived(secret) {
|
|
139
|
+
// Currently we only receive the decryption key without any key backup version. It is important to
|
|
140
|
+
// check that the secret is valid for the current version before storing it.
|
|
141
|
+
// We force a check to ensure to have the latest version.
|
|
142
|
+
let latestBackupInfo;
|
|
143
|
+
try {
|
|
144
|
+
latestBackupInfo = await this.requestKeyBackupVersion();
|
|
145
|
+
} catch (e) {
|
|
146
|
+
this.logger.warn("handleBackupSecretReceived: Error checking for latest key backup", e);
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (!latestBackupInfo?.version) {
|
|
150
|
+
// There is no server-side key backup.
|
|
151
|
+
// This decryption key is useless to us.
|
|
152
|
+
this.logger.warn("handleBackupSecretReceived: Received a backup decryption key, but there is no server-side key backup");
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
let backupDecryptionKey;
|
|
156
|
+
try {
|
|
157
|
+
backupDecryptionKey = RustSdkCryptoJs.BackupDecryptionKey.fromBase64(secret);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
this.logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e);
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const privateKeyMatches = this.backupInfoMatchesBackupDecryptionKey(latestBackupInfo, backupDecryptionKey);
|
|
164
|
+
if (!privateKeyMatches) {
|
|
165
|
+
this.logger.warn(`handleBackupSecretReceived: Private decryption key does not match the public key of the current server-side backup version (${latestBackupInfo.version})`);
|
|
166
|
+
// just ignore the secret
|
|
174
167
|
return false;
|
|
175
168
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
yield _this4.saveBackupDecryptionKey(backupDecryptionKey, latestBackupInfo.version);
|
|
185
|
-
|
|
186
|
-
// Check if backup upload should be enabled (e.g. the encryption key matches the decryption key),
|
|
187
|
-
// and enable it if so.
|
|
188
|
-
if (_this4.keyBackupCheckInProgress) {
|
|
189
|
-
_this4.logger.debug("handleBackupSecretReceived: waiting for ongoing keybackup check to complete");
|
|
190
|
-
yield _this4.keyBackupCheckInProgress;
|
|
191
|
-
}
|
|
192
|
-
_this4.logger.debug("handleBackupSecretReceived: checking if we can enable keybackup upload");
|
|
193
|
-
_this4.keyBackupCheckInProgress = _this4.doCheckKeyBackup(latestBackupInfo).finally(() => {
|
|
194
|
-
_this4.keyBackupCheckInProgress = null;
|
|
195
|
-
});
|
|
196
|
-
yield _this4.keyBackupCheckInProgress;
|
|
197
|
-
return true;
|
|
198
|
-
} catch (e) {
|
|
199
|
-
_this4.logger.warn("handleBackupSecretReceived: Unable to validate backup decryption key", e);
|
|
169
|
+
this.logger.info(`handleBackupSecretReceived: Valid decryption key for the current server-side backup version (${latestBackupInfo.version}) received`);
|
|
170
|
+
await this.saveBackupDecryptionKey(backupDecryptionKey, latestBackupInfo.version);
|
|
171
|
+
|
|
172
|
+
// Check if backup upload should be enabled (e.g. the encryption key matches the decryption key),
|
|
173
|
+
// and enable it if so.
|
|
174
|
+
if (this.keyBackupCheckInProgress) {
|
|
175
|
+
this.logger.debug("handleBackupSecretReceived: waiting for ongoing keybackup check to complete");
|
|
176
|
+
await this.keyBackupCheckInProgress;
|
|
200
177
|
}
|
|
201
|
-
|
|
202
|
-
|
|
178
|
+
this.logger.debug("handleBackupSecretReceived: checking if we can enable keybackup upload");
|
|
179
|
+
this.keyBackupCheckInProgress = this.doCheckKeyBackup(latestBackupInfo).finally(() => {
|
|
180
|
+
this.keyBackupCheckInProgress = null;
|
|
181
|
+
});
|
|
182
|
+
await this.keyBackupCheckInProgress;
|
|
183
|
+
return true;
|
|
184
|
+
} catch (e) {
|
|
185
|
+
this.logger.warn("handleBackupSecretReceived: Unable to validate backup decryption key", e);
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
203
188
|
}
|
|
204
|
-
saveBackupDecryptionKey(backupDecryptionKey, version) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// importing keys from backup if needed.
|
|
210
|
-
_this5.emit(CryptoEvent.KeyBackupDecryptionKeyCached, version);
|
|
211
|
-
})();
|
|
189
|
+
async saveBackupDecryptionKey(backupDecryptionKey, version) {
|
|
190
|
+
await this.olmMachine.saveBackupDecryptionKey(backupDecryptionKey, version);
|
|
191
|
+
// Emit an event that we have a new backup decryption key, so that the sdk can start
|
|
192
|
+
// importing keys from backup if needed.
|
|
193
|
+
this.emit(CryptoEvent.KeyBackupDecryptionKeyCached, version);
|
|
212
194
|
}
|
|
213
195
|
|
|
214
196
|
/**
|
|
@@ -218,11 +200,8 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
218
200
|
* @param opts - options object
|
|
219
201
|
* @returns a promise which resolves once the keys have been imported
|
|
220
202
|
*/
|
|
221
|
-
importRoomKeys(keys, opts) {
|
|
222
|
-
|
|
223
|
-
return _asyncToGenerator(function* () {
|
|
224
|
-
yield _this6.importRoomKeysAsJson(JSON.stringify(keys), opts);
|
|
225
|
-
})();
|
|
203
|
+
async importRoomKeys(keys, opts) {
|
|
204
|
+
await this.importRoomKeysAsJson(JSON.stringify(keys), opts);
|
|
226
205
|
}
|
|
227
206
|
|
|
228
207
|
/**
|
|
@@ -233,125 +212,111 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
233
212
|
* @param opts - options object
|
|
234
213
|
* @returns a promise which resolves once the keys have been imported
|
|
235
214
|
*/
|
|
236
|
-
importRoomKeysAsJson(jsonKeys, opts) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
};
|
|
247
|
-
opts === null || opts === void 0 || (_opts$progressCallbac = opts.progressCallback) === null || _opts$progressCallbac === void 0 || _opts$progressCallbac.call(opts, importOpt);
|
|
248
|
-
});
|
|
249
|
-
})();
|
|
215
|
+
async importRoomKeysAsJson(jsonKeys, opts) {
|
|
216
|
+
await this.olmMachine.importExportedRoomKeys(jsonKeys, (progress, total) => {
|
|
217
|
+
const importOpt = {
|
|
218
|
+
total: Number(total),
|
|
219
|
+
successes: Number(progress),
|
|
220
|
+
stage: ImportRoomKeyStage.LoadKeys,
|
|
221
|
+
failures: 0
|
|
222
|
+
};
|
|
223
|
+
opts?.progressCallback?.(importOpt);
|
|
224
|
+
});
|
|
250
225
|
}
|
|
251
226
|
|
|
252
227
|
/**
|
|
253
228
|
* Implementation of {@link CryptoBackend#importBackedUpRoomKeys}.
|
|
254
229
|
*/
|
|
255
|
-
importBackedUpRoomKeys(keys, backupVersion, opts) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (!keysByRoom.has(roomId)) {
|
|
262
|
-
keysByRoom.set(roomId, new Map());
|
|
263
|
-
}
|
|
264
|
-
keysByRoom.get(roomId).set(key.session_id, key);
|
|
230
|
+
async importBackedUpRoomKeys(keys, backupVersion, opts) {
|
|
231
|
+
const keysByRoom = new Map();
|
|
232
|
+
for (const key of keys) {
|
|
233
|
+
const roomId = new RustSdkCryptoJs.RoomId(key.room_id);
|
|
234
|
+
if (!keysByRoom.has(roomId)) {
|
|
235
|
+
keysByRoom.set(roomId, new Map());
|
|
265
236
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
})
|
|
237
|
+
keysByRoom.get(roomId).set(key.session_id, key);
|
|
238
|
+
}
|
|
239
|
+
await this.olmMachine.importBackedUpRoomKeys(keysByRoom, (progress, total, failures) => {
|
|
240
|
+
const importOpt = {
|
|
241
|
+
total: Number(total),
|
|
242
|
+
successes: Number(progress),
|
|
243
|
+
stage: ImportRoomKeyStage.LoadKeys,
|
|
244
|
+
failures: Number(failures)
|
|
245
|
+
};
|
|
246
|
+
opts?.progressCallback?.(importOpt);
|
|
247
|
+
}, backupVersion);
|
|
277
248
|
}
|
|
278
249
|
/** Helper to check the key backup status, and enable/disable it as appropriate
|
|
279
250
|
*
|
|
280
251
|
* A KeyBackupInfo can be passed if it was fetched recently, to avoid trying to
|
|
281
252
|
* re-fetch it from the server.
|
|
282
253
|
*/
|
|
283
|
-
doCheckKeyBackup(backupInfo) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if (!backupInfo) {
|
|
289
|
-
backupInfo = yield _this9.requestKeyBackupVersion();
|
|
290
|
-
}
|
|
291
|
-
} catch (e) {
|
|
292
|
-
_this9.logger.warn("Error checking for active key backup", e);
|
|
293
|
-
_this9.serverBackupInfo = undefined;
|
|
294
|
-
return null;
|
|
254
|
+
async doCheckKeyBackup(backupInfo) {
|
|
255
|
+
this.logger.debug("Checking key backup status...");
|
|
256
|
+
try {
|
|
257
|
+
if (!backupInfo) {
|
|
258
|
+
backupInfo = await this.requestKeyBackupVersion();
|
|
295
259
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
260
|
+
} catch (e) {
|
|
261
|
+
this.logger.warn("Error checking for active key backup", e);
|
|
262
|
+
this.serverBackupInfo = undefined;
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
this.checkedForBackup = true;
|
|
266
|
+
if (backupInfo && !backupInfo.version) {
|
|
267
|
+
this.logger.warn("active backup lacks a useful 'version'; ignoring it");
|
|
268
|
+
backupInfo = undefined;
|
|
269
|
+
}
|
|
270
|
+
this.serverBackupInfo = backupInfo;
|
|
271
|
+
const activeVersion = await this.getActiveBackupVersion();
|
|
272
|
+
if (!backupInfo) {
|
|
273
|
+
if (activeVersion !== null) {
|
|
274
|
+
this.logger.debug("No key backup present on server: disabling key backup");
|
|
275
|
+
await this.disableKeyBackup();
|
|
276
|
+
} else {
|
|
277
|
+
this.logger.debug("No key backup present on server: not enabling key backup");
|
|
300
278
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
const trustInfo = await this.isKeyBackupTrusted(backupInfo);
|
|
282
|
+
|
|
283
|
+
// Per the spec, we should enable key upload if either (a) the backup is signed by a trusted key, or
|
|
284
|
+
// (b) the public key matches the private decryption key that we have received from 4S.
|
|
285
|
+
if (!trustInfo.matchesDecryptionKey && !trustInfo.trusted) {
|
|
286
|
+
if (activeVersion !== null) {
|
|
287
|
+
this.logger.debug("Key backup present on server but not trusted: disabling key backup");
|
|
288
|
+
await this.disableKeyBackup();
|
|
289
|
+
} else {
|
|
290
|
+
this.logger.debug("Key backup present on server but not trusted: not enabling key backup");
|
|
311
291
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
292
|
+
} else {
|
|
293
|
+
if (activeVersion === null) {
|
|
294
|
+
this.logger.debug(`Found usable key backup v${backupInfo.version}: enabling key backups`);
|
|
295
|
+
await this.enableKeyBackup(backupInfo);
|
|
296
|
+
} else if (activeVersion !== backupInfo.version) {
|
|
297
|
+
this.logger.debug(`On backup version ${activeVersion} but found version ${backupInfo.version}: switching.`);
|
|
298
|
+
// This will remove any pending backup request, remove the backup key and reset the backup state of each room key we have.
|
|
299
|
+
await this.disableKeyBackup();
|
|
300
|
+
// Enabling will now trigger re-upload of all the keys
|
|
301
|
+
await this.enableKeyBackup(backupInfo);
|
|
323
302
|
} else {
|
|
324
|
-
|
|
325
|
-
_this9.logger.debug("Found usable key backup v".concat(backupInfo.version, ": enabling key backups"));
|
|
326
|
-
yield _this9.enableKeyBackup(backupInfo);
|
|
327
|
-
} else if (activeVersion !== backupInfo.version) {
|
|
328
|
-
_this9.logger.debug("On backup version ".concat(activeVersion, " but found version ").concat(backupInfo.version, ": switching."));
|
|
329
|
-
// This will remove any pending backup request, remove the backup key and reset the backup state of each room key we have.
|
|
330
|
-
yield _this9.disableKeyBackup();
|
|
331
|
-
// Enabling will now trigger re-upload of all the keys
|
|
332
|
-
yield _this9.enableKeyBackup(backupInfo);
|
|
333
|
-
} else {
|
|
334
|
-
_this9.logger.debug("Backup version ".concat(backupInfo.version, " still current"));
|
|
335
|
-
}
|
|
303
|
+
this.logger.debug(`Backup version ${backupInfo.version} still current`);
|
|
336
304
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
enableKeyBackup(backupInfo) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
_this0.emit(CryptoEvent.KeyBackupStatus, true);
|
|
353
|
-
_this0.backupKeysLoop();
|
|
354
|
-
})();
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
backupInfo,
|
|
308
|
+
trustInfo
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
async enableKeyBackup(backupInfo) {
|
|
312
|
+
// we know for certain it must be a Curve25519 key, because we have verified it and only Curve25519
|
|
313
|
+
// keys can be verified.
|
|
314
|
+
//
|
|
315
|
+
// we also checked it has a valid `version`.
|
|
316
|
+
await this.olmMachine.enableBackupV1(backupInfo.auth_data.public_key, backupInfo.version);
|
|
317
|
+
this.activeBackupVersion = backupInfo.version;
|
|
318
|
+
this.emit(CryptoEvent.KeyBackupStatus, true);
|
|
319
|
+
this.backupKeysLoop();
|
|
355
320
|
}
|
|
356
321
|
|
|
357
322
|
/**
|
|
@@ -359,139 +324,128 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
359
324
|
* Doesn't try to check the backup server side. To be called when a new
|
|
360
325
|
* megolm key is known locally.
|
|
361
326
|
*/
|
|
362
|
-
maybeUploadKey() {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
//
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
return yield _this11.olmMachine.backupRoomKeys();
|
|
409
|
-
}));
|
|
410
|
-
} catch (err) {
|
|
411
|
-
_this11.logger.error("Backup: Failed to get keys to backup from rust crypto-sdk", err);
|
|
327
|
+
async maybeUploadKey() {
|
|
328
|
+
if (this.activeBackupVersion != null) {
|
|
329
|
+
this.backupKeysLoop();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async disableKeyBackup() {
|
|
333
|
+
await this.olmMachine.disableBackup();
|
|
334
|
+
this.activeBackupVersion = null;
|
|
335
|
+
this.emit(CryptoEvent.KeyBackupStatus, false);
|
|
336
|
+
}
|
|
337
|
+
async backupKeysLoop(maxDelay = 10000) {
|
|
338
|
+
if (this.backupKeysLoopRunning) {
|
|
339
|
+
this.logger.debug(`Backup loop already running`);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this.backupKeysLoopRunning = true;
|
|
343
|
+
this.logger.debug(`Backup: Starting keys upload loop for backup version:${this.activeBackupVersion}.`);
|
|
344
|
+
|
|
345
|
+
// wait between 0 and `maxDelay` seconds, to avoid backup
|
|
346
|
+
// requests from different clients hitting the server all at
|
|
347
|
+
// the same time when a new key is sent
|
|
348
|
+
const delay = Math.random() * maxDelay;
|
|
349
|
+
await sleep(delay);
|
|
350
|
+
try {
|
|
351
|
+
// number of consecutive network failures for exponential backoff
|
|
352
|
+
let numFailures = 0;
|
|
353
|
+
// The number of keys left to back up. (Populated lazily: see more comments below.)
|
|
354
|
+
let remainingToUploadCount = null;
|
|
355
|
+
// To avoid computing the key when only a few keys were added (after a sync for example),
|
|
356
|
+
// we compute the count only when at least two iterations are needed.
|
|
357
|
+
let isFirstIteration = true;
|
|
358
|
+
while (!this.stopped) {
|
|
359
|
+
// Get a batch of room keys to upload
|
|
360
|
+
let request = undefined;
|
|
361
|
+
try {
|
|
362
|
+
request = await logDuration(this.logger, "BackupRoomKeys: Get keys to backup from rust crypto-sdk", async () => {
|
|
363
|
+
return await this.olmMachine.backupRoomKeys();
|
|
364
|
+
});
|
|
365
|
+
} catch (err) {
|
|
366
|
+
this.logger.error("Backup: Failed to get keys to backup from rust crypto-sdk", err);
|
|
367
|
+
}
|
|
368
|
+
if (!request || this.stopped || !this.activeBackupVersion) {
|
|
369
|
+
this.logger.debug(`Backup: Ending loop for version ${this.activeBackupVersion}.`);
|
|
370
|
+
if (!request) {
|
|
371
|
+
// nothing more to upload
|
|
372
|
+
this.emit(CryptoEvent.KeyBackupSessionsRemaining, 0);
|
|
412
373
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
await this.outgoingRequestProcessor.makeOutgoingRequest(request);
|
|
378
|
+
numFailures = 0;
|
|
379
|
+
if (this.stopped) break;
|
|
380
|
+
|
|
381
|
+
// Key count performance (`olmMachine.roomKeyCounts()`) can be pretty bad on some configurations.
|
|
382
|
+
// In particular, we detected on some M1 macs that when the object store reaches a threshold, the count
|
|
383
|
+
// performance stops growing in O(n) and suddenly becomes very slow (40s, 60s or more).
|
|
384
|
+
// For reference, the performance drop occurs around 300-400k keys on the platforms where this issue is observed.
|
|
385
|
+
// Even on other configurations, the count can take several seconds.
|
|
386
|
+
// This will block other operations on the database, like sending messages.
|
|
387
|
+
//
|
|
388
|
+
// This is a workaround to avoid calling `olmMachine.roomKeyCounts()` too often, and only when necessary.
|
|
389
|
+
// We don't call it on the first loop because there could be only a few keys to upload, and we don't want to wait for the count.
|
|
390
|
+
if (!isFirstIteration && remainingToUploadCount === null) {
|
|
391
|
+
try {
|
|
392
|
+
const keyCount = await this.olmMachine.roomKeyCounts();
|
|
393
|
+
remainingToUploadCount = keyCount.total - keyCount.backedUp;
|
|
394
|
+
} catch (err) {
|
|
395
|
+
this.logger.error("Backup: Failed to get key counts from rust crypto-sdk", err);
|
|
418
396
|
}
|
|
419
|
-
return;
|
|
420
397
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
398
|
+
if (remainingToUploadCount !== null) {
|
|
399
|
+
this.emit(CryptoEvent.KeyBackupSessionsRemaining, remainingToUploadCount);
|
|
400
|
+
const keysCountInBatch = this.keysCountInBatch(request);
|
|
401
|
+
// `OlmMachine.roomKeyCounts` is called only once for the current backupKeysLoop. But new
|
|
402
|
+
// keys could be added during the current loop (after a sync for example).
|
|
403
|
+
// So the count can get out of sync with the real number of remaining keys to upload.
|
|
404
|
+
// Depending on the number of new keys imported and the time to complete the loop,
|
|
405
|
+
// this could result in multiple events being emitted with a remaining key count of 0.
|
|
406
|
+
remainingToUploadCount = Math.max(remainingToUploadCount - keysCountInBatch, 0);
|
|
407
|
+
}
|
|
408
|
+
} catch (err) {
|
|
409
|
+
numFailures++;
|
|
410
|
+
this.logger.error("Backup: Error processing backup request for rust crypto-sdk", err);
|
|
411
|
+
if (err instanceof MatrixError) {
|
|
412
|
+
const errCode = err.data.errcode;
|
|
413
|
+
if (errCode == "M_NOT_FOUND" || errCode == "M_WRONG_ROOM_KEYS_VERSION") {
|
|
414
|
+
this.logger.debug(`Backup: Failed to upload keys to current vesion: ${errCode}.`);
|
|
436
415
|
try {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
_this11.logger.error("Backup: Failed to get key counts from rust crypto-sdk", err);
|
|
416
|
+
await this.disableKeyBackup();
|
|
417
|
+
} catch (error) {
|
|
418
|
+
this.logger.error("Backup: An error occurred while disabling key backup:", error);
|
|
441
419
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
_this11.logger.error("Backup: Error processing backup request for rust crypto-sdk", err);
|
|
456
|
-
if (err instanceof MatrixError) {
|
|
457
|
-
var errCode = err.data.errcode;
|
|
458
|
-
if (errCode == "M_NOT_FOUND" || errCode == "M_WRONG_ROOM_KEYS_VERSION") {
|
|
459
|
-
_this11.logger.debug("Backup: Failed to upload keys to current vesion: ".concat(errCode, "."));
|
|
460
|
-
try {
|
|
461
|
-
yield _this11.disableKeyBackup();
|
|
462
|
-
} catch (error) {
|
|
463
|
-
_this11.logger.error("Backup: An error occurred while disabling key backup:", error);
|
|
420
|
+
this.emit(CryptoEvent.KeyBackupFailed, err.data.errcode);
|
|
421
|
+
// There was an active backup and we are out of sync with the server
|
|
422
|
+
// force a check server side
|
|
423
|
+
this.backupKeysLoopRunning = false;
|
|
424
|
+
this.checkKeyBackupAndEnable(true);
|
|
425
|
+
return;
|
|
426
|
+
} else if (err.isRateLimitError()) {
|
|
427
|
+
// wait for that and then continue?
|
|
428
|
+
try {
|
|
429
|
+
const waitTime = err.getRetryAfterMs();
|
|
430
|
+
if (waitTime && waitTime > 0) {
|
|
431
|
+
await sleep(waitTime);
|
|
432
|
+
continue;
|
|
464
433
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
_this11.backupKeysLoopRunning = false;
|
|
469
|
-
_this11.checkKeyBackupAndEnable(true);
|
|
470
|
-
return;
|
|
471
|
-
} else if (err.isRateLimitError()) {
|
|
472
|
-
// wait for that and then continue?
|
|
473
|
-
try {
|
|
474
|
-
var waitTime = err.getRetryAfterMs();
|
|
475
|
-
if (waitTime && waitTime > 0) {
|
|
476
|
-
yield sleep(waitTime);
|
|
477
|
-
continue;
|
|
478
|
-
}
|
|
479
|
-
} catch (error) {
|
|
480
|
-
_this11.logger.warn("Backup: An error occurred while retrieving a rate-limit retry delay", error);
|
|
481
|
-
} // else go to the normal backoff
|
|
482
|
-
}
|
|
434
|
+
} catch (error) {
|
|
435
|
+
this.logger.warn("Backup: An error occurred while retrieving a rate-limit retry delay", error);
|
|
436
|
+
} // else go to the normal backoff
|
|
483
437
|
}
|
|
484
|
-
|
|
485
|
-
// Some other errors (mx, network, or CORS or invalid urls?) anyhow backoff
|
|
486
|
-
// exponential backoff if we have failures
|
|
487
|
-
yield sleep(1000 * Math.pow(2, Math.min(numFailures - 1, 4)));
|
|
488
438
|
}
|
|
489
|
-
|
|
439
|
+
|
|
440
|
+
// Some other errors (mx, network, or CORS or invalid urls?) anyhow backoff
|
|
441
|
+
// exponential backoff if we have failures
|
|
442
|
+
await sleep(1000 * Math.pow(2, Math.min(numFailures - 1, 4)));
|
|
490
443
|
}
|
|
491
|
-
|
|
492
|
-
_this11.backupKeysLoopRunning = false;
|
|
444
|
+
isFirstIteration = false;
|
|
493
445
|
}
|
|
494
|
-
}
|
|
446
|
+
} finally {
|
|
447
|
+
this.backupKeysLoopRunning = false;
|
|
448
|
+
}
|
|
495
449
|
}
|
|
496
450
|
|
|
497
451
|
/**
|
|
@@ -503,7 +457,7 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
503
457
|
* @returns The number of keys in the backup request.
|
|
504
458
|
*/
|
|
505
459
|
keysCountInBatch(batch) {
|
|
506
|
-
|
|
460
|
+
const parsedBody = JSON.parse(batch.body);
|
|
507
461
|
return countKeysInBackup(parsedBody);
|
|
508
462
|
}
|
|
509
463
|
|
|
@@ -515,11 +469,8 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
515
469
|
* @param version - The version of the backup to get information about.
|
|
516
470
|
* @returns Information object from API or null if there is no active backup.
|
|
517
471
|
*/
|
|
518
|
-
requestKeyBackupVersion(version) {
|
|
519
|
-
|
|
520
|
-
return _asyncToGenerator(function* () {
|
|
521
|
-
return yield requestKeyBackupVersion(_this12.http, version);
|
|
522
|
-
})();
|
|
472
|
+
async requestKeyBackupVersion(version) {
|
|
473
|
+
return await requestKeyBackupVersion(this.http, version);
|
|
523
474
|
}
|
|
524
475
|
|
|
525
476
|
/**
|
|
@@ -532,31 +483,28 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
532
483
|
* existing identity.
|
|
533
484
|
* @returns a KeyBackupCreationInfo - All information related to the backup.
|
|
534
485
|
*/
|
|
535
|
-
setupKeyBackup(signObject) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
decryptionKey: randomKey
|
|
558
|
-
};
|
|
559
|
-
})();
|
|
486
|
+
async setupKeyBackup(signObject) {
|
|
487
|
+
// Clean up any existing backup
|
|
488
|
+
await this.deleteAllKeyBackupVersions();
|
|
489
|
+
const randomKey = RustSdkCryptoJs.BackupDecryptionKey.createRandomKey();
|
|
490
|
+
const pubKey = randomKey.megolmV1PublicKey;
|
|
491
|
+
const authData = {
|
|
492
|
+
public_key: pubKey.publicKeyBase64
|
|
493
|
+
};
|
|
494
|
+
await signObject(authData);
|
|
495
|
+
const res = await this.http.authedRequest(Method.Post, "/room_keys/version", undefined, {
|
|
496
|
+
algorithm: pubKey.algorithm,
|
|
497
|
+
auth_data: authData
|
|
498
|
+
}, {
|
|
499
|
+
prefix: ClientPrefix.V3
|
|
500
|
+
});
|
|
501
|
+
await this.saveBackupDecryptionKey(randomKey, res.version);
|
|
502
|
+
return {
|
|
503
|
+
version: res.version,
|
|
504
|
+
algorithm: pubKey.algorithm,
|
|
505
|
+
authData: authData,
|
|
506
|
+
decryptionKey: randomKey
|
|
507
|
+
};
|
|
560
508
|
}
|
|
561
509
|
|
|
562
510
|
/**
|
|
@@ -564,20 +512,15 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
564
512
|
*
|
|
565
513
|
* Will call the API to delete active backup until there is no more present.
|
|
566
514
|
*/
|
|
567
|
-
deleteAllKeyBackupVersions() {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
var _yield$_this14$reques3, _yield$_this14$reques4;
|
|
575
|
-
yield _this14.deleteKeyBackupVersion(current);
|
|
576
|
-
current = (_yield$_this14$reques3 = (_yield$_this14$reques4 = yield _this14.requestKeyBackupVersion()) === null || _yield$_this14$reques4 === void 0 ? void 0 : _yield$_this14$reques4.version) !== null && _yield$_this14$reques3 !== void 0 ? _yield$_this14$reques3 : null;
|
|
577
|
-
}
|
|
515
|
+
async deleteAllKeyBackupVersions() {
|
|
516
|
+
// there could be several backup versions. Delete all to be safe.
|
|
517
|
+
let current = (await this.requestKeyBackupVersion())?.version ?? null;
|
|
518
|
+
while (current != null) {
|
|
519
|
+
await this.deleteKeyBackupVersion(current);
|
|
520
|
+
current = (await this.requestKeyBackupVersion())?.version ?? null;
|
|
521
|
+
}
|
|
578
522
|
|
|
579
|
-
|
|
580
|
-
})();
|
|
523
|
+
// XXX: Should this also update Secret Storage and delete any existing keys?
|
|
581
524
|
}
|
|
582
525
|
|
|
583
526
|
/**
|
|
@@ -585,22 +528,19 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
585
528
|
*
|
|
586
529
|
* @param version - The backup version to delete.
|
|
587
530
|
*/
|
|
588
|
-
deleteKeyBackupVersion(version) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
yield _this15.disableKeyBackup();
|
|
602
|
-
}
|
|
603
|
-
})();
|
|
531
|
+
async deleteKeyBackupVersion(version) {
|
|
532
|
+
this.logger.debug(`deleteKeyBackupVersion v:${version}`);
|
|
533
|
+
const path = encodeUri("/room_keys/version/$version", {
|
|
534
|
+
$version: version
|
|
535
|
+
});
|
|
536
|
+
await this.http.authedRequest(Method.Delete, path, undefined, undefined, {
|
|
537
|
+
prefix: ClientPrefix.V3
|
|
538
|
+
});
|
|
539
|
+
// If the backup we are deleting is the active one, we need to disable the key backup and to have the local properties reset
|
|
540
|
+
if (this.activeBackupVersion === version) {
|
|
541
|
+
this.serverBackupInfo = null;
|
|
542
|
+
await this.disableKeyBackup();
|
|
543
|
+
}
|
|
604
544
|
}
|
|
605
545
|
|
|
606
546
|
/**
|
|
@@ -619,12 +559,9 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
619
559
|
* @param opts - Options for the restore.
|
|
620
560
|
* @returns The total number of keys and the total imported.
|
|
621
561
|
*/
|
|
622
|
-
restoreKeyBackup(backupVersion, backupDecryptor, opts) {
|
|
623
|
-
|
|
624
|
-
return
|
|
625
|
-
var keyBackup = yield _this16.downloadKeyBackup(backupVersion);
|
|
626
|
-
return _this16.importKeyBackup(keyBackup, backupVersion, backupDecryptor, opts);
|
|
627
|
-
})();
|
|
562
|
+
async restoreKeyBackup(backupVersion, backupDecryptor, opts) {
|
|
563
|
+
const keyBackup = await this.downloadKeyBackup(backupVersion);
|
|
564
|
+
return this.importKeyBackup(keyBackup, backupVersion, backupDecryptor, opts);
|
|
628
565
|
}
|
|
629
566
|
|
|
630
567
|
/**
|
|
@@ -632,26 +569,24 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
632
569
|
*
|
|
633
570
|
* @param roomId - The room in question.
|
|
634
571
|
*/
|
|
635
|
-
downloadLatestRoomKeyBackup(roomId) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
sessions
|
|
651
|
-
}
|
|
572
|
+
async downloadLatestRoomKeyBackup(roomId) {
|
|
573
|
+
const {
|
|
574
|
+
backupVersion,
|
|
575
|
+
decryptionKey
|
|
576
|
+
} = await this.olmMachine.getBackupKeys();
|
|
577
|
+
if (!backupVersion || !decryptionKey) {
|
|
578
|
+
this.logger.warn(`downloadLatestRoomKeyBackup: Could not download backup (backupVersion=${backupVersion}, hasDecryptionKey=${!!decryptionKey})`);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
const sessions = await this.downloadRoomKeyBackup(backupVersion, roomId);
|
|
582
|
+
const backupDecryptor = this.createBackupDecryptor(decryptionKey);
|
|
583
|
+
this.importKeyBackup({
|
|
584
|
+
rooms: {
|
|
585
|
+
[roomId]: {
|
|
586
|
+
sessions
|
|
652
587
|
}
|
|
653
|
-
}
|
|
654
|
-
})
|
|
588
|
+
}
|
|
589
|
+
}, backupVersion, backupDecryptor);
|
|
655
590
|
}
|
|
656
591
|
|
|
657
592
|
/**
|
|
@@ -676,7 +611,7 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
676
611
|
* @returns The key backup response.
|
|
677
612
|
*/
|
|
678
613
|
downloadRoomKeyBackup(backupVersion, roomId) {
|
|
679
|
-
|
|
614
|
+
const path = encodeUri("/room_keys/keys/$roomId", {
|
|
680
615
|
$roomId: roomId
|
|
681
616
|
});
|
|
682
617
|
return this.http.authedRequest(Method.Get, path, {
|
|
@@ -699,112 +634,93 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
699
634
|
*
|
|
700
635
|
* @private
|
|
701
636
|
*/
|
|
702
|
-
importKeyBackup(keyBackup, backupVersion, backupDecryptor, opts) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
637
|
+
async importKeyBackup(keyBackup, backupVersion, backupDecryptor, opts) {
|
|
638
|
+
// We have a full backup here, it can get quite big, so we need to decrypt and import it in chunks.
|
|
639
|
+
|
|
640
|
+
const CHUNK_SIZE = 200;
|
|
641
|
+
// Get the total count as a first pass
|
|
642
|
+
const totalKeyCount = countKeysInBackup(keyBackup);
|
|
643
|
+
let totalImported = 0;
|
|
644
|
+
let totalFailures = 0;
|
|
645
|
+
opts?.progressCallback?.({
|
|
646
|
+
total: totalKeyCount,
|
|
647
|
+
successes: totalImported,
|
|
648
|
+
stage: ImportRoomKeyStage.LoadKeys,
|
|
649
|
+
failures: totalFailures
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* This method is called when we have enough chunks to decrypt.
|
|
654
|
+
* It will decrypt the chunks and try to import the room keys.
|
|
655
|
+
* @param roomChunks
|
|
656
|
+
*/
|
|
657
|
+
const handleChunkCallback = async roomChunks => {
|
|
658
|
+
const currentChunk = [];
|
|
659
|
+
for (const roomId of roomChunks.keys()) {
|
|
660
|
+
// Decrypt the sessions for the given room
|
|
661
|
+
const decryptedSessions = await backupDecryptor.decryptSessions(roomChunks.get(roomId));
|
|
662
|
+
// Add the decrypted sessions to the current chunk
|
|
663
|
+
decryptedSessions.forEach(session => {
|
|
664
|
+
// We set the room_id for each session
|
|
665
|
+
session.room_id = roomId;
|
|
666
|
+
currentChunk.push(session);
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// We have a chunk of decrypted keys: import them
|
|
671
|
+
try {
|
|
672
|
+
await this.importBackedUpRoomKeys(currentChunk, backupVersion);
|
|
673
|
+
totalImported += currentChunk.length;
|
|
674
|
+
} catch (e) {
|
|
675
|
+
totalFailures += currentChunk.length;
|
|
676
|
+
// We failed to import some keys, but we should still try to import the rest?
|
|
677
|
+
// Log the error and continue
|
|
678
|
+
this.logger.error("Error importing keys from backup", e);
|
|
679
|
+
}
|
|
680
|
+
opts?.progressCallback?.({
|
|
714
681
|
total: totalKeyCount,
|
|
715
682
|
successes: totalImported,
|
|
716
683
|
stage: ImportRoomKeyStage.LoadKeys,
|
|
717
684
|
failures: totalFailures
|
|
718
685
|
});
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
yield _this18.importBackedUpRoomKeys(currentChunk, backupVersion);
|
|
746
|
-
totalImported += currentChunk.length;
|
|
747
|
-
} catch (e) {
|
|
748
|
-
totalFailures += currentChunk.length;
|
|
749
|
-
// We failed to import some keys, but we should still try to import the rest?
|
|
750
|
-
// Log the error and continue
|
|
751
|
-
_this18.logger.error("Error importing keys from backup", e);
|
|
752
|
-
}
|
|
753
|
-
opts === null || opts === void 0 || (_opts$progressCallbac4 = opts.progressCallback) === null || _opts$progressCallbac4 === void 0 || _opts$progressCallbac4.call(opts, {
|
|
754
|
-
total: totalKeyCount,
|
|
755
|
-
successes: totalImported,
|
|
756
|
-
stage: ImportRoomKeyStage.LoadKeys,
|
|
757
|
-
failures: totalFailures
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
return function handleChunkCallback(_x) {
|
|
761
|
-
return _ref2.apply(this, arguments);
|
|
762
|
-
};
|
|
763
|
-
}();
|
|
764
|
-
var groupChunkCount = 0;
|
|
765
|
-
var chunkGroupByRoom = new Map();
|
|
766
|
-
|
|
767
|
-
// Iterate over the rooms and sessions to group them in chunks
|
|
768
|
-
// And we call the handleChunkCallback when we have enough chunks to decrypt
|
|
769
|
-
for (var _ref5 of Object.entries(keyBackup.rooms)) {
|
|
770
|
-
var _ref4 = _slicedToArray(_ref5, 2);
|
|
771
|
-
var roomId = _ref4[0];
|
|
772
|
-
var roomData = _ref4[1];
|
|
773
|
-
// If there are no sessions for the room, skip it
|
|
774
|
-
if (!roomData.sessions) continue;
|
|
775
|
-
|
|
776
|
-
// Initialize a new chunk group for the current room
|
|
777
|
-
chunkGroupByRoom.set(roomId, {});
|
|
778
|
-
for (var _ref8 of Object.entries(roomData.sessions)) {
|
|
779
|
-
var _ref7 = _slicedToArray(_ref8, 2);
|
|
780
|
-
var sessionId = _ref7[0];
|
|
781
|
-
var session = _ref7[1];
|
|
782
|
-
// We set previously the chunk group for the current room, so we can safely get it
|
|
783
|
-
var sessionsForRoom = chunkGroupByRoom.get(roomId);
|
|
784
|
-
sessionsForRoom[sessionId] = session;
|
|
785
|
-
groupChunkCount += 1;
|
|
786
|
-
// If we have enough chunks to decrypt, call the block callback
|
|
787
|
-
if (groupChunkCount >= CHUNK_SIZE) {
|
|
788
|
-
// We have enough chunks to decrypt
|
|
789
|
-
yield handleChunkCallback(chunkGroupByRoom);
|
|
790
|
-
// Reset the chunk group
|
|
791
|
-
chunkGroupByRoom = new Map();
|
|
792
|
-
// There might be remaining keys for that room, so add back an entry for the current room.
|
|
793
|
-
chunkGroupByRoom.set(roomId, {});
|
|
794
|
-
groupChunkCount = 0;
|
|
795
|
-
}
|
|
686
|
+
};
|
|
687
|
+
let groupChunkCount = 0;
|
|
688
|
+
let chunkGroupByRoom = new Map();
|
|
689
|
+
|
|
690
|
+
// Iterate over the rooms and sessions to group them in chunks
|
|
691
|
+
// And we call the handleChunkCallback when we have enough chunks to decrypt
|
|
692
|
+
for (const [roomId, roomData] of Object.entries(keyBackup.rooms)) {
|
|
693
|
+
// If there are no sessions for the room, skip it
|
|
694
|
+
if (!roomData.sessions) continue;
|
|
695
|
+
|
|
696
|
+
// Initialize a new chunk group for the current room
|
|
697
|
+
chunkGroupByRoom.set(roomId, {});
|
|
698
|
+
for (const [sessionId, session] of Object.entries(roomData.sessions)) {
|
|
699
|
+
// We set previously the chunk group for the current room, so we can safely get it
|
|
700
|
+
const sessionsForRoom = chunkGroupByRoom.get(roomId);
|
|
701
|
+
sessionsForRoom[sessionId] = session;
|
|
702
|
+
groupChunkCount += 1;
|
|
703
|
+
// If we have enough chunks to decrypt, call the block callback
|
|
704
|
+
if (groupChunkCount >= CHUNK_SIZE) {
|
|
705
|
+
// We have enough chunks to decrypt
|
|
706
|
+
await handleChunkCallback(chunkGroupByRoom);
|
|
707
|
+
// Reset the chunk group
|
|
708
|
+
chunkGroupByRoom = new Map();
|
|
709
|
+
// There might be remaining keys for that room, so add back an entry for the current room.
|
|
710
|
+
chunkGroupByRoom.set(roomId, {});
|
|
711
|
+
groupChunkCount = 0;
|
|
796
712
|
}
|
|
797
713
|
}
|
|
714
|
+
}
|
|
798
715
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
})();
|
|
716
|
+
// Handle remaining chunk if needed
|
|
717
|
+
if (groupChunkCount > 0) {
|
|
718
|
+
await handleChunkCallback(chunkGroupByRoom);
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
total: totalKeyCount,
|
|
722
|
+
imported: totalImported
|
|
723
|
+
};
|
|
808
724
|
}
|
|
809
725
|
|
|
810
726
|
/**
|
|
@@ -815,12 +731,11 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
815
731
|
* @returns `true` if the private key can decrypt the backup, `false` otherwise.
|
|
816
732
|
*/
|
|
817
733
|
backupInfoMatchesBackupDecryptionKey(info, backupDecryptionKey) {
|
|
818
|
-
var _info$auth_data;
|
|
819
734
|
if (info.algorithm !== "m.megolm_backup.v1.curve25519-aes-sha2") {
|
|
820
735
|
this.logger.warn("backupMatchesPrivateKey: Unsupported backup algorithm", info.algorithm);
|
|
821
736
|
return false;
|
|
822
737
|
}
|
|
823
|
-
return
|
|
738
|
+
return info.auth_data?.public_key === backupDecryptionKey.megolmV1PublicKey.publicKeyBase64;
|
|
824
739
|
}
|
|
825
740
|
}
|
|
826
741
|
/**
|
|
@@ -828,9 +743,9 @@ export class RustBackupManager extends TypedEventEmitter {
|
|
|
828
743
|
*/
|
|
829
744
|
export class RustBackupDecryptor {
|
|
830
745
|
constructor(logger, decryptionKey) {
|
|
831
|
-
this.logger = logger;
|
|
832
746
|
_defineProperty(this, "decryptionKey", void 0);
|
|
833
747
|
_defineProperty(this, "sourceTrusted", void 0);
|
|
748
|
+
this.logger = logger;
|
|
834
749
|
this.decryptionKey = decryptionKey;
|
|
835
750
|
this.sourceTrusted = false;
|
|
836
751
|
}
|
|
@@ -838,24 +753,18 @@ export class RustBackupDecryptor {
|
|
|
838
753
|
/**
|
|
839
754
|
* Implements {@link BackupDecryptor#decryptSessions}
|
|
840
755
|
*/
|
|
841
|
-
decryptSessions(ciphertexts) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
var decrypted = JSON.parse(_this19.decryptionKey.decryptV1(sessionData.session_data.ephemeral, sessionData.session_data.mac, sessionData.session_data.ciphertext));
|
|
851
|
-
decrypted.session_id = sessionId;
|
|
852
|
-
keys.push(decrypted);
|
|
853
|
-
} catch (e) {
|
|
854
|
-
_this19.logger.debug("Failed to decrypt megolm session from backup", e, sessionData);
|
|
855
|
-
}
|
|
756
|
+
async decryptSessions(ciphertexts) {
|
|
757
|
+
const keys = [];
|
|
758
|
+
for (const [sessionId, sessionData] of Object.entries(ciphertexts)) {
|
|
759
|
+
try {
|
|
760
|
+
const decrypted = JSON.parse(this.decryptionKey.decryptV1(sessionData.session_data.ephemeral, sessionData.session_data.mac, sessionData.session_data.ciphertext));
|
|
761
|
+
decrypted.session_id = sessionId;
|
|
762
|
+
keys.push(decrypted);
|
|
763
|
+
} catch (e) {
|
|
764
|
+
this.logger.debug("Failed to decrypt megolm session from backup", e, sessionData);
|
|
856
765
|
}
|
|
857
|
-
|
|
858
|
-
|
|
766
|
+
}
|
|
767
|
+
return keys;
|
|
859
768
|
}
|
|
860
769
|
|
|
861
770
|
/**
|
|
@@ -879,8 +788,21 @@ export class RustBackupDecryptor {
|
|
|
879
788
|
* @param version - the specific version of the backup info to fetch
|
|
880
789
|
* @returns The key backup info or null if there is no backup.
|
|
881
790
|
*/
|
|
882
|
-
export function requestKeyBackupVersion(
|
|
883
|
-
|
|
791
|
+
export async function requestKeyBackupVersion(http, version) {
|
|
792
|
+
try {
|
|
793
|
+
const path = version ? encodeUri("/room_keys/version/$version", {
|
|
794
|
+
$version: version
|
|
795
|
+
}) : "/room_keys/version";
|
|
796
|
+
return await http.authedRequest(Method.Get, path, undefined, undefined, {
|
|
797
|
+
prefix: ClientPrefix.V3
|
|
798
|
+
});
|
|
799
|
+
} catch (e) {
|
|
800
|
+
if (e.errcode === "M_NOT_FOUND") {
|
|
801
|
+
return null;
|
|
802
|
+
} else {
|
|
803
|
+
throw e;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
884
806
|
}
|
|
885
807
|
|
|
886
808
|
/**
|
|
@@ -890,27 +812,8 @@ export function requestKeyBackupVersion(_x2, _x3) {
|
|
|
890
812
|
* @param keyBackupInfo - The key backup info to check against.
|
|
891
813
|
* @returns `true` if the decryption key matches the key backup info, `false` otherwise.
|
|
892
814
|
*/
|
|
893
|
-
function _requestKeyBackupVersion() {
|
|
894
|
-
_requestKeyBackupVersion = _asyncToGenerator(function* (http, version) {
|
|
895
|
-
try {
|
|
896
|
-
var path = version ? encodeUri("/room_keys/version/$version", {
|
|
897
|
-
$version: version
|
|
898
|
-
}) : "/room_keys/version";
|
|
899
|
-
return yield http.authedRequest(Method.Get, path, undefined, undefined, {
|
|
900
|
-
prefix: ClientPrefix.V3
|
|
901
|
-
});
|
|
902
|
-
} catch (e) {
|
|
903
|
-
if (e.errcode === "M_NOT_FOUND") {
|
|
904
|
-
return null;
|
|
905
|
-
} else {
|
|
906
|
-
throw e;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
});
|
|
910
|
-
return _requestKeyBackupVersion.apply(this, arguments);
|
|
911
|
-
}
|
|
912
815
|
export function decryptionKeyMatchesKeyBackupInfo(decryptionKey, keyBackupInfo) {
|
|
913
|
-
|
|
816
|
+
const authData = keyBackupInfo.auth_data;
|
|
914
817
|
return authData.public_key === decryptionKey.megolmV1PublicKey.publicKeyBase64;
|
|
915
818
|
}
|
|
916
819
|
|
|
@@ -920,9 +823,10 @@ export function decryptionKeyMatchesKeyBackupInfo(decryptionKey, keyBackupInfo)
|
|
|
920
823
|
* @returns The total number of keys in the backup.
|
|
921
824
|
*/
|
|
922
825
|
function countKeysInBackup(keyBackup) {
|
|
923
|
-
|
|
924
|
-
for (
|
|
925
|
-
|
|
826
|
+
let count = 0;
|
|
827
|
+
for (const {
|
|
828
|
+
sessions
|
|
829
|
+
} of Object.values(keyBackup.rooms)) {
|
|
926
830
|
count += Object.keys(sessions).length;
|
|
927
831
|
}
|
|
928
832
|
return count;
|