@jeongsu816/matrix-bot-sdk 0.0.0-stage → 0.8.1
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/LICENSE +21 -0
- package/README.md +50 -2
- package/lib/AdminApis.d.ts +52 -0
- package/lib/AdminApis.js +29 -0
- package/lib/AdminApis.js.map +1 -0
- package/lib/DMs.d.ts +48 -0
- package/lib/DMs.js +160 -0
- package/lib/DMs.js.map +1 -0
- package/lib/IFilter.d.ts +7 -0
- package/lib/IFilter.js +3 -0
- package/lib/IFilter.js.map +1 -0
- package/lib/MatrixAuth.d.ts +45 -0
- package/lib/MatrixAuth.js +125 -0
- package/lib/MatrixAuth.js.map +1 -0
- package/lib/MatrixClient.d.ts +834 -0
- package/lib/MatrixClient.js +2268 -0
- package/lib/MatrixClient.js.map +1 -0
- package/lib/PantalaimonClient.d.ts +42 -0
- package/lib/PantalaimonClient.js +44 -0
- package/lib/PantalaimonClient.js.map +1 -0
- package/lib/SynapseAdminApis.d.ts +350 -0
- package/lib/SynapseAdminApis.js +244 -0
- package/lib/SynapseAdminApis.js.map +1 -0
- package/lib/SynchronousMatrixClient.d.ts +82 -0
- package/lib/SynchronousMatrixClient.js +130 -0
- package/lib/SynchronousMatrixClient.js.map +1 -0
- package/lib/UnstableApis.d.ts +43 -0
- package/lib/UnstableApis.js +74 -0
- package/lib/UnstableApis.js.map +1 -0
- package/lib/appservice/Appservice.d.ts +328 -0
- package/lib/appservice/Appservice.js +803 -0
- package/lib/appservice/Appservice.js.map +1 -0
- package/lib/appservice/Intent.d.ts +113 -0
- package/lib/appservice/Intent.js +363 -0
- package/lib/appservice/Intent.js.map +1 -0
- package/lib/appservice/MatrixBridge.d.ts +85 -0
- package/lib/appservice/MatrixBridge.js +111 -0
- package/lib/appservice/MatrixBridge.js.map +1 -0
- package/lib/appservice/UnstableAppserviceApis.d.ts +41 -0
- package/lib/appservice/UnstableAppserviceApis.js +62 -0
- package/lib/appservice/UnstableAppserviceApis.js.map +1 -0
- package/lib/appservice/http_responses.d.ts +77 -0
- package/lib/appservice/http_responses.js +3 -0
- package/lib/appservice/http_responses.js.map +1 -0
- package/lib/b64.d.ts +42 -0
- package/lib/b64.js +68 -0
- package/lib/b64.js.map +1 -0
- package/lib/e2ee/CrossSigningBootstrap.d.ts +73 -0
- package/lib/e2ee/CrossSigningBootstrap.js +86 -0
- package/lib/e2ee/CrossSigningBootstrap.js.map +1 -0
- package/lib/e2ee/CryptoClient.d.ts +163 -0
- package/lib/e2ee/CryptoClient.js +382 -0
- package/lib/e2ee/CryptoClient.js.map +1 -0
- package/lib/e2ee/ICryptoRoomInformation.d.ts +8 -0
- package/lib/e2ee/ICryptoRoomInformation.js +3 -0
- package/lib/e2ee/ICryptoRoomInformation.js.map +1 -0
- package/lib/e2ee/RoomTracker.d.ts +41 -0
- package/lib/e2ee/RoomTracker.js +96 -0
- package/lib/e2ee/RoomTracker.js.map +1 -0
- package/lib/e2ee/RustEngine.d.ts +149 -0
- package/lib/e2ee/RustEngine.js +467 -0
- package/lib/e2ee/RustEngine.js.map +1 -0
- package/lib/e2ee/decorators.d.ts +10 -0
- package/lib/e2ee/decorators.js +37 -0
- package/lib/e2ee/decorators.js.map +1 -0
- package/lib/helpers/MatrixEntity.d.ts +37 -0
- package/lib/helpers/MatrixEntity.js +67 -0
- package/lib/helpers/MatrixEntity.js.map +1 -0
- package/lib/helpers/MatrixGlob.d.ts +22 -0
- package/lib/helpers/MatrixGlob.js +35 -0
- package/lib/helpers/MatrixGlob.js.map +1 -0
- package/lib/helpers/MentionPill.d.ts +40 -0
- package/lib/helpers/MentionPill.js +91 -0
- package/lib/helpers/MentionPill.js.map +1 -0
- package/lib/helpers/Permalinks.d.ts +58 -0
- package/lib/helpers/Permalinks.js +73 -0
- package/lib/helpers/Permalinks.js.map +1 -0
- package/lib/helpers/ProfileCache.d.ts +48 -0
- package/lib/helpers/ProfileCache.js +114 -0
- package/lib/helpers/ProfileCache.js.map +1 -0
- package/lib/helpers/RichReply.d.ts +17 -0
- package/lib/helpers/RichReply.js +47 -0
- package/lib/helpers/RichReply.js.map +1 -0
- package/lib/helpers/UnpaddedBase64.d.ts +31 -0
- package/lib/helpers/UnpaddedBase64.js +45 -0
- package/lib/helpers/UnpaddedBase64.js.map +1 -0
- package/lib/http.d.ts +17 -0
- package/lib/http.js +147 -0
- package/lib/http.js.map +1 -0
- package/lib/identity/IdentityClient.d.ts +93 -0
- package/lib/identity/IdentityClient.js +248 -0
- package/lib/identity/IdentityClient.js.map +1 -0
- package/lib/index.d.ts +91 -0
- package/lib/index.js +125 -0
- package/lib/index.js.map +1 -0
- package/lib/logging/ConsoleLogger.d.ts +12 -0
- package/lib/logging/ConsoleLogger.js +28 -0
- package/lib/logging/ConsoleLogger.js.map +1 -0
- package/lib/logging/ILogger.d.ts +36 -0
- package/lib/logging/ILogger.js +3 -0
- package/lib/logging/ILogger.js.map +1 -0
- package/lib/logging/LogService.d.ts +100 -0
- package/lib/logging/LogService.js +169 -0
- package/lib/logging/LogService.js.map +1 -0
- package/lib/logging/RichConsoleLogger.d.ts +20 -0
- package/lib/logging/RichConsoleLogger.js +41 -0
- package/lib/logging/RichConsoleLogger.js.map +1 -0
- package/lib/metrics/IMetricListener.d.ts +52 -0
- package/lib/metrics/IMetricListener.js +3 -0
- package/lib/metrics/IMetricListener.js.map +1 -0
- package/lib/metrics/Metrics.d.ts +66 -0
- package/lib/metrics/Metrics.js +128 -0
- package/lib/metrics/Metrics.js.map +1 -0
- package/lib/metrics/contexts.d.ts +51 -0
- package/lib/metrics/contexts.js +3 -0
- package/lib/metrics/contexts.js.map +1 -0
- package/lib/metrics/decorators.d.ts +15 -0
- package/lib/metrics/decorators.js +92 -0
- package/lib/metrics/decorators.js.map +1 -0
- package/lib/metrics/names.d.ts +45 -0
- package/lib/metrics/names.js +49 -0
- package/lib/metrics/names.js.map +1 -0
- package/lib/mixins/AutojoinRoomsMixin.d.ts +10 -0
- package/lib/mixins/AutojoinRoomsMixin.js +25 -0
- package/lib/mixins/AutojoinRoomsMixin.js.map +1 -0
- package/lib/mixins/AutojoinUpgradedRoomsMixin.d.ts +10 -0
- package/lib/mixins/AutojoinUpgradedRoomsMixin.js +40 -0
- package/lib/mixins/AutojoinUpgradedRoomsMixin.js.map +1 -0
- package/lib/models/Account.d.ts +8 -0
- package/lib/models/Account.js +3 -0
- package/lib/models/Account.js.map +1 -0
- package/lib/models/CreateRoom.d.ts +125 -0
- package/lib/models/CreateRoom.js +3 -0
- package/lib/models/CreateRoom.js.map +1 -0
- package/lib/models/Crypto.d.ts +167 -0
- package/lib/models/Crypto.js +31 -0
- package/lib/models/Crypto.js.map +1 -0
- package/lib/models/EventContext.d.ts +19 -0
- package/lib/models/EventContext.js +3 -0
- package/lib/models/EventContext.js.map +1 -0
- package/lib/models/IdentityServerModels.d.ts +20 -0
- package/lib/models/IdentityServerModels.js +3 -0
- package/lib/models/IdentityServerModels.js.map +1 -0
- package/lib/models/MSC2176.d.ts +42 -0
- package/lib/models/MSC2176.js +3 -0
- package/lib/models/MSC2176.js.map +1 -0
- package/lib/models/MatrixError.d.ts +38 -0
- package/lib/models/MatrixError.js +30 -0
- package/lib/models/MatrixError.js.map +1 -0
- package/lib/models/MatrixProfile.d.ts +43 -0
- package/lib/models/MatrixProfile.js +43 -0
- package/lib/models/MatrixProfile.js.map +1 -0
- package/lib/models/OpenIDConnect.d.ts +10 -0
- package/lib/models/OpenIDConnect.js +3 -0
- package/lib/models/OpenIDConnect.js.map +1 -0
- package/lib/models/Policies.d.ts +25 -0
- package/lib/models/Policies.js +3 -0
- package/lib/models/Policies.js.map +1 -0
- package/lib/models/PowerLevelAction.d.ts +27 -0
- package/lib/models/PowerLevelAction.js +32 -0
- package/lib/models/PowerLevelAction.js.map +1 -0
- package/lib/models/PowerLevelBounds.d.ts +15 -0
- package/lib/models/PowerLevelBounds.js +3 -0
- package/lib/models/PowerLevelBounds.js.map +1 -0
- package/lib/models/Presence.d.ts +25 -0
- package/lib/models/Presence.js +38 -0
- package/lib/models/Presence.js.map +1 -0
- package/lib/models/ServerVersions.d.ts +8 -0
- package/lib/models/ServerVersions.js +3 -0
- package/lib/models/ServerVersions.js.map +1 -0
- package/lib/models/Spaces.d.ts +116 -0
- package/lib/models/Spaces.js +91 -0
- package/lib/models/Spaces.js.map +1 -0
- package/lib/models/Threepid.d.ts +8 -0
- package/lib/models/Threepid.js +3 -0
- package/lib/models/Threepid.js.map +1 -0
- package/lib/models/events/AliasesEvent.d.ts +27 -0
- package/lib/models/events/AliasesEvent.js +27 -0
- package/lib/models/events/AliasesEvent.js.map +1 -0
- package/lib/models/events/CanonicalAliasEvent.d.ts +23 -0
- package/lib/models/events/CanonicalAliasEvent.js +21 -0
- package/lib/models/events/CanonicalAliasEvent.js.map +1 -0
- package/lib/models/events/CreateEvent.d.ts +63 -0
- package/lib/models/events/CreateEvent.js +33 -0
- package/lib/models/events/CreateEvent.js.map +1 -0
- package/lib/models/events/EncryptedRoomEvent.d.ts +42 -0
- package/lib/models/events/EncryptedRoomEvent.js +28 -0
- package/lib/models/events/EncryptedRoomEvent.js.map +1 -0
- package/lib/models/events/EncryptionEvent.d.ts +47 -0
- package/lib/models/events/EncryptionEvent.js +42 -0
- package/lib/models/events/EncryptionEvent.js.map +1 -0
- package/lib/models/events/Event.d.ts +26 -0
- package/lib/models/events/Event.js +40 -0
- package/lib/models/events/Event.js.map +1 -0
- package/lib/models/events/EventKind.d.ts +15 -0
- package/lib/models/events/EventKind.js +20 -0
- package/lib/models/events/EventKind.js.map +1 -0
- package/lib/models/events/InvalidEventError.d.ts +14 -0
- package/lib/models/events/InvalidEventError.js +24 -0
- package/lib/models/events/InvalidEventError.js.map +1 -0
- package/lib/models/events/JoinRulesEvent.d.ts +29 -0
- package/lib/models/events/JoinRulesEvent.js +21 -0
- package/lib/models/events/JoinRulesEvent.js.map +1 -0
- package/lib/models/events/MembershipEvent.d.ts +54 -0
- package/lib/models/events/MembershipEvent.js +49 -0
- package/lib/models/events/MembershipEvent.js.map +1 -0
- package/lib/models/events/MessageEvent.d.ts +233 -0
- package/lib/models/events/MessageEvent.js +49 -0
- package/lib/models/events/MessageEvent.js.map +1 -0
- package/lib/models/events/PinnedEventsEvent.d.ts +23 -0
- package/lib/models/events/PinnedEventsEvent.js +21 -0
- package/lib/models/events/PinnedEventsEvent.js.map +1 -0
- package/lib/models/events/PowerLevelsEvent.d.ts +96 -0
- package/lib/models/events/PowerLevelsEvent.js +70 -0
- package/lib/models/events/PowerLevelsEvent.js.map +1 -0
- package/lib/models/events/PresenceEvent.d.ts +56 -0
- package/lib/models/events/PresenceEvent.js +21 -0
- package/lib/models/events/PresenceEvent.js.map +1 -0
- package/lib/models/events/RedactionEvent.d.ts +28 -0
- package/lib/models/events/RedactionEvent.js +36 -0
- package/lib/models/events/RedactionEvent.js.map +1 -0
- package/lib/models/events/RoomAvatarEvent.d.ts +28 -0
- package/lib/models/events/RoomAvatarEvent.js +21 -0
- package/lib/models/events/RoomAvatarEvent.js.map +1 -0
- package/lib/models/events/RoomEvent.d.ts +58 -0
- package/lib/models/events/RoomEvent.js +57 -0
- package/lib/models/events/RoomEvent.js.map +1 -0
- package/lib/models/events/RoomNameEvent.d.ts +20 -0
- package/lib/models/events/RoomNameEvent.js +21 -0
- package/lib/models/events/RoomNameEvent.js.map +1 -0
- package/lib/models/events/RoomTopicEvent.d.ts +20 -0
- package/lib/models/events/RoomTopicEvent.js +21 -0
- package/lib/models/events/RoomTopicEvent.js.map +1 -0
- package/lib/models/events/SpaceChildEvent.d.ts +53 -0
- package/lib/models/events/SpaceChildEvent.js +49 -0
- package/lib/models/events/SpaceChildEvent.js.map +1 -0
- package/lib/models/events/converter.d.ts +8 -0
- package/lib/models/events/converter.js +50 -0
- package/lib/models/events/converter.js.map +1 -0
- package/lib/models/unstable/MediaInfo.d.ts +16 -0
- package/lib/models/unstable/MediaInfo.js +3 -0
- package/lib/models/unstable/MediaInfo.js.map +1 -0
- package/lib/preprocessors/IPreprocessor.d.ts +22 -0
- package/lib/preprocessors/IPreprocessor.js +3 -0
- package/lib/preprocessors/IPreprocessor.js.map +1 -0
- package/lib/preprocessors/RichRepliesPreprocessor.d.ts +67 -0
- package/lib/preprocessors/RichRepliesPreprocessor.js +112 -0
- package/lib/preprocessors/RichRepliesPreprocessor.js.map +1 -0
- package/lib/request.d.ts +13 -0
- package/lib/request.js +23 -0
- package/lib/request.js.map +1 -0
- package/lib/simple-validation.d.ts +10 -0
- package/lib/simple-validation.js +30 -0
- package/lib/simple-validation.js.map +1 -0
- package/lib/storage/IAppserviceStorageProvider.d.ts +48 -0
- package/lib/storage/IAppserviceStorageProvider.js +3 -0
- package/lib/storage/IAppserviceStorageProvider.js.map +1 -0
- package/lib/storage/ICryptoStorageProvider.d.ts +32 -0
- package/lib/storage/ICryptoStorageProvider.js +3 -0
- package/lib/storage/ICryptoStorageProvider.js.map +1 -0
- package/lib/storage/IStorageProvider.d.ts +47 -0
- package/lib/storage/IStorageProvider.js +3 -0
- package/lib/storage/IStorageProvider.js.map +1 -0
- package/lib/storage/MemoryStorageProvider.d.ts +26 -0
- package/lib/storage/MemoryStorageProvider.js +55 -0
- package/lib/storage/MemoryStorageProvider.js.map +1 -0
- package/lib/storage/RustSdkCryptoStorageProvider.d.ts +38 -0
- package/lib/storage/RustSdkCryptoStorageProvider.js +69 -0
- package/lib/storage/RustSdkCryptoStorageProvider.js.map +1 -0
- package/lib/storage/SimpleFsStorageProvider.d.ts +31 -0
- package/lib/storage/SimpleFsStorageProvider.js +122 -0
- package/lib/storage/SimpleFsStorageProvider.js.map +1 -0
- package/lib/storage/SimplePostgresStorageProvider.d.ts +32 -0
- package/lib/storage/SimplePostgresStorageProvider.js +148 -0
- package/lib/storage/SimplePostgresStorageProvider.js.map +1 -0
- package/lib/strategies/AppserviceJoinRoomStrategy.d.ts +14 -0
- package/lib/strategies/AppserviceJoinRoomStrategy.js +54 -0
- package/lib/strategies/AppserviceJoinRoomStrategy.js.map +1 -0
- package/lib/strategies/JoinRoomStrategy.d.ts +11 -0
- package/lib/strategies/JoinRoomStrategy.js +44 -0
- package/lib/strategies/JoinRoomStrategy.js.map +1 -0
- package/package.json +136 -4
- package/src/AdminApis.ts +60 -0
- package/src/DMs.ts +164 -0
- package/src/IFilter.ts +7 -0
- package/src/MatrixAuth.ts +129 -0
- package/src/MatrixClient.ts +2046 -0
- package/src/PantalaimonClient.ts +62 -0
- package/src/SynapseAdminApis.ts +482 -0
- package/src/SynchronousMatrixClient.ts +129 -0
- package/src/UnstableApis.ts +75 -0
- package/src/appservice/Appservice.ts +1089 -0
- package/src/appservice/Intent.ts +342 -0
- package/src/appservice/MatrixBridge.ts +139 -0
- package/src/appservice/UnstableAppserviceApis.ts +63 -0
- package/src/appservice/http_responses.ts +77 -0
- package/src/b64.ts +63 -0
- package/src/e2ee/CrossSigningBootstrap.ts +141 -0
- package/src/e2ee/CryptoClient.ts +378 -0
- package/src/e2ee/ICryptoRoomInformation.ts +9 -0
- package/src/e2ee/RoomTracker.ts +99 -0
- package/src/e2ee/RustEngine.ts +580 -0
- package/src/e2ee/decorators.ts +38 -0
- package/src/helpers/MatrixEntity.ts +65 -0
- package/src/helpers/MatrixGlob.ts +38 -0
- package/src/helpers/MentionPill.ts +95 -0
- package/src/helpers/Permalinks.ts +101 -0
- package/src/helpers/ProfileCache.ts +119 -0
- package/src/helpers/RichReply.ts +46 -0
- package/src/helpers/UnpaddedBase64.ts +44 -0
- package/src/http.ts +166 -0
- package/src/identity/IdentityClient.ts +225 -0
- package/src/index.ts +125 -0
- package/src/logging/ConsoleLogger.ts +31 -0
- package/src/logging/ILogger.ts +40 -0
- package/src/logging/LogService.ts +167 -0
- package/src/logging/RichConsoleLogger.ts +70 -0
- package/src/metrics/IMetricListener.ts +57 -0
- package/src/metrics/Metrics.ts +134 -0
- package/src/metrics/contexts.ts +56 -0
- package/src/metrics/decorators.ts +94 -0
- package/src/metrics/names.ts +53 -0
- package/src/mixins/AutojoinRoomsMixin.ts +24 -0
- package/src/mixins/AutojoinUpgradedRoomsMixin.ts +37 -0
- package/src/models/Account.ts +8 -0
- package/src/models/CreateRoom.ts +144 -0
- package/src/models/Crypto.ts +188 -0
- package/src/models/EventContext.ts +23 -0
- package/src/models/IdentityServerModels.ts +18 -0
- package/src/models/MSC2176.ts +47 -0
- package/src/models/MatrixError.ts +39 -0
- package/src/models/MatrixProfile.ts +55 -0
- package/src/models/OpenIDConnect.ts +10 -0
- package/src/models/Policies.ts +28 -0
- package/src/models/PowerLevelAction.ts +31 -0
- package/src/models/PowerLevelBounds.ts +16 -0
- package/src/models/Presence.ts +38 -0
- package/src/models/ServerVersions.ts +8 -0
- package/src/models/Spaces.ts +167 -0
- package/src/models/Threepid.ts +8 -0
- package/src/models/events/AliasesEvent.ts +37 -0
- package/src/models/events/CanonicalAliasEvent.ts +30 -0
- package/src/models/events/CreateEvent.ts +82 -0
- package/src/models/events/EncryptedRoomEvent.ts +58 -0
- package/src/models/events/EncryptionEvent.ts +63 -0
- package/src/models/events/Event.ts +38 -0
- package/src/models/events/EventKind.ts +16 -0
- package/src/models/events/InvalidEventError.ts +19 -0
- package/src/models/events/JoinRulesEvent.ts +37 -0
- package/src/models/events/MembershipEvent.ts +77 -0
- package/src/models/events/MessageEvent.ts +292 -0
- package/src/models/events/PinnedEventsEvent.ts +30 -0
- package/src/models/events/PowerLevelsEvent.ts +135 -0
- package/src/models/events/PresenceEvent.ts +69 -0
- package/src/models/events/RedactionEvent.ts +44 -0
- package/src/models/events/RoomAvatarEvent.ts +36 -0
- package/src/models/events/RoomEvent.ts +83 -0
- package/src/models/events/RoomNameEvent.ts +27 -0
- package/src/models/events/RoomTopicEvent.ts +27 -0
- package/src/models/events/SpaceChildEvent.ts +74 -0
- package/src/models/events/_MissingEvents.md +35 -0
- package/src/models/events/converter.ts +47 -0
- package/src/models/unstable/MediaInfo.ts +16 -0
- package/src/preprocessors/IPreprocessor.ts +24 -0
- package/src/preprocessors/RichRepliesPreprocessor.ts +159 -0
- package/src/request.ts +21 -0
- package/src/simple-validation.ts +30 -0
- package/src/storage/IAppserviceStorageProvider.ts +54 -0
- package/src/storage/ICryptoStorageProvider.ts +36 -0
- package/src/storage/IStorageProvider.ts +53 -0
- package/src/storage/MemoryStorageProvider.ts +65 -0
- package/src/storage/RustSdkCryptoStorageProvider.ts +81 -0
- package/src/storage/SimpleFsStorageProvider.ts +142 -0
- package/src/storage/SimplePostgresStorageProvider.ts +168 -0
- package/src/strategies/AppserviceJoinRoomStrategy.ts +47 -0
- package/src/strategies/JoinRoomStrategy.ts +45 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { MatrixClient } from "../MatrixClient";
|
|
2
|
+
import { LogService } from "../logging/LogService";
|
|
3
|
+
import { UIACallback } from "./RustEngine";
|
|
4
|
+
|
|
5
|
+
export type { UIACallback };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The subset of RustEngine used by the cross-signing helpers below.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface CrossSigningEngine {
|
|
12
|
+
bootstrapCrossSigning(uiaCallback: UIACallback, reset?: boolean): Promise<void>;
|
|
13
|
+
bootstrapSecretStorageFromPassphrase(passphrase: string, opts?: { withKeyBackup?: boolean, reset?: boolean }): Promise<void>;
|
|
14
|
+
restoreSecretsFromSecretStorage(passphrase: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Result of {@link CryptoClient.ensureCrossSigning}.
|
|
19
|
+
* - `already-signed`: our device was already signed by the account's self-signing key.
|
|
20
|
+
* - `restored`: the cross-signing keys were restored from secret storage (no reset).
|
|
21
|
+
* - `bootstrapped`: a new cross-signing identity was created and uploaded (reset).
|
|
22
|
+
* - `skipped-no-auth`: bootstrapping was needed, but no UIA callback was given.
|
|
23
|
+
* @category Encryption
|
|
24
|
+
*/
|
|
25
|
+
export type EnsureCrossSigningResult = "already-signed" | "restored" | "bootstrapped" | "skipped-no-auth";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Result of {@link CryptoClient.ensureSecretStorage}.
|
|
29
|
+
* @category Encryption
|
|
30
|
+
*/
|
|
31
|
+
export type EnsureSecretStorageResult = "already-configured" | "bootstrapped";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Options for {@link CryptoClient.ensureCrossSigning}.
|
|
35
|
+
* @category Encryption
|
|
36
|
+
*/
|
|
37
|
+
export interface EnsureCrossSigningOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Answers the UIA challenge when uploading new cross-signing keys. Without it,
|
|
40
|
+
* bootstrapping is skipped. See {@link passwordUiaCallback}.
|
|
41
|
+
*/
|
|
42
|
+
uiaCallback?: UIACallback;
|
|
43
|
+
/**
|
|
44
|
+
* Secret storage passphrase. When set and the account has secret storage, the
|
|
45
|
+
* existing cross-signing keys are restored from it before falling back to a reset.
|
|
46
|
+
*/
|
|
47
|
+
recoveryPassphrase?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Builds a UIA callback that answers with an `m.login.password` stage.
|
|
52
|
+
* @category Encryption
|
|
53
|
+
*/
|
|
54
|
+
export function passwordUiaCallback(userId: string, password: string): UIACallback {
|
|
55
|
+
return async (uia) => ({
|
|
56
|
+
type: "m.login.password",
|
|
57
|
+
identifier: { type: "m.id.user", user: userId },
|
|
58
|
+
password,
|
|
59
|
+
session: uia.session,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Checks whether the given device is signed by the account's self-signing key.
|
|
65
|
+
*
|
|
66
|
+
* This deliberately checks our device, not just whether the account has a master
|
|
67
|
+
* key: another client may have set up cross-signing without ever signing us.
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
export async function isOwnDeviceCrossSigned(client: MatrixClient, deviceId: string): Promise<boolean> {
|
|
71
|
+
const userId = await client.getUserId();
|
|
72
|
+
const resp = await client.doRequest("POST", "/_matrix/client/v3/keys/query", null, {
|
|
73
|
+
device_keys: { [userId]: [] },
|
|
74
|
+
});
|
|
75
|
+
const selfSigningKeyIds = Object.keys(resp?.["self_signing_keys"]?.[userId]?.["keys"] ?? {});
|
|
76
|
+
const deviceSignatures = resp?.["device_keys"]?.[userId]?.[deviceId]?.["signatures"]?.[userId] ?? {};
|
|
77
|
+
return selfSigningKeyIds.some((keyId) => keyId in deviceSignatures);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Checks whether the account has a default secret storage key configured.
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export async function hasSecretStorage(client: MatrixClient): Promise<boolean> {
|
|
85
|
+
try {
|
|
86
|
+
const data = await client.getAccountData<{ key?: string }>("m.secret_storage.default_key");
|
|
87
|
+
return Boolean(data?.key);
|
|
88
|
+
} catch {
|
|
89
|
+
// getAccountData throws (404) when the event doesn't exist.
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
export async function ensureCrossSigning(
|
|
98
|
+
client: MatrixClient,
|
|
99
|
+
engine: CrossSigningEngine,
|
|
100
|
+
deviceId: string,
|
|
101
|
+
opts: EnsureCrossSigningOptions,
|
|
102
|
+
): Promise<EnsureCrossSigningResult> {
|
|
103
|
+
if (await isOwnDeviceCrossSigned(client, deviceId)) {
|
|
104
|
+
return "already-signed";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (opts.recoveryPassphrase && await hasSecretStorage(client)) {
|
|
108
|
+
try {
|
|
109
|
+
await engine.restoreSecretsFromSecretStorage(opts.recoveryPassphrase);
|
|
110
|
+
return "restored";
|
|
111
|
+
} catch (e) {
|
|
112
|
+
LogService.warn("CryptoClient", "Restoring cross-signing keys from secret storage failed, falling back to a reset:", e);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!opts.uiaCallback) {
|
|
117
|
+
return "skipped-no-auth";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Neither signed nor restorable: create a fresh identity. This replaces any
|
|
121
|
+
// existing cross-signing keys on the account, so other devices' trust in the
|
|
122
|
+
// old identity is lost.
|
|
123
|
+
await engine.bootstrapCrossSigning(opts.uiaCallback, true);
|
|
124
|
+
return "bootstrapped";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
export async function ensureSecretStorage(
|
|
131
|
+
client: MatrixClient,
|
|
132
|
+
engine: CrossSigningEngine,
|
|
133
|
+
passphrase: string,
|
|
134
|
+
opts: { withKeyBackup?: boolean },
|
|
135
|
+
): Promise<EnsureSecretStorageResult> {
|
|
136
|
+
if (await hasSecretStorage(client)) {
|
|
137
|
+
return "already-configured";
|
|
138
|
+
}
|
|
139
|
+
await engine.bootstrapSecretStorageFromPassphrase(passphrase, { withKeyBackup: opts.withKeyBackup ?? true });
|
|
140
|
+
return "bootstrapped";
|
|
141
|
+
}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeviceId,
|
|
3
|
+
OlmMachine,
|
|
4
|
+
UserId,
|
|
5
|
+
DeviceLists,
|
|
6
|
+
RoomId,
|
|
7
|
+
Attachment,
|
|
8
|
+
EncryptedAttachment,
|
|
9
|
+
} from "@matrix-org/matrix-sdk-crypto-nodejs";
|
|
10
|
+
|
|
11
|
+
import { MatrixClient } from "../MatrixClient";
|
|
12
|
+
import { LogService } from "../logging/LogService";
|
|
13
|
+
import {
|
|
14
|
+
IMegolmEncrypted,
|
|
15
|
+
IOlmEncrypted,
|
|
16
|
+
IToDeviceMessage,
|
|
17
|
+
OTKAlgorithm,
|
|
18
|
+
OTKCounts,
|
|
19
|
+
Signatures,
|
|
20
|
+
} from "../models/Crypto";
|
|
21
|
+
import { requiresReady } from "./decorators";
|
|
22
|
+
import { RoomTracker } from "./RoomTracker";
|
|
23
|
+
import { EncryptedRoomEvent } from "../models/events/EncryptedRoomEvent";
|
|
24
|
+
import { RoomEvent } from "../models/events/RoomEvent";
|
|
25
|
+
import { EncryptedFile } from "../models/events/MessageEvent";
|
|
26
|
+
import { RustSdkCryptoStorageProvider } from "../storage/RustSdkCryptoStorageProvider";
|
|
27
|
+
import { RustEngine, SYNC_LOCK_NAME, UIACallback } from "./RustEngine";
|
|
28
|
+
import {
|
|
29
|
+
ensureCrossSigning,
|
|
30
|
+
EnsureCrossSigningOptions,
|
|
31
|
+
EnsureCrossSigningResult,
|
|
32
|
+
ensureSecretStorage,
|
|
33
|
+
EnsureSecretStorageResult,
|
|
34
|
+
hasSecretStorage,
|
|
35
|
+
isOwnDeviceCrossSigned,
|
|
36
|
+
} from "./CrossSigningBootstrap";
|
|
37
|
+
import { MembershipEvent } from "../models/events/MembershipEvent";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Manages encryption for a MatrixClient. Get an instance from a MatrixClient directly
|
|
41
|
+
* rather than creating one manually.
|
|
42
|
+
* @category Encryption
|
|
43
|
+
*/
|
|
44
|
+
export class CryptoClient {
|
|
45
|
+
private ready = false;
|
|
46
|
+
private deviceId: string;
|
|
47
|
+
private deviceEd25519: string;
|
|
48
|
+
private deviceCurve25519: string;
|
|
49
|
+
private roomTracker: RoomTracker;
|
|
50
|
+
private engine: RustEngine;
|
|
51
|
+
|
|
52
|
+
public constructor(private client: MatrixClient) {
|
|
53
|
+
this.roomTracker = new RoomTracker(this.client);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private get storage(): RustSdkCryptoStorageProvider {
|
|
57
|
+
return <RustSdkCryptoStorageProvider> this.client.cryptoStore;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The device ID for the MatrixClient.
|
|
62
|
+
*/
|
|
63
|
+
public get clientDeviceId(): string {
|
|
64
|
+
return this.deviceId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The device's Ed25519 identity
|
|
69
|
+
*/
|
|
70
|
+
public get clientDeviceEd25519(): string {
|
|
71
|
+
return this.deviceEd25519;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether or not the crypto client is ready to be used. If not ready, prepare() should be called.
|
|
76
|
+
* @see prepare
|
|
77
|
+
*/
|
|
78
|
+
public get isReady(): boolean {
|
|
79
|
+
return this.ready;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Prepares the crypto client for usage.
|
|
84
|
+
* @param {string[]} roomIds The room IDs the MatrixClient is joined to.
|
|
85
|
+
*/
|
|
86
|
+
public async prepare(roomIds: string[]) {
|
|
87
|
+
await this.roomTracker.prepare(roomIds);
|
|
88
|
+
|
|
89
|
+
if (this.ready) return; // stop re-preparing here
|
|
90
|
+
|
|
91
|
+
const storedDeviceId = await this.client.cryptoStore.getDeviceId();
|
|
92
|
+
if (storedDeviceId) {
|
|
93
|
+
this.deviceId = storedDeviceId;
|
|
94
|
+
} else {
|
|
95
|
+
const deviceId = (await this.client.getWhoAmI())['device_id'];
|
|
96
|
+
if (!deviceId) {
|
|
97
|
+
throw new Error("Encryption not possible: server not revealing device ID");
|
|
98
|
+
}
|
|
99
|
+
this.deviceId = deviceId;
|
|
100
|
+
await this.client.cryptoStore.setDeviceId(this.deviceId);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
LogService.info("CryptoClient", "Starting with device ID:", this.deviceId); // info so all bots know for debugging
|
|
104
|
+
|
|
105
|
+
const machine = await OlmMachine.initialize(
|
|
106
|
+
new UserId(await this.client.getUserId()),
|
|
107
|
+
new DeviceId(this.deviceId),
|
|
108
|
+
this.storage.storagePath, "",
|
|
109
|
+
this.storage.storageType,
|
|
110
|
+
);
|
|
111
|
+
this.engine = new RustEngine(machine, this.client);
|
|
112
|
+
await this.engine.run();
|
|
113
|
+
|
|
114
|
+
const identity = this.engine.machine.identityKeys;
|
|
115
|
+
this.deviceCurve25519 = identity.curve25519.toBase64();
|
|
116
|
+
this.deviceEd25519 = identity.ed25519.toBase64();
|
|
117
|
+
|
|
118
|
+
LogService.debug("CryptoClient", "Running with device Ed25519 identity:", this.deviceEd25519); // info so all bots know for debugging
|
|
119
|
+
|
|
120
|
+
this.ready = true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles a room event.
|
|
125
|
+
* @internal
|
|
126
|
+
* @param roomId The room ID.
|
|
127
|
+
* @param event The event.
|
|
128
|
+
*/
|
|
129
|
+
public async onRoomEvent(roomId: string, event: any) {
|
|
130
|
+
await this.roomTracker.onRoomEvent(roomId, event);
|
|
131
|
+
if (typeof event['state_key'] !== 'string') return;
|
|
132
|
+
if (event['type'] === 'm.room.member') {
|
|
133
|
+
const membership = new MembershipEvent(event);
|
|
134
|
+
if (membership.effectiveMembership !== 'join' && membership.effectiveMembership !== 'invite') return;
|
|
135
|
+
await this.engine.addTrackedUsers([membership.membershipFor]);
|
|
136
|
+
} else if (event['type'] === 'm.room.encryption') {
|
|
137
|
+
const members = await this.client.getRoomMembers(roomId, null, ['join', 'invite']);
|
|
138
|
+
await this.engine.addTrackedUsers(members.map(e => e.membershipFor));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Handles a room join.
|
|
144
|
+
* @internal
|
|
145
|
+
* @param roomId The room ID.
|
|
146
|
+
*/
|
|
147
|
+
public async onRoomJoin(roomId: string) {
|
|
148
|
+
await this.roomTracker.onRoomJoin(roomId);
|
|
149
|
+
if (await this.isRoomEncrypted(roomId)) {
|
|
150
|
+
const members = await this.client.getRoomMembers(roomId, null, ['join', 'invite']);
|
|
151
|
+
await this.engine.addTrackedUsers(members.map(e => e.membershipFor));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Checks if a room is encrypted.
|
|
157
|
+
* @param {string} roomId The room ID to check.
|
|
158
|
+
* @returns {Promise<boolean>} Resolves to true if encrypted, false otherwise.
|
|
159
|
+
*/
|
|
160
|
+
@requiresReady()
|
|
161
|
+
public async isRoomEncrypted(roomId: string): Promise<boolean> {
|
|
162
|
+
const config = await this.roomTracker.getRoomCryptoConfig(roomId);
|
|
163
|
+
return !!config?.algorithm;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Updates the client's sync-related data.
|
|
168
|
+
* @param {Array.<IToDeviceMessage<IOlmEncrypted>>} toDeviceMessages The to-device messages received.
|
|
169
|
+
* @param {OTKCounts} otkCounts The current OTK counts.
|
|
170
|
+
* @param {OTKAlgorithm[]} unusedFallbackKeyAlgs The unused fallback key algorithms.
|
|
171
|
+
* @param {string[]} changedDeviceLists The user IDs which had device list changes.
|
|
172
|
+
* @param {string[]} leftDeviceLists The user IDs which the server believes we no longer need to track.
|
|
173
|
+
* @returns {Promise<void>} Resolves when complete.
|
|
174
|
+
*/
|
|
175
|
+
@requiresReady()
|
|
176
|
+
public async updateSyncData(
|
|
177
|
+
toDeviceMessages: IToDeviceMessage<IOlmEncrypted>[],
|
|
178
|
+
otkCounts: OTKCounts,
|
|
179
|
+
unusedFallbackKeyAlgs: OTKAlgorithm[],
|
|
180
|
+
changedDeviceLists: string[],
|
|
181
|
+
leftDeviceLists: string[],
|
|
182
|
+
): Promise<void> {
|
|
183
|
+
const deviceMessages = JSON.stringify(toDeviceMessages);
|
|
184
|
+
const deviceLists = new DeviceLists(
|
|
185
|
+
changedDeviceLists.map(u => new UserId(u)),
|
|
186
|
+
leftDeviceLists.map(u => new UserId(u)));
|
|
187
|
+
|
|
188
|
+
await this.engine.lock.acquire(SYNC_LOCK_NAME, async () => {
|
|
189
|
+
const syncResp = await this.engine.machine.receiveSyncChanges(deviceMessages, deviceLists, otkCounts, unusedFallbackKeyAlgs);
|
|
190
|
+
const decryptedToDeviceMessages = JSON.parse(syncResp);
|
|
191
|
+
if (Array.isArray(decryptedToDeviceMessages)) {
|
|
192
|
+
for (const msg of decryptedToDeviceMessages) {
|
|
193
|
+
this.client.emit("to_device.decrypted", msg);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
await this.engine.run();
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Signs an object using the device keys.
|
|
203
|
+
* @param {object} obj The object to sign.
|
|
204
|
+
* @returns {Promise<Signatures>} The signatures for the object.
|
|
205
|
+
*/
|
|
206
|
+
@requiresReady()
|
|
207
|
+
public async sign(obj: object): Promise<Signatures> {
|
|
208
|
+
obj = JSON.parse(JSON.stringify(obj));
|
|
209
|
+
const existingSignatures = obj['signatures'] || {};
|
|
210
|
+
|
|
211
|
+
delete obj['signatures'];
|
|
212
|
+
delete obj['unsigned'];
|
|
213
|
+
|
|
214
|
+
const container = await this.engine.machine.sign(JSON.stringify(obj));
|
|
215
|
+
const userSignature = container.get(new UserId(await this.client.getUserId()));
|
|
216
|
+
const sig: Signatures = {
|
|
217
|
+
[await this.client.getUserId()]: {},
|
|
218
|
+
};
|
|
219
|
+
for (const [key, maybeSignature] of Object.entries(userSignature)) {
|
|
220
|
+
if (maybeSignature.isValid) {
|
|
221
|
+
sig[await this.client.getUserId()][key] = maybeSignature.signature.toBase64();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
...sig,
|
|
226
|
+
...existingSignatures,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Encrypts the details of a room event, returning an encrypted payload to be sent in an
|
|
232
|
+
* `m.room.encrypted` event to the room. If needed, this function will send decryption keys
|
|
233
|
+
* to the appropriate devices in the room (this happens when the Megolm session rotates or
|
|
234
|
+
* gets created).
|
|
235
|
+
* @param {string} roomId The room ID to encrypt within. If the room is not encrypted, an
|
|
236
|
+
* error is thrown.
|
|
237
|
+
* @param {string} eventType The event type being encrypted.
|
|
238
|
+
* @param {any} content The event content being encrypted.
|
|
239
|
+
* @returns {Promise<IMegolmEncrypted>} Resolves to the encrypted content for an `m.room.encrypted` event.
|
|
240
|
+
*/
|
|
241
|
+
@requiresReady()
|
|
242
|
+
public async encryptRoomEvent(roomId: string, eventType: string, content: any): Promise<IMegolmEncrypted> {
|
|
243
|
+
if (!(await this.isRoomEncrypted(roomId))) {
|
|
244
|
+
throw new Error("Room is not encrypted");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
await this.engine.prepareEncrypt(roomId, await this.roomTracker.getRoomCryptoConfig(roomId));
|
|
248
|
+
|
|
249
|
+
const encrypted = JSON.parse(await this.engine.machine.encryptRoomEvent(new RoomId(roomId), eventType, JSON.stringify(content)));
|
|
250
|
+
await this.engine.run();
|
|
251
|
+
return encrypted as IMegolmEncrypted;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Decrypts a room event. Currently only supports Megolm-encrypted events (default for this SDK).
|
|
256
|
+
* @param {EncryptedRoomEvent} event The encrypted event.
|
|
257
|
+
* @param {string} roomId The room ID where the event was sent.
|
|
258
|
+
* @returns {Promise<RoomEvent<unknown>>} Resolves to a decrypted room event, or rejects/throws with
|
|
259
|
+
* an error if the event is undecryptable.
|
|
260
|
+
*/
|
|
261
|
+
@requiresReady()
|
|
262
|
+
public async decryptRoomEvent(event: EncryptedRoomEvent, roomId: string): Promise<RoomEvent<unknown>> {
|
|
263
|
+
const decrypted = await this.engine.machine.decryptRoomEvent(JSON.stringify(event.raw), new RoomId(roomId));
|
|
264
|
+
const clearEvent = JSON.parse(decrypted.event);
|
|
265
|
+
|
|
266
|
+
return new RoomEvent<unknown>({
|
|
267
|
+
...event.raw,
|
|
268
|
+
type: clearEvent.type || "io.t2bot.unknown",
|
|
269
|
+
content: (typeof (clearEvent.content) === 'object') ? clearEvent.content : {},
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Encrypts a file for uploading in a room, returning the encrypted data and information
|
|
275
|
+
* to include in a message event (except media URL) for sending.
|
|
276
|
+
* @param {Buffer} file The file to encrypt.
|
|
277
|
+
* @returns {{buffer: Buffer, file: Omit<EncryptedFile, "url">}} Resolves to the encrypted
|
|
278
|
+
* contents and file information.
|
|
279
|
+
*/
|
|
280
|
+
@requiresReady()
|
|
281
|
+
public async encryptMedia(file: Buffer): Promise<{ buffer: Buffer, file: Omit<EncryptedFile, "url"> }> {
|
|
282
|
+
const encrypted = Attachment.encrypt(file);
|
|
283
|
+
const info = JSON.parse(encrypted.mediaEncryptionInfo);
|
|
284
|
+
return {
|
|
285
|
+
buffer: Buffer.from(encrypted.encryptedData),
|
|
286
|
+
file: info,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Decrypts a previously-uploaded encrypted file, validating the fields along the way.
|
|
292
|
+
* @param {EncryptedFile} file The file to decrypt.
|
|
293
|
+
* @returns {Promise<Buffer>} Resolves to the decrypted file contents.
|
|
294
|
+
*/
|
|
295
|
+
@requiresReady()
|
|
296
|
+
public async decryptMedia(file: EncryptedFile): Promise<Buffer> {
|
|
297
|
+
const contents = (await this.client.downloadContent(file.url)).data;
|
|
298
|
+
const encrypted = new EncryptedAttachment(
|
|
299
|
+
contents,
|
|
300
|
+
JSON.stringify(file),
|
|
301
|
+
);
|
|
302
|
+
const decrypted = Attachment.decrypt(encrypted);
|
|
303
|
+
return Buffer.from(decrypted);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Creates and uploads a cross-signing identity, then signs this device with it.
|
|
308
|
+
* @param {UIACallback} uiaCallback Answers the UIA challenge for the key upload.
|
|
309
|
+
* @param {boolean} reset Whether to replace an existing local identity.
|
|
310
|
+
*/
|
|
311
|
+
@requiresReady()
|
|
312
|
+
public async bootstrapCrossSigning(uiaCallback: UIACallback, reset = false): Promise<void> {
|
|
313
|
+
return this.engine.bootstrapCrossSigning(uiaCallback, reset);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Sets up secret storage (4S) from a passphrase and stores the cross-signing
|
|
318
|
+
* keys in it. Requires the cross-signing private keys to be available locally.
|
|
319
|
+
* @param {string} passphrase The secret storage passphrase.
|
|
320
|
+
* @param opts Whether to also set up server-side key backup, and whether to reset.
|
|
321
|
+
*/
|
|
322
|
+
@requiresReady()
|
|
323
|
+
public async bootstrapSecretStorageFromPassphrase(passphrase: string, opts: { withKeyBackup?: boolean, reset?: boolean } = {}): Promise<void> {
|
|
324
|
+
return this.engine.bootstrapSecretStorageFromPassphrase(passphrase, opts);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Restores the cross-signing keys from secret storage, e.g. after losing the
|
|
329
|
+
* crypto store, without invalidating other devices' trust.
|
|
330
|
+
* @param {string} passphrase The secret storage passphrase.
|
|
331
|
+
*/
|
|
332
|
+
@requiresReady()
|
|
333
|
+
public async restoreSecretsFromSecretStorage(passphrase: string): Promise<void> {
|
|
334
|
+
return this.engine.restoreSecretsFromSecretStorage(passphrase);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Whether this device is signed by the account's self-signing key.
|
|
339
|
+
*/
|
|
340
|
+
@requiresReady()
|
|
341
|
+
public async isOwnDeviceCrossSigned(): Promise<boolean> {
|
|
342
|
+
return isOwnDeviceCrossSigned(this.client, this.deviceId);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Whether the account has a default secret storage key.
|
|
347
|
+
*/
|
|
348
|
+
@requiresReady()
|
|
349
|
+
public async hasSecretStorage(): Promise<boolean> {
|
|
350
|
+
return hasSecretStorage(this.client);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Makes sure this device is cross-signed. In order: does nothing if it already
|
|
355
|
+
* is; restores the keys from secret storage if a passphrase is given and the
|
|
356
|
+
* account has secret storage; otherwise creates a new identity (replacing the
|
|
357
|
+
* account's existing one) if a UIA callback is given. Errors are thrown.
|
|
358
|
+
* @param {EnsureCrossSigningOptions} opts Credentials for restoring or bootstrapping.
|
|
359
|
+
* @returns {Promise<EnsureCrossSigningResult>} What was done.
|
|
360
|
+
*/
|
|
361
|
+
@requiresReady()
|
|
362
|
+
public async ensureCrossSigning(opts: EnsureCrossSigningOptions = {}): Promise<EnsureCrossSigningResult> {
|
|
363
|
+
return ensureCrossSigning(this.client, this.engine, this.deviceId, opts);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Sets up secret storage from a passphrase unless the account already has it.
|
|
368
|
+
* Call after {@link ensureCrossSigning}, since the cross-signing private keys
|
|
369
|
+
* must be available locally to be stored.
|
|
370
|
+
* @param {string} passphrase The secret storage passphrase.
|
|
371
|
+
* @param opts Whether to also set up server-side key backup (default true).
|
|
372
|
+
* @returns {Promise<EnsureSecretStorageResult>} What was done.
|
|
373
|
+
*/
|
|
374
|
+
@requiresReady()
|
|
375
|
+
public async ensureSecretStorage(passphrase: string, opts: { withKeyBackup?: boolean } = {}): Promise<EnsureSecretStorageResult> {
|
|
376
|
+
return ensureSecretStorage(this.client, this.engine, passphrase, opts);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EncryptionEventContent } from "../models/events/EncryptionEvent";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Information about a room for the purposes of crypto.
|
|
5
|
+
* @category Encryption
|
|
6
|
+
*/
|
|
7
|
+
export interface ICryptoRoomInformation extends Partial<EncryptionEventContent> {
|
|
8
|
+
historyVisibility?: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { MatrixClient } from "../MatrixClient";
|
|
2
|
+
import { EncryptionEventContent } from "../models/events/EncryptionEvent";
|
|
3
|
+
import { ICryptoRoomInformation } from "./ICryptoRoomInformation";
|
|
4
|
+
|
|
5
|
+
// noinspection ES6RedundantAwait
|
|
6
|
+
/**
|
|
7
|
+
* Tracks room encryption status for a MatrixClient.
|
|
8
|
+
* @category Encryption
|
|
9
|
+
*/
|
|
10
|
+
export class RoomTracker {
|
|
11
|
+
public constructor(private client: MatrixClient) {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handles a room join
|
|
16
|
+
* @internal
|
|
17
|
+
* @param roomId The room ID.
|
|
18
|
+
*/
|
|
19
|
+
public async onRoomJoin(roomId: string) {
|
|
20
|
+
await this.queueRoomCheck(roomId);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handles a room event.
|
|
25
|
+
* @internal
|
|
26
|
+
* @param roomId The room ID.
|
|
27
|
+
* @param event The event.
|
|
28
|
+
*/
|
|
29
|
+
public async onRoomEvent(roomId: string, event: any) {
|
|
30
|
+
if (event['state_key'] !== '') return; // we don't care about anything else
|
|
31
|
+
if (event['type'] === 'm.room.encryption' || event['type'] === 'm.room.history_visibility') {
|
|
32
|
+
await this.queueRoomCheck(roomId);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Prepares the room tracker to track the given rooms.
|
|
38
|
+
* @param {string[]} roomIds The room IDs to track. This should be the joined rooms set.
|
|
39
|
+
*/
|
|
40
|
+
public async prepare(roomIds: string[]) {
|
|
41
|
+
for (const roomId of roomIds) {
|
|
42
|
+
await this.queueRoomCheck(roomId);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Queues a room check for the tracker. If the room needs an update to the store, an
|
|
48
|
+
* update will be made.
|
|
49
|
+
* @param {string} roomId The room ID to check.
|
|
50
|
+
*/
|
|
51
|
+
public async queueRoomCheck(roomId: string) {
|
|
52
|
+
const config = await this.client.cryptoStore.getRoom(roomId);
|
|
53
|
+
if (config) {
|
|
54
|
+
if (config.algorithm !== undefined) {
|
|
55
|
+
return; // assume no change to encryption config
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let encEvent: Partial<EncryptionEventContent>;
|
|
60
|
+
try {
|
|
61
|
+
encEvent = await this.client.getRoomStateEvent(roomId, "m.room.encryption", "");
|
|
62
|
+
encEvent.algorithm = encEvent.algorithm ?? 'UNKNOWN';
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return; // failure == no encryption
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Pick out the history visibility setting too
|
|
68
|
+
let historyVisibility: string;
|
|
69
|
+
try {
|
|
70
|
+
const ev = await this.client.getRoomStateEvent(roomId, "m.room.history_visibility", "");
|
|
71
|
+
historyVisibility = ev.history_visibility;
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// ignore - we'll just treat history visibility as normal
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await this.client.cryptoStore.storeRoom(roomId, {
|
|
77
|
+
...encEvent,
|
|
78
|
+
historyVisibility,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets the room's crypto configuration, as known by the underlying store. If the room is
|
|
84
|
+
* not encrypted then this will return an empty object.
|
|
85
|
+
* @param {string} roomId The room ID to get the config for.
|
|
86
|
+
* @returns {Promise<ICryptoRoomInformation>} Resolves to the encryption config.
|
|
87
|
+
*/
|
|
88
|
+
public async getRoomCryptoConfig(roomId: string): Promise<ICryptoRoomInformation> {
|
|
89
|
+
let config = await this.client.cryptoStore.getRoom(roomId);
|
|
90
|
+
if (!config) {
|
|
91
|
+
await this.queueRoomCheck(roomId);
|
|
92
|
+
config = await this.client.cryptoStore.getRoom(roomId);
|
|
93
|
+
}
|
|
94
|
+
if (!config) {
|
|
95
|
+
return {};
|
|
96
|
+
}
|
|
97
|
+
return config;
|
|
98
|
+
}
|
|
99
|
+
}
|