@unwanted/matrix-sdk-mini 34.12.0-1 → 34.12.0-3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (636) hide show
  1. package/git-revision.txt +1 -1
  2. package/lib/@types/event.d.ts +0 -19
  3. package/lib/@types/event.d.ts.map +1 -1
  4. package/lib/@types/event.js.map +1 -1
  5. package/lib/@types/global.d.js +0 -2
  6. package/lib/@types/global.d.js.map +1 -1
  7. package/lib/browser-index.d.ts.map +1 -1
  8. package/lib/browser-index.js +0 -11
  9. package/lib/browser-index.js.map +1 -1
  10. package/lib/client.d.ts +2 -1224
  11. package/lib/client.d.ts.map +1 -1
  12. package/lib/client.js +345 -2826
  13. package/lib/client.js.map +1 -1
  14. package/lib/embedded.d.ts +0 -22
  15. package/lib/embedded.d.ts.map +1 -1
  16. package/lib/embedded.js +24 -167
  17. package/lib/embedded.js.map +1 -1
  18. package/lib/event-mapper.d.ts.map +1 -1
  19. package/lib/event-mapper.js +0 -4
  20. package/lib/event-mapper.js.map +1 -1
  21. package/lib/matrix.d.ts +0 -25
  22. package/lib/matrix.d.ts.map +1 -1
  23. package/lib/matrix.js +1 -30
  24. package/lib/matrix.js.map +1 -1
  25. package/lib/models/MSC3089Branch.d.ts.map +1 -1
  26. package/lib/models/MSC3089Branch.js +0 -3
  27. package/lib/models/MSC3089Branch.js.map +1 -1
  28. package/lib/models/event.d.ts +0 -94
  29. package/lib/models/event.d.ts.map +1 -1
  30. package/lib/models/event.js +0 -274
  31. package/lib/models/event.js.map +1 -1
  32. package/lib/models/poll.d.ts.map +1 -1
  33. package/lib/models/poll.js +1 -5
  34. package/lib/models/poll.js.map +1 -1
  35. package/lib/models/relations-container.d.ts.map +1 -1
  36. package/lib/models/relations-container.js +1 -7
  37. package/lib/models/relations-container.js.map +1 -1
  38. package/lib/models/relations.d.ts +0 -1
  39. package/lib/models/relations.d.ts.map +1 -1
  40. package/lib/models/relations.js +0 -8
  41. package/lib/models/relations.js.map +1 -1
  42. package/lib/models/room-state.d.ts.map +1 -1
  43. package/lib/models/room-state.js +10 -26
  44. package/lib/models/room-state.js.map +1 -1
  45. package/lib/models/room.d.ts +0 -18
  46. package/lib/models/room.d.ts.map +1 -1
  47. package/lib/models/room.js +94 -148
  48. package/lib/models/room.js.map +1 -1
  49. package/lib/models/thread.d.ts.map +1 -1
  50. package/lib/models/thread.js +0 -1
  51. package/lib/models/thread.js.map +1 -1
  52. package/lib/sliding-sync-sdk.d.ts +2 -3
  53. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  54. package/lib/sliding-sync-sdk.js +41 -90
  55. package/lib/sliding-sync-sdk.js.map +1 -1
  56. package/lib/sync.d.ts +0 -12
  57. package/lib/sync.d.ts.map +1 -1
  58. package/lib/sync.js +1 -73
  59. package/lib/sync.js.map +1 -1
  60. package/lib/testing.d.ts +0 -48
  61. package/lib/testing.d.ts.map +1 -1
  62. package/lib/testing.js +0 -105
  63. package/lib/testing.js.map +1 -1
  64. package/package.json +1 -3
  65. package/src/@types/event.ts +2 -36
  66. package/src/@types/global.d.ts +0 -3
  67. package/src/browser-index.ts +0 -11
  68. package/src/client.ts +52 -2876
  69. package/src/embedded.ts +3 -132
  70. package/src/event-mapper.ts +0 -4
  71. package/src/matrix.ts +0 -41
  72. package/src/models/MSC3089Branch.ts +0 -3
  73. package/src/models/event.ts +0 -289
  74. package/src/models/poll.ts +0 -6
  75. package/src/models/relations-container.ts +1 -8
  76. package/src/models/relations.ts +0 -8
  77. package/src/models/room-state.ts +2 -8
  78. package/src/models/room.ts +0 -62
  79. package/src/models/thread.ts +0 -1
  80. package/src/sliding-sync-sdk.ts +2 -72
  81. package/src/sync.ts +1 -98
  82. package/src/testing.ts +0 -108
  83. package/lib/@types/crypto.d.ts +0 -47
  84. package/lib/@types/crypto.d.ts.map +0 -1
  85. package/lib/@types/crypto.js +0 -1
  86. package/lib/@types/crypto.js.map +0 -1
  87. package/lib/@types/matrix-sdk-crypto-wasm.d.js +0 -1
  88. package/lib/@types/matrix-sdk-crypto-wasm.d.js.map +0 -1
  89. package/lib/common-crypto/CryptoBackend.d.ts +0 -240
  90. package/lib/common-crypto/CryptoBackend.d.ts.map +0 -1
  91. package/lib/common-crypto/CryptoBackend.js +0 -73
  92. package/lib/common-crypto/CryptoBackend.js.map +0 -1
  93. package/lib/common-crypto/key-passphrase.d.ts +0 -14
  94. package/lib/common-crypto/key-passphrase.d.ts.map +0 -1
  95. package/lib/common-crypto/key-passphrase.js +0 -33
  96. package/lib/common-crypto/key-passphrase.js.map +0 -1
  97. package/lib/crypto/CrossSigning.d.ts +0 -184
  98. package/lib/crypto/CrossSigning.d.ts.map +0 -1
  99. package/lib/crypto/CrossSigning.js +0 -718
  100. package/lib/crypto/CrossSigning.js.map +0 -1
  101. package/lib/crypto/DeviceList.d.ts +0 -216
  102. package/lib/crypto/DeviceList.d.ts.map +0 -1
  103. package/lib/crypto/DeviceList.js +0 -892
  104. package/lib/crypto/DeviceList.js.map +0 -1
  105. package/lib/crypto/EncryptionSetup.d.ts +0 -152
  106. package/lib/crypto/EncryptionSetup.d.ts.map +0 -1
  107. package/lib/crypto/EncryptionSetup.js +0 -356
  108. package/lib/crypto/EncryptionSetup.js.map +0 -1
  109. package/lib/crypto/OlmDevice.d.ts +0 -457
  110. package/lib/crypto/OlmDevice.d.ts.map +0 -1
  111. package/lib/crypto/OlmDevice.js +0 -1241
  112. package/lib/crypto/OlmDevice.js.map +0 -1
  113. package/lib/crypto/OutgoingRoomKeyRequestManager.d.ts +0 -109
  114. package/lib/crypto/OutgoingRoomKeyRequestManager.d.ts.map +0 -1
  115. package/lib/crypto/OutgoingRoomKeyRequestManager.js +0 -415
  116. package/lib/crypto/OutgoingRoomKeyRequestManager.js.map +0 -1
  117. package/lib/crypto/RoomList.d.ts +0 -26
  118. package/lib/crypto/RoomList.d.ts.map +0 -1
  119. package/lib/crypto/RoomList.js +0 -71
  120. package/lib/crypto/RoomList.js.map +0 -1
  121. package/lib/crypto/SecretSharing.d.ts +0 -24
  122. package/lib/crypto/SecretSharing.d.ts.map +0 -1
  123. package/lib/crypto/SecretSharing.js +0 -194
  124. package/lib/crypto/SecretSharing.js.map +0 -1
  125. package/lib/crypto/SecretStorage.d.ts +0 -55
  126. package/lib/crypto/SecretStorage.d.ts.map +0 -1
  127. package/lib/crypto/SecretStorage.js +0 -118
  128. package/lib/crypto/SecretStorage.js.map +0 -1
  129. package/lib/crypto/aes.d.ts +0 -6
  130. package/lib/crypto/aes.d.ts.map +0 -1
  131. package/lib/crypto/aes.js +0 -24
  132. package/lib/crypto/aes.js.map +0 -1
  133. package/lib/crypto/algorithms/base.d.ts +0 -156
  134. package/lib/crypto/algorithms/base.d.ts.map +0 -1
  135. package/lib/crypto/algorithms/base.js +0 -187
  136. package/lib/crypto/algorithms/base.js.map +0 -1
  137. package/lib/crypto/algorithms/index.d.ts +0 -4
  138. package/lib/crypto/algorithms/index.d.ts.map +0 -1
  139. package/lib/crypto/algorithms/index.js +0 -20
  140. package/lib/crypto/algorithms/index.js.map +0 -1
  141. package/lib/crypto/algorithms/megolm.d.ts +0 -385
  142. package/lib/crypto/algorithms/megolm.d.ts.map +0 -1
  143. package/lib/crypto/algorithms/megolm.js +0 -1822
  144. package/lib/crypto/algorithms/megolm.js.map +0 -1
  145. package/lib/crypto/algorithms/olm.d.ts +0 -5
  146. package/lib/crypto/algorithms/olm.d.ts.map +0 -1
  147. package/lib/crypto/algorithms/olm.js +0 -299
  148. package/lib/crypto/algorithms/olm.js.map +0 -1
  149. package/lib/crypto/api.d.ts +0 -32
  150. package/lib/crypto/api.d.ts.map +0 -1
  151. package/lib/crypto/api.js +0 -22
  152. package/lib/crypto/api.js.map +0 -1
  153. package/lib/crypto/backup.d.ts +0 -227
  154. package/lib/crypto/backup.d.ts.map +0 -1
  155. package/lib/crypto/backup.js +0 -824
  156. package/lib/crypto/backup.js.map +0 -1
  157. package/lib/crypto/crypto.d.ts +0 -3
  158. package/lib/crypto/crypto.d.ts.map +0 -1
  159. package/lib/crypto/crypto.js +0 -19
  160. package/lib/crypto/crypto.js.map +0 -1
  161. package/lib/crypto/dehydration.d.ts +0 -34
  162. package/lib/crypto/dehydration.d.ts.map +0 -1
  163. package/lib/crypto/dehydration.js +0 -252
  164. package/lib/crypto/dehydration.js.map +0 -1
  165. package/lib/crypto/device-converter.d.ts +0 -9
  166. package/lib/crypto/device-converter.d.ts.map +0 -1
  167. package/lib/crypto/device-converter.js +0 -42
  168. package/lib/crypto/device-converter.js.map +0 -1
  169. package/lib/crypto/deviceinfo.d.ts +0 -99
  170. package/lib/crypto/deviceinfo.d.ts.map +0 -1
  171. package/lib/crypto/deviceinfo.js +0 -148
  172. package/lib/crypto/deviceinfo.js.map +0 -1
  173. package/lib/crypto/index.d.ts +0 -1209
  174. package/lib/crypto/index.d.ts.map +0 -1
  175. package/lib/crypto/index.js +0 -4097
  176. package/lib/crypto/index.js.map +0 -1
  177. package/lib/crypto/key_passphrase.d.ts +0 -14
  178. package/lib/crypto/key_passphrase.d.ts.map +0 -1
  179. package/lib/crypto/key_passphrase.js +0 -44
  180. package/lib/crypto/key_passphrase.js.map +0 -1
  181. package/lib/crypto/keybackup.d.ts +0 -18
  182. package/lib/crypto/keybackup.d.ts.map +0 -1
  183. package/lib/crypto/keybackup.js +0 -1
  184. package/lib/crypto/keybackup.js.map +0 -1
  185. package/lib/crypto/olmlib.d.ts +0 -129
  186. package/lib/crypto/olmlib.d.ts.map +0 -1
  187. package/lib/crypto/olmlib.js +0 -492
  188. package/lib/crypto/olmlib.js.map +0 -1
  189. package/lib/crypto/recoverykey.d.ts +0 -2
  190. package/lib/crypto/recoverykey.d.ts.map +0 -1
  191. package/lib/crypto/recoverykey.js +0 -19
  192. package/lib/crypto/recoverykey.js.map +0 -1
  193. package/lib/crypto/store/base.d.ts +0 -252
  194. package/lib/crypto/store/base.d.ts.map +0 -1
  195. package/lib/crypto/store/base.js +0 -64
  196. package/lib/crypto/store/base.js.map +0 -1
  197. package/lib/crypto/store/indexeddb-crypto-store-backend.d.ts +0 -187
  198. package/lib/crypto/store/indexeddb-crypto-store-backend.d.ts.map +0 -1
  199. package/lib/crypto/store/indexeddb-crypto-store-backend.js +0 -1145
  200. package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +0 -1
  201. package/lib/crypto/store/indexeddb-crypto-store.d.ts +0 -432
  202. package/lib/crypto/store/indexeddb-crypto-store.d.ts.map +0 -1
  203. package/lib/crypto/store/indexeddb-crypto-store.js +0 -728
  204. package/lib/crypto/store/indexeddb-crypto-store.js.map +0 -1
  205. package/lib/crypto/store/localStorage-crypto-store.d.ts +0 -119
  206. package/lib/crypto/store/localStorage-crypto-store.d.ts.map +0 -1
  207. package/lib/crypto/store/localStorage-crypto-store.js +0 -531
  208. package/lib/crypto/store/localStorage-crypto-store.js.map +0 -1
  209. package/lib/crypto/store/memory-crypto-store.d.ts +0 -215
  210. package/lib/crypto/store/memory-crypto-store.d.ts.map +0 -1
  211. package/lib/crypto/store/memory-crypto-store.js +0 -622
  212. package/lib/crypto/store/memory-crypto-store.js.map +0 -1
  213. package/lib/crypto/verification/Base.d.ts +0 -105
  214. package/lib/crypto/verification/Base.d.ts.map +0 -1
  215. package/lib/crypto/verification/Base.js +0 -372
  216. package/lib/crypto/verification/Base.js.map +0 -1
  217. package/lib/crypto/verification/Error.d.ts +0 -35
  218. package/lib/crypto/verification/Error.d.ts.map +0 -1
  219. package/lib/crypto/verification/Error.js +0 -86
  220. package/lib/crypto/verification/Error.js.map +0 -1
  221. package/lib/crypto/verification/IllegalMethod.d.ts +0 -15
  222. package/lib/crypto/verification/IllegalMethod.d.ts.map +0 -1
  223. package/lib/crypto/verification/IllegalMethod.js +0 -43
  224. package/lib/crypto/verification/IllegalMethod.js.map +0 -1
  225. package/lib/crypto/verification/QRCode.d.ts +0 -51
  226. package/lib/crypto/verification/QRCode.d.ts.map +0 -1
  227. package/lib/crypto/verification/QRCode.js +0 -277
  228. package/lib/crypto/verification/QRCode.js.map +0 -1
  229. package/lib/crypto/verification/SAS.d.ts +0 -27
  230. package/lib/crypto/verification/SAS.d.ts.map +0 -1
  231. package/lib/crypto/verification/SAS.js +0 -485
  232. package/lib/crypto/verification/SAS.js.map +0 -1
  233. package/lib/crypto/verification/SASDecimal.d.ts +0 -8
  234. package/lib/crypto/verification/SASDecimal.d.ts.map +0 -1
  235. package/lib/crypto/verification/SASDecimal.js +0 -34
  236. package/lib/crypto/verification/SASDecimal.js.map +0 -1
  237. package/lib/crypto/verification/request/Channel.d.ts +0 -18
  238. package/lib/crypto/verification/request/Channel.d.ts.map +0 -1
  239. package/lib/crypto/verification/request/Channel.js +0 -1
  240. package/lib/crypto/verification/request/Channel.js.map +0 -1
  241. package/lib/crypto/verification/request/InRoomChannel.d.ts +0 -113
  242. package/lib/crypto/verification/request/InRoomChannel.d.ts.map +0 -1
  243. package/lib/crypto/verification/request/InRoomChannel.js +0 -351
  244. package/lib/crypto/verification/request/InRoomChannel.js.map +0 -1
  245. package/lib/crypto/verification/request/ToDeviceChannel.d.ts +0 -105
  246. package/lib/crypto/verification/request/ToDeviceChannel.d.ts.map +0 -1
  247. package/lib/crypto/verification/request/ToDeviceChannel.js +0 -328
  248. package/lib/crypto/verification/request/ToDeviceChannel.js.map +0 -1
  249. package/lib/crypto/verification/request/VerificationRequest.d.ts +0 -227
  250. package/lib/crypto/verification/request/VerificationRequest.d.ts.map +0 -1
  251. package/lib/crypto/verification/request/VerificationRequest.js +0 -937
  252. package/lib/crypto/verification/request/VerificationRequest.js.map +0 -1
  253. package/lib/crypto-api/CryptoEvent.d.ts +0 -69
  254. package/lib/crypto-api/CryptoEvent.d.ts.map +0 -1
  255. package/lib/crypto-api/CryptoEvent.js +0 -33
  256. package/lib/crypto-api/CryptoEvent.js.map +0 -1
  257. package/lib/crypto-api/CryptoEventHandlerMap.d.ts +0 -16
  258. package/lib/crypto-api/CryptoEventHandlerMap.d.ts.map +0 -1
  259. package/lib/crypto-api/CryptoEventHandlerMap.js +0 -22
  260. package/lib/crypto-api/CryptoEventHandlerMap.js.map +0 -1
  261. package/lib/crypto-api/index.d.ts +0 -978
  262. package/lib/crypto-api/index.d.ts.map +0 -1
  263. package/lib/crypto-api/index.js +0 -304
  264. package/lib/crypto-api/index.js.map +0 -1
  265. package/lib/crypto-api/key-passphrase.d.ts +0 -11
  266. package/lib/crypto-api/key-passphrase.d.ts.map +0 -1
  267. package/lib/crypto-api/key-passphrase.js +0 -51
  268. package/lib/crypto-api/key-passphrase.js.map +0 -1
  269. package/lib/crypto-api/keybackup.d.ts +0 -88
  270. package/lib/crypto-api/keybackup.d.ts.map +0 -1
  271. package/lib/crypto-api/keybackup.js +0 -1
  272. package/lib/crypto-api/keybackup.js.map +0 -1
  273. package/lib/crypto-api/recovery-key.d.ts +0 -11
  274. package/lib/crypto-api/recovery-key.d.ts.map +0 -1
  275. package/lib/crypto-api/recovery-key.js +0 -65
  276. package/lib/crypto-api/recovery-key.js.map +0 -1
  277. package/lib/crypto-api/verification.d.ts +0 -344
  278. package/lib/crypto-api/verification.d.ts.map +0 -1
  279. package/lib/crypto-api/verification.js +0 -91
  280. package/lib/crypto-api/verification.js.map +0 -1
  281. package/lib/matrixrtc/CallMembership.d.ts +0 -66
  282. package/lib/matrixrtc/CallMembership.d.ts.map +0 -1
  283. package/lib/matrixrtc/CallMembership.js +0 -197
  284. package/lib/matrixrtc/CallMembership.js.map +0 -1
  285. package/lib/matrixrtc/LivekitFocus.d.ts +0 -16
  286. package/lib/matrixrtc/LivekitFocus.d.ts.map +0 -1
  287. package/lib/matrixrtc/LivekitFocus.js +0 -20
  288. package/lib/matrixrtc/LivekitFocus.js.map +0 -1
  289. package/lib/matrixrtc/MatrixRTCSession.d.ts +0 -295
  290. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +0 -1
  291. package/lib/matrixrtc/MatrixRTCSession.js +0 -1043
  292. package/lib/matrixrtc/MatrixRTCSession.js.map +0 -1
  293. package/lib/matrixrtc/MatrixRTCSessionManager.d.ts +0 -40
  294. package/lib/matrixrtc/MatrixRTCSessionManager.d.ts.map +0 -1
  295. package/lib/matrixrtc/MatrixRTCSessionManager.js +0 -146
  296. package/lib/matrixrtc/MatrixRTCSessionManager.js.map +0 -1
  297. package/lib/matrixrtc/focus.d.ts +0 -10
  298. package/lib/matrixrtc/focus.d.ts.map +0 -1
  299. package/lib/matrixrtc/focus.js +0 -1
  300. package/lib/matrixrtc/focus.js.map +0 -1
  301. package/lib/matrixrtc/index.d.ts +0 -7
  302. package/lib/matrixrtc/index.d.ts.map +0 -1
  303. package/lib/matrixrtc/index.js +0 -21
  304. package/lib/matrixrtc/index.js.map +0 -1
  305. package/lib/matrixrtc/types.d.ts +0 -19
  306. package/lib/matrixrtc/types.d.ts.map +0 -1
  307. package/lib/matrixrtc/types.js +0 -1
  308. package/lib/matrixrtc/types.js.map +0 -1
  309. package/lib/rendezvous/MSC4108SignInWithQR.d.ts +0 -112
  310. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +0 -1
  311. package/lib/rendezvous/MSC4108SignInWithQR.js +0 -392
  312. package/lib/rendezvous/MSC4108SignInWithQR.js.map +0 -1
  313. package/lib/rendezvous/RendezvousChannel.d.ts +0 -27
  314. package/lib/rendezvous/RendezvousChannel.d.ts.map +0 -1
  315. package/lib/rendezvous/RendezvousChannel.js +0 -1
  316. package/lib/rendezvous/RendezvousChannel.js.map +0 -1
  317. package/lib/rendezvous/RendezvousCode.d.ts +0 -9
  318. package/lib/rendezvous/RendezvousCode.d.ts.map +0 -1
  319. package/lib/rendezvous/RendezvousCode.js +0 -1
  320. package/lib/rendezvous/RendezvousCode.js.map +0 -1
  321. package/lib/rendezvous/RendezvousError.d.ts +0 -6
  322. package/lib/rendezvous/RendezvousError.d.ts.map +0 -1
  323. package/lib/rendezvous/RendezvousError.js +0 -23
  324. package/lib/rendezvous/RendezvousError.js.map +0 -1
  325. package/lib/rendezvous/RendezvousFailureReason.d.ts +0 -31
  326. package/lib/rendezvous/RendezvousFailureReason.d.ts.map +0 -1
  327. package/lib/rendezvous/RendezvousFailureReason.js +0 -38
  328. package/lib/rendezvous/RendezvousFailureReason.js.map +0 -1
  329. package/lib/rendezvous/RendezvousIntent.d.ts +0 -5
  330. package/lib/rendezvous/RendezvousIntent.d.ts.map +0 -1
  331. package/lib/rendezvous/RendezvousIntent.js +0 -22
  332. package/lib/rendezvous/RendezvousIntent.js.map +0 -1
  333. package/lib/rendezvous/RendezvousTransport.d.ts +0 -36
  334. package/lib/rendezvous/RendezvousTransport.d.ts.map +0 -1
  335. package/lib/rendezvous/RendezvousTransport.js +0 -1
  336. package/lib/rendezvous/RendezvousTransport.js.map +0 -1
  337. package/lib/rendezvous/channels/MSC4108SecureChannel.d.ts +0 -58
  338. package/lib/rendezvous/channels/MSC4108SecureChannel.d.ts.map +0 -1
  339. package/lib/rendezvous/channels/MSC4108SecureChannel.js +0 -246
  340. package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +0 -1
  341. package/lib/rendezvous/channels/index.d.ts +0 -2
  342. package/lib/rendezvous/channels/index.d.ts.map +0 -1
  343. package/lib/rendezvous/channels/index.js +0 -18
  344. package/lib/rendezvous/channels/index.js.map +0 -1
  345. package/lib/rendezvous/index.d.ts +0 -10
  346. package/lib/rendezvous/index.d.ts.map +0 -1
  347. package/lib/rendezvous/index.js +0 -23
  348. package/lib/rendezvous/index.js.map +0 -1
  349. package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +0 -61
  350. package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts.map +0 -1
  351. package/lib/rendezvous/transports/MSC4108RendezvousSession.js +0 -253
  352. package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +0 -1
  353. package/lib/rendezvous/transports/index.d.ts +0 -2
  354. package/lib/rendezvous/transports/index.d.ts.map +0 -1
  355. package/lib/rendezvous/transports/index.js +0 -18
  356. package/lib/rendezvous/transports/index.js.map +0 -1
  357. package/lib/rust-crypto/CrossSigningIdentity.d.ts +0 -33
  358. package/lib/rust-crypto/CrossSigningIdentity.d.ts.map +0 -1
  359. package/lib/rust-crypto/CrossSigningIdentity.js +0 -157
  360. package/lib/rust-crypto/CrossSigningIdentity.js.map +0 -1
  361. package/lib/rust-crypto/DehydratedDeviceManager.d.ts +0 -98
  362. package/lib/rust-crypto/DehydratedDeviceManager.d.ts.map +0 -1
  363. package/lib/rust-crypto/DehydratedDeviceManager.js +0 -285
  364. package/lib/rust-crypto/DehydratedDeviceManager.js.map +0 -1
  365. package/lib/rust-crypto/KeyClaimManager.d.ts +0 -33
  366. package/lib/rust-crypto/KeyClaimManager.d.ts.map +0 -1
  367. package/lib/rust-crypto/KeyClaimManager.js +0 -82
  368. package/lib/rust-crypto/KeyClaimManager.js.map +0 -1
  369. package/lib/rust-crypto/OutgoingRequestProcessor.d.ts +0 -43
  370. package/lib/rust-crypto/OutgoingRequestProcessor.d.ts.map +0 -1
  371. package/lib/rust-crypto/OutgoingRequestProcessor.js +0 -195
  372. package/lib/rust-crypto/OutgoingRequestProcessor.js.map +0 -1
  373. package/lib/rust-crypto/OutgoingRequestsManager.d.ts +0 -47
  374. package/lib/rust-crypto/OutgoingRequestsManager.d.ts.map +0 -1
  375. package/lib/rust-crypto/OutgoingRequestsManager.js +0 -148
  376. package/lib/rust-crypto/OutgoingRequestsManager.js.map +0 -1
  377. package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +0 -120
  378. package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts.map +0 -1
  379. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +0 -467
  380. package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +0 -1
  381. package/lib/rust-crypto/RoomEncryptor.d.ts +0 -98
  382. package/lib/rust-crypto/RoomEncryptor.d.ts.map +0 -1
  383. package/lib/rust-crypto/RoomEncryptor.js +0 -299
  384. package/lib/rust-crypto/RoomEncryptor.js.map +0 -1
  385. package/lib/rust-crypto/backup.d.ts +0 -254
  386. package/lib/rust-crypto/backup.d.ts.map +0 -1
  387. package/lib/rust-crypto/backup.js +0 -837
  388. package/lib/rust-crypto/backup.js.map +0 -1
  389. package/lib/rust-crypto/constants.d.ts +0 -3
  390. package/lib/rust-crypto/constants.d.ts.map +0 -1
  391. package/lib/rust-crypto/constants.js +0 -19
  392. package/lib/rust-crypto/constants.js.map +0 -1
  393. package/lib/rust-crypto/device-converter.d.ts +0 -28
  394. package/lib/rust-crypto/device-converter.d.ts.map +0 -1
  395. package/lib/rust-crypto/device-converter.js +0 -123
  396. package/lib/rust-crypto/device-converter.js.map +0 -1
  397. package/lib/rust-crypto/index.d.ts +0 -61
  398. package/lib/rust-crypto/index.d.ts.map +0 -1
  399. package/lib/rust-crypto/index.js +0 -152
  400. package/lib/rust-crypto/index.js.map +0 -1
  401. package/lib/rust-crypto/libolm_migration.d.ts +0 -81
  402. package/lib/rust-crypto/libolm_migration.d.ts.map +0 -1
  403. package/lib/rust-crypto/libolm_migration.js +0 -459
  404. package/lib/rust-crypto/libolm_migration.js.map +0 -1
  405. package/lib/rust-crypto/rust-crypto.d.ts +0 -556
  406. package/lib/rust-crypto/rust-crypto.d.ts.map +0 -1
  407. package/lib/rust-crypto/rust-crypto.js +0 -2016
  408. package/lib/rust-crypto/rust-crypto.js.map +0 -1
  409. package/lib/rust-crypto/secret-storage.d.ts +0 -22
  410. package/lib/rust-crypto/secret-storage.d.ts.map +0 -1
  411. package/lib/rust-crypto/secret-storage.js +0 -63
  412. package/lib/rust-crypto/secret-storage.js.map +0 -1
  413. package/lib/rust-crypto/verification.d.ts +0 -319
  414. package/lib/rust-crypto/verification.d.ts.map +0 -1
  415. package/lib/rust-crypto/verification.js +0 -816
  416. package/lib/rust-crypto/verification.js.map +0 -1
  417. package/lib/secret-storage.d.ts +0 -370
  418. package/lib/secret-storage.d.ts.map +0 -1
  419. package/lib/secret-storage.js +0 -466
  420. package/lib/secret-storage.js.map +0 -1
  421. package/lib/webrtc/audioContext.d.ts +0 -15
  422. package/lib/webrtc/audioContext.d.ts.map +0 -1
  423. package/lib/webrtc/audioContext.js +0 -46
  424. package/lib/webrtc/audioContext.js.map +0 -1
  425. package/lib/webrtc/call.d.ts +0 -560
  426. package/lib/webrtc/call.d.ts.map +0 -1
  427. package/lib/webrtc/call.js +0 -2541
  428. package/lib/webrtc/call.js.map +0 -1
  429. package/lib/webrtc/callEventHandler.d.ts +0 -37
  430. package/lib/webrtc/callEventHandler.d.ts.map +0 -1
  431. package/lib/webrtc/callEventHandler.js +0 -344
  432. package/lib/webrtc/callEventHandler.js.map +0 -1
  433. package/lib/webrtc/callEventTypes.d.ts +0 -73
  434. package/lib/webrtc/callEventTypes.d.ts.map +0 -1
  435. package/lib/webrtc/callEventTypes.js +0 -13
  436. package/lib/webrtc/callEventTypes.js.map +0 -1
  437. package/lib/webrtc/callFeed.d.ts +0 -128
  438. package/lib/webrtc/callFeed.d.ts.map +0 -1
  439. package/lib/webrtc/callFeed.js +0 -289
  440. package/lib/webrtc/callFeed.js.map +0 -1
  441. package/lib/webrtc/groupCall.d.ts +0 -323
  442. package/lib/webrtc/groupCall.d.ts.map +0 -1
  443. package/lib/webrtc/groupCall.js +0 -1337
  444. package/lib/webrtc/groupCall.js.map +0 -1
  445. package/lib/webrtc/groupCallEventHandler.d.ts +0 -31
  446. package/lib/webrtc/groupCallEventHandler.d.ts.map +0 -1
  447. package/lib/webrtc/groupCallEventHandler.js +0 -178
  448. package/lib/webrtc/groupCallEventHandler.js.map +0 -1
  449. package/lib/webrtc/mediaHandler.d.ts +0 -89
  450. package/lib/webrtc/mediaHandler.d.ts.map +0 -1
  451. package/lib/webrtc/mediaHandler.js +0 -437
  452. package/lib/webrtc/mediaHandler.js.map +0 -1
  453. package/lib/webrtc/stats/callFeedStatsReporter.d.ts +0 -8
  454. package/lib/webrtc/stats/callFeedStatsReporter.d.ts.map +0 -1
  455. package/lib/webrtc/stats/callFeedStatsReporter.js +0 -82
  456. package/lib/webrtc/stats/callFeedStatsReporter.js.map +0 -1
  457. package/lib/webrtc/stats/callStatsReportGatherer.d.ts +0 -25
  458. package/lib/webrtc/stats/callStatsReportGatherer.d.ts.map +0 -1
  459. package/lib/webrtc/stats/callStatsReportGatherer.js +0 -199
  460. package/lib/webrtc/stats/callStatsReportGatherer.js.map +0 -1
  461. package/lib/webrtc/stats/callStatsReportSummary.d.ts +0 -17
  462. package/lib/webrtc/stats/callStatsReportSummary.d.ts.map +0 -1
  463. package/lib/webrtc/stats/callStatsReportSummary.js +0 -1
  464. package/lib/webrtc/stats/callStatsReportSummary.js.map +0 -1
  465. package/lib/webrtc/stats/connectionStats.d.ts +0 -28
  466. package/lib/webrtc/stats/connectionStats.d.ts.map +0 -1
  467. package/lib/webrtc/stats/connectionStats.js +0 -26
  468. package/lib/webrtc/stats/connectionStats.js.map +0 -1
  469. package/lib/webrtc/stats/connectionStatsBuilder.d.ts +0 -5
  470. package/lib/webrtc/stats/connectionStatsBuilder.d.ts.map +0 -1
  471. package/lib/webrtc/stats/connectionStatsBuilder.js +0 -27
  472. package/lib/webrtc/stats/connectionStatsBuilder.js.map +0 -1
  473. package/lib/webrtc/stats/connectionStatsReportBuilder.d.ts +0 -7
  474. package/lib/webrtc/stats/connectionStatsReportBuilder.d.ts.map +0 -1
  475. package/lib/webrtc/stats/connectionStatsReportBuilder.js +0 -121
  476. package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +0 -1
  477. package/lib/webrtc/stats/groupCallStats.d.ts +0 -22
  478. package/lib/webrtc/stats/groupCallStats.d.ts.map +0 -1
  479. package/lib/webrtc/stats/groupCallStats.js +0 -78
  480. package/lib/webrtc/stats/groupCallStats.js.map +0 -1
  481. package/lib/webrtc/stats/media/mediaSsrcHandler.d.ts +0 -10
  482. package/lib/webrtc/stats/media/mediaSsrcHandler.d.ts.map +0 -1
  483. package/lib/webrtc/stats/media/mediaSsrcHandler.js +0 -57
  484. package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +0 -1
  485. package/lib/webrtc/stats/media/mediaTrackHandler.d.ts +0 -12
  486. package/lib/webrtc/stats/media/mediaTrackHandler.d.ts.map +0 -1
  487. package/lib/webrtc/stats/media/mediaTrackHandler.js +0 -62
  488. package/lib/webrtc/stats/media/mediaTrackHandler.js.map +0 -1
  489. package/lib/webrtc/stats/media/mediaTrackStats.d.ts +0 -86
  490. package/lib/webrtc/stats/media/mediaTrackStats.d.ts.map +0 -1
  491. package/lib/webrtc/stats/media/mediaTrackStats.js +0 -142
  492. package/lib/webrtc/stats/media/mediaTrackStats.js.map +0 -1
  493. package/lib/webrtc/stats/media/mediaTrackStatsHandler.d.ts +0 -22
  494. package/lib/webrtc/stats/media/mediaTrackStatsHandler.d.ts.map +0 -1
  495. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +0 -76
  496. package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +0 -1
  497. package/lib/webrtc/stats/statsReport.d.ts +0 -99
  498. package/lib/webrtc/stats/statsReport.d.ts.map +0 -1
  499. package/lib/webrtc/stats/statsReport.js +0 -32
  500. package/lib/webrtc/stats/statsReport.js.map +0 -1
  501. package/lib/webrtc/stats/statsReportEmitter.d.ts +0 -15
  502. package/lib/webrtc/stats/statsReportEmitter.d.ts.map +0 -1
  503. package/lib/webrtc/stats/statsReportEmitter.js +0 -33
  504. package/lib/webrtc/stats/statsReportEmitter.js.map +0 -1
  505. package/lib/webrtc/stats/summaryStatsReportGatherer.d.ts +0 -16
  506. package/lib/webrtc/stats/summaryStatsReportGatherer.d.ts.map +0 -1
  507. package/lib/webrtc/stats/summaryStatsReportGatherer.js +0 -116
  508. package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +0 -1
  509. package/lib/webrtc/stats/trackStatsBuilder.d.ts +0 -19
  510. package/lib/webrtc/stats/trackStatsBuilder.d.ts.map +0 -1
  511. package/lib/webrtc/stats/trackStatsBuilder.js +0 -168
  512. package/lib/webrtc/stats/trackStatsBuilder.js.map +0 -1
  513. package/lib/webrtc/stats/transportStats.d.ts +0 -11
  514. package/lib/webrtc/stats/transportStats.d.ts.map +0 -1
  515. package/lib/webrtc/stats/transportStats.js +0 -1
  516. package/lib/webrtc/stats/transportStats.js.map +0 -1
  517. package/lib/webrtc/stats/transportStatsBuilder.d.ts +0 -5
  518. package/lib/webrtc/stats/transportStatsBuilder.d.ts.map +0 -1
  519. package/lib/webrtc/stats/transportStatsBuilder.js +0 -34
  520. package/lib/webrtc/stats/transportStatsBuilder.js.map +0 -1
  521. package/lib/webrtc/stats/valueFormatter.d.ts +0 -4
  522. package/lib/webrtc/stats/valueFormatter.d.ts.map +0 -1
  523. package/lib/webrtc/stats/valueFormatter.js +0 -25
  524. package/lib/webrtc/stats/valueFormatter.js.map +0 -1
  525. package/src/@types/crypto.ts +0 -73
  526. package/src/@types/matrix-sdk-crypto-wasm.d.ts +0 -44
  527. package/src/common-crypto/CryptoBackend.ts +0 -302
  528. package/src/common-crypto/README.md +0 -4
  529. package/src/common-crypto/key-passphrase.ts +0 -43
  530. package/src/crypto/CrossSigning.ts +0 -773
  531. package/src/crypto/DeviceList.ts +0 -989
  532. package/src/crypto/EncryptionSetup.ts +0 -351
  533. package/src/crypto/OlmDevice.ts +0 -1500
  534. package/src/crypto/OutgoingRoomKeyRequestManager.ts +0 -485
  535. package/src/crypto/RoomList.ts +0 -70
  536. package/src/crypto/SecretSharing.ts +0 -240
  537. package/src/crypto/SecretStorage.ts +0 -136
  538. package/src/crypto/aes.ts +0 -23
  539. package/src/crypto/algorithms/base.ts +0 -236
  540. package/src/crypto/algorithms/index.ts +0 -20
  541. package/src/crypto/algorithms/megolm.ts +0 -2216
  542. package/src/crypto/algorithms/olm.ts +0 -381
  543. package/src/crypto/api.ts +0 -70
  544. package/src/crypto/backup.ts +0 -922
  545. package/src/crypto/crypto.ts +0 -18
  546. package/src/crypto/dehydration.ts +0 -272
  547. package/src/crypto/device-converter.ts +0 -45
  548. package/src/crypto/deviceinfo.ts +0 -158
  549. package/src/crypto/index.ts +0 -4414
  550. package/src/crypto/key_passphrase.ts +0 -42
  551. package/src/crypto/keybackup.ts +0 -47
  552. package/src/crypto/olmlib.ts +0 -539
  553. package/src/crypto/recoverykey.ts +0 -18
  554. package/src/crypto/store/base.ts +0 -348
  555. package/src/crypto/store/indexeddb-crypto-store-backend.ts +0 -1250
  556. package/src/crypto/store/indexeddb-crypto-store.ts +0 -845
  557. package/src/crypto/store/localStorage-crypto-store.ts +0 -579
  558. package/src/crypto/store/memory-crypto-store.ts +0 -680
  559. package/src/crypto/verification/Base.ts +0 -409
  560. package/src/crypto/verification/Error.ts +0 -76
  561. package/src/crypto/verification/IllegalMethod.ts +0 -50
  562. package/src/crypto/verification/QRCode.ts +0 -310
  563. package/src/crypto/verification/SAS.ts +0 -494
  564. package/src/crypto/verification/SASDecimal.ts +0 -37
  565. package/src/crypto/verification/request/Channel.ts +0 -34
  566. package/src/crypto/verification/request/InRoomChannel.ts +0 -371
  567. package/src/crypto/verification/request/ToDeviceChannel.ts +0 -354
  568. package/src/crypto/verification/request/VerificationRequest.ts +0 -976
  569. package/src/crypto-api/CryptoEvent.ts +0 -93
  570. package/src/crypto-api/CryptoEventHandlerMap.ts +0 -32
  571. package/src/crypto-api/index.ts +0 -1175
  572. package/src/crypto-api/key-passphrase.ts +0 -58
  573. package/src/crypto-api/keybackup.ts +0 -115
  574. package/src/crypto-api/recovery-key.ts +0 -69
  575. package/src/crypto-api/verification.ts +0 -408
  576. package/src/matrixrtc/CallMembership.ts +0 -247
  577. package/src/matrixrtc/LivekitFocus.ts +0 -39
  578. package/src/matrixrtc/MatrixRTCSession.ts +0 -1319
  579. package/src/matrixrtc/MatrixRTCSessionManager.ts +0 -166
  580. package/src/matrixrtc/focus.ts +0 -25
  581. package/src/matrixrtc/index.ts +0 -22
  582. package/src/matrixrtc/types.ts +0 -36
  583. package/src/rendezvous/MSC4108SignInWithQR.ts +0 -444
  584. package/src/rendezvous/RendezvousChannel.ts +0 -48
  585. package/src/rendezvous/RendezvousCode.ts +0 -25
  586. package/src/rendezvous/RendezvousError.ts +0 -26
  587. package/src/rendezvous/RendezvousFailureReason.ts +0 -49
  588. package/src/rendezvous/RendezvousIntent.ts +0 -20
  589. package/src/rendezvous/RendezvousTransport.ts +0 -58
  590. package/src/rendezvous/channels/MSC4108SecureChannel.ts +0 -270
  591. package/src/rendezvous/channels/index.ts +0 -17
  592. package/src/rendezvous/index.ts +0 -25
  593. package/src/rendezvous/transports/MSC4108RendezvousSession.ts +0 -270
  594. package/src/rendezvous/transports/index.ts +0 -17
  595. package/src/rust-crypto/CrossSigningIdentity.ts +0 -183
  596. package/src/rust-crypto/DehydratedDeviceManager.ts +0 -306
  597. package/src/rust-crypto/KeyClaimManager.ts +0 -86
  598. package/src/rust-crypto/OutgoingRequestProcessor.ts +0 -236
  599. package/src/rust-crypto/OutgoingRequestsManager.ts +0 -143
  600. package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +0 -501
  601. package/src/rust-crypto/RoomEncryptor.ts +0 -352
  602. package/src/rust-crypto/backup.ts +0 -881
  603. package/src/rust-crypto/constants.ts +0 -18
  604. package/src/rust-crypto/device-converter.ts +0 -128
  605. package/src/rust-crypto/index.ts +0 -237
  606. package/src/rust-crypto/libolm_migration.ts +0 -530
  607. package/src/rust-crypto/rust-crypto.ts +0 -2205
  608. package/src/rust-crypto/secret-storage.ts +0 -60
  609. package/src/rust-crypto/verification.ts +0 -830
  610. package/src/secret-storage.ts +0 -693
  611. package/src/webrtc/audioContext.ts +0 -44
  612. package/src/webrtc/call.ts +0 -3074
  613. package/src/webrtc/callEventHandler.ts +0 -425
  614. package/src/webrtc/callEventTypes.ts +0 -93
  615. package/src/webrtc/callFeed.ts +0 -364
  616. package/src/webrtc/groupCall.ts +0 -1735
  617. package/src/webrtc/groupCallEventHandler.ts +0 -234
  618. package/src/webrtc/mediaHandler.ts +0 -484
  619. package/src/webrtc/stats/callFeedStatsReporter.ts +0 -94
  620. package/src/webrtc/stats/callStatsReportGatherer.ts +0 -219
  621. package/src/webrtc/stats/callStatsReportSummary.ts +0 -30
  622. package/src/webrtc/stats/connectionStats.ts +0 -47
  623. package/src/webrtc/stats/connectionStatsBuilder.ts +0 -28
  624. package/src/webrtc/stats/connectionStatsReportBuilder.ts +0 -140
  625. package/src/webrtc/stats/groupCallStats.ts +0 -93
  626. package/src/webrtc/stats/media/mediaSsrcHandler.ts +0 -57
  627. package/src/webrtc/stats/media/mediaTrackHandler.ts +0 -76
  628. package/src/webrtc/stats/media/mediaTrackStats.ts +0 -176
  629. package/src/webrtc/stats/media/mediaTrackStatsHandler.ts +0 -90
  630. package/src/webrtc/stats/statsReport.ts +0 -133
  631. package/src/webrtc/stats/statsReportEmitter.ts +0 -49
  632. package/src/webrtc/stats/summaryStatsReportGatherer.ts +0 -148
  633. package/src/webrtc/stats/trackStatsBuilder.ts +0 -207
  634. package/src/webrtc/stats/transportStats.ts +0 -26
  635. package/src/webrtc/stats/transportStatsBuilder.ts +0 -48
  636. package/src/webrtc/stats/valueFormatter.ts +0 -27
@@ -1,2216 +0,0 @@
1
- /*
2
- Copyright 2015 - 2021, 2023 The Matrix.org Foundation C.I.C.
3
-
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
-
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
15
- */
16
-
17
- /**
18
- * Defines m.olm encryption/decryption
19
- */
20
-
21
- import { v4 as uuidv4 } from "uuid";
22
-
23
- import type { IEventDecryptionResult, IMegolmSessionData } from "../../@types/crypto.ts";
24
- import { logger, Logger } from "../../logger.ts";
25
- import * as olmlib from "../olmlib.ts";
26
- import {
27
- DecryptionAlgorithm,
28
- DecryptionClassParams,
29
- EncryptionAlgorithm,
30
- IParams,
31
- registerAlgorithm,
32
- UnknownDeviceError,
33
- } from "./base.ts";
34
- import { IDecryptedGroupMessage, WITHHELD_MESSAGES } from "../OlmDevice.ts";
35
- import { Room } from "../../models/room.ts";
36
- import { DeviceInfo } from "../deviceinfo.ts";
37
- import { IOlmSessionResult } from "../olmlib.ts";
38
- import { DeviceInfoMap } from "../DeviceList.ts";
39
- import { IContent, MatrixEvent } from "../../models/event.ts";
40
- import { EventType, MsgType, ToDeviceMessageId } from "../../@types/event.ts";
41
- import { IMegolmEncryptedContent, IncomingRoomKeyRequest, IEncryptedContent } from "../index.ts";
42
- import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager.ts";
43
- import { OlmGroupSessionExtraData } from "../../@types/crypto.ts";
44
- import { MatrixError } from "../../http-api/index.ts";
45
- import { immediate, MapWithDefault } from "../../utils.ts";
46
- import { KnownMembership } from "../../@types/membership.ts";
47
- import { DecryptionFailureCode } from "../../crypto-api/index.ts";
48
- import { DecryptionError } from "../../common-crypto/CryptoBackend.ts";
49
-
50
- // determine whether the key can be shared with invitees
51
- export function isRoomSharedHistory(room: Room): boolean {
52
- const visibilityEvent = room?.currentState?.getStateEvents("m.room.history_visibility", "");
53
- // NOTE: if the room visibility is unset, it would normally default to
54
- // "world_readable".
55
- // (https://spec.matrix.org/unstable/client-server-api/#server-behaviour-5)
56
- // But we will be paranoid here, and treat it as a situation where the room
57
- // is not shared-history
58
- const visibility = visibilityEvent?.getContent()?.history_visibility;
59
- return ["world_readable", "shared"].includes(visibility);
60
- }
61
-
62
- interface IBlockedDevice {
63
- code: string;
64
- reason: string;
65
- deviceInfo: DeviceInfo;
66
- }
67
-
68
- // map user Id → device Id → IBlockedDevice
69
- type BlockedMap = Map<string, Map<string, IBlockedDevice>>;
70
-
71
- export interface IOlmDevice<T = DeviceInfo> {
72
- userId: string;
73
- deviceInfo: T;
74
- }
75
-
76
- /**
77
- * Tests whether an encrypted content has a ciphertext.
78
- * Ciphertext can be a string or object depending on the content type {@link IEncryptedContent}.
79
- *
80
- * @param content - Encrypted content
81
- * @returns true: has ciphertext, else false
82
- */
83
- const hasCiphertext = (content: IEncryptedContent): boolean => {
84
- return typeof content.ciphertext === "string"
85
- ? !!content.ciphertext.length
86
- : !!Object.keys(content.ciphertext).length;
87
- };
88
-
89
- /** The result of parsing the an `m.room_key` or `m.forwarded_room_key` to-device event */
90
- interface RoomKey {
91
- /**
92
- * The Curve25519 key of the megolm session creator.
93
- *
94
- * For `m.room_key`, this is also the sender of the `m.room_key` to-device event.
95
- * For `m.forwarded_room_key`, the two are different (and the key of the sender of the
96
- * `m.forwarded_room_key` event is included in `forwardingKeyChain`)
97
- */
98
- senderKey: string;
99
- sessionId: string;
100
- sessionKey: string;
101
- exportFormat: boolean;
102
- roomId: string;
103
- algorithm: string;
104
- /**
105
- * A list of the curve25519 keys of the users involved in forwarding this key, most recent last.
106
- * For `m.room_key` events, this is empty.
107
- */
108
- forwardingKeyChain: string[];
109
- keysClaimed: Partial<Record<"ed25519", string>>;
110
- extraSessionData: OlmGroupSessionExtraData;
111
- }
112
-
113
- export interface IOutboundGroupSessionKey {
114
- chain_index: number;
115
- key: string;
116
- }
117
-
118
- interface IMessage {
119
- type: string;
120
- content: {
121
- "algorithm": string;
122
- "room_id": string;
123
- "sender_key"?: string;
124
- "sender_claimed_ed25519_key"?: string;
125
- "session_id": string;
126
- "session_key": string;
127
- "chain_index": number;
128
- "forwarding_curve25519_key_chain"?: string[];
129
- "org.matrix.msc3061.shared_history": boolean;
130
- };
131
- }
132
-
133
- interface IKeyForwardingMessage extends IMessage {
134
- type: "m.forwarded_room_key";
135
- }
136
-
137
- interface IPayload extends Partial<IMessage> {
138
- code?: string;
139
- reason?: string;
140
- room_id?: string;
141
- session_id?: string;
142
- algorithm?: string;
143
- sender_key?: string;
144
- }
145
-
146
- interface SharedWithData {
147
- // The identity key of the device we shared with
148
- deviceKey: string;
149
- // The message index of the ratchet we shared with that device
150
- messageIndex: number;
151
- }
152
-
153
- /**
154
- * @internal
155
- */
156
- class OutboundSessionInfo {
157
- /** number of times this session has been used */
158
- public useCount = 0;
159
- /** when the session was created (ms since the epoch) */
160
- public creationTime: number;
161
- /** devices with which we have shared the session key `userId -> {deviceId -> SharedWithData}` */
162
- public sharedWithDevices: MapWithDefault<string, Map<string, SharedWithData>> = new MapWithDefault(() => new Map());
163
- public blockedDevicesNotified: MapWithDefault<string, Map<string, boolean>> = new MapWithDefault(() => new Map());
164
-
165
- /**
166
- * @param sharedHistory - whether the session can be freely shared with
167
- * other group members, according to the room history visibility settings
168
- */
169
- public constructor(
170
- public readonly sessionId: string,
171
- public readonly sharedHistory = false,
172
- ) {
173
- this.creationTime = new Date().getTime();
174
- }
175
-
176
- /**
177
- * Check if it's time to rotate the session
178
- */
179
- public needsRotation(rotationPeriodMsgs: number, rotationPeriodMs: number): boolean {
180
- const sessionLifetime = new Date().getTime() - this.creationTime;
181
-
182
- if (this.useCount >= rotationPeriodMsgs || sessionLifetime >= rotationPeriodMs) {
183
- logger.log("Rotating megolm session after " + this.useCount + " messages, " + sessionLifetime + "ms");
184
- return true;
185
- }
186
-
187
- return false;
188
- }
189
-
190
- public markSharedWithDevice(userId: string, deviceId: string, deviceKey: string, chainIndex: number): void {
191
- this.sharedWithDevices.getOrCreate(userId).set(deviceId, { deviceKey, messageIndex: chainIndex });
192
- }
193
-
194
- public markNotifiedBlockedDevice(userId: string, deviceId: string): void {
195
- this.blockedDevicesNotified.getOrCreate(userId).set(deviceId, true);
196
- }
197
-
198
- /**
199
- * Determine if this session has been shared with devices which it shouldn't
200
- * have been.
201
- *
202
- * @param devicesInRoom - `userId -> {deviceId -> object}`
203
- * devices we should shared the session with.
204
- *
205
- * @returns true if we have shared the session with devices which aren't
206
- * in devicesInRoom.
207
- */
208
- public sharedWithTooManyDevices(devicesInRoom: DeviceInfoMap): boolean {
209
- for (const [userId, devices] of this.sharedWithDevices) {
210
- if (!devicesInRoom.has(userId)) {
211
- logger.log("Starting new megolm session because we shared with " + userId);
212
- return true;
213
- }
214
-
215
- for (const [deviceId] of devices) {
216
- if (!devicesInRoom.get(userId)?.get(deviceId)) {
217
- logger.log("Starting new megolm session because we shared with " + userId + ":" + deviceId);
218
- return true;
219
- }
220
- }
221
- }
222
-
223
- return false;
224
- }
225
- }
226
-
227
- /**
228
- * Megolm encryption implementation
229
- *
230
- * @param params - parameters, as per {@link EncryptionAlgorithm}
231
- */
232
- export class MegolmEncryption extends EncryptionAlgorithm {
233
- // the most recent attempt to set up a session. This is used to serialise
234
- // the session setups, so that we have a race-free view of which session we
235
- // are using, and which devices we have shared the keys with. It resolves
236
- // with an OutboundSessionInfo (or undefined, for the first message in the
237
- // room).
238
- private setupPromise = Promise.resolve<OutboundSessionInfo | null>(null);
239
-
240
- // Map of outbound sessions by sessions ID. Used if we need a particular
241
- // session (the session we're currently using to send is always obtained
242
- // using setupPromise).
243
- private outboundSessions: Record<string, OutboundSessionInfo> = {};
244
-
245
- private readonly sessionRotationPeriodMsgs: number;
246
- private readonly sessionRotationPeriodMs: number;
247
- private encryptionPreparation?: {
248
- promise: Promise<void>;
249
- startTime: number;
250
- cancel: () => void;
251
- };
252
-
253
- protected readonly roomId: string;
254
- private readonly prefixedLogger: Logger;
255
-
256
- public constructor(params: IParams & Required<Pick<IParams, "roomId">>) {
257
- super(params);
258
- this.roomId = params.roomId;
259
- this.prefixedLogger = logger.getChild(`[${this.roomId} encryption]`);
260
-
261
- this.sessionRotationPeriodMsgs = params.config?.rotation_period_msgs ?? 100;
262
- this.sessionRotationPeriodMs = params.config?.rotation_period_ms ?? 7 * 24 * 3600 * 1000;
263
- }
264
-
265
- /**
266
- * @internal
267
- *
268
- * @param devicesInRoom - The devices in this room, indexed by user ID
269
- * @param blocked - The devices that are blocked, indexed by user ID
270
- * @param singleOlmCreationPhase - Only perform one round of olm
271
- * session creation
272
- *
273
- * This method updates the setupPromise field of the class by chaining a new
274
- * call on top of the existing promise, and then catching and discarding any
275
- * errors that might happen while setting up the outbound group session. This
276
- * is done to ensure that `setupPromise` always resolves to `null` or the
277
- * `OutboundSessionInfo`.
278
- *
279
- * Using `>>=` to represent the promise chaining operation, it does the
280
- * following:
281
- *
282
- * ```
283
- * setupPromise = previousSetupPromise >>= setup >>= discardErrors
284
- * ```
285
- *
286
- * The initial value for the `setupPromise` is a promise that resolves to
287
- * `null`. The forceDiscardSession() resets setupPromise to this initial
288
- * promise.
289
- *
290
- * @returns Promise which resolves to the
291
- * OutboundSessionInfo when setup is complete.
292
- */
293
- private async ensureOutboundSession(
294
- room: Room,
295
- devicesInRoom: DeviceInfoMap,
296
- blocked: BlockedMap,
297
- singleOlmCreationPhase = false,
298
- ): Promise<OutboundSessionInfo> {
299
- // takes the previous OutboundSessionInfo, and considers whether to create
300
- // a new one. Also shares the key with any (new) devices in the room.
301
- //
302
- // returns a promise which resolves once the keyshare is successful.
303
- const setup = async (oldSession: OutboundSessionInfo | null): Promise<OutboundSessionInfo> => {
304
- const sharedHistory = isRoomSharedHistory(room);
305
- const session = await this.prepareSession(devicesInRoom, sharedHistory, oldSession);
306
-
307
- await this.shareSession(devicesInRoom, sharedHistory, singleOlmCreationPhase, blocked, session);
308
-
309
- return session;
310
- };
311
-
312
- // first wait for the previous share to complete
313
- const fallible = this.setupPromise.then(setup);
314
-
315
- // Ensure any failures are logged for debugging and make sure that the
316
- // promise chain remains unbroken
317
- //
318
- // setupPromise resolves to `null` or the `OutboundSessionInfo` whether
319
- // or not the share succeeds
320
- this.setupPromise = fallible.catch((e) => {
321
- this.prefixedLogger.error(`Failed to setup outbound session`, e);
322
- return null;
323
- });
324
-
325
- // but we return a promise which only resolves if the share was successful.
326
- return fallible;
327
- }
328
-
329
- private async prepareSession(
330
- devicesInRoom: DeviceInfoMap,
331
- sharedHistory: boolean,
332
- session: OutboundSessionInfo | null,
333
- ): Promise<OutboundSessionInfo> {
334
- // history visibility changed
335
- if (session && sharedHistory !== session.sharedHistory) {
336
- session = null;
337
- }
338
-
339
- // need to make a brand new session?
340
- if (session?.needsRotation(this.sessionRotationPeriodMsgs, this.sessionRotationPeriodMs)) {
341
- this.prefixedLogger.debug("Starting new megolm session because we need to rotate.");
342
- session = null;
343
- }
344
-
345
- // determine if we have shared with anyone we shouldn't have
346
- if (session?.sharedWithTooManyDevices(devicesInRoom)) {
347
- session = null;
348
- }
349
-
350
- if (!session) {
351
- this.prefixedLogger.debug("Starting new megolm session");
352
- session = await this.prepareNewSession(sharedHistory);
353
- this.prefixedLogger.debug(`Started new megolm session ${session.sessionId}`);
354
- this.outboundSessions[session.sessionId] = session;
355
- }
356
-
357
- return session;
358
- }
359
-
360
- private async shareSession(
361
- devicesInRoom: DeviceInfoMap,
362
- sharedHistory: boolean,
363
- singleOlmCreationPhase: boolean,
364
- blocked: BlockedMap,
365
- session: OutboundSessionInfo,
366
- ): Promise<void> {
367
- // now check if we need to share with any devices
368
- const shareMap: Record<string, DeviceInfo[]> = {};
369
-
370
- for (const [userId, userDevices] of devicesInRoom) {
371
- for (const [deviceId, deviceInfo] of userDevices) {
372
- const key = deviceInfo.getIdentityKey();
373
- if (key == this.olmDevice.deviceCurve25519Key) {
374
- // don't bother sending to ourself
375
- continue;
376
- }
377
-
378
- if (!session.sharedWithDevices.get(userId)?.get(deviceId)) {
379
- shareMap[userId] = shareMap[userId] || [];
380
- shareMap[userId].push(deviceInfo);
381
- }
382
- }
383
- }
384
-
385
- const key = this.olmDevice.getOutboundGroupSessionKey(session.sessionId);
386
- const payload: IPayload = {
387
- type: "m.room_key",
388
- content: {
389
- "algorithm": olmlib.MEGOLM_ALGORITHM,
390
- "room_id": this.roomId,
391
- "session_id": session.sessionId,
392
- "session_key": key.key,
393
- "chain_index": key.chain_index,
394
- "org.matrix.msc3061.shared_history": sharedHistory,
395
- },
396
- };
397
- const [devicesWithoutSession, olmSessions] = await olmlib.getExistingOlmSessions(
398
- this.olmDevice,
399
- this.baseApis,
400
- shareMap,
401
- );
402
-
403
- await Promise.all([
404
- (async (): Promise<void> => {
405
- // share keys with devices that we already have a session for
406
- const olmSessionList = Array.from(olmSessions.entries())
407
- .map(([userId, sessionsByUser]) =>
408
- Array.from(sessionsByUser.entries()).map(
409
- ([deviceId, session]) => `${userId}/${deviceId}: ${session.sessionId}`,
410
- ),
411
- )
412
- .flat(1);
413
- this.prefixedLogger.debug("Sharing keys with devices with existing Olm sessions:", olmSessionList);
414
- await this.shareKeyWithOlmSessions(session, key, payload, olmSessions);
415
- this.prefixedLogger.debug("Shared keys with existing Olm sessions");
416
- })(),
417
- (async (): Promise<void> => {
418
- const deviceList = Array.from(devicesWithoutSession.entries())
419
- .map(([userId, devicesByUser]) => devicesByUser.map((device) => `${userId}/${device.deviceId}`))
420
- .flat(1);
421
- this.prefixedLogger.debug(
422
- "Sharing keys (start phase 1) with devices without existing Olm sessions:",
423
- deviceList,
424
- );
425
- const errorDevices: IOlmDevice[] = [];
426
-
427
- // meanwhile, establish olm sessions for devices that we don't
428
- // already have a session for, and share keys with them. If
429
- // we're doing two phases of olm session creation, use a
430
- // shorter timeout when fetching one-time keys for the first
431
- // phase.
432
- const start = Date.now();
433
- const failedServers: string[] = [];
434
- await this.shareKeyWithDevices(
435
- session,
436
- key,
437
- payload,
438
- devicesWithoutSession,
439
- errorDevices,
440
- singleOlmCreationPhase ? 10000 : 2000,
441
- failedServers,
442
- );
443
- this.prefixedLogger.debug("Shared keys (end phase 1) with devices without existing Olm sessions");
444
-
445
- if (!singleOlmCreationPhase && Date.now() - start < 10000) {
446
- // perform the second phase of olm session creation if requested,
447
- // and if the first phase didn't take too long
448
- (async (): Promise<void> => {
449
- // Retry sending keys to devices that we were unable to establish
450
- // an olm session for. This time, we use a longer timeout, but we
451
- // do this in the background and don't block anything else while we
452
- // do this. We only need to retry users from servers that didn't
453
- // respond the first time.
454
- const retryDevices: MapWithDefault<string, DeviceInfo[]> = new MapWithDefault(() => []);
455
- const failedServerMap = new Set();
456
- for (const server of failedServers) {
457
- failedServerMap.add(server);
458
- }
459
- const failedDevices: IOlmDevice[] = [];
460
- for (const { userId, deviceInfo } of errorDevices) {
461
- const userHS = userId.slice(userId.indexOf(":") + 1);
462
- if (failedServerMap.has(userHS)) {
463
- retryDevices.getOrCreate(userId).push(deviceInfo);
464
- } else {
465
- // if we aren't going to retry, then handle it
466
- // as a failed device
467
- failedDevices.push({ userId, deviceInfo });
468
- }
469
- }
470
-
471
- const retryDeviceList = Array.from(retryDevices.entries())
472
- .map(([userId, devicesByUser]) =>
473
- devicesByUser.map((device) => `${userId}/${device.deviceId}`),
474
- )
475
- .flat(1);
476
-
477
- if (retryDeviceList.length > 0) {
478
- this.prefixedLogger.debug(
479
- "Sharing keys (start phase 2) with devices without existing Olm sessions:",
480
- retryDeviceList,
481
- );
482
- await this.shareKeyWithDevices(session, key, payload, retryDevices, failedDevices, 30000);
483
- this.prefixedLogger.debug(
484
- "Shared keys (end phase 2) with devices without existing Olm sessions",
485
- );
486
- }
487
-
488
- await this.notifyFailedOlmDevices(session, key, failedDevices);
489
- })();
490
- } else {
491
- await this.notifyFailedOlmDevices(session, key, errorDevices);
492
- }
493
- })(),
494
- (async (): Promise<void> => {
495
- this.prefixedLogger.debug(
496
- `There are ${blocked.size} blocked devices:`,
497
- Array.from(blocked.entries())
498
- .map(([userId, blockedByUser]) =>
499
- Array.from(blockedByUser.entries()).map(
500
- ([deviceId, _deviceInfo]) => `${userId}/${deviceId}`,
501
- ),
502
- )
503
- .flat(1),
504
- );
505
-
506
- // also, notify newly blocked devices that they're blocked
507
- const blockedMap: MapWithDefault<string, Map<string, { device: IBlockedDevice }>> = new MapWithDefault(
508
- () => new Map(),
509
- );
510
- let blockedCount = 0;
511
- for (const [userId, userBlockedDevices] of blocked) {
512
- for (const [deviceId, device] of userBlockedDevices) {
513
- if (session.blockedDevicesNotified.get(userId)?.get(deviceId) === undefined) {
514
- blockedMap.getOrCreate(userId).set(deviceId, { device });
515
- blockedCount++;
516
- }
517
- }
518
- }
519
-
520
- if (blockedCount) {
521
- this.prefixedLogger.debug(
522
- `Notifying ${blockedCount} newly blocked devices:`,
523
- Array.from(blockedMap.entries())
524
- .map(([userId, blockedByUser]) =>
525
- Object.entries(blockedByUser).map(([deviceId, _deviceInfo]) => `${userId}/${deviceId}`),
526
- )
527
- .flat(1),
528
- );
529
- await this.notifyBlockedDevices(session, blockedMap);
530
- this.prefixedLogger.debug(`Notified ${blockedCount} newly blocked devices`);
531
- }
532
- })(),
533
- ]);
534
- }
535
-
536
- /**
537
- * @internal
538
- *
539
- *
540
- * @returns session
541
- */
542
- private async prepareNewSession(sharedHistory: boolean): Promise<OutboundSessionInfo> {
543
- const sessionId = this.olmDevice.createOutboundGroupSession();
544
- const key = this.olmDevice.getOutboundGroupSessionKey(sessionId);
545
-
546
- await this.olmDevice.addInboundGroupSession(
547
- this.roomId,
548
- this.olmDevice.deviceCurve25519Key!,
549
- [],
550
- sessionId,
551
- key.key,
552
- { ed25519: this.olmDevice.deviceEd25519Key! },
553
- false,
554
- { sharedHistory },
555
- );
556
-
557
- // don't wait for it to complete
558
- this.crypto.backupManager.backupGroupSession(this.olmDevice.deviceCurve25519Key!, sessionId);
559
-
560
- return new OutboundSessionInfo(sessionId, sharedHistory);
561
- }
562
-
563
- /**
564
- * Determines what devices in devicesByUser don't have an olm session as given
565
- * in devicemap.
566
- *
567
- * @internal
568
- *
569
- * @param deviceMap - the devices that have olm sessions, as returned by
570
- * olmlib.ensureOlmSessionsForDevices.
571
- * @param devicesByUser - a map of user IDs to array of deviceInfo
572
- * @param noOlmDevices - an array to fill with devices that don't have
573
- * olm sessions
574
- *
575
- * @returns an array of devices that don't have olm sessions. If
576
- * noOlmDevices is specified, then noOlmDevices will be returned.
577
- */
578
- private getDevicesWithoutSessions(
579
- deviceMap: Map<string, Map<string, IOlmSessionResult>>,
580
- devicesByUser: Map<string, DeviceInfo[]>,
581
- noOlmDevices: IOlmDevice[] = [],
582
- ): IOlmDevice[] {
583
- for (const [userId, devicesToShareWith] of devicesByUser) {
584
- const sessionResults = deviceMap.get(userId);
585
-
586
- for (const deviceInfo of devicesToShareWith) {
587
- const deviceId = deviceInfo.deviceId;
588
-
589
- const sessionResult = sessionResults?.get(deviceId);
590
- if (!sessionResult?.sessionId) {
591
- // no session with this device, probably because there
592
- // were no one-time keys.
593
-
594
- noOlmDevices.push({ userId, deviceInfo });
595
- sessionResults?.delete(deviceId);
596
-
597
- // ensureOlmSessionsForUsers has already done the logging,
598
- // so just skip it.
599
- continue;
600
- }
601
- }
602
- }
603
-
604
- return noOlmDevices;
605
- }
606
-
607
- /**
608
- * Splits the user device map into multiple chunks to reduce the number of
609
- * devices we encrypt to per API call.
610
- *
611
- * @internal
612
- *
613
- * @param devicesByUser - map from userid to list of devices
614
- *
615
- * @returns the blocked devices, split into chunks
616
- */
617
- private splitDevices<T extends DeviceInfo | IBlockedDevice>(
618
- devicesByUser: Map<string, Map<string, { device: T }>>,
619
- ): IOlmDevice<T>[][] {
620
- const maxDevicesPerRequest = 20;
621
-
622
- // use an array where the slices of a content map gets stored
623
- let currentSlice: IOlmDevice<T>[] = [];
624
- const mapSlices = [currentSlice];
625
-
626
- for (const [userId, userDevices] of devicesByUser) {
627
- for (const deviceInfo of userDevices.values()) {
628
- currentSlice.push({
629
- userId: userId,
630
- deviceInfo: deviceInfo.device,
631
- });
632
- }
633
-
634
- // We do this in the per-user loop as we prefer that all messages to the
635
- // same user end up in the same API call to make it easier for the
636
- // server (e.g. only have to send one EDU if a remote user, etc). This
637
- // does mean that if a user has many devices we may go over the desired
638
- // limit, but its not a hard limit so that is fine.
639
- if (currentSlice.length > maxDevicesPerRequest) {
640
- // the current slice is filled up. Start inserting into the next slice
641
- currentSlice = [];
642
- mapSlices.push(currentSlice);
643
- }
644
- }
645
- if (currentSlice.length === 0) {
646
- mapSlices.pop();
647
- }
648
- return mapSlices;
649
- }
650
-
651
- /**
652
- * @internal
653
- *
654
- *
655
- * @param chainIndex - current chain index
656
- *
657
- * @param userDeviceMap - mapping from userId to deviceInfo
658
- *
659
- * @param payload - fields to include in the encrypted payload
660
- *
661
- * @returns Promise which resolves once the key sharing
662
- * for the given userDeviceMap is generated and has been sent.
663
- */
664
- private encryptAndSendKeysToDevices(
665
- session: OutboundSessionInfo,
666
- chainIndex: number,
667
- devices: IOlmDevice[],
668
- payload: IPayload,
669
- ): Promise<void> {
670
- return this.crypto
671
- .encryptAndSendToDevices(devices, payload)
672
- .then(() => {
673
- // store that we successfully uploaded the keys of the current slice
674
- for (const device of devices) {
675
- session.markSharedWithDevice(
676
- device.userId,
677
- device.deviceInfo.deviceId,
678
- device.deviceInfo.getIdentityKey(),
679
- chainIndex,
680
- );
681
- }
682
- })
683
- .catch((error) => {
684
- this.prefixedLogger.error("failed to encryptAndSendToDevices", error);
685
- throw error;
686
- });
687
- }
688
-
689
- /**
690
- * @internal
691
- *
692
- *
693
- * @param userDeviceMap - list of blocked devices to notify
694
- *
695
- * @param payload - fields to include in the notification payload
696
- *
697
- * @returns Promise which resolves once the notifications
698
- * for the given userDeviceMap is generated and has been sent.
699
- */
700
- private async sendBlockedNotificationsToDevices(
701
- session: OutboundSessionInfo,
702
- userDeviceMap: IOlmDevice<IBlockedDevice>[],
703
- payload: IPayload,
704
- ): Promise<void> {
705
- const contentMap: MapWithDefault<string, Map<string, IPayload>> = new MapWithDefault(() => new Map());
706
-
707
- for (const val of userDeviceMap) {
708
- const userId = val.userId;
709
- const blockedInfo = val.deviceInfo;
710
- const deviceInfo = blockedInfo.deviceInfo;
711
- const deviceId = deviceInfo.deviceId;
712
-
713
- const message = {
714
- ...payload,
715
- code: blockedInfo.code,
716
- reason: blockedInfo.reason,
717
- [ToDeviceMessageId]: uuidv4(),
718
- };
719
-
720
- if (message.code === "m.no_olm") {
721
- delete message.room_id;
722
- delete message.session_id;
723
- }
724
-
725
- contentMap.getOrCreate(userId).set(deviceId, message);
726
- }
727
-
728
- await this.baseApis.sendToDevice("m.room_key.withheld", contentMap);
729
-
730
- // record the fact that we notified these blocked devices
731
- for (const [userId, userDeviceMap] of contentMap) {
732
- for (const deviceId of userDeviceMap.keys()) {
733
- session.markNotifiedBlockedDevice(userId, deviceId);
734
- }
735
- }
736
- }
737
-
738
- /**
739
- * Re-shares a megolm session key with devices if the key has already been
740
- * sent to them.
741
- *
742
- * @param senderKey - The key of the originating device for the session
743
- * @param sessionId - ID of the outbound session to share
744
- * @param userId - ID of the user who owns the target device
745
- * @param device - The target device
746
- */
747
- public async reshareKeyWithDevice(
748
- senderKey: string,
749
- sessionId: string,
750
- userId: string,
751
- device: DeviceInfo,
752
- ): Promise<void> {
753
- const obSessionInfo = this.outboundSessions[sessionId];
754
- if (!obSessionInfo) {
755
- this.prefixedLogger.debug(`megolm session ${senderKey}|${sessionId} not found: not re-sharing keys`);
756
- return;
757
- }
758
-
759
- // The chain index of the key we previously sent this device
760
- if (!obSessionInfo.sharedWithDevices.has(userId)) {
761
- this.prefixedLogger.debug(`megolm session ${senderKey}|${sessionId} never shared with user ${userId}`);
762
- return;
763
- }
764
- const sessionSharedData = obSessionInfo.sharedWithDevices.get(userId)?.get(device.deviceId);
765
- if (sessionSharedData === undefined) {
766
- this.prefixedLogger.debug(
767
- `megolm session ${senderKey}|${sessionId} never shared with device ${userId}:${device.deviceId}`,
768
- );
769
- return;
770
- }
771
-
772
- if (sessionSharedData.deviceKey !== device.getIdentityKey()) {
773
- this.prefixedLogger.warn(
774
- `Megolm session ${senderKey}|${sessionId} has been shared with device ${device.deviceId} but ` +
775
- `with identity key ${sessionSharedData.deviceKey}. Key is now ${device.getIdentityKey()}!`,
776
- );
777
- return;
778
- }
779
-
780
- // get the key from the inbound session: the outbound one will already
781
- // have been ratcheted to the next chain index.
782
- const key = await this.olmDevice.getInboundGroupSessionKey(
783
- this.roomId,
784
- senderKey,
785
- sessionId,
786
- sessionSharedData.messageIndex,
787
- );
788
-
789
- if (!key) {
790
- this.prefixedLogger.warn(
791
- `No inbound session key found for megolm session ${senderKey}|${sessionId}: not re-sharing keys`,
792
- );
793
- return;
794
- }
795
-
796
- await olmlib.ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, new Map([[userId, [device]]]));
797
-
798
- const payload = {
799
- type: "m.forwarded_room_key",
800
- content: {
801
- "algorithm": olmlib.MEGOLM_ALGORITHM,
802
- "room_id": this.roomId,
803
- "session_id": sessionId,
804
- "session_key": key.key,
805
- "chain_index": key.chain_index,
806
- "sender_key": senderKey,
807
- "sender_claimed_ed25519_key": key.sender_claimed_ed25519_key,
808
- "forwarding_curve25519_key_chain": key.forwarding_curve25519_key_chain,
809
- "org.matrix.msc3061.shared_history": key.shared_history || false,
810
- },
811
- };
812
-
813
- const encryptedContent: IEncryptedContent = {
814
- algorithm: olmlib.OLM_ALGORITHM,
815
- sender_key: this.olmDevice.deviceCurve25519Key!,
816
- ciphertext: {},
817
- [ToDeviceMessageId]: uuidv4(),
818
- };
819
- await olmlib.encryptMessageForDevice(
820
- encryptedContent.ciphertext,
821
- this.userId,
822
- this.deviceId,
823
- this.olmDevice,
824
- userId,
825
- device,
826
- payload,
827
- );
828
-
829
- await this.baseApis.sendToDevice(
830
- "m.room.encrypted",
831
- new Map([[userId, new Map([[device.deviceId, encryptedContent]])]]),
832
- );
833
- this.prefixedLogger.debug(
834
- `Re-shared key for megolm session ${senderKey}|${sessionId} with ${userId}:${device.deviceId}`,
835
- );
836
- }
837
-
838
- /**
839
- * @internal
840
- *
841
- *
842
- * @param key - the session key as returned by
843
- * OlmDevice.getOutboundGroupSessionKey
844
- *
845
- * @param payload - the base to-device message payload for sharing keys
846
- *
847
- * @param devicesByUser - map from userid to list of devices
848
- *
849
- * @param errorDevices - array that will be populated with the devices that we can't get an
850
- * olm session for
851
- *
852
- * @param otkTimeout - The timeout in milliseconds when requesting
853
- * one-time keys for establishing new olm sessions.
854
- *
855
- * @param failedServers - An array to fill with remote servers that
856
- * failed to respond to one-time-key requests.
857
- */
858
- private async shareKeyWithDevices(
859
- session: OutboundSessionInfo,
860
- key: IOutboundGroupSessionKey,
861
- payload: IPayload,
862
- devicesByUser: Map<string, DeviceInfo[]>,
863
- errorDevices: IOlmDevice[],
864
- otkTimeout: number,
865
- failedServers?: string[],
866
- ): Promise<void> {
867
- const devicemap = await olmlib.ensureOlmSessionsForDevices(
868
- this.olmDevice,
869
- this.baseApis,
870
- devicesByUser,
871
- false,
872
- otkTimeout,
873
- failedServers,
874
- this.prefixedLogger,
875
- );
876
- this.getDevicesWithoutSessions(devicemap, devicesByUser, errorDevices);
877
- await this.shareKeyWithOlmSessions(session, key, payload, devicemap);
878
- }
879
-
880
- private async shareKeyWithOlmSessions(
881
- session: OutboundSessionInfo,
882
- key: IOutboundGroupSessionKey,
883
- payload: IPayload,
884
- deviceMap: Map<string, Map<string, IOlmSessionResult>>,
885
- ): Promise<void> {
886
- const userDeviceMaps = this.splitDevices(deviceMap);
887
-
888
- for (let i = 0; i < userDeviceMaps.length; i++) {
889
- const taskDetail = `megolm keys for ${session.sessionId} (slice ${i + 1}/${userDeviceMaps.length})`;
890
- try {
891
- this.prefixedLogger.debug(
892
- `Sharing ${taskDetail}`,
893
- userDeviceMaps[i].map((d) => `${d.userId}/${d.deviceInfo.deviceId}`),
894
- );
895
- await this.encryptAndSendKeysToDevices(session, key.chain_index, userDeviceMaps[i], payload);
896
- this.prefixedLogger.debug(`Shared ${taskDetail}`);
897
- } catch (e) {
898
- this.prefixedLogger.error(`Failed to share ${taskDetail}`);
899
- throw e;
900
- }
901
- }
902
- }
903
-
904
- /**
905
- * Notify devices that we weren't able to create olm sessions.
906
- *
907
- *
908
- *
909
- * @param failedDevices - the devices that we were unable to
910
- * create olm sessions for, as returned by shareKeyWithDevices
911
- */
912
- private async notifyFailedOlmDevices(
913
- session: OutboundSessionInfo,
914
- key: IOutboundGroupSessionKey,
915
- failedDevices: IOlmDevice[],
916
- ): Promise<void> {
917
- this.prefixedLogger.debug(`Notifying ${failedDevices.length} devices we failed to create Olm sessions`);
918
-
919
- // mark the devices that failed as "handled" because we don't want to try
920
- // to claim a one-time-key for dead devices on every message.
921
- for (const { userId, deviceInfo } of failedDevices) {
922
- const deviceId = deviceInfo.deviceId;
923
-
924
- session.markSharedWithDevice(userId, deviceId, deviceInfo.getIdentityKey(), key.chain_index);
925
- }
926
-
927
- const unnotifiedFailedDevices = await this.olmDevice.filterOutNotifiedErrorDevices(failedDevices);
928
- this.prefixedLogger.debug(
929
- `Need to notify ${unnotifiedFailedDevices.length} failed devices which haven't been notified before`,
930
- );
931
- const blockedMap: MapWithDefault<string, Map<string, { device: IBlockedDevice }>> = new MapWithDefault(
932
- () => new Map(),
933
- );
934
- for (const { userId, deviceInfo } of unnotifiedFailedDevices) {
935
- // we use a similar format to what
936
- // olmlib.ensureOlmSessionsForDevices returns, so that
937
- // we can use the same function to split
938
- blockedMap.getOrCreate(userId).set(deviceInfo.deviceId, {
939
- device: {
940
- code: "m.no_olm",
941
- reason: WITHHELD_MESSAGES["m.no_olm"],
942
- deviceInfo,
943
- },
944
- });
945
- }
946
-
947
- // send the notifications
948
- await this.notifyBlockedDevices(session, blockedMap);
949
- this.prefixedLogger.debug(
950
- `Notified ${unnotifiedFailedDevices.length} devices we failed to create Olm sessions`,
951
- );
952
- }
953
-
954
- /**
955
- * Notify blocked devices that they have been blocked.
956
- *
957
- *
958
- * @param devicesByUser - map from userid to device ID to blocked data
959
- */
960
- private async notifyBlockedDevices(
961
- session: OutboundSessionInfo,
962
- devicesByUser: Map<string, Map<string, { device: IBlockedDevice }>>,
963
- ): Promise<void> {
964
- const payload: IPayload = {
965
- room_id: this.roomId,
966
- session_id: session.sessionId,
967
- algorithm: olmlib.MEGOLM_ALGORITHM,
968
- sender_key: this.olmDevice.deviceCurve25519Key!,
969
- };
970
-
971
- const userDeviceMaps = this.splitDevices(devicesByUser);
972
-
973
- for (let i = 0; i < userDeviceMaps.length; i++) {
974
- try {
975
- await this.sendBlockedNotificationsToDevices(session, userDeviceMaps[i], payload);
976
- this.prefixedLogger.debug(
977
- `Completed blacklist notification for ${session.sessionId} ` +
978
- `(slice ${i + 1}/${userDeviceMaps.length})`,
979
- );
980
- } catch (e) {
981
- this.prefixedLogger.debug(
982
- `blacklist notification for ${session.sessionId} ` +
983
- `(slice ${i + 1}/${userDeviceMaps.length}) failed`,
984
- );
985
-
986
- throw e;
987
- }
988
- }
989
- }
990
-
991
- /**
992
- * Perform any background tasks that can be done before a message is ready to
993
- * send, in order to speed up sending of the message.
994
- *
995
- * @param room - the room the event is in
996
- * @returns A function that, when called, will stop the preparation
997
- */
998
- public prepareToEncrypt(room: Room): () => void {
999
- if (room.roomId !== this.roomId) {
1000
- throw new Error("MegolmEncryption.prepareToEncrypt called on unexpected room");
1001
- }
1002
-
1003
- if (this.encryptionPreparation != null) {
1004
- // We're already preparing something, so don't do anything else.
1005
- const elapsedTime = Date.now() - this.encryptionPreparation.startTime;
1006
- this.prefixedLogger.debug(
1007
- `Already started preparing to encrypt for this room ${elapsedTime}ms ago, skipping`,
1008
- );
1009
- return this.encryptionPreparation.cancel;
1010
- }
1011
-
1012
- this.prefixedLogger.debug("Preparing to encrypt events");
1013
-
1014
- let cancelled = false;
1015
- const isCancelled = (): boolean => cancelled;
1016
-
1017
- this.encryptionPreparation = {
1018
- startTime: Date.now(),
1019
- promise: (async (): Promise<void> => {
1020
- try {
1021
- // Attempt to enumerate the devices in room, and gracefully
1022
- // handle cancellation if it occurs.
1023
- const getDevicesResult = await this.getDevicesInRoom(room, false, isCancelled);
1024
- if (getDevicesResult === null) return;
1025
- const [devicesInRoom, blocked] = getDevicesResult;
1026
-
1027
- if (this.crypto.globalErrorOnUnknownDevices) {
1028
- // Drop unknown devices for now. When the message gets sent, we'll
1029
- // throw an error, but we'll still be prepared to send to the known
1030
- // devices.
1031
- this.removeUnknownDevices(devicesInRoom);
1032
- }
1033
-
1034
- this.prefixedLogger.debug("Ensuring outbound megolm session");
1035
- await this.ensureOutboundSession(room, devicesInRoom, blocked, true);
1036
-
1037
- this.prefixedLogger.debug("Ready to encrypt events");
1038
- } catch (e) {
1039
- this.prefixedLogger.error("Failed to prepare to encrypt events", e);
1040
- } finally {
1041
- delete this.encryptionPreparation;
1042
- }
1043
- })(),
1044
-
1045
- cancel: (): void => {
1046
- // The caller has indicated that the process should be cancelled,
1047
- // so tell the promise that we'd like to halt, and reset the preparation state.
1048
- cancelled = true;
1049
- delete this.encryptionPreparation;
1050
- },
1051
- };
1052
-
1053
- return this.encryptionPreparation.cancel;
1054
- }
1055
-
1056
- /**
1057
- * @param content - plaintext event content
1058
- *
1059
- * @returns Promise which resolves to the new event body
1060
- */
1061
- public async encryptMessage(room: Room, eventType: string, content: IContent): Promise<IMegolmEncryptedContent> {
1062
- this.prefixedLogger.debug("Starting to encrypt event");
1063
-
1064
- if (this.encryptionPreparation != null) {
1065
- // If we started sending keys, wait for it to be done.
1066
- // FIXME: check if we need to cancel
1067
- // (https://github.com/matrix-org/matrix-js-sdk/issues/1255)
1068
- try {
1069
- await this.encryptionPreparation.promise;
1070
- } catch {
1071
- // ignore any errors -- if the preparation failed, we'll just
1072
- // restart everything here
1073
- }
1074
- }
1075
-
1076
- /**
1077
- * When using in-room messages and the room has encryption enabled,
1078
- * clients should ensure that encryption does not hinder the verification.
1079
- */
1080
- const forceDistributeToUnverified = this.isVerificationEvent(eventType, content);
1081
- const [devicesInRoom, blocked] = await this.getDevicesInRoom(room, forceDistributeToUnverified);
1082
-
1083
- // check if any of these devices are not yet known to the user.
1084
- // if so, warn the user so they can verify or ignore.
1085
- if (this.crypto.globalErrorOnUnknownDevices) {
1086
- this.checkForUnknownDevices(devicesInRoom);
1087
- }
1088
-
1089
- const session = await this.ensureOutboundSession(room, devicesInRoom, blocked);
1090
- const payloadJson = {
1091
- room_id: this.roomId,
1092
- type: eventType,
1093
- content: content,
1094
- };
1095
-
1096
- const ciphertext = this.olmDevice.encryptGroupMessage(session.sessionId, JSON.stringify(payloadJson));
1097
- const encryptedContent: IEncryptedContent = {
1098
- algorithm: olmlib.MEGOLM_ALGORITHM,
1099
- sender_key: this.olmDevice.deviceCurve25519Key!,
1100
- ciphertext: ciphertext,
1101
- session_id: session.sessionId,
1102
- // Include our device ID so that recipients can send us a
1103
- // m.new_device message if they don't have our session key.
1104
- // XXX: Do we still need this now that m.new_device messages
1105
- // no longer exist since #483?
1106
- device_id: this.deviceId,
1107
- };
1108
-
1109
- session.useCount++;
1110
- return encryptedContent;
1111
- }
1112
-
1113
- private isVerificationEvent(eventType: string, content: IContent): boolean {
1114
- switch (eventType) {
1115
- case EventType.KeyVerificationCancel:
1116
- case EventType.KeyVerificationDone:
1117
- case EventType.KeyVerificationMac:
1118
- case EventType.KeyVerificationStart:
1119
- case EventType.KeyVerificationKey:
1120
- case EventType.KeyVerificationReady:
1121
- case EventType.KeyVerificationAccept: {
1122
- return true;
1123
- }
1124
- case EventType.RoomMessage: {
1125
- return content["msgtype"] === MsgType.KeyVerificationRequest;
1126
- }
1127
- default: {
1128
- return false;
1129
- }
1130
- }
1131
- }
1132
-
1133
- /**
1134
- * Forces the current outbound group session to be discarded such
1135
- * that another one will be created next time an event is sent.
1136
- *
1137
- * This should not normally be necessary.
1138
- */
1139
- public forceDiscardSession(): void {
1140
- this.setupPromise = this.setupPromise.then(() => null);
1141
- }
1142
-
1143
- /**
1144
- * Checks the devices we're about to send to and see if any are entirely
1145
- * unknown to the user. If so, warn the user, and mark them as known to
1146
- * give the user a chance to go verify them before re-sending this message.
1147
- *
1148
- * @param devicesInRoom - `userId -> {deviceId -> object}`
1149
- * devices we should shared the session with.
1150
- */
1151
- private checkForUnknownDevices(devicesInRoom: DeviceInfoMap): void {
1152
- const unknownDevices: MapWithDefault<string, Map<string, DeviceInfo>> = new MapWithDefault(() => new Map());
1153
-
1154
- for (const [userId, userDevices] of devicesInRoom) {
1155
- for (const [deviceId, device] of userDevices) {
1156
- if (device.isUnverified() && !device.isKnown()) {
1157
- unknownDevices.getOrCreate(userId).set(deviceId, device);
1158
- }
1159
- }
1160
- }
1161
-
1162
- if (unknownDevices.size) {
1163
- // it'd be kind to pass unknownDevices up to the user in this error
1164
- throw new UnknownDeviceError(
1165
- "This room contains unknown devices which have not been verified. " +
1166
- "We strongly recommend you verify them before continuing.",
1167
- unknownDevices,
1168
- );
1169
- }
1170
- }
1171
-
1172
- /**
1173
- * Remove unknown devices from a set of devices. The devicesInRoom parameter
1174
- * will be modified.
1175
- *
1176
- * @param devicesInRoom - `userId -> {deviceId -> object}`
1177
- * devices we should shared the session with.
1178
- */
1179
- private removeUnknownDevices(devicesInRoom: DeviceInfoMap): void {
1180
- for (const [userId, userDevices] of devicesInRoom) {
1181
- for (const [deviceId, device] of userDevices) {
1182
- if (device.isUnverified() && !device.isKnown()) {
1183
- userDevices.delete(deviceId);
1184
- }
1185
- }
1186
-
1187
- if (userDevices.size === 0) {
1188
- devicesInRoom.delete(userId);
1189
- }
1190
- }
1191
- }
1192
-
1193
- /**
1194
- * Get the list of unblocked devices for all users in the room
1195
- *
1196
- * @param forceDistributeToUnverified - if set to true will include the unverified devices
1197
- * even if setting is set to block them (useful for verification)
1198
- * @param isCancelled - will cause the procedure to abort early if and when it starts
1199
- * returning `true`. If omitted, cancellation won't happen.
1200
- *
1201
- * @returns Promise which resolves to `null`, or an array whose
1202
- * first element is a {@link DeviceInfoMap} indicating
1203
- * the devices that messages should be encrypted to, and whose second
1204
- * element is a map from userId to deviceId to data indicating the devices
1205
- * that are in the room but that have been blocked.
1206
- * If `isCancelled` is provided and returns `true` while processing, `null`
1207
- * will be returned.
1208
- * If `isCancelled` is not provided, the Promise will never resolve to `null`.
1209
- */
1210
- private async getDevicesInRoom(
1211
- room: Room,
1212
- forceDistributeToUnverified?: boolean,
1213
- ): Promise<[DeviceInfoMap, BlockedMap]>;
1214
- private async getDevicesInRoom(
1215
- room: Room,
1216
- forceDistributeToUnverified?: boolean,
1217
- isCancelled?: () => boolean,
1218
- ): Promise<null | [DeviceInfoMap, BlockedMap]>;
1219
- private async getDevicesInRoom(
1220
- room: Room,
1221
- forceDistributeToUnverified = false,
1222
- isCancelled?: () => boolean,
1223
- ): Promise<null | [DeviceInfoMap, BlockedMap]> {
1224
- const members = await room.getEncryptionTargetMembers();
1225
- this.prefixedLogger.debug(
1226
- `Encrypting for users (shouldEncryptForInvitedMembers: ${room.shouldEncryptForInvitedMembers()}):`,
1227
- members.map((u) => `${u.userId} (${u.membership})`),
1228
- );
1229
-
1230
- const roomMembers = members.map(function (u) {
1231
- return u.userId;
1232
- });
1233
-
1234
- // The global value is treated as a default for when rooms don't specify a value.
1235
- let isBlacklisting = this.crypto.globalBlacklistUnverifiedDevices;
1236
- const isRoomBlacklisting = room.getBlacklistUnverifiedDevices();
1237
- if (typeof isRoomBlacklisting === "boolean") {
1238
- isBlacklisting = isRoomBlacklisting;
1239
- }
1240
-
1241
- // We are happy to use a cached version here: we assume that if we already
1242
- // have a list of the user's devices, then we already share an e2e room
1243
- // with them, which means that they will have announced any new devices via
1244
- // device_lists in their /sync response. This cache should then be maintained
1245
- // using all the device_lists changes and left fields.
1246
- // See https://github.com/vector-im/element-web/issues/2305 for details.
1247
- const devices = await this.crypto.downloadKeys(roomMembers, false);
1248
-
1249
- if (isCancelled?.() === true) {
1250
- return null;
1251
- }
1252
-
1253
- const blocked = new MapWithDefault<string, Map<string, IBlockedDevice>>(() => new Map());
1254
- // remove any blocked devices
1255
- for (const [userId, userDevices] of devices) {
1256
- for (const [deviceId, userDevice] of userDevices) {
1257
- // Yield prior to checking each device so that we don't block
1258
- // updating/rendering for too long.
1259
- // See https://github.com/vector-im/element-web/issues/21612
1260
- if (isCancelled !== undefined) await immediate();
1261
- if (isCancelled?.() === true) return null;
1262
- const deviceTrust = this.crypto.checkDeviceTrust(userId, deviceId);
1263
-
1264
- if (
1265
- userDevice.isBlocked() ||
1266
- (!deviceTrust.isVerified() && isBlacklisting && !forceDistributeToUnverified)
1267
- ) {
1268
- const blockedDevices = blocked.getOrCreate(userId);
1269
- const isBlocked = userDevice.isBlocked();
1270
- blockedDevices.set(deviceId, {
1271
- code: isBlocked ? "m.blacklisted" : "m.unverified",
1272
- reason: WITHHELD_MESSAGES[isBlocked ? "m.blacklisted" : "m.unverified"],
1273
- deviceInfo: userDevice,
1274
- });
1275
- userDevices.delete(deviceId);
1276
- }
1277
- }
1278
- }
1279
-
1280
- return [devices, blocked];
1281
- }
1282
- }
1283
-
1284
- /**
1285
- * Megolm decryption implementation
1286
- *
1287
- * @param params - parameters, as per {@link DecryptionAlgorithm}
1288
- */
1289
- export class MegolmDecryption extends DecryptionAlgorithm {
1290
- // events which we couldn't decrypt due to unknown sessions /
1291
- // indexes, or which we could only decrypt with untrusted keys:
1292
- // map from senderKey|sessionId to Set of MatrixEvents
1293
- private pendingEvents = new Map<string, Map<string, Set<MatrixEvent>>>();
1294
-
1295
- // this gets stubbed out by the unit tests.
1296
- private olmlib = olmlib;
1297
-
1298
- protected readonly roomId: string;
1299
- private readonly prefixedLogger: Logger;
1300
-
1301
- public constructor(params: DecryptionClassParams<IParams & Required<Pick<IParams, "roomId">>>) {
1302
- super(params);
1303
- this.roomId = params.roomId;
1304
- this.prefixedLogger = logger.getChild(`[${this.roomId} decryption]`);
1305
- }
1306
-
1307
- /**
1308
- * returns a promise which resolves to a
1309
- * {@link EventDecryptionResult} once we have finished
1310
- * decrypting, or rejects with an `algorithms.DecryptionError` if there is a
1311
- * problem decrypting the event.
1312
- */
1313
- public async decryptEvent(event: MatrixEvent): Promise<IEventDecryptionResult> {
1314
- const content = event.getWireContent();
1315
-
1316
- if (!content.sender_key || !content.session_id || !content.ciphertext) {
1317
- throw new DecryptionError(DecryptionFailureCode.MEGOLM_MISSING_FIELDS, "Missing fields in input");
1318
- }
1319
-
1320
- // we add the event to the pending list *before* we start decryption.
1321
- //
1322
- // then, if the key turns up while decryption is in progress (and
1323
- // decryption fails), we will schedule a retry.
1324
- // (fixes https://github.com/vector-im/element-web/issues/5001)
1325
- this.addEventToPendingList(event);
1326
-
1327
- let res: IDecryptedGroupMessage | null;
1328
- try {
1329
- res = await this.olmDevice.decryptGroupMessage(
1330
- event.getRoomId()!,
1331
- content.sender_key,
1332
- content.session_id,
1333
- content.ciphertext,
1334
- event.getId()!,
1335
- event.getTs(),
1336
- );
1337
- } catch (e) {
1338
- if ((<Error>e).name === "DecryptionError") {
1339
- // re-throw decryption errors as-is
1340
- throw e;
1341
- }
1342
-
1343
- let errorCode = DecryptionFailureCode.OLM_DECRYPT_GROUP_MESSAGE_ERROR;
1344
-
1345
- if ((<MatrixError>e)?.message === "OLM.UNKNOWN_MESSAGE_INDEX") {
1346
- this.requestKeysForEvent(event);
1347
-
1348
- errorCode = DecryptionFailureCode.OLM_UNKNOWN_MESSAGE_INDEX;
1349
- }
1350
-
1351
- throw new DecryptionError(errorCode, e instanceof Error ? e.message : "Unknown Error: Error is undefined", {
1352
- session: content.sender_key + "|" + content.session_id,
1353
- });
1354
- }
1355
-
1356
- if (res === null) {
1357
- // We've got a message for a session we don't have.
1358
- // try and get the missing key from the backup first
1359
- this.crypto.backupManager.queryKeyBackupRateLimited(event.getRoomId(), content.session_id).catch(() => {});
1360
-
1361
- // (XXX: We might actually have received this key since we started
1362
- // decrypting, in which case we'll have scheduled a retry, and this
1363
- // request will be redundant. We could probably check to see if the
1364
- // event is still in the pending list; if not, a retry will have been
1365
- // scheduled, so we needn't send out the request here.)
1366
- this.requestKeysForEvent(event);
1367
-
1368
- // See if there was a problem with the olm session at the time the
1369
- // event was sent. Use a fuzz factor of 2 minutes.
1370
- const problem = await this.olmDevice.sessionMayHaveProblems(content.sender_key, event.getTs() - 120000);
1371
- if (problem) {
1372
- this.prefixedLogger.info(
1373
- `When handling UISI from ${event.getSender()} (sender key ${content.sender_key}): ` +
1374
- `recent session problem with that sender:`,
1375
- problem,
1376
- );
1377
- let problemDescription = PROBLEM_DESCRIPTIONS[problem.type as "no_olm"] || PROBLEM_DESCRIPTIONS.unknown;
1378
- if (problem.fixed) {
1379
- problemDescription += " Trying to create a new secure channel and re-requesting the keys.";
1380
- }
1381
- throw new DecryptionError(DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID, problemDescription, {
1382
- session: content.sender_key + "|" + content.session_id,
1383
- });
1384
- }
1385
-
1386
- throw new DecryptionError(
1387
- DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID,
1388
- "The sender's device has not sent us the keys for this message.",
1389
- {
1390
- session: content.sender_key + "|" + content.session_id,
1391
- },
1392
- );
1393
- }
1394
-
1395
- // Success. We can remove the event from the pending list, if
1396
- // that hasn't already happened. However, if the event was
1397
- // decrypted with an untrusted key, leave it on the pending
1398
- // list so it will be retried if we find a trusted key later.
1399
- if (!res.untrusted) {
1400
- this.removeEventFromPendingList(event);
1401
- }
1402
-
1403
- const payload = JSON.parse(res.result);
1404
-
1405
- // belt-and-braces check that the room id matches that indicated by the HS
1406
- // (this is somewhat redundant, since the megolm session is scoped to the
1407
- // room, so neither the sender nor a MITM can lie about the room_id).
1408
- if (payload.room_id !== event.getRoomId()) {
1409
- throw new DecryptionError(
1410
- DecryptionFailureCode.MEGOLM_BAD_ROOM,
1411
- "Message intended for room " + payload.room_id,
1412
- );
1413
- }
1414
-
1415
- return {
1416
- clearEvent: payload,
1417
- senderCurve25519Key: res.senderKey,
1418
- claimedEd25519Key: res.keysClaimed.ed25519,
1419
- forwardingCurve25519KeyChain: res.forwardingCurve25519KeyChain,
1420
- untrusted: res.untrusted,
1421
- };
1422
- }
1423
-
1424
- private requestKeysForEvent(event: MatrixEvent): void {
1425
- const wireContent = event.getWireContent();
1426
-
1427
- const recipients = event.getKeyRequestRecipients(this.userId);
1428
-
1429
- this.crypto.requestRoomKey(
1430
- {
1431
- room_id: event.getRoomId()!,
1432
- algorithm: wireContent.algorithm,
1433
- sender_key: wireContent.sender_key,
1434
- session_id: wireContent.session_id,
1435
- },
1436
- recipients,
1437
- );
1438
- }
1439
-
1440
- /**
1441
- * Add an event to the list of those awaiting their session keys.
1442
- *
1443
- * @internal
1444
- *
1445
- */
1446
- private addEventToPendingList(event: MatrixEvent): void {
1447
- const content = event.getWireContent();
1448
- const senderKey = content.sender_key;
1449
- const sessionId = content.session_id;
1450
- if (!this.pendingEvents.has(senderKey)) {
1451
- this.pendingEvents.set(senderKey, new Map<string, Set<MatrixEvent>>());
1452
- }
1453
- const senderPendingEvents = this.pendingEvents.get(senderKey)!;
1454
- if (!senderPendingEvents.has(sessionId)) {
1455
- senderPendingEvents.set(sessionId, new Set());
1456
- }
1457
- senderPendingEvents.get(sessionId)?.add(event);
1458
- }
1459
-
1460
- /**
1461
- * Remove an event from the list of those awaiting their session keys.
1462
- *
1463
- * @internal
1464
- *
1465
- */
1466
- private removeEventFromPendingList(event: MatrixEvent): void {
1467
- const content = event.getWireContent();
1468
- const senderKey = content.sender_key;
1469
- const sessionId = content.session_id;
1470
- const senderPendingEvents = this.pendingEvents.get(senderKey);
1471
- const pendingEvents = senderPendingEvents?.get(sessionId);
1472
- if (!pendingEvents) {
1473
- return;
1474
- }
1475
-
1476
- pendingEvents.delete(event);
1477
- if (pendingEvents.size === 0) {
1478
- senderPendingEvents!.delete(sessionId);
1479
- }
1480
- if (senderPendingEvents!.size === 0) {
1481
- this.pendingEvents.delete(senderKey);
1482
- }
1483
- }
1484
-
1485
- /**
1486
- * Parse a RoomKey out of an `m.room_key` event.
1487
- *
1488
- * @param event - the event containing the room key.
1489
- *
1490
- * @returns The `RoomKey` if it could be successfully parsed out of the
1491
- * event.
1492
- *
1493
- * @internal
1494
- *
1495
- */
1496
- private roomKeyFromEvent(event: MatrixEvent): RoomKey | undefined {
1497
- const senderKey = event.getSenderKey()!;
1498
- const content = event.getContent<Partial<IMessage["content"]>>();
1499
- const extraSessionData: OlmGroupSessionExtraData = {};
1500
-
1501
- if (!content.room_id || !content.session_key || !content.session_id || !content.algorithm) {
1502
- this.prefixedLogger.error("key event is missing fields");
1503
- return;
1504
- }
1505
-
1506
- if (!olmlib.isOlmEncrypted(event)) {
1507
- this.prefixedLogger.error("key event not properly encrypted");
1508
- return;
1509
- }
1510
-
1511
- if (content["org.matrix.msc3061.shared_history"]) {
1512
- extraSessionData.sharedHistory = true;
1513
- }
1514
-
1515
- const roomKey: RoomKey = {
1516
- senderKey: senderKey,
1517
- sessionId: content.session_id,
1518
- sessionKey: content.session_key,
1519
- extraSessionData,
1520
- exportFormat: false,
1521
- roomId: content.room_id,
1522
- algorithm: content.algorithm,
1523
- forwardingKeyChain: [],
1524
- keysClaimed: event.getKeysClaimed(),
1525
- };
1526
-
1527
- return roomKey;
1528
- }
1529
-
1530
- /**
1531
- * Parse a RoomKey out of an `m.forwarded_room_key` event.
1532
- *
1533
- * @param event - the event containing the forwarded room key.
1534
- *
1535
- * @returns The `RoomKey` if it could be successfully parsed out of the
1536
- * event.
1537
- *
1538
- * @internal
1539
- *
1540
- */
1541
- private forwardedRoomKeyFromEvent(event: MatrixEvent): RoomKey | undefined {
1542
- // the properties in m.forwarded_room_key are a superset of those in m.room_key, so
1543
- // start by parsing the m.room_key fields.
1544
- const roomKey = this.roomKeyFromEvent(event);
1545
-
1546
- if (!roomKey) {
1547
- return;
1548
- }
1549
-
1550
- const senderKey = event.getSenderKey()!;
1551
- const content = event.getContent<Partial<IMessage["content"]>>();
1552
-
1553
- const senderKeyUser = this.baseApis.crypto!.deviceList.getUserByIdentityKey(olmlib.OLM_ALGORITHM, senderKey);
1554
-
1555
- // We received this to-device event from event.getSenderKey(), but the original
1556
- // creator of the room key is claimed in the content.
1557
- const claimedCurve25519Key = content.sender_key;
1558
- const claimedEd25519Key = content.sender_claimed_ed25519_key;
1559
-
1560
- let forwardingKeyChain = Array.isArray(content.forwarding_curve25519_key_chain)
1561
- ? content.forwarding_curve25519_key_chain
1562
- : [];
1563
-
1564
- // copy content before we modify it
1565
- forwardingKeyChain = forwardingKeyChain.slice();
1566
- forwardingKeyChain.push(senderKey);
1567
-
1568
- // Check if we have all the fields we need.
1569
- if (senderKeyUser !== event.getSender()) {
1570
- this.prefixedLogger.error("sending device does not belong to the user it claims to be from");
1571
- return;
1572
- }
1573
-
1574
- if (!claimedCurve25519Key) {
1575
- this.prefixedLogger.error("forwarded_room_key event is missing sender_key field");
1576
- return;
1577
- }
1578
-
1579
- if (!claimedEd25519Key) {
1580
- this.prefixedLogger.error(`forwarded_room_key_event is missing sender_claimed_ed25519_key field`);
1581
- return;
1582
- }
1583
-
1584
- const keysClaimed = {
1585
- ed25519: claimedEd25519Key,
1586
- };
1587
-
1588
- // FIXME: We're reusing the same field to track both:
1589
- //
1590
- // 1. The Olm identity we've received this room key from.
1591
- // 2. The Olm identity deduced (in the trusted case) or claiming (in the
1592
- // untrusted case) to be the original creator of this room key.
1593
- //
1594
- // We now overwrite the value tracking usage 1 with the value tracking usage 2.
1595
- roomKey.senderKey = claimedCurve25519Key;
1596
- // Replace our keysClaimed as well.
1597
- roomKey.keysClaimed = keysClaimed;
1598
- roomKey.exportFormat = true;
1599
- roomKey.forwardingKeyChain = forwardingKeyChain;
1600
- // forwarded keys are always untrusted
1601
- roomKey.extraSessionData.untrusted = true;
1602
-
1603
- return roomKey;
1604
- }
1605
-
1606
- /**
1607
- * Determine if we should accept the forwarded room key that was found in the given
1608
- * event.
1609
- *
1610
- * @param event - An `m.forwarded_room_key` event.
1611
- * @param roomKey - The room key that was found in the event.
1612
- *
1613
- * @returns promise that will resolve to a boolean telling us if it's ok to
1614
- * accept the given forwarded room key.
1615
- *
1616
- * @internal
1617
- *
1618
- */
1619
- private async shouldAcceptForwardedKey(event: MatrixEvent, roomKey: RoomKey): Promise<boolean> {
1620
- const senderKey = event.getSenderKey()!;
1621
-
1622
- const sendingDevice =
1623
- this.crypto.deviceList.getDeviceByIdentityKey(olmlib.OLM_ALGORITHM, senderKey) ?? undefined;
1624
- const deviceTrust = this.crypto.checkDeviceInfoTrust(event.getSender()!, sendingDevice);
1625
-
1626
- // Using the plaintext sender here is fine since we checked that the
1627
- // sender matches to the user id in the device keys when this event was
1628
- // originally decrypted. This can obviously only happen if the device
1629
- // keys have been downloaded, but if they haven't the
1630
- // `deviceTrust.isVerified()` flag would be false as well.
1631
- //
1632
- // It would still be far nicer if the `sendingDevice` had a user ID
1633
- // attached to it that went through signature checks.
1634
- const fromUs = event.getSender() === this.baseApis.getUserId();
1635
- const keyFromOurVerifiedDevice = deviceTrust.isVerified() && fromUs;
1636
- const weRequested = await this.wasRoomKeyRequested(event, roomKey);
1637
- const fromInviter = this.wasRoomKeyForwardedByInviter(event, roomKey);
1638
- const sharedAsHistory = this.wasRoomKeyForwardedAsHistory(roomKey);
1639
-
1640
- return (weRequested && keyFromOurVerifiedDevice) || (fromInviter && sharedAsHistory);
1641
- }
1642
-
1643
- /**
1644
- * Did we ever request the given room key from the event sender and its
1645
- * accompanying device.
1646
- *
1647
- * @param event - An `m.forwarded_room_key` event.
1648
- * @param roomKey - The room key that was found in the event.
1649
- *
1650
- * @internal
1651
- *
1652
- */
1653
- private async wasRoomKeyRequested(event: MatrixEvent, roomKey: RoomKey): Promise<boolean> {
1654
- // We send the `m.room_key_request` out as a wildcard to-device request,
1655
- // otherwise we would have to duplicate the same content for each
1656
- // device. This is why we need to pass in "*" as the device id here.
1657
- const outgoingRequests = await this.crypto.cryptoStore.getOutgoingRoomKeyRequestsByTarget(
1658
- event.getSender()!,
1659
- "*",
1660
- [RoomKeyRequestState.Sent],
1661
- );
1662
-
1663
- return outgoingRequests.some(
1664
- (req) => req.requestBody.room_id === roomKey.roomId && req.requestBody.session_id === roomKey.sessionId,
1665
- );
1666
- }
1667
-
1668
- private wasRoomKeyForwardedByInviter(event: MatrixEvent, roomKey: RoomKey): boolean {
1669
- // TODO: This is supposed to have a time limit. We should only accept
1670
- // such keys if we happen to receive them for a recently joined room.
1671
- const room = this.baseApis.getRoom(roomKey.roomId);
1672
- const senderKey = event.getSenderKey();
1673
-
1674
- if (!senderKey) {
1675
- return false;
1676
- }
1677
-
1678
- const senderKeyUser = this.crypto.deviceList.getUserByIdentityKey(olmlib.OLM_ALGORITHM, senderKey);
1679
-
1680
- if (!senderKeyUser) {
1681
- return false;
1682
- }
1683
-
1684
- const memberEvent = room?.getMember(this.userId)?.events.member;
1685
- const fromInviter =
1686
- memberEvent?.getSender() === senderKeyUser ||
1687
- (memberEvent?.getUnsigned()?.prev_sender === senderKeyUser &&
1688
- memberEvent?.getPrevContent()?.membership === KnownMembership.Invite);
1689
-
1690
- if (room && fromInviter) {
1691
- return true;
1692
- } else {
1693
- return false;
1694
- }
1695
- }
1696
-
1697
- private wasRoomKeyForwardedAsHistory(roomKey: RoomKey): boolean {
1698
- const room = this.baseApis.getRoom(roomKey.roomId);
1699
-
1700
- // If the key is not for a known room, then something fishy is going on,
1701
- // so we reject the key out of caution. In practice, this is a bit moot
1702
- // because we'll only accept shared_history forwarded by the inviter, and
1703
- // we won't know who was the inviter for an unknown room, so we'll reject
1704
- // it anyway.
1705
- if (room && roomKey.extraSessionData.sharedHistory) {
1706
- return true;
1707
- } else {
1708
- return false;
1709
- }
1710
- }
1711
-
1712
- /**
1713
- * Check if a forwarded room key should be parked.
1714
- *
1715
- * A forwarded room key should be parked if it's a key for a room we're not
1716
- * in. We park the forwarded room key in case *this sender* invites us to
1717
- * that room later.
1718
- */
1719
- private shouldParkForwardedKey(roomKey: RoomKey): boolean {
1720
- const room = this.baseApis.getRoom(roomKey.roomId);
1721
-
1722
- if (!room && roomKey.extraSessionData.sharedHistory) {
1723
- return true;
1724
- } else {
1725
- return false;
1726
- }
1727
- }
1728
-
1729
- /**
1730
- * Park the given room key to our store.
1731
- *
1732
- * @param event - An `m.forwarded_room_key` event.
1733
- * @param roomKey - The room key that was found in the event.
1734
- *
1735
- * @internal
1736
- *
1737
- */
1738
- private async parkForwardedKey(event: MatrixEvent, roomKey: RoomKey): Promise<void> {
1739
- const parkedData = {
1740
- senderId: event.getSender()!,
1741
- senderKey: roomKey.senderKey,
1742
- sessionId: roomKey.sessionId,
1743
- sessionKey: roomKey.sessionKey,
1744
- keysClaimed: roomKey.keysClaimed,
1745
- forwardingCurve25519KeyChain: roomKey.forwardingKeyChain,
1746
- };
1747
- await this.crypto.cryptoStore.doTxn(
1748
- "readwrite",
1749
- ["parked_shared_history"],
1750
- (txn) => this.crypto.cryptoStore.addParkedSharedHistory(roomKey.roomId, parkedData, txn),
1751
- logger.getChild("[addParkedSharedHistory]"),
1752
- );
1753
- }
1754
-
1755
- /**
1756
- * Add the given room key to our store.
1757
- *
1758
- * @param roomKey - The room key that should be added to the store.
1759
- *
1760
- * @internal
1761
- *
1762
- */
1763
- private async addRoomKey(roomKey: RoomKey): Promise<void> {
1764
- try {
1765
- await this.olmDevice.addInboundGroupSession(
1766
- roomKey.roomId,
1767
- roomKey.senderKey,
1768
- roomKey.forwardingKeyChain,
1769
- roomKey.sessionId,
1770
- roomKey.sessionKey,
1771
- roomKey.keysClaimed,
1772
- roomKey.exportFormat,
1773
- roomKey.extraSessionData,
1774
- );
1775
-
1776
- // have another go at decrypting events sent with this session.
1777
- if (await this.retryDecryption(roomKey.senderKey, roomKey.sessionId, !roomKey.extraSessionData.untrusted)) {
1778
- // cancel any outstanding room key requests for this session.
1779
- // Only do this if we managed to decrypt every message in the
1780
- // session, because if we didn't, we leave the other key
1781
- // requests in the hopes that someone sends us a key that
1782
- // includes an earlier index.
1783
- this.crypto.cancelRoomKeyRequest({
1784
- algorithm: roomKey.algorithm,
1785
- room_id: roomKey.roomId,
1786
- session_id: roomKey.sessionId,
1787
- sender_key: roomKey.senderKey,
1788
- });
1789
- }
1790
-
1791
- // don't wait for the keys to be backed up for the server
1792
- await this.crypto.backupManager.backupGroupSession(roomKey.senderKey, roomKey.sessionId);
1793
- } catch (e) {
1794
- this.prefixedLogger.error(`Error handling m.room_key_event: ${e}`);
1795
- }
1796
- }
1797
-
1798
- /**
1799
- * Handle room keys that have been forwarded to us as an
1800
- * `m.forwarded_room_key` event.
1801
- *
1802
- * Forwarded room keys need special handling since we have no way of knowing
1803
- * who the original creator of the room key was. This naturally means that
1804
- * forwarded room keys are always untrusted and should only be accepted in
1805
- * some cases.
1806
- *
1807
- * @param event - An `m.forwarded_room_key` event.
1808
- *
1809
- * @internal
1810
- *
1811
- */
1812
- private async onForwardedRoomKey(event: MatrixEvent): Promise<void> {
1813
- const roomKey = this.forwardedRoomKeyFromEvent(event);
1814
-
1815
- if (!roomKey) {
1816
- return;
1817
- }
1818
-
1819
- if (await this.shouldAcceptForwardedKey(event, roomKey)) {
1820
- await this.addRoomKey(roomKey);
1821
- } else if (this.shouldParkForwardedKey(roomKey)) {
1822
- await this.parkForwardedKey(event, roomKey);
1823
- }
1824
- }
1825
-
1826
- public async onRoomKeyEvent(event: MatrixEvent): Promise<void> {
1827
- if (event.getType() == "m.forwarded_room_key") {
1828
- await this.onForwardedRoomKey(event);
1829
- } else {
1830
- const roomKey = this.roomKeyFromEvent(event);
1831
-
1832
- if (!roomKey) {
1833
- return;
1834
- }
1835
-
1836
- await this.addRoomKey(roomKey);
1837
- }
1838
- }
1839
-
1840
- /**
1841
- * @param event - key event
1842
- */
1843
- public async onRoomKeyWithheldEvent(event: MatrixEvent): Promise<void> {
1844
- const content = event.getContent();
1845
- const senderKey = content.sender_key;
1846
-
1847
- if (content.code === "m.no_olm") {
1848
- await this.onNoOlmWithheldEvent(event);
1849
- } else if (content.code === "m.unavailable") {
1850
- // this simply means that the other device didn't have the key, which isn't very useful information. Don't
1851
- // record it in the storage
1852
- } else {
1853
- await this.olmDevice.addInboundGroupSessionWithheld(
1854
- content.room_id,
1855
- senderKey,
1856
- content.session_id,
1857
- content.code,
1858
- content.reason,
1859
- );
1860
- }
1861
-
1862
- // Having recorded the problem, retry decryption on any affected messages.
1863
- // It's unlikely we'll be able to decrypt sucessfully now, but this will
1864
- // update the error message.
1865
- //
1866
- if (content.session_id) {
1867
- await this.retryDecryption(senderKey, content.session_id);
1868
- } else {
1869
- // no_olm messages aren't specific to a given megolm session, so
1870
- // we trigger retrying decryption for all the messages from the sender's
1871
- // key, so that we can update the error message to indicate the olm
1872
- // session problem.
1873
- await this.retryDecryptionFromSender(senderKey);
1874
- }
1875
- }
1876
-
1877
- private async onNoOlmWithheldEvent(event: MatrixEvent): Promise<void> {
1878
- const content = event.getContent();
1879
- const senderKey = content.sender_key;
1880
- const sender = event.getSender()!;
1881
- this.prefixedLogger.warn(`${sender}:${senderKey} was unable to establish an olm session with us`);
1882
- // if the sender says that they haven't been able to establish an olm
1883
- // session, let's proactively establish one
1884
-
1885
- if (await this.olmDevice.getSessionIdForDevice(senderKey)) {
1886
- // a session has already been established, so we don't need to
1887
- // create a new one.
1888
- this.prefixedLogger.debug("New session already created. Not creating a new one.");
1889
- await this.olmDevice.recordSessionProblem(senderKey, "no_olm", true);
1890
- return;
1891
- }
1892
- let device = this.crypto.deviceList.getDeviceByIdentityKey(content.algorithm, senderKey);
1893
- if (!device) {
1894
- // if we don't know about the device, fetch the user's devices again
1895
- // and retry before giving up
1896
- await this.crypto.downloadKeys([sender], false);
1897
- device = this.crypto.deviceList.getDeviceByIdentityKey(content.algorithm, senderKey);
1898
- if (!device) {
1899
- this.prefixedLogger.info(
1900
- "Couldn't find device for identity key " + senderKey + ": not establishing session",
1901
- );
1902
- await this.olmDevice.recordSessionProblem(senderKey, "no_olm", false);
1903
- return;
1904
- }
1905
- }
1906
-
1907
- // XXX: switch this to use encryptAndSendToDevices() rather than duplicating it?
1908
-
1909
- await olmlib.ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, new Map([[sender, [device]]]), false);
1910
- const encryptedContent: IEncryptedContent = {
1911
- algorithm: olmlib.OLM_ALGORITHM,
1912
- sender_key: this.olmDevice.deviceCurve25519Key!,
1913
- ciphertext: {},
1914
- [ToDeviceMessageId]: uuidv4(),
1915
- };
1916
- await olmlib.encryptMessageForDevice(
1917
- encryptedContent.ciphertext,
1918
- this.userId,
1919
- undefined,
1920
- this.olmDevice,
1921
- sender,
1922
- device,
1923
- { type: "m.dummy" },
1924
- );
1925
-
1926
- await this.olmDevice.recordSessionProblem(senderKey, "no_olm", true);
1927
-
1928
- await this.baseApis.sendToDevice(
1929
- "m.room.encrypted",
1930
- new Map([[sender, new Map([[device.deviceId, encryptedContent]])]]),
1931
- );
1932
- }
1933
-
1934
- public hasKeysForKeyRequest(keyRequest: IncomingRoomKeyRequest): Promise<boolean> {
1935
- const body = keyRequest.requestBody;
1936
-
1937
- return this.olmDevice.hasInboundSessionKeys(
1938
- body.room_id,
1939
- body.sender_key,
1940
- body.session_id,
1941
- // TODO: ratchet index
1942
- );
1943
- }
1944
-
1945
- public shareKeysWithDevice(keyRequest: IncomingRoomKeyRequest): void {
1946
- const userId = keyRequest.userId;
1947
- const deviceId = keyRequest.deviceId;
1948
- const deviceInfo = this.crypto.getStoredDevice(userId, deviceId)!;
1949
- const body = keyRequest.requestBody;
1950
-
1951
- // XXX: switch this to use encryptAndSendToDevices()?
1952
-
1953
- this.olmlib
1954
- .ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, new Map([[userId, [deviceInfo]]]))
1955
- .then((devicemap) => {
1956
- const olmSessionResult = devicemap.get(userId)?.get(deviceId);
1957
- if (!olmSessionResult?.sessionId) {
1958
- // no session with this device, probably because there
1959
- // were no one-time keys.
1960
- //
1961
- // ensureOlmSessionsForUsers has already done the logging,
1962
- // so just skip it.
1963
- return null;
1964
- }
1965
-
1966
- this.prefixedLogger.debug(
1967
- "sharing keys for session " +
1968
- body.sender_key +
1969
- "|" +
1970
- body.session_id +
1971
- " with device " +
1972
- userId +
1973
- ":" +
1974
- deviceId,
1975
- );
1976
-
1977
- return this.buildKeyForwardingMessage(body.room_id, body.sender_key, body.session_id);
1978
- })
1979
- .then((payload) => {
1980
- const encryptedContent: IEncryptedContent = {
1981
- algorithm: olmlib.OLM_ALGORITHM,
1982
- sender_key: this.olmDevice.deviceCurve25519Key!,
1983
- ciphertext: {},
1984
- [ToDeviceMessageId]: uuidv4(),
1985
- };
1986
-
1987
- return this.olmlib
1988
- .encryptMessageForDevice(
1989
- encryptedContent.ciphertext,
1990
- this.userId,
1991
- undefined,
1992
- this.olmDevice,
1993
- userId,
1994
- deviceInfo,
1995
- payload!,
1996
- )
1997
- .then(() => {
1998
- // TODO: retries
1999
- return this.baseApis.sendToDevice(
2000
- "m.room.encrypted",
2001
- new Map([[userId, new Map([[deviceId, encryptedContent]])]]),
2002
- );
2003
- });
2004
- });
2005
- }
2006
-
2007
- private async buildKeyForwardingMessage(
2008
- roomId: string,
2009
- senderKey: string,
2010
- sessionId: string,
2011
- ): Promise<IKeyForwardingMessage> {
2012
- const key = await this.olmDevice.getInboundGroupSessionKey(roomId, senderKey, sessionId);
2013
-
2014
- return {
2015
- type: "m.forwarded_room_key",
2016
- content: {
2017
- "algorithm": olmlib.MEGOLM_ALGORITHM,
2018
- "room_id": roomId,
2019
- "sender_key": senderKey,
2020
- "sender_claimed_ed25519_key": key!.sender_claimed_ed25519_key!,
2021
- "session_id": sessionId,
2022
- "session_key": key!.key,
2023
- "chain_index": key!.chain_index,
2024
- "forwarding_curve25519_key_chain": key!.forwarding_curve25519_key_chain,
2025
- "org.matrix.msc3061.shared_history": key!.shared_history || false,
2026
- },
2027
- };
2028
- }
2029
-
2030
- /**
2031
- * @param untrusted - whether the key should be considered as untrusted
2032
- * @param source - where the key came from
2033
- */
2034
- public importRoomKey(
2035
- session: IMegolmSessionData,
2036
- { untrusted, source }: { untrusted?: boolean; source?: string } = {},
2037
- ): Promise<void> {
2038
- const extraSessionData: OlmGroupSessionExtraData = {};
2039
- if (untrusted || session.untrusted) {
2040
- extraSessionData.untrusted = true;
2041
- }
2042
- if (session["org.matrix.msc3061.shared_history"]) {
2043
- extraSessionData.sharedHistory = true;
2044
- }
2045
- return this.olmDevice
2046
- .addInboundGroupSession(
2047
- session.room_id,
2048
- session.sender_key,
2049
- session.forwarding_curve25519_key_chain,
2050
- session.session_id,
2051
- session.session_key,
2052
- session.sender_claimed_keys,
2053
- true,
2054
- extraSessionData,
2055
- )
2056
- .then(() => {
2057
- if (source !== "backup") {
2058
- // don't wait for it to complete
2059
- this.crypto.backupManager.backupGroupSession(session.sender_key, session.session_id).catch((e) => {
2060
- // This throws if the upload failed, but this is fine
2061
- // since it will have written it to the db and will retry.
2062
- this.prefixedLogger.debug("Failed to back up megolm session", e);
2063
- });
2064
- }
2065
- // have another go at decrypting events sent with this session.
2066
- this.retryDecryption(session.sender_key, session.session_id, !extraSessionData.untrusted);
2067
- });
2068
- }
2069
-
2070
- /**
2071
- * Have another go at decrypting events after we receive a key. Resolves once
2072
- * decryption has been re-attempted on all events.
2073
- *
2074
- * @internal
2075
- * @param forceRedecryptIfUntrusted - whether messages that were already
2076
- * successfully decrypted using untrusted keys should be re-decrypted
2077
- *
2078
- * @returns whether all messages were successfully
2079
- * decrypted with trusted keys
2080
- */
2081
- private async retryDecryption(
2082
- senderKey: string,
2083
- sessionId: string,
2084
- forceRedecryptIfUntrusted?: boolean,
2085
- ): Promise<boolean> {
2086
- const senderPendingEvents = this.pendingEvents.get(senderKey);
2087
- if (!senderPendingEvents) {
2088
- return true;
2089
- }
2090
-
2091
- const pending = senderPendingEvents.get(sessionId);
2092
- if (!pending) {
2093
- return true;
2094
- }
2095
-
2096
- const pendingList = [...pending];
2097
- this.prefixedLogger.debug(
2098
- "Retrying decryption on events:",
2099
- pendingList.map((e) => `${e.getId()}`),
2100
- );
2101
-
2102
- await Promise.all(
2103
- pendingList.map(async (ev) => {
2104
- try {
2105
- await ev.attemptDecryption(this.crypto, { isRetry: true, forceRedecryptIfUntrusted });
2106
- } catch {
2107
- // don't die if something goes wrong
2108
- }
2109
- }),
2110
- );
2111
-
2112
- // If decrypted successfully with trusted keys, they'll have
2113
- // been removed from pendingEvents
2114
- return !this.pendingEvents.get(senderKey)?.has(sessionId);
2115
- }
2116
-
2117
- public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
2118
- const senderPendingEvents = this.pendingEvents.get(senderKey);
2119
- if (!senderPendingEvents) {
2120
- return true;
2121
- }
2122
-
2123
- this.pendingEvents.delete(senderKey);
2124
-
2125
- await Promise.all(
2126
- [...senderPendingEvents].map(async ([_sessionId, pending]) => {
2127
- await Promise.all(
2128
- [...pending].map(async (ev) => {
2129
- try {
2130
- await ev.attemptDecryption(this.crypto);
2131
- } catch {
2132
- // don't die if something goes wrong
2133
- }
2134
- }),
2135
- );
2136
- }),
2137
- );
2138
-
2139
- return !this.pendingEvents.has(senderKey);
2140
- }
2141
-
2142
- public async sendSharedHistoryInboundSessions(devicesByUser: Map<string, DeviceInfo[]>): Promise<void> {
2143
- await olmlib.ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, devicesByUser);
2144
-
2145
- const sharedHistorySessions = await this.olmDevice.getSharedHistoryInboundGroupSessions(this.roomId);
2146
- this.prefixedLogger.debug(
2147
- `Sharing history in with users ${Array.from(devicesByUser.keys())}`,
2148
- sharedHistorySessions.map(([senderKey, sessionId]) => `${senderKey}|${sessionId}`),
2149
- );
2150
- for (const [senderKey, sessionId] of sharedHistorySessions) {
2151
- const payload = await this.buildKeyForwardingMessage(this.roomId, senderKey, sessionId);
2152
-
2153
- // FIXME: use encryptAndSendToDevices() rather than duplicating it here.
2154
- const promises: Promise<unknown>[] = [];
2155
- const contentMap: Map<string, Map<string, IEncryptedContent>> = new Map();
2156
- for (const [userId, devices] of devicesByUser) {
2157
- const deviceMessages = new Map();
2158
- contentMap.set(userId, deviceMessages);
2159
- for (const deviceInfo of devices) {
2160
- const encryptedContent: IEncryptedContent = {
2161
- algorithm: olmlib.OLM_ALGORITHM,
2162
- sender_key: this.olmDevice.deviceCurve25519Key!,
2163
- ciphertext: {},
2164
- [ToDeviceMessageId]: uuidv4(),
2165
- };
2166
- deviceMessages.set(deviceInfo.deviceId, encryptedContent);
2167
- promises.push(
2168
- olmlib.encryptMessageForDevice(
2169
- encryptedContent.ciphertext,
2170
- this.userId,
2171
- undefined,
2172
- this.olmDevice,
2173
- userId,
2174
- deviceInfo,
2175
- payload,
2176
- ),
2177
- );
2178
- }
2179
- }
2180
- await Promise.all(promises);
2181
-
2182
- // prune out any devices that encryptMessageForDevice could not encrypt for,
2183
- // in which case it will have just not added anything to the ciphertext object.
2184
- // There's no point sending messages to devices if we couldn't encrypt to them,
2185
- // since that's effectively a blank message.
2186
- for (const [userId, deviceMessages] of contentMap) {
2187
- for (const [deviceId, content] of deviceMessages) {
2188
- if (!hasCiphertext(content)) {
2189
- this.prefixedLogger.debug("No ciphertext for device " + userId + ":" + deviceId + ": pruning");
2190
- deviceMessages.delete(deviceId);
2191
- }
2192
- }
2193
- // No devices left for that user? Strip that too.
2194
- if (deviceMessages.size === 0) {
2195
- this.prefixedLogger.debug("Pruned all devices for user " + userId);
2196
- contentMap.delete(userId);
2197
- }
2198
- }
2199
-
2200
- // Is there anything left?
2201
- if (contentMap.size === 0) {
2202
- this.prefixedLogger.debug("No users left to send to: aborting");
2203
- return;
2204
- }
2205
-
2206
- await this.baseApis.sendToDevice("m.room.encrypted", contentMap);
2207
- }
2208
- }
2209
- }
2210
-
2211
- const PROBLEM_DESCRIPTIONS = {
2212
- no_olm: "The sender was unable to establish a secure channel.",
2213
- unknown: "The secure channel with the sender was corrupted.",
2214
- };
2215
-
2216
- registerAlgorithm(olmlib.MEGOLM_ALGORITHM, MegolmEncryption, MegolmDecryption);