@kodelyth/matrix 2026.5.39 → 2026.5.42

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.
Files changed (321) hide show
  1. package/CHANGELOG.md +321 -0
  2. package/SPEC-SUPPORT.md +116 -0
  3. package/api.ts +38 -0
  4. package/auth-presence.ts +56 -0
  5. package/channel-plugin-api.ts +3 -0
  6. package/cli-metadata.ts +11 -0
  7. package/contract-api.ts +17 -0
  8. package/dist/account-selection-Y50DNJ2l.js +158 -0
  9. package/dist/active-client-CmFdvPdO.js +20 -0
  10. package/dist/api.js +12 -0
  11. package/dist/approval-handler.runtime-BIi4fL0R.js +377 -0
  12. package/dist/approval-ids-BGHK7PnZ.js +7 -0
  13. package/dist/approval-reaction-auth-CL0-nCNV.js +27 -0
  14. package/dist/approval-reactions-nDm2x-K5.js +162 -0
  15. package/dist/async-lock-SsmtFXtt.js +19 -0
  16. package/dist/auth-presence.js +26 -0
  17. package/dist/backup-health-3BHbHxyd.js +60 -0
  18. package/dist/channel-C0kCyTNB.js +1380 -0
  19. package/dist/channel-plugin-api.js +2 -0
  20. package/dist/channel.runtime-CdrdEN-0.js +250 -0
  21. package/dist/cli-FtY6Nuzw.js +1338 -0
  22. package/dist/cli-metadata-Dkwua7CB.js +22 -0
  23. package/dist/cli-metadata.js +2 -0
  24. package/dist/client-BnohYygh.js +25 -0
  25. package/dist/client-PhrTwuC4.js +30 -0
  26. package/dist/client-bootstrap-Mcj8ChJ5.js +114 -0
  27. package/dist/config-paths-DVvt6vM3.js +114 -0
  28. package/dist/config-schema-BMGOlhdI.js +308 -0
  29. package/dist/config-secret-input.runtime-Dv_4Br_f.js +2 -0
  30. package/dist/contract-api.js +8 -0
  31. package/dist/create-client-J0htTaRj.js +64 -0
  32. package/dist/credentials-B7GsBbgQ.js +56 -0
  33. package/dist/credentials-read-8fE4qoWs.js +112 -0
  34. package/dist/credentials-write.runtime-BibplB4Y.js +17 -0
  35. package/dist/crypto-node.runtime-D9qxgRPa.js +12 -0
  36. package/dist/crypto-runtime-1pKW4O2F.js +1214 -0
  37. package/dist/deps-DVpDS81G.js +208 -0
  38. package/dist/device-health-Ct2wDSPG.js +16 -0
  39. package/dist/directory-live-i3T8uORc.js +150 -0
  40. package/dist/doctor-contract-BLzYHl_9.js +246 -0
  41. package/dist/doctor-contract-api.js +2 -0
  42. package/dist/doctor-diR5gE7D.js +153 -0
  43. package/dist/draft-stream-HpPJ_VJt.js +143 -0
  44. package/dist/encryption-guidance-BNEgckrZ.js +15 -0
  45. package/dist/env-auth-UFiTGkDM.js +63 -0
  46. package/dist/env-vars-EQKQv-FE.js +63 -0
  47. package/dist/errors-BETj3zr9.js +17 -0
  48. package/dist/exec-approval-resolver-BxPorU_t.js +15 -0
  49. package/dist/helper-api.js +4 -0
  50. package/dist/http-client-DoQgbQsU.js +331 -0
  51. package/dist/index.js +46 -0
  52. package/dist/legacy-crypto-inspector-zK0hDCbt.js +41 -0
  53. package/dist/legacy-crypto-restore-DSFIXuDo.js +85 -0
  54. package/dist/logging-Df7aPD1z.js +99 -0
  55. package/dist/matrix-migration.runtime-BNoT1Prt.js +525 -0
  56. package/dist/media-text-ZhGA8Pcs.js +146 -0
  57. package/dist/messages-CRA9WGg0.js +140 -0
  58. package/dist/migration-snapshot-backup-BR-xD7Ew.js +69 -0
  59. package/dist/migration-snapshot.runtime-BLcy_Nvw.js +2 -0
  60. package/dist/monitor-DQm7_13y.js +4331 -0
  61. package/dist/plugin-entry.handlers.runtime.js +51 -0
  62. package/dist/probe.runtime-CjJS53Kz.js +3 -0
  63. package/dist/profile-update-DqkPgZ1P.js +68 -0
  64. package/dist/reaction-common-CmVLzP-u.js +71 -0
  65. package/dist/reaction-events-D0nUJuZV.js +121 -0
  66. package/dist/record-shared-DGvSFn5M.js +2 -0
  67. package/dist/resolve-targets-ChECUzD2.js +140 -0
  68. package/dist/resolver.runtime-hdY3n0GO.js +5 -0
  69. package/dist/rolldown-runtime-DUslC3ob.js +14 -0
  70. package/dist/route-xRKj_ESW.js +161 -0
  71. package/dist/runtime-B-Fyrmxo.js +8 -0
  72. package/dist/runtime-api-BYXXkxq2.js +24 -0
  73. package/dist/runtime-api.js +25 -0
  74. package/dist/runtime-heavy-api.js +3 -0
  75. package/dist/runtime-lwTSy9Yt.js +6 -0
  76. package/dist/runtime-setter-api.js +2 -0
  77. package/dist/sdk-Jhq7mLtD.js +1704 -0
  78. package/dist/secret-contract-DEMcDsjl.js +120 -0
  79. package/dist/secret-contract-api.js +2 -0
  80. package/dist/send-CJunc6QM.js +1517 -0
  81. package/dist/setup-bootstrap-rJ0qZWPe.js +62 -0
  82. package/dist/setup-core-BEYoXF3J.js +677 -0
  83. package/dist/setup-entry.js +19 -0
  84. package/dist/setup-plugin-api.js +43 -0
  85. package/dist/setup-surface-c28ON6jq.js +537 -0
  86. package/dist/shared-D6MFMnpG.js +642 -0
  87. package/dist/startup-abort-B2J3MU_h.js +109 -0
  88. package/dist/startup-verification-CkD4Cwce.js +132 -0
  89. package/dist/storage-nyO0DOFE.js +281 -0
  90. package/dist/storage-paths-BTAketfg.js +52 -0
  91. package/dist/subagent-hooks-api-Dr_xnMRG.js +170 -0
  92. package/dist/subagent-hooks-api.js +2 -0
  93. package/dist/sync-state-Bx0gPaGA.js +12 -0
  94. package/dist/target-ids-Bsazo8si.js +77 -0
  95. package/dist/test-api.js +4 -0
  96. package/dist/thread-binding-api-IGU0-L70.js +17 -0
  97. package/dist/thread-binding-api.js +2 -0
  98. package/dist/thread-bindings-FjAZmDUP.js +352 -0
  99. package/dist/thread-bindings-runtime.js +2 -0
  100. package/dist/thread-bindings-shared-fvfP7jVs.js +97 -0
  101. package/dist/timeout-abort-signal-DpSHDHhR.js +2 -0
  102. package/dist/tool-actions.runtime-Cbo7YcYZ.js +532 -0
  103. package/dist/url-validation-DlrXNjAE.js +36 -0
  104. package/dist/verification-7tDPRpJU.js +345 -0
  105. package/doctor-contract-api.ts +1 -0
  106. package/helper-api.ts +3 -0
  107. package/index.ts +55 -0
  108. package/klaw.plugin.json +3 -891
  109. package/package.json +4 -4
  110. package/plugin-entry.handlers.runtime.ts +1 -0
  111. package/runtime-api.ts +72 -0
  112. package/runtime-heavy-api.ts +1 -0
  113. package/runtime-setter-api.ts +3 -0
  114. package/secret-contract-api.ts +5 -0
  115. package/setup-entry.ts +17 -0
  116. package/setup-plugin-api.ts +3 -0
  117. package/src/account-selection.ts +223 -0
  118. package/src/actions.ts +346 -0
  119. package/src/approval-auth.ts +25 -0
  120. package/src/approval-handler.runtime.ts +592 -0
  121. package/src/approval-ids.ts +6 -0
  122. package/src/approval-native.ts +345 -0
  123. package/src/approval-reaction-auth.ts +45 -0
  124. package/src/approval-reactions.ts +313 -0
  125. package/src/auth-precedence.ts +61 -0
  126. package/src/channel-account-paths.ts +97 -0
  127. package/src/channel.runtime.ts +17 -0
  128. package/src/channel.setup.ts +48 -0
  129. package/src/channel.ts +667 -0
  130. package/src/cli-metadata.ts +19 -0
  131. package/src/cli.ts +2298 -0
  132. package/src/config-adapter.ts +41 -0
  133. package/src/config-schema.ts +159 -0
  134. package/src/config-ui-hints.ts +56 -0
  135. package/src/directory-live.ts +238 -0
  136. package/src/doctor-contract.ts +287 -0
  137. package/src/doctor.ts +262 -0
  138. package/src/env-vars.ts +92 -0
  139. package/src/exec-approval-resolver.ts +23 -0
  140. package/src/exec-approvals.ts +287 -0
  141. package/src/group-mentions.ts +41 -0
  142. package/src/legacy-crypto-inspector-availability.ts +60 -0
  143. package/src/legacy-crypto.ts +531 -0
  144. package/src/legacy-state.ts +156 -0
  145. package/src/matrix/account-config.ts +175 -0
  146. package/src/matrix/accounts.ts +194 -0
  147. package/src/matrix/actions/client.ts +31 -0
  148. package/src/matrix/actions/devices.ts +34 -0
  149. package/src/matrix/actions/limits.ts +6 -0
  150. package/src/matrix/actions/messages.ts +129 -0
  151. package/src/matrix/actions/pins.ts +63 -0
  152. package/src/matrix/actions/polls.ts +109 -0
  153. package/src/matrix/actions/profile.ts +37 -0
  154. package/src/matrix/actions/reactions.ts +59 -0
  155. package/src/matrix/actions/room.ts +71 -0
  156. package/src/matrix/actions/summary.ts +88 -0
  157. package/src/matrix/actions/types.ts +63 -0
  158. package/src/matrix/actions/verification.ts +589 -0
  159. package/src/matrix/actions.ts +37 -0
  160. package/src/matrix/active-client.ts +26 -0
  161. package/src/matrix/async-lock.ts +18 -0
  162. package/src/matrix/backup-health.ts +124 -0
  163. package/src/matrix/client/config-runtime-api.ts +9 -0
  164. package/src/matrix/client/config-secret-input.runtime.ts +1 -0
  165. package/src/matrix/client/config.ts +853 -0
  166. package/src/matrix/client/create-client.ts +105 -0
  167. package/src/matrix/client/env-auth.ts +95 -0
  168. package/src/matrix/client/file-sync-store.ts +289 -0
  169. package/src/matrix/client/logging.ts +140 -0
  170. package/src/matrix/client/migration-snapshot.runtime.ts +1 -0
  171. package/src/matrix/client/private-network-host.ts +1 -0
  172. package/src/matrix/client/runtime.ts +4 -0
  173. package/src/matrix/client/shared.ts +316 -0
  174. package/src/matrix/client/storage.ts +543 -0
  175. package/src/matrix/client/types.ts +50 -0
  176. package/src/matrix/client/url-validation.ts +73 -0
  177. package/src/matrix/client-bootstrap.ts +173 -0
  178. package/src/matrix/client.ts +23 -0
  179. package/src/matrix/config-paths.ts +31 -0
  180. package/src/matrix/config-update.ts +292 -0
  181. package/src/matrix/credentials-read.ts +208 -0
  182. package/src/matrix/credentials-write.runtime.ts +35 -0
  183. package/src/matrix/credentials.ts +95 -0
  184. package/src/matrix/deps.ts +309 -0
  185. package/src/matrix/device-health.ts +29 -0
  186. package/src/matrix/direct-management.ts +349 -0
  187. package/src/matrix/direct-room.ts +128 -0
  188. package/src/matrix/draft-stream.ts +225 -0
  189. package/src/matrix/encryption-guidance.ts +24 -0
  190. package/src/matrix/errors.ts +21 -0
  191. package/src/matrix/format.ts +426 -0
  192. package/src/matrix/legacy-crypto-inspector.ts +95 -0
  193. package/src/matrix/media-errors.ts +20 -0
  194. package/src/matrix/media-text.ts +162 -0
  195. package/src/matrix/monitor/access-state.ts +145 -0
  196. package/src/matrix/monitor/ack-config.ts +27 -0
  197. package/src/matrix/monitor/allowlist.ts +89 -0
  198. package/src/matrix/monitor/auto-join.ts +86 -0
  199. package/src/matrix/monitor/config.ts +569 -0
  200. package/src/matrix/monitor/context-summary.ts +43 -0
  201. package/src/matrix/monitor/direct.ts +296 -0
  202. package/src/matrix/monitor/events.ts +397 -0
  203. package/src/matrix/monitor/handler.ts +2266 -0
  204. package/src/matrix/monitor/inbound-dedupe.ts +267 -0
  205. package/src/matrix/monitor/index.ts +540 -0
  206. package/src/matrix/monitor/legacy-crypto-restore.ts +139 -0
  207. package/src/matrix/monitor/location.ts +108 -0
  208. package/src/matrix/monitor/media.ts +119 -0
  209. package/src/matrix/monitor/mentions.ts +256 -0
  210. package/src/matrix/monitor/reaction-events.ts +197 -0
  211. package/src/matrix/monitor/recent-invite.ts +30 -0
  212. package/src/matrix/monitor/replies.ts +136 -0
  213. package/src/matrix/monitor/reply-context.ts +92 -0
  214. package/src/matrix/monitor/room-history.ts +301 -0
  215. package/src/matrix/monitor/room-info.ts +126 -0
  216. package/src/matrix/monitor/rooms.ts +52 -0
  217. package/src/matrix/monitor/route.ts +179 -0
  218. package/src/matrix/monitor/runtime-api.ts +28 -0
  219. package/src/matrix/monitor/startup-verification.ts +237 -0
  220. package/src/matrix/monitor/startup.ts +218 -0
  221. package/src/matrix/monitor/status.ts +120 -0
  222. package/src/matrix/monitor/sync-lifecycle.ts +91 -0
  223. package/src/matrix/monitor/task-runner.ts +38 -0
  224. package/src/matrix/monitor/test-events.ts +21 -0
  225. package/src/matrix/monitor/thread-context.ts +108 -0
  226. package/src/matrix/monitor/threads.ts +85 -0
  227. package/src/matrix/monitor/types.ts +30 -0
  228. package/src/matrix/monitor/verification-events.ts +643 -0
  229. package/src/matrix/monitor/verification-utils.ts +46 -0
  230. package/src/matrix/outbound-media-runtime.ts +1 -0
  231. package/src/matrix/poll-summary.ts +110 -0
  232. package/src/matrix/poll-types.ts +429 -0
  233. package/src/matrix/probe.runtime.ts +4 -0
  234. package/src/matrix/probe.ts +97 -0
  235. package/src/matrix/profile.ts +184 -0
  236. package/src/matrix/reaction-common.ts +147 -0
  237. package/src/matrix/sdk/crypto-bootstrap.ts +438 -0
  238. package/src/matrix/sdk/crypto-facade.ts +242 -0
  239. package/src/matrix/sdk/crypto-node.runtime.ts +17 -0
  240. package/src/matrix/sdk/crypto-runtime.ts +14 -0
  241. package/src/matrix/sdk/decrypt-bridge.ts +410 -0
  242. package/src/matrix/sdk/event-helpers.ts +83 -0
  243. package/src/matrix/sdk/http-client.ts +87 -0
  244. package/src/matrix/sdk/idb-persistence-lock.ts +51 -0
  245. package/src/matrix/sdk/idb-persistence.ts +288 -0
  246. package/src/matrix/sdk/logger.ts +108 -0
  247. package/src/matrix/sdk/read-response-with-limit.ts +19 -0
  248. package/src/matrix/sdk/recovery-key-store.ts +453 -0
  249. package/src/matrix/sdk/timeout-abort-signal.ts +1 -0
  250. package/src/matrix/sdk/transport-runtime-api.ts +18 -0
  251. package/src/matrix/sdk/transport.ts +352 -0
  252. package/src/matrix/sdk/types.ts +245 -0
  253. package/src/matrix/sdk/verification-manager.ts +795 -0
  254. package/src/matrix/sdk/verification-status.ts +23 -0
  255. package/src/matrix/sdk.ts +2152 -0
  256. package/src/matrix/send/client.ts +93 -0
  257. package/src/matrix/send/formatting.ts +189 -0
  258. package/src/matrix/send/media.ts +244 -0
  259. package/src/matrix/send/targets.ts +104 -0
  260. package/src/matrix/send/types.ts +131 -0
  261. package/src/matrix/send.ts +660 -0
  262. package/src/matrix/session-store-metadata.ts +108 -0
  263. package/src/matrix/startup-abort.ts +44 -0
  264. package/src/matrix/subagent-hooks.ts +308 -0
  265. package/src/matrix/sync-state.ts +27 -0
  266. package/src/matrix/target-ids.ts +79 -0
  267. package/src/matrix/thread-bindings-shared.ts +206 -0
  268. package/src/matrix/thread-bindings.ts +580 -0
  269. package/src/matrix-migration.runtime.ts +9 -0
  270. package/src/migration-config.ts +243 -0
  271. package/src/migration-snapshot-backup.ts +116 -0
  272. package/src/migration-snapshot.ts +53 -0
  273. package/src/onboarding.ts +775 -0
  274. package/src/outbound.ts +248 -0
  275. package/src/plugin-entry.runtime.js +115 -0
  276. package/src/plugin-entry.runtime.ts +70 -0
  277. package/src/profile-update.ts +71 -0
  278. package/src/record-shared.ts +3 -0
  279. package/src/resolve-targets.ts +175 -0
  280. package/src/resolver.runtime.ts +5 -0
  281. package/src/resolver.ts +21 -0
  282. package/src/runtime-api.ts +106 -0
  283. package/src/runtime.ts +13 -0
  284. package/src/secret-contract.ts +174 -0
  285. package/src/session-route.ts +126 -0
  286. package/src/setup-bootstrap.ts +102 -0
  287. package/src/setup-config.ts +222 -0
  288. package/src/setup-contract.ts +90 -0
  289. package/src/setup-core.ts +146 -0
  290. package/src/setup-dm-policy.ts +15 -0
  291. package/src/setup-surface.ts +4 -0
  292. package/src/startup-maintenance.ts +114 -0
  293. package/src/storage-paths.ts +92 -0
  294. package/src/thread-binding-api.ts +23 -0
  295. package/src/tool-actions.runtime.ts +1 -0
  296. package/src/tool-actions.ts +498 -0
  297. package/src/types.ts +257 -0
  298. package/subagent-hooks-api.ts +31 -0
  299. package/test-api.ts +21 -0
  300. package/thread-binding-api.ts +4 -0
  301. package/thread-bindings-runtime.ts +4 -0
  302. package/tsconfig.json +16 -0
  303. package/api.js +0 -7
  304. package/auth-presence.js +0 -7
  305. package/channel-plugin-api.js +0 -7
  306. package/cli-metadata.js +0 -7
  307. package/contract-api.js +0 -7
  308. package/doctor-contract-api.js +0 -7
  309. package/helper-api.js +0 -7
  310. package/index.js +0 -7
  311. package/plugin-entry.handlers.runtime.js +0 -7
  312. package/runtime-api.js +0 -7
  313. package/runtime-heavy-api.js +0 -7
  314. package/runtime-setter-api.js +0 -7
  315. package/secret-contract-api.js +0 -7
  316. package/setup-entry.js +0 -7
  317. package/setup-plugin-api.js +0 -7
  318. package/subagent-hooks-api.js +0 -7
  319. package/test-api.js +0 -7
  320. package/thread-binding-api.js +0 -7
  321. package/thread-bindings-runtime.js +0 -7
@@ -0,0 +1,1214 @@
1
+ import { t as formatMatrixErrorMessage } from "./errors-BETj3zr9.js";
2
+ import { t as ensureMatrixCryptoRuntime } from "./deps-DVpDS81G.js";
3
+ import { o as LogService, s as noop } from "./startup-abort-B2J3MU_h.js";
4
+ import { i as MATRIX_IDB_SNAPSHOT_LOCK_OPTIONS, r as isRepairableSecretStorageAccessError } from "./sdk-Jhq7mLtD.js";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { MatrixEventEvent } from "matrix-js-sdk/lib/matrix.js";
8
+ import { VerificationMethod } from "matrix-js-sdk/lib/types.js";
9
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
10
+ import "fake-indexeddb/auto";
11
+ import { CryptoEvent } from "matrix-js-sdk/lib/crypto-api/CryptoEvent.js";
12
+ import { DecryptionFailureCode } from "matrix-js-sdk/lib/crypto-api/index.js";
13
+ import { indexedDB } from "fake-indexeddb";
14
+ import { withFileLock } from "klaw/plugin-sdk/file-lock";
15
+ import { VerificationPhase, VerificationRequestEvent, VerifierEvent } from "matrix-js-sdk/lib/crypto-api/verification.js";
16
+ //#region extensions/matrix/src/matrix/sdk/verification-status.ts
17
+ function isMatrixDeviceLocallyVerified(status) {
18
+ return status?.localVerified === true;
19
+ }
20
+ function isMatrixDeviceOwnerVerified(status) {
21
+ return status?.crossSigningVerified === true;
22
+ }
23
+ function isMatrixDeviceVerifiedInCurrentClient(status) {
24
+ return status?.isVerified?.() === true || isMatrixDeviceLocallyVerified(status) || isMatrixDeviceOwnerVerified(status);
25
+ }
26
+ //#endregion
27
+ //#region extensions/matrix/src/matrix/sdk/crypto-bootstrap.ts
28
+ const CROSS_SIGNING_PUBLICATION_WAIT_MS = 5e3;
29
+ var MatrixCryptoBootstrapper = class {
30
+ constructor(deps) {
31
+ this.deps = deps;
32
+ this.verificationHandlerRegistered = false;
33
+ }
34
+ async bootstrap(crypto, options = {}) {
35
+ const strict = options.strict === true;
36
+ const deferSecretStorageBootstrapUntilAfterCrossSigning = options.forceResetCrossSigning === true;
37
+ this.registerVerificationRequestHandler(crypto);
38
+ if (!deferSecretStorageBootstrapUntilAfterCrossSigning) await this.bootstrapSecretStorage(crypto, {
39
+ strict,
40
+ allowSecretStorageRecreateWithoutRecoveryKey: options.allowSecretStorageRecreateWithoutRecoveryKey === true
41
+ });
42
+ let crossSigning = await this.bootstrapCrossSigning(crypto, {
43
+ forceResetCrossSigning: options.forceResetCrossSigning === true,
44
+ allowAutomaticCrossSigningReset: options.allowAutomaticCrossSigningReset !== false,
45
+ allowSecretStorageRecreateWithoutRecoveryKey: options.allowSecretStorageRecreateWithoutRecoveryKey === true,
46
+ strict
47
+ });
48
+ await this.bootstrapSecretStorage(crypto, {
49
+ strict,
50
+ allowSecretStorageRecreateWithoutRecoveryKey: options.allowSecretStorageRecreateWithoutRecoveryKey === true
51
+ });
52
+ if (deferSecretStorageBootstrapUntilAfterCrossSigning) crossSigning = await this.bootstrapCrossSigning(crypto, {
53
+ forceResetCrossSigning: false,
54
+ allowAutomaticCrossSigningReset: false,
55
+ allowSecretStorageRecreateWithoutRecoveryKey: options.allowSecretStorageRecreateWithoutRecoveryKey === true,
56
+ strict
57
+ });
58
+ const ownDeviceVerified = await this.ensureOwnDeviceTrust(crypto, { strict });
59
+ return {
60
+ crossSigningReady: crossSigning.ready,
61
+ crossSigningPublished: crossSigning.published,
62
+ ownDeviceVerified
63
+ };
64
+ }
65
+ createSigningKeysUiAuthCallback(params) {
66
+ return async (makeRequest) => {
67
+ try {
68
+ return await makeRequest(null);
69
+ } catch {
70
+ try {
71
+ return await makeRequest({ type: "m.login.dummy" });
72
+ } catch {
73
+ if (!params.password?.trim()) throw new Error("Matrix cross-signing key upload requires UIA; provide matrix.password for m.login.password fallback");
74
+ return await makeRequest({
75
+ type: "m.login.password",
76
+ identifier: {
77
+ type: "m.id.user",
78
+ user: params.userId
79
+ },
80
+ password: params.password
81
+ });
82
+ }
83
+ }
84
+ };
85
+ }
86
+ async bootstrapCrossSigning(crypto, options) {
87
+ const userId = await this.deps.getUserId();
88
+ const authUploadDeviceSigningKeys = this.createSigningKeysUiAuthCallback({
89
+ userId,
90
+ password: this.deps.getPassword?.()
91
+ });
92
+ const hasPublishedCrossSigningKeys = async () => {
93
+ if (typeof crypto.userHasCrossSigningKeys !== "function") return true;
94
+ try {
95
+ return await crypto.userHasCrossSigningKeys(userId, true);
96
+ } catch {
97
+ return false;
98
+ }
99
+ };
100
+ const refreshPublishedCrossSigningKeys = async () => {
101
+ if (typeof crypto.userHasCrossSigningKeys !== "function") return;
102
+ try {
103
+ await crypto.userHasCrossSigningKeys(userId, true);
104
+ } catch {}
105
+ };
106
+ const isCrossSigningReady = async () => {
107
+ if (typeof crypto.isCrossSigningReady !== "function") return true;
108
+ try {
109
+ return await crypto.isCrossSigningReady();
110
+ } catch {
111
+ return false;
112
+ }
113
+ };
114
+ const finalize = async () => {
115
+ const ready = await isCrossSigningReady();
116
+ const published = ready ? await waitForPublishedCrossSigningKeys() : await hasPublishedCrossSigningKeys();
117
+ if (ready && published) {
118
+ LogService.info("MatrixClientLite", "Cross-signing bootstrap complete");
119
+ return {
120
+ ready,
121
+ published
122
+ };
123
+ }
124
+ const message = "Cross-signing bootstrap finished but server keys are still not published";
125
+ LogService.warn("MatrixClientLite", message);
126
+ if (options.strict) throw new Error(message);
127
+ return {
128
+ ready,
129
+ published
130
+ };
131
+ };
132
+ const waitForPublishedCrossSigningKeys = async () => {
133
+ const startedAt = Date.now();
134
+ do {
135
+ if (await hasPublishedCrossSigningKeys()) return true;
136
+ await setTimeout$1(250);
137
+ } while (Date.now() - startedAt < CROSS_SIGNING_PUBLICATION_WAIT_MS);
138
+ return false;
139
+ };
140
+ if (options.forceResetCrossSigning) {
141
+ const resetCrossSigning = async () => {
142
+ await crypto.bootstrapCrossSigning({
143
+ setupNewCrossSigning: true,
144
+ authUploadDeviceSigningKeys
145
+ });
146
+ };
147
+ try {
148
+ await resetCrossSigning();
149
+ await this.trustFreshOwnIdentity(crypto);
150
+ } catch (err) {
151
+ if (options.allowSecretStorageRecreateWithoutRecoveryKey && isRepairableSecretStorageAccessError(err)) {
152
+ LogService.warn("MatrixClientLite", "Forced cross-signing reset could not unlock secret storage; recreating secret storage and retrying.");
153
+ try {
154
+ await this.deps.recoveryKeyStore.bootstrapSecretStorageWithRecoveryKey(crypto, {
155
+ allowSecretStorageRecreateWithoutRecoveryKey: true,
156
+ forceNewSecretStorage: true
157
+ });
158
+ await resetCrossSigning();
159
+ await this.trustFreshOwnIdentity(crypto);
160
+ } catch (repairErr) {
161
+ LogService.warn("MatrixClientLite", "Forced cross-signing reset failed:", repairErr);
162
+ if (options.strict) throw repairErr instanceof Error ? repairErr : new Error(String(repairErr));
163
+ return {
164
+ ready: false,
165
+ published: false
166
+ };
167
+ }
168
+ return await finalize();
169
+ }
170
+ LogService.warn("MatrixClientLite", "Forced cross-signing reset failed:", err);
171
+ if (options.strict) throw err instanceof Error ? err : new Error(String(err));
172
+ return {
173
+ ready: false,
174
+ published: false
175
+ };
176
+ }
177
+ return await finalize();
178
+ }
179
+ try {
180
+ await refreshPublishedCrossSigningKeys();
181
+ await crypto.bootstrapCrossSigning({ authUploadDeviceSigningKeys });
182
+ } catch (err) {
183
+ if (options.allowSecretStorageRecreateWithoutRecoveryKey && isRepairableSecretStorageAccessError(err)) {
184
+ LogService.warn("MatrixClientLite", "Cross-signing bootstrap could not unlock secret storage; recreating secret storage during explicit bootstrap and retrying.");
185
+ await this.deps.recoveryKeyStore.bootstrapSecretStorageWithRecoveryKey(crypto, {
186
+ allowSecretStorageRecreateWithoutRecoveryKey: true,
187
+ forceNewSecretStorage: true
188
+ });
189
+ await crypto.bootstrapCrossSigning({ authUploadDeviceSigningKeys });
190
+ } else if (!options.allowAutomaticCrossSigningReset) {
191
+ LogService.warn("MatrixClientLite", "Initial cross-signing bootstrap failed and automatic reset is disabled:", err);
192
+ return {
193
+ ready: false,
194
+ published: false
195
+ };
196
+ } else {
197
+ LogService.warn("MatrixClientLite", "Initial cross-signing bootstrap failed, trying reset:", err);
198
+ try {
199
+ await crypto.bootstrapCrossSigning({
200
+ setupNewCrossSigning: true,
201
+ authUploadDeviceSigningKeys
202
+ });
203
+ } catch (resetErr) {
204
+ LogService.warn("MatrixClientLite", "Failed to bootstrap cross-signing:", resetErr);
205
+ if (options.strict) throw resetErr instanceof Error ? resetErr : new Error(String(resetErr));
206
+ return {
207
+ ready: false,
208
+ published: false
209
+ };
210
+ }
211
+ }
212
+ }
213
+ const firstPassReady = await isCrossSigningReady();
214
+ const firstPassPublished = await hasPublishedCrossSigningKeys();
215
+ if (firstPassReady && firstPassPublished) {
216
+ LogService.info("MatrixClientLite", "Cross-signing bootstrap complete");
217
+ return {
218
+ ready: true,
219
+ published: true
220
+ };
221
+ }
222
+ if (!options.allowAutomaticCrossSigningReset) return {
223
+ ready: firstPassReady,
224
+ published: firstPassPublished
225
+ };
226
+ try {
227
+ await crypto.bootstrapCrossSigning({
228
+ setupNewCrossSigning: true,
229
+ authUploadDeviceSigningKeys
230
+ });
231
+ await this.trustFreshOwnIdentity(crypto);
232
+ } catch (err) {
233
+ LogService.warn("MatrixClientLite", "Fallback cross-signing bootstrap failed:", err);
234
+ if (options.strict) throw err instanceof Error ? err : new Error(String(err));
235
+ return {
236
+ ready: false,
237
+ published: false
238
+ };
239
+ }
240
+ return await finalize();
241
+ }
242
+ async trustFreshOwnIdentity(crypto) {
243
+ const ownIdentity = typeof crypto.getOwnIdentity === "function" ? await crypto.getOwnIdentity().catch(() => void 0) : void 0;
244
+ if (!ownIdentity) return;
245
+ try {
246
+ if (typeof ownIdentity.isVerified === "function" && ownIdentity.isVerified()) return;
247
+ await ownIdentity.verify?.();
248
+ } finally {
249
+ ownIdentity.free?.();
250
+ }
251
+ }
252
+ async bootstrapSecretStorage(crypto, options) {
253
+ try {
254
+ await this.deps.recoveryKeyStore.bootstrapSecretStorageWithRecoveryKey(crypto, { allowSecretStorageRecreateWithoutRecoveryKey: options.allowSecretStorageRecreateWithoutRecoveryKey });
255
+ LogService.info("MatrixClientLite", "Secret storage bootstrap complete");
256
+ } catch (err) {
257
+ LogService.warn("MatrixClientLite", "Failed to bootstrap secret storage:", err);
258
+ if (options.strict) throw err instanceof Error ? err : new Error(String(err));
259
+ }
260
+ }
261
+ registerVerificationRequestHandler(crypto) {
262
+ if (this.verificationHandlerRegistered) return;
263
+ this.verificationHandlerRegistered = true;
264
+ crypto.on(CryptoEvent.VerificationRequestReceived, async (request) => {
265
+ const verificationRequest = request;
266
+ try {
267
+ this.deps.verificationManager.trackVerificationRequest(verificationRequest);
268
+ } catch (err) {
269
+ LogService.warn("MatrixClientLite", `Failed to track verification request from ${verificationRequest.otherUserId}:`, err);
270
+ }
271
+ });
272
+ this.deps.decryptBridge.bindCryptoRetrySignals(crypto);
273
+ LogService.info("MatrixClientLite", "Verification request handler registered");
274
+ }
275
+ async ensureOwnDeviceTrust(crypto, options) {
276
+ const deviceId = this.deps.getDeviceId()?.trim();
277
+ if (!deviceId) return null;
278
+ const userId = await this.deps.getUserId();
279
+ if (isMatrixDeviceOwnerVerified(typeof crypto.getDeviceVerificationStatus === "function" ? await crypto.getDeviceVerificationStatus(userId, deviceId).catch(() => null) : null)) return true;
280
+ if (typeof crypto.setDeviceVerified === "function") await crypto.setDeviceVerified(userId, deviceId, true);
281
+ if (typeof crypto.crossSignDevice === "function") {
282
+ if (typeof crypto.isCrossSigningReady === "function" ? await crypto.isCrossSigningReady() : true) await crypto.crossSignDevice(deviceId);
283
+ }
284
+ const verified = isMatrixDeviceOwnerVerified(typeof crypto.getDeviceVerificationStatus === "function" ? await crypto.getDeviceVerificationStatus(userId, deviceId).catch(() => null) : null);
285
+ if (!verified && options.strict) throw new Error(`Matrix own device ${deviceId} does not have full Matrix identity trust after bootstrap`);
286
+ return verified;
287
+ }
288
+ };
289
+ //#endregion
290
+ //#region extensions/matrix/src/matrix/sdk/crypto-facade.ts
291
+ let matrixCryptoNodeRuntimePromise = null;
292
+ async function loadMatrixCryptoNodeRuntime() {
293
+ matrixCryptoNodeRuntimePromise ??= import("./crypto-node.runtime-D9qxgRPa.js").catch((error) => {
294
+ matrixCryptoNodeRuntimePromise = null;
295
+ throw error;
296
+ });
297
+ return await matrixCryptoNodeRuntimePromise;
298
+ }
299
+ async function loadMatrixCryptoNodeBindings() {
300
+ await ensureMatrixCryptoRuntime();
301
+ return (await loadMatrixCryptoNodeRuntime()).loadMatrixCryptoNodeBindings();
302
+ }
303
+ function trackInProgressToDeviceVerifications(deps) {
304
+ const crypto = deps.client.getCrypto();
305
+ const userId = deps.client.getUserId();
306
+ if (!userId || typeof crypto?.getVerificationRequestsToDeviceInProgress !== "function") return;
307
+ for (const request of crypto.getVerificationRequestsToDeviceInProgress(userId)) deps.verificationManager.trackVerificationRequest(request);
308
+ }
309
+ function createMatrixCryptoFacade(deps) {
310
+ return {
311
+ prepare: async (_joinedRooms) => {},
312
+ updateSyncData: async (_toDeviceMessages, _otkCounts, _unusedFallbackKeyAlgs, _changedDeviceLists, _leftDeviceLists) => {},
313
+ isRoomEncrypted: async (roomId) => {
314
+ if (deps.client.getRoom(roomId)?.hasEncryptionStateEvent()) return true;
315
+ try {
316
+ const event = await deps.getRoomStateEvent(roomId, "m.room.encryption", "");
317
+ return typeof event.algorithm === "string" && event.algorithm.length > 0;
318
+ } catch {
319
+ return false;
320
+ }
321
+ },
322
+ requestOwnUserVerification: async () => {
323
+ const crypto = deps.client.getCrypto();
324
+ return await deps.verificationManager.requestOwnUserVerification(crypto);
325
+ },
326
+ encryptMedia: async (buffer) => {
327
+ const { Attachment } = await loadMatrixCryptoNodeBindings();
328
+ const encrypted = Attachment.encrypt(new Uint8Array(buffer));
329
+ const mediaInfoJson = encrypted.mediaEncryptionInfo;
330
+ if (!mediaInfoJson) throw new Error("Matrix media encryption failed: missing media encryption info");
331
+ const parsed = JSON.parse(mediaInfoJson);
332
+ return {
333
+ buffer: Buffer.from(encrypted.encryptedData),
334
+ file: {
335
+ key: parsed.key,
336
+ iv: parsed.iv,
337
+ hashes: parsed.hashes,
338
+ v: parsed.v
339
+ }
340
+ };
341
+ },
342
+ decryptMedia: async (file, opts) => {
343
+ const { Attachment, EncryptedAttachment } = await loadMatrixCryptoNodeBindings();
344
+ const encrypted = await deps.downloadContent(file.url, opts);
345
+ const metadata = {
346
+ url: file.url,
347
+ key: file.key,
348
+ iv: file.iv,
349
+ hashes: file.hashes,
350
+ v: file.v
351
+ };
352
+ const attachment = new EncryptedAttachment(new Uint8Array(encrypted), JSON.stringify(metadata));
353
+ const decrypted = Attachment.decrypt(attachment);
354
+ return Buffer.from(decrypted);
355
+ },
356
+ getRecoveryKey: async () => {
357
+ return deps.recoveryKeyStore.getRecoveryKeySummary();
358
+ },
359
+ listVerifications: async () => {
360
+ trackInProgressToDeviceVerifications(deps);
361
+ return deps.verificationManager.listVerifications();
362
+ },
363
+ ensureVerificationDmTracked: async ({ roomId, userId }) => {
364
+ const crypto = deps.client.getCrypto();
365
+ const request = typeof crypto?.findVerificationRequestDMInProgress === "function" ? crypto.findVerificationRequestDMInProgress(roomId, userId) : void 0;
366
+ if (!request) return null;
367
+ return deps.verificationManager.trackVerificationRequest(request);
368
+ },
369
+ requestVerification: async (params) => {
370
+ const crypto = deps.client.getCrypto();
371
+ return await deps.verificationManager.requestVerification(crypto, params);
372
+ },
373
+ acceptVerification: async (id) => {
374
+ trackInProgressToDeviceVerifications(deps);
375
+ return await deps.verificationManager.acceptVerification(id);
376
+ },
377
+ cancelVerification: async (id, params) => {
378
+ trackInProgressToDeviceVerifications(deps);
379
+ return await deps.verificationManager.cancelVerification(id, params);
380
+ },
381
+ startVerification: async (id, method = "sas") => {
382
+ trackInProgressToDeviceVerifications(deps);
383
+ return await deps.verificationManager.startVerification(id, method);
384
+ },
385
+ generateVerificationQr: async (id) => {
386
+ trackInProgressToDeviceVerifications(deps);
387
+ return await deps.verificationManager.generateVerificationQr(id);
388
+ },
389
+ scanVerificationQr: async (id, qrDataBase64) => {
390
+ trackInProgressToDeviceVerifications(deps);
391
+ return await deps.verificationManager.scanVerificationQr(id, qrDataBase64);
392
+ },
393
+ confirmVerificationSas: async (id) => {
394
+ trackInProgressToDeviceVerifications(deps);
395
+ return await deps.verificationManager.confirmVerificationSas(id);
396
+ },
397
+ mismatchVerificationSas: async (id) => {
398
+ trackInProgressToDeviceVerifications(deps);
399
+ return deps.verificationManager.mismatchVerificationSas(id);
400
+ },
401
+ confirmVerificationReciprocateQr: async (id) => {
402
+ trackInProgressToDeviceVerifications(deps);
403
+ return deps.verificationManager.confirmVerificationReciprocateQr(id);
404
+ },
405
+ getVerificationSas: async (id) => {
406
+ trackInProgressToDeviceVerifications(deps);
407
+ return deps.verificationManager.getVerificationSas(id);
408
+ }
409
+ };
410
+ }
411
+ //#endregion
412
+ //#region extensions/matrix/src/matrix/sdk/decrypt-bridge.ts
413
+ const MATRIX_DECRYPT_RETRY_BASE_DELAY_MS = 1500;
414
+ const MATRIX_DECRYPT_RETRY_MAX_DELAY_MS = 3e4;
415
+ const MATRIX_DECRYPT_RETRY_MAX_ATTEMPTS = 8;
416
+ function resolveDecryptRetryKey(roomId, eventId) {
417
+ if (!roomId || !eventId) return null;
418
+ return `${roomId}|${eventId}`;
419
+ }
420
+ function isDecryptionFailure(event) {
421
+ return typeof event.isDecryptionFailure === "function" && event.isDecryptionFailure();
422
+ }
423
+ function getDecryptionFailureReason(event) {
424
+ const reason = event.decryptionFailureReason;
425
+ return typeof reason === "string" && reason in DecryptionFailureCode ? reason : null;
426
+ }
427
+ function shouldRetryDecryptionFailure(event) {
428
+ if (!isDecryptionFailure(event)) return false;
429
+ const reason = getDecryptionFailureReason(event);
430
+ if (!reason) return true;
431
+ return reason === DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID || reason === DecryptionFailureCode.OLM_UNKNOWN_MESSAGE_INDEX || reason === DecryptionFailureCode.UNKNOWN_ERROR;
432
+ }
433
+ var MatrixDecryptBridge = class {
434
+ constructor(deps) {
435
+ this.deps = deps;
436
+ this.trackedEncryptedEvents = /* @__PURE__ */ new WeakSet();
437
+ this.decryptedMessageDedupe = /* @__PURE__ */ new Map();
438
+ this.decryptRetries = /* @__PURE__ */ new Map();
439
+ this.failedDecryptionsNotified = /* @__PURE__ */ new Set();
440
+ this.exhaustedDecryptRetries = /* @__PURE__ */ new Set();
441
+ this.activeRetryRuns = 0;
442
+ this.retryIdleResolvers = /* @__PURE__ */ new Set();
443
+ this.cryptoRetrySignalsBound = false;
444
+ }
445
+ shouldEmitUnencryptedMessage(roomId, eventId) {
446
+ if (!eventId) return true;
447
+ const key = `${roomId}|${eventId}`;
448
+ if (this.decryptedMessageDedupe.get(key) === void 0) return true;
449
+ this.decryptedMessageDedupe.delete(key);
450
+ return false;
451
+ }
452
+ attachEncryptedEvent(event, roomId) {
453
+ if (this.trackedEncryptedEvents.has(event)) return;
454
+ this.trackedEncryptedEvents.add(event);
455
+ event.on(MatrixEventEvent.Decrypted, (decryptedEvent, err) => {
456
+ this.handleEncryptedEventDecrypted({
457
+ roomId,
458
+ encryptedEvent: event,
459
+ decryptedEvent,
460
+ err
461
+ });
462
+ });
463
+ if (shouldRetryDecryptionFailure(event)) {
464
+ const eventId = this.deps.toRaw(event).event_id || event.getId() || "";
465
+ this.scheduleDecryptRetry({
466
+ event,
467
+ roomId,
468
+ eventId
469
+ });
470
+ }
471
+ }
472
+ retryPendingNow(reason) {
473
+ const pending = Array.from(this.decryptRetries.entries());
474
+ if (pending.length === 0) return;
475
+ LogService.debug("MatrixClientLite", `Retrying pending decryptions due to ${reason}`);
476
+ for (const [retryKey, state] of pending) {
477
+ if (state.timer) {
478
+ clearTimeout(state.timer);
479
+ state.timer = null;
480
+ }
481
+ if (state.inFlight) continue;
482
+ this.runDecryptRetry(retryKey).catch(noop);
483
+ }
484
+ }
485
+ bindCryptoRetrySignals(crypto) {
486
+ if (!crypto || this.cryptoRetrySignalsBound) return;
487
+ this.cryptoRetrySignalsBound = true;
488
+ const trigger = (reason) => {
489
+ this.retryPendingNow(reason);
490
+ };
491
+ crypto.on(CryptoEvent.KeyBackupDecryptionKeyCached, () => {
492
+ trigger("crypto.keyBackupDecryptionKeyCached");
493
+ });
494
+ crypto.on(CryptoEvent.RehydrationCompleted, () => {
495
+ trigger("dehydration.RehydrationCompleted");
496
+ });
497
+ crypto.on(CryptoEvent.DevicesUpdated, () => {
498
+ trigger("crypto.devicesUpdated");
499
+ });
500
+ crypto.on(CryptoEvent.KeysChanged, () => {
501
+ trigger("crossSigning.keysChanged");
502
+ });
503
+ }
504
+ stop() {
505
+ for (const retryKey of this.decryptRetries.keys()) this.clearDecryptRetry(retryKey);
506
+ }
507
+ async drainPendingDecryptions(reason) {
508
+ for (let attempts = 0; attempts < MATRIX_DECRYPT_RETRY_MAX_ATTEMPTS; attempts += 1) {
509
+ if (this.decryptRetries.size === 0) return;
510
+ this.retryPendingNow(reason);
511
+ await this.waitForActiveRetryRunsToFinish();
512
+ if (!Array.from(this.decryptRetries.values()).some((state) => state.timer || state.inFlight)) return;
513
+ }
514
+ }
515
+ handleEncryptedEventDecrypted(params) {
516
+ const decryptedRoomId = params.decryptedEvent.getRoomId() || params.roomId;
517
+ const decryptedRaw = this.deps.toRaw(params.decryptedEvent);
518
+ const retryEventId = decryptedRaw.event_id || params.encryptedEvent.getId() || "";
519
+ const retryKey = resolveDecryptRetryKey(decryptedRoomId, retryEventId);
520
+ if (params.err) {
521
+ this.emitFailedDecryptionOnce(retryKey, decryptedRoomId, decryptedRaw, params.err);
522
+ if (shouldRetryDecryptionFailure(params.decryptedEvent)) this.scheduleDecryptRetry({
523
+ event: params.encryptedEvent,
524
+ roomId: decryptedRoomId,
525
+ eventId: retryEventId
526
+ });
527
+ else if (retryKey) this.clearDecryptRetry(retryKey);
528
+ return;
529
+ }
530
+ if (isDecryptionFailure(params.decryptedEvent)) {
531
+ this.emitFailedDecryptionOnce(retryKey, decryptedRoomId, decryptedRaw, /* @__PURE__ */ new Error("Matrix event failed to decrypt"));
532
+ if (shouldRetryDecryptionFailure(params.decryptedEvent)) this.scheduleDecryptRetry({
533
+ event: params.encryptedEvent,
534
+ roomId: decryptedRoomId,
535
+ eventId: retryEventId
536
+ });
537
+ else if (retryKey) this.clearDecryptRetry(retryKey);
538
+ return;
539
+ }
540
+ if (retryKey) this.clearDecryptRetry(retryKey);
541
+ this.rememberDecryptedMessage(decryptedRoomId, decryptedRaw.event_id);
542
+ this.deps.emitDecryptedEvent(decryptedRoomId, decryptedRaw);
543
+ this.deps.emitMessage(decryptedRoomId, decryptedRaw);
544
+ }
545
+ emitFailedDecryptionOnce(retryKey, roomId, event, error) {
546
+ if (retryKey) {
547
+ if (this.failedDecryptionsNotified.has(retryKey)) return;
548
+ this.failedDecryptionsNotified.add(retryKey);
549
+ }
550
+ this.deps.emitFailedDecryption(roomId, event, error);
551
+ }
552
+ scheduleDecryptRetry(params) {
553
+ const retryKey = resolveDecryptRetryKey(params.roomId, params.eventId);
554
+ if (!retryKey) return;
555
+ const existing = this.decryptRetries.get(retryKey);
556
+ if (this.exhaustedDecryptRetries.has(retryKey)) return;
557
+ if (existing?.timer || existing?.inFlight) return;
558
+ const attempts = (existing?.attempts ?? 0) + 1;
559
+ if (attempts > MATRIX_DECRYPT_RETRY_MAX_ATTEMPTS) {
560
+ const retry = this.decryptRetries.get(retryKey);
561
+ if (retry?.timer) clearTimeout(retry.timer);
562
+ this.decryptRetries.delete(retryKey);
563
+ this.exhaustedDecryptRetries.add(retryKey);
564
+ LogService.debug("MatrixClientLite", `Giving up decryption retry for ${params.eventId} in ${params.roomId} after ${attempts - 1} attempts`);
565
+ return;
566
+ }
567
+ const delayMs = Math.min(MATRIX_DECRYPT_RETRY_BASE_DELAY_MS * 2 ** (attempts - 1), MATRIX_DECRYPT_RETRY_MAX_DELAY_MS);
568
+ const next = {
569
+ event: params.event,
570
+ roomId: params.roomId,
571
+ eventId: params.eventId,
572
+ attempts,
573
+ inFlight: false,
574
+ timer: null
575
+ };
576
+ next.timer = setTimeout(() => {
577
+ this.runDecryptRetry(retryKey).catch(noop);
578
+ }, delayMs);
579
+ this.decryptRetries.set(retryKey, next);
580
+ }
581
+ async runDecryptRetry(retryKey) {
582
+ const state = this.decryptRetries.get(retryKey);
583
+ if (!state || state.inFlight) return;
584
+ state.inFlight = true;
585
+ state.timer = null;
586
+ this.activeRetryRuns += 1;
587
+ if (!(typeof this.deps.client.decryptEventIfNeeded === "function")) {
588
+ this.clearDecryptRetry(retryKey);
589
+ this.activeRetryRuns = Math.max(0, this.activeRetryRuns - 1);
590
+ this.resolveRetryIdleIfNeeded();
591
+ return;
592
+ }
593
+ try {
594
+ await this.deps.client.decryptEventIfNeeded?.(state.event, { isRetry: true });
595
+ } catch {} finally {
596
+ state.inFlight = false;
597
+ this.activeRetryRuns = Math.max(0, this.activeRetryRuns - 1);
598
+ this.resolveRetryIdleIfNeeded();
599
+ }
600
+ if (this.decryptRetries.get(retryKey) !== state) return;
601
+ if (isDecryptionFailure(state.event)) {
602
+ if (!shouldRetryDecryptionFailure(state.event)) {
603
+ this.clearDecryptRetry(retryKey);
604
+ return;
605
+ }
606
+ this.scheduleDecryptRetry(state);
607
+ return;
608
+ }
609
+ this.clearDecryptRetry(retryKey);
610
+ const raw = this.deps.toRaw(state.event);
611
+ this.rememberDecryptedMessage(state.roomId, raw.event_id);
612
+ this.deps.emitDecryptedEvent(state.roomId, raw);
613
+ this.deps.emitMessage(state.roomId, raw);
614
+ }
615
+ clearDecryptRetry(retryKey) {
616
+ const state = this.decryptRetries.get(retryKey);
617
+ if (state?.timer) clearTimeout(state.timer);
618
+ this.decryptRetries.delete(retryKey);
619
+ this.exhaustedDecryptRetries.delete(retryKey);
620
+ this.failedDecryptionsNotified.delete(retryKey);
621
+ }
622
+ rememberDecryptedMessage(roomId, eventId) {
623
+ if (!eventId) return;
624
+ const now = Date.now();
625
+ this.pruneDecryptedMessageDedupe(now);
626
+ this.decryptedMessageDedupe.set(`${roomId}|${eventId}`, now);
627
+ }
628
+ pruneDecryptedMessageDedupe(now) {
629
+ const ttlMs = 3e4;
630
+ for (const [key, createdAt] of this.decryptedMessageDedupe) if (now - createdAt > ttlMs) this.decryptedMessageDedupe.delete(key);
631
+ const maxEntries = 2048;
632
+ while (this.decryptedMessageDedupe.size > maxEntries) {
633
+ const oldest = this.decryptedMessageDedupe.keys().next().value;
634
+ if (oldest === void 0) break;
635
+ this.decryptedMessageDedupe.delete(oldest);
636
+ }
637
+ }
638
+ async waitForActiveRetryRunsToFinish() {
639
+ if (this.activeRetryRuns === 0) return;
640
+ await new Promise((resolve) => {
641
+ this.retryIdleResolvers.add(resolve);
642
+ if (this.activeRetryRuns === 0) {
643
+ this.retryIdleResolvers.delete(resolve);
644
+ resolve();
645
+ }
646
+ });
647
+ }
648
+ resolveRetryIdleIfNeeded() {
649
+ if (this.activeRetryRuns !== 0) return;
650
+ for (const resolve of this.retryIdleResolvers) resolve();
651
+ this.retryIdleResolvers.clear();
652
+ }
653
+ };
654
+ //#endregion
655
+ //#region extensions/matrix/src/matrix/sdk/idb-persistence.ts
656
+ function isValidIdbIndexSnapshot(value) {
657
+ if (!value || typeof value !== "object") return false;
658
+ const candidate = value;
659
+ return typeof candidate.name === "string" && (typeof candidate.keyPath === "string" || Array.isArray(candidate.keyPath) && candidate.keyPath.every((entry) => typeof entry === "string")) && typeof candidate.multiEntry === "boolean" && typeof candidate.unique === "boolean";
660
+ }
661
+ function isValidIdbRecordSnapshot(value) {
662
+ if (!value || typeof value !== "object") return false;
663
+ return "key" in value && "value" in value;
664
+ }
665
+ function isValidIdbStoreSnapshot(value) {
666
+ if (!value || typeof value !== "object") return false;
667
+ const candidate = value;
668
+ const validKeyPath = candidate.keyPath === null || typeof candidate.keyPath === "string" || Array.isArray(candidate.keyPath) && candidate.keyPath.every((entry) => typeof entry === "string");
669
+ return typeof candidate.name === "string" && validKeyPath && typeof candidate.autoIncrement === "boolean" && Array.isArray(candidate.indexes) && candidate.indexes.every((entry) => isValidIdbIndexSnapshot(entry)) && Array.isArray(candidate.records) && candidate.records.every((entry) => isValidIdbRecordSnapshot(entry));
670
+ }
671
+ function isValidIdbDatabaseSnapshot(value) {
672
+ if (!value || typeof value !== "object") return false;
673
+ const candidate = value;
674
+ return typeof candidate.name === "string" && typeof candidate.version === "number" && Number.isFinite(candidate.version) && candidate.version > 0 && Array.isArray(candidate.stores) && candidate.stores.every((entry) => isValidIdbStoreSnapshot(entry));
675
+ }
676
+ function parseSnapshotPayload(data) {
677
+ const parsed = JSON.parse(data);
678
+ if (!Array.isArray(parsed) || parsed.length === 0) return null;
679
+ if (!parsed.every((entry) => isValidIdbDatabaseSnapshot(entry))) throw new Error("Malformed IndexedDB snapshot payload");
680
+ return parsed;
681
+ }
682
+ function idbReq(req) {
683
+ return new Promise((resolve, reject) => {
684
+ req.addEventListener("success", () => resolve(req.result), { once: true });
685
+ req.addEventListener("error", () => reject(req.error), { once: true });
686
+ });
687
+ }
688
+ async function dumpIndexedDatabases(databasePrefix) {
689
+ const idb = indexedDB;
690
+ const dbList = await idb.databases();
691
+ const snapshot = [];
692
+ const expectedPrefix = databasePrefix ? `${databasePrefix}::` : null;
693
+ for (const { name, version } of dbList) {
694
+ if (!name || !version) continue;
695
+ if (expectedPrefix && !name.startsWith(expectedPrefix)) continue;
696
+ const db = await new Promise((resolve, reject) => {
697
+ const r = idb.open(name, version);
698
+ r.addEventListener("success", () => resolve(r.result), { once: true });
699
+ r.addEventListener("error", () => reject(r.error), { once: true });
700
+ });
701
+ const stores = [];
702
+ for (const storeName of db.objectStoreNames) {
703
+ const store = db.transaction(storeName, "readonly").objectStore(storeName);
704
+ const storeInfo = {
705
+ name: storeName,
706
+ keyPath: store.keyPath,
707
+ autoIncrement: store.autoIncrement,
708
+ indexes: [],
709
+ records: []
710
+ };
711
+ for (const idxName of store.indexNames) {
712
+ const idx = store.index(idxName);
713
+ storeInfo.indexes.push({
714
+ name: idxName,
715
+ keyPath: idx.keyPath,
716
+ multiEntry: idx.multiEntry,
717
+ unique: idx.unique
718
+ });
719
+ }
720
+ const keys = await idbReq(store.getAllKeys());
721
+ const values = await idbReq(store.getAll());
722
+ storeInfo.records = keys.map((k, i) => ({
723
+ key: k,
724
+ value: values[i]
725
+ }));
726
+ stores.push(storeInfo);
727
+ }
728
+ snapshot.push({
729
+ name,
730
+ version,
731
+ stores
732
+ });
733
+ db.close();
734
+ }
735
+ return snapshot;
736
+ }
737
+ async function restoreIndexedDatabases(snapshot) {
738
+ const idb = indexedDB;
739
+ for (const dbSnap of snapshot) await new Promise((resolve, reject) => {
740
+ const r = idb.open(dbSnap.name, dbSnap.version);
741
+ r.addEventListener("upgradeneeded", () => {
742
+ const db = r.result;
743
+ for (const storeSnap of dbSnap.stores) {
744
+ const opts = {};
745
+ if (storeSnap.keyPath !== null) opts.keyPath = storeSnap.keyPath;
746
+ if (storeSnap.autoIncrement) opts.autoIncrement = true;
747
+ const store = db.createObjectStore(storeSnap.name, opts);
748
+ for (const idx of storeSnap.indexes) store.createIndex(idx.name, idx.keyPath, {
749
+ unique: idx.unique,
750
+ multiEntry: idx.multiEntry
751
+ });
752
+ }
753
+ });
754
+ r.addEventListener("success", () => {
755
+ (async () => {
756
+ const db = r.result;
757
+ for (const storeSnap of dbSnap.stores) {
758
+ if (storeSnap.records.length === 0) continue;
759
+ const tx = db.transaction(storeSnap.name, "readwrite");
760
+ const store = tx.objectStore(storeSnap.name);
761
+ for (const rec of storeSnap.records) if (storeSnap.keyPath !== null) store.put(rec.value);
762
+ else store.put(rec.value, rec.key);
763
+ await new Promise((res) => {
764
+ tx.addEventListener("complete", () => res(), { once: true });
765
+ });
766
+ }
767
+ db.close();
768
+ resolve();
769
+ })().catch(reject);
770
+ }, { once: true });
771
+ r.addEventListener("error", () => reject(r.error), { once: true });
772
+ });
773
+ }
774
+ function resolveDefaultIdbSnapshotPath() {
775
+ const stateDir = process.env.KLAW_STATE_DIR?.trim() || process.env.KLAW_STATE_DIR?.trim() || path.join(process.env.HOME || "/tmp", ".klaw");
776
+ return path.join(stateDir, "matrix", "crypto-idb-snapshot.json");
777
+ }
778
+ async function restoreIdbFromDisk(snapshotPath) {
779
+ const candidatePaths = snapshotPath ? [snapshotPath] : [resolveDefaultIdbSnapshotPath()];
780
+ for (const resolvedPath of candidatePaths) {
781
+ if (!fs.existsSync(resolvedPath)) continue;
782
+ try {
783
+ if (await withFileLock(resolvedPath, MATRIX_IDB_SNAPSHOT_LOCK_OPTIONS, async () => {
784
+ const snapshot = parseSnapshotPayload(fs.readFileSync(resolvedPath, "utf8"));
785
+ if (!snapshot) return false;
786
+ await restoreIndexedDatabases(snapshot);
787
+ LogService.info("IdbPersistence", `Restored ${snapshot.length} IndexedDB database(s) from ${resolvedPath}`);
788
+ return true;
789
+ })) return true;
790
+ } catch (err) {
791
+ LogService.warn("IdbPersistence", `Failed to restore IndexedDB snapshot from ${resolvedPath}:`, err);
792
+ continue;
793
+ }
794
+ }
795
+ return false;
796
+ }
797
+ async function persistIdbToDisk(params) {
798
+ const snapshotPath = params?.snapshotPath ?? resolveDefaultIdbSnapshotPath();
799
+ try {
800
+ fs.mkdirSync(path.dirname(snapshotPath), { recursive: true });
801
+ const persistedCount = await withFileLock(snapshotPath, MATRIX_IDB_SNAPSHOT_LOCK_OPTIONS, async () => {
802
+ const snapshot = await dumpIndexedDatabases(params?.databasePrefix);
803
+ if (snapshot.length === 0) return 0;
804
+ fs.writeFileSync(snapshotPath, JSON.stringify(snapshot));
805
+ fs.chmodSync(snapshotPath, 384);
806
+ return snapshot.length;
807
+ });
808
+ if (persistedCount === 0) return;
809
+ LogService.debug("IdbPersistence", `Persisted ${persistedCount} IndexedDB database(s) to ${snapshotPath}`);
810
+ } catch (err) {
811
+ LogService.warn("IdbPersistence", "Failed to persist IndexedDB snapshot:", err);
812
+ }
813
+ }
814
+ //#endregion
815
+ //#region extensions/matrix/src/matrix/sdk/verification-manager.ts
816
+ const MATRIX_VERIFICATION_PHASES = new Set([
817
+ -1,
818
+ VerificationPhase.Unsent,
819
+ VerificationPhase.Requested,
820
+ VerificationPhase.Ready,
821
+ VerificationPhase.Started,
822
+ VerificationPhase.Cancelled,
823
+ VerificationPhase.Done
824
+ ]);
825
+ function isMatrixVerificationPhase(value) {
826
+ return typeof value === "number" && MATRIX_VERIFICATION_PHASES.has(value);
827
+ }
828
+ const MAX_TRACKED_VERIFICATION_SESSIONS = 256;
829
+ const TERMINAL_SESSION_RETENTION_MS = 1440 * 60 * 1e3;
830
+ const SAS_AUTO_CONFIRM_DELAY_MS = 3e4;
831
+ var MatrixVerificationManager = class {
832
+ constructor(opts = {}) {
833
+ this.opts = opts;
834
+ this.verificationSessions = /* @__PURE__ */ new Map();
835
+ this.verificationSessionCounter = 0;
836
+ this.trackedVerificationRequests = /* @__PURE__ */ new WeakSet();
837
+ this.trackedVerificationVerifiers = /* @__PURE__ */ new WeakSet();
838
+ this.summaryListeners = /* @__PURE__ */ new Set();
839
+ }
840
+ readRequestValue(_request, reader, fallback) {
841
+ try {
842
+ return reader();
843
+ } catch {
844
+ return fallback;
845
+ }
846
+ }
847
+ readVerificationPhase(request, fallback) {
848
+ const phase = this.readRequestValue(request, () => request.phase, fallback);
849
+ return isMatrixVerificationPhase(phase) ? phase : fallback;
850
+ }
851
+ readVerificationRequestIdentity(request) {
852
+ return {
853
+ transactionId: this.readRequestValue(request, () => request.transactionId?.trim() ?? "", ""),
854
+ roomId: this.readRequestValue(request, () => request.roomId ?? "", ""),
855
+ otherUserId: this.readRequestValue(request, () => request.otherUserId, ""),
856
+ otherDeviceId: this.readRequestValue(request, () => request.otherDeviceId ?? "", ""),
857
+ isSelfVerification: this.readRequestValue(request, () => request.isSelfVerification, false),
858
+ initiatedByMe: this.readRequestValue(request, () => request.initiatedByMe, false)
859
+ };
860
+ }
861
+ isSameLogicalVerificationRequest(left, right) {
862
+ const leftIdentity = this.readVerificationRequestIdentity(left);
863
+ const rightIdentity = this.readVerificationRequestIdentity(right);
864
+ return leftIdentity.transactionId !== "" && leftIdentity.transactionId === rightIdentity.transactionId && leftIdentity.roomId === rightIdentity.roomId && leftIdentity.otherUserId === rightIdentity.otherUserId && this.isSameOptionalIdentityValue(leftIdentity.otherDeviceId, rightIdentity.otherDeviceId) && leftIdentity.isSelfVerification === rightIdentity.isSelfVerification && leftIdentity.initiatedByMe === rightIdentity.initiatedByMe;
865
+ }
866
+ isSameOptionalIdentityValue(left, right) {
867
+ return left === "" || right === "" || left === right;
868
+ }
869
+ pruneVerificationSessions(nowMs) {
870
+ for (const [id, session] of this.verificationSessions) {
871
+ const phase = this.readVerificationPhase(session.request, -1);
872
+ if ((phase === VerificationPhase.Done || phase === VerificationPhase.Cancelled) && nowMs - session.updatedAtMs > TERMINAL_SESSION_RETENTION_MS) this.verificationSessions.delete(id);
873
+ }
874
+ if (this.verificationSessions.size <= MAX_TRACKED_VERIFICATION_SESSIONS) return;
875
+ const sortedByAge = Array.from(this.verificationSessions.entries()).toSorted((a, b) => a[1].updatedAtMs - b[1].updatedAtMs);
876
+ const overflow = this.verificationSessions.size - MAX_TRACKED_VERIFICATION_SESSIONS;
877
+ for (let i = 0; i < overflow; i += 1) {
878
+ const entry = sortedByAge[i];
879
+ if (entry) this.verificationSessions.delete(entry[0]);
880
+ }
881
+ }
882
+ getVerificationPhaseName(phase) {
883
+ switch (phase) {
884
+ case VerificationPhase.Unsent: return "unsent";
885
+ case VerificationPhase.Requested: return "requested";
886
+ case VerificationPhase.Ready: return "ready";
887
+ case VerificationPhase.Started: return "started";
888
+ case VerificationPhase.Cancelled: return "cancelled";
889
+ case VerificationPhase.Done: return "done";
890
+ default: return `unknown(${phase})`;
891
+ }
892
+ }
893
+ emitVerificationSummary(session) {
894
+ const summary = this.buildVerificationSummary(session);
895
+ for (const listener of this.summaryListeners) listener(summary);
896
+ }
897
+ touchVerificationSession(session) {
898
+ session.updatedAtMs = Date.now();
899
+ this.emitVerificationSummary(session);
900
+ }
901
+ clearSasAutoConfirmTimer(session) {
902
+ if (!session.sasAutoConfirmTimer) return;
903
+ clearTimeout(session.sasAutoConfirmTimer);
904
+ session.sasAutoConfirmTimer = void 0;
905
+ }
906
+ buildVerificationSummary(session) {
907
+ const request = session.request;
908
+ const phase = this.readVerificationPhase(request, VerificationPhase.Requested);
909
+ const accepting = this.readRequestValue(request, () => request.accepting, false);
910
+ const declining = this.readRequestValue(request, () => request.declining, false);
911
+ const pending = this.readRequestValue(request, () => request.pending, false);
912
+ const methodsRaw = this.readRequestValue(request, () => request.methods, []);
913
+ const methods = Array.isArray(methodsRaw) ? methodsRaw.filter((entry) => typeof entry === "string") : [];
914
+ const sasCallbacks = session.sasCallbacks ?? session.activeVerifier?.getShowSasCallbacks();
915
+ if (sasCallbacks) session.sasCallbacks = sasCallbacks;
916
+ const canAccept = phase < VerificationPhase.Ready && !accepting && !declining;
917
+ return {
918
+ id: session.id,
919
+ transactionId: this.readRequestValue(request, () => request.transactionId, void 0),
920
+ roomId: this.readRequestValue(request, () => request.roomId, void 0),
921
+ otherUserId: this.readRequestValue(request, () => request.otherUserId, "unknown"),
922
+ otherDeviceId: this.readRequestValue(request, () => request.otherDeviceId, void 0),
923
+ isSelfVerification: this.readRequestValue(request, () => request.isSelfVerification, false),
924
+ initiatedByMe: this.readRequestValue(request, () => request.initiatedByMe, false),
925
+ phase,
926
+ phaseName: this.getVerificationPhaseName(phase),
927
+ pending,
928
+ methods,
929
+ chosenMethod: this.readRequestValue(request, () => request.chosenMethod ?? null, null),
930
+ canAccept,
931
+ hasSas: Boolean(sasCallbacks),
932
+ sas: sasCallbacks ? {
933
+ decimal: sasCallbacks.sas.decimal,
934
+ emoji: sasCallbacks.sas.emoji
935
+ } : void 0,
936
+ hasReciprocateQr: Boolean(session.reciprocateQrCallbacks),
937
+ completed: phase === VerificationPhase.Done,
938
+ error: session.error,
939
+ createdAt: new Date(session.createdAtMs).toISOString(),
940
+ updatedAt: new Date(session.updatedAtMs).toISOString()
941
+ };
942
+ }
943
+ findVerificationSession(id) {
944
+ const direct = this.verificationSessions.get(id);
945
+ if (direct) return direct;
946
+ const transactionMatches = Array.from(this.verificationSessions.values()).filter((session) => {
947
+ return this.readRequestValue(session.request, () => session.request.transactionId?.trim(), "") === id;
948
+ });
949
+ if (transactionMatches.length === 1) return transactionMatches[0];
950
+ if (transactionMatches.length > 1) throw new Error(`Matrix verification request id is ambiguous for transaction ${id}; use the verification id instead`);
951
+ throw new Error(`Matrix verification request not found: ${id}`);
952
+ }
953
+ ensureVerificationRequestTracked(session) {
954
+ const requestObj = session.request;
955
+ if (this.trackedVerificationRequests.has(requestObj)) return;
956
+ this.trackedVerificationRequests.add(requestObj);
957
+ session.request.on(VerificationRequestEvent.Change, () => {
958
+ this.touchVerificationSession(session);
959
+ this.maybeAutoAcceptInboundRequest(session);
960
+ const verifier = this.readRequestValue(session.request, () => session.request.verifier, null);
961
+ if (verifier) this.attachVerifierToVerificationSession(session, verifier);
962
+ this.maybeAutoStartInboundSas(session);
963
+ });
964
+ }
965
+ maybeAutoAcceptInboundRequest(session) {
966
+ if (session.acceptRequested) return;
967
+ const request = session.request;
968
+ const isSelfVerification = this.readRequestValue(request, () => request.isSelfVerification, false);
969
+ const initiatedByMe = this.readRequestValue(request, () => request.initiatedByMe, false);
970
+ const phase = this.readVerificationPhase(request, VerificationPhase.Requested);
971
+ const accepting = this.readRequestValue(request, () => request.accepting, false);
972
+ const declining = this.readRequestValue(request, () => request.declining, false);
973
+ if (isSelfVerification || initiatedByMe) return;
974
+ if (phase !== VerificationPhase.Requested || accepting || declining) return;
975
+ session.acceptRequested = true;
976
+ request.accept().then(() => {
977
+ this.touchVerificationSession(session);
978
+ }).catch((err) => {
979
+ session.acceptRequested = false;
980
+ session.error = formatMatrixErrorMessage(err);
981
+ this.touchVerificationSession(session);
982
+ });
983
+ }
984
+ maybeAutoStartInboundSas(session) {
985
+ if (session.activeVerifier || session.verifyStarted || session.startRequested) return;
986
+ if (this.readRequestValue(session.request, () => session.request.initiatedByMe, true)) return;
987
+ if (!this.readRequestValue(session.request, () => session.request.isSelfVerification, false)) return;
988
+ const phase = this.readVerificationPhase(session.request, VerificationPhase.Requested);
989
+ if (phase < VerificationPhase.Ready || phase >= VerificationPhase.Cancelled) return;
990
+ const methodsRaw = this.readRequestValue(session.request, () => session.request.methods, []);
991
+ const methods = Array.isArray(methodsRaw) ? methodsRaw.filter((entry) => typeof entry === "string") : [];
992
+ const chosenMethod = this.readRequestValue(session.request, () => session.request.chosenMethod, null);
993
+ if (!(methods.includes(VerificationMethod.Sas) || chosenMethod === VerificationMethod.Sas)) return;
994
+ session.startRequested = true;
995
+ session.request.startVerification(VerificationMethod.Sas).then((verifier) => {
996
+ this.attachVerifierToVerificationSession(session, verifier);
997
+ this.touchVerificationSession(session);
998
+ }).catch(() => {
999
+ session.startRequested = false;
1000
+ });
1001
+ }
1002
+ attachVerifierToVerificationSession(session, verifier) {
1003
+ session.activeVerifier = verifier;
1004
+ this.touchVerificationSession(session);
1005
+ const maybeSas = verifier.getShowSasCallbacks();
1006
+ if (maybeSas) {
1007
+ session.sasCallbacks = maybeSas;
1008
+ this.maybeAutoConfirmSas(session);
1009
+ }
1010
+ const maybeReciprocateQr = verifier.getReciprocateQrCodeCallbacks();
1011
+ if (maybeReciprocateQr) session.reciprocateQrCallbacks = maybeReciprocateQr;
1012
+ const verifierObj = verifier;
1013
+ if (this.trackedVerificationVerifiers.has(verifierObj)) {
1014
+ this.ensureVerificationStarted(session);
1015
+ return;
1016
+ }
1017
+ this.trackedVerificationVerifiers.add(verifierObj);
1018
+ verifier.on(VerifierEvent.ShowSas, (sas) => {
1019
+ session.sasCallbacks = sas;
1020
+ this.touchVerificationSession(session);
1021
+ this.maybeAutoConfirmSas(session);
1022
+ });
1023
+ verifier.on(VerifierEvent.ShowReciprocateQr, (qr) => {
1024
+ session.reciprocateQrCallbacks = qr;
1025
+ this.touchVerificationSession(session);
1026
+ });
1027
+ verifier.on(VerifierEvent.Cancel, (err) => {
1028
+ this.clearSasAutoConfirmTimer(session);
1029
+ session.error = formatMatrixErrorMessage(err);
1030
+ this.touchVerificationSession(session);
1031
+ });
1032
+ this.ensureVerificationStarted(session);
1033
+ }
1034
+ maybeAutoConfirmSas(session) {
1035
+ if (session.sasAutoConfirmStarted || session.sasAutoConfirmTimer) return;
1036
+ if (this.readRequestValue(session.request, () => session.request.initiatedByMe, true)) return;
1037
+ const callbacks = session.sasCallbacks ?? session.activeVerifier?.getShowSasCallbacks();
1038
+ if (!callbacks) return;
1039
+ session.sasCallbacks = callbacks;
1040
+ session.sasAutoConfirmTimer = setTimeout(() => {
1041
+ session.sasAutoConfirmTimer = void 0;
1042
+ if (this.readVerificationPhase(session.request, VerificationPhase.Requested) >= VerificationPhase.Cancelled) return;
1043
+ session.sasAutoConfirmStarted = true;
1044
+ this.confirmSasForSession(session, callbacks, { trustOwnDevice: true }).then(() => {
1045
+ this.touchVerificationSession(session);
1046
+ }).catch((err) => {
1047
+ session.error = formatMatrixErrorMessage(err);
1048
+ this.touchVerificationSession(session);
1049
+ });
1050
+ }, SAS_AUTO_CONFIRM_DELAY_MS);
1051
+ }
1052
+ async confirmSasForSession(session, callbacks, opts = { trustOwnDevice: true }) {
1053
+ await callbacks.confirm();
1054
+ if (opts.trustOwnDevice) await this.trustOwnDeviceAfterConfirmedSas(session);
1055
+ }
1056
+ ensureVerificationStarted(session) {
1057
+ if (!session.activeVerifier || session.verifyStarted) return;
1058
+ session.verifyStarted = true;
1059
+ session.verifyPromise = session.activeVerifier.verify().then(() => {
1060
+ this.touchVerificationSession(session);
1061
+ }).catch((err) => {
1062
+ session.error = formatMatrixErrorMessage(err);
1063
+ this.touchVerificationSession(session);
1064
+ });
1065
+ }
1066
+ async trustOwnDeviceAfterConfirmedSas(session) {
1067
+ if (!this.readRequestValue(session.request, () => session.request.isSelfVerification, false)) return;
1068
+ const deviceId = this.readRequestValue(session.request, () => session.request.otherDeviceId?.trim(), "");
1069
+ if (!deviceId || !this.opts.trustOwnDeviceAfterSas) return;
1070
+ await this.opts.trustOwnDeviceAfterSas(deviceId);
1071
+ }
1072
+ onSummaryChanged(listener) {
1073
+ this.summaryListeners.add(listener);
1074
+ return () => {
1075
+ this.summaryListeners.delete(listener);
1076
+ };
1077
+ }
1078
+ trackVerificationRequest(request) {
1079
+ this.pruneVerificationSessions(Date.now());
1080
+ const requestObj = request;
1081
+ for (const existing of this.verificationSessions.values()) if (existing.request === requestObj) {
1082
+ this.touchVerificationSession(existing);
1083
+ return this.buildVerificationSummary(existing);
1084
+ }
1085
+ if (this.readVerificationRequestIdentity(request).transactionId) {
1086
+ for (const existing of this.verificationSessions.values()) if (this.isSameLogicalVerificationRequest(existing.request, request)) {
1087
+ existing.request = request;
1088
+ this.ensureVerificationRequestTracked(existing);
1089
+ const verifier = this.readRequestValue(request, () => request.verifier, null);
1090
+ if (verifier) this.attachVerifierToVerificationSession(existing, verifier);
1091
+ this.touchVerificationSession(existing);
1092
+ return this.buildVerificationSummary(existing);
1093
+ }
1094
+ }
1095
+ const now = Date.now();
1096
+ const session = {
1097
+ id: `verification-${++this.verificationSessionCounter}`,
1098
+ request,
1099
+ createdAtMs: now,
1100
+ updatedAtMs: now,
1101
+ verifyStarted: false,
1102
+ startRequested: false,
1103
+ acceptRequested: false,
1104
+ sasAutoConfirmStarted: false
1105
+ };
1106
+ this.verificationSessions.set(session.id, session);
1107
+ this.ensureVerificationRequestTracked(session);
1108
+ this.maybeAutoAcceptInboundRequest(session);
1109
+ const verifier = this.readRequestValue(request, () => request.verifier, null);
1110
+ if (verifier) this.attachVerifierToVerificationSession(session, verifier);
1111
+ this.maybeAutoStartInboundSas(session);
1112
+ this.emitVerificationSummary(session);
1113
+ return this.buildVerificationSummary(session);
1114
+ }
1115
+ async requestOwnUserVerification(crypto) {
1116
+ if (!crypto) return null;
1117
+ const request = await crypto.requestOwnUserVerification();
1118
+ if (!request) return null;
1119
+ return this.trackVerificationRequest(request);
1120
+ }
1121
+ listVerifications() {
1122
+ this.pruneVerificationSessions(Date.now());
1123
+ return Array.from(this.verificationSessions.values()).map((session) => this.buildVerificationSummary(session)).toSorted((a, b) => b.updatedAt.localeCompare(a.updatedAt));
1124
+ }
1125
+ async requestVerification(crypto, params) {
1126
+ if (!crypto) throw new Error("Matrix crypto is not available");
1127
+ let request = null;
1128
+ if (params.ownUser) request = await crypto.requestOwnUserVerification();
1129
+ else if (params.userId && params.deviceId && crypto.requestDeviceVerification) request = await crypto.requestDeviceVerification(params.userId, params.deviceId);
1130
+ else if (params.userId && params.roomId && crypto.requestVerificationDM) request = await crypto.requestVerificationDM(params.userId, params.roomId);
1131
+ else throw new Error("Matrix verification request requires one of: ownUser, userId+deviceId, or userId+roomId");
1132
+ if (!request) throw new Error("Matrix verification request could not be created");
1133
+ return this.trackVerificationRequest(request);
1134
+ }
1135
+ async acceptVerification(id) {
1136
+ const session = this.findVerificationSession(id);
1137
+ await session.request.accept();
1138
+ this.touchVerificationSession(session);
1139
+ return this.buildVerificationSummary(session);
1140
+ }
1141
+ async cancelVerification(id, params) {
1142
+ const session = this.findVerificationSession(id);
1143
+ await session.request.cancel(params);
1144
+ this.touchVerificationSession(session);
1145
+ return this.buildVerificationSummary(session);
1146
+ }
1147
+ async startVerification(id, method = "sas") {
1148
+ const session = this.findVerificationSession(id);
1149
+ if (method !== "sas") throw new Error("Matrix startVerification currently supports only SAS directly");
1150
+ const verifier = await session.request.startVerification(VerificationMethod.Sas);
1151
+ this.attachVerifierToVerificationSession(session, verifier);
1152
+ this.ensureVerificationStarted(session);
1153
+ return this.buildVerificationSummary(session);
1154
+ }
1155
+ async generateVerificationQr(id) {
1156
+ const qr = await this.findVerificationSession(id).request.generateQRCode();
1157
+ if (!qr) throw new Error("Matrix verification QR data is not available yet");
1158
+ return { qrDataBase64: Buffer.from(qr).toString("base64") };
1159
+ }
1160
+ async scanVerificationQr(id, qrDataBase64) {
1161
+ const session = this.findVerificationSession(id);
1162
+ const trimmed = qrDataBase64.trim();
1163
+ if (!trimmed) throw new Error("Matrix verification QR payload is required");
1164
+ const qrBytes = Buffer.from(trimmed, "base64");
1165
+ if (qrBytes.length === 0) throw new Error("Matrix verification QR payload is invalid base64");
1166
+ const verifier = await session.request.scanQRCode(new Uint8ClampedArray(qrBytes));
1167
+ this.attachVerifierToVerificationSession(session, verifier);
1168
+ this.ensureVerificationStarted(session);
1169
+ return this.buildVerificationSummary(session);
1170
+ }
1171
+ async confirmVerificationSas(id) {
1172
+ const session = this.findVerificationSession(id);
1173
+ const callbacks = session.sasCallbacks ?? session.activeVerifier?.getShowSasCallbacks();
1174
+ if (!callbacks) throw new Error("Matrix SAS confirmation is not available for this verification request");
1175
+ this.clearSasAutoConfirmTimer(session);
1176
+ session.sasCallbacks = callbacks;
1177
+ session.sasAutoConfirmStarted = true;
1178
+ await this.confirmSasForSession(session, callbacks);
1179
+ if (session.verifyPromise) await session.verifyPromise;
1180
+ this.touchVerificationSession(session);
1181
+ return this.buildVerificationSummary(session);
1182
+ }
1183
+ mismatchVerificationSas(id) {
1184
+ const session = this.findVerificationSession(id);
1185
+ const callbacks = session.sasCallbacks ?? session.activeVerifier?.getShowSasCallbacks();
1186
+ if (!callbacks) throw new Error("Matrix SAS mismatch is not available for this verification request");
1187
+ this.clearSasAutoConfirmTimer(session);
1188
+ session.sasCallbacks = callbacks;
1189
+ callbacks.mismatch();
1190
+ this.touchVerificationSession(session);
1191
+ return this.buildVerificationSummary(session);
1192
+ }
1193
+ confirmVerificationReciprocateQr(id) {
1194
+ const session = this.findVerificationSession(id);
1195
+ const callbacks = session.reciprocateQrCallbacks ?? session.activeVerifier?.getReciprocateQrCodeCallbacks();
1196
+ if (!callbacks) throw new Error("Matrix reciprocate-QR confirmation is not available for this verification request");
1197
+ session.reciprocateQrCallbacks = callbacks;
1198
+ callbacks.confirm();
1199
+ this.touchVerificationSession(session);
1200
+ return this.buildVerificationSummary(session);
1201
+ }
1202
+ getVerificationSas(id) {
1203
+ const session = this.findVerificationSession(id);
1204
+ const callbacks = session.sasCallbacks ?? session.activeVerifier?.getShowSasCallbacks();
1205
+ if (!callbacks) throw new Error("Matrix SAS data is not available for this verification request");
1206
+ session.sasCallbacks = callbacks;
1207
+ return {
1208
+ decimal: callbacks.sas.decimal,
1209
+ emoji: callbacks.sas.emoji
1210
+ };
1211
+ }
1212
+ };
1213
+ //#endregion
1214
+ export { MatrixCryptoBootstrapper, MatrixDecryptBridge, MatrixVerificationManager, createMatrixCryptoFacade, isMatrixDeviceOwnerVerified, isMatrixDeviceVerifiedInCurrentClient, persistIdbToDisk, restoreIdbFromDisk };