zapo-js 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/README.md +16 -4
  2. package/dist/appstate/WaAppStateCrypto.js +50 -42
  3. package/dist/appstate/WaAppStateSyncClient.js +215 -133
  4. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  5. package/dist/appstate/index.js +9 -7
  6. package/dist/appstate/utils.js +0 -5
  7. package/dist/auth/WaAuthClient.js +55 -57
  8. package/dist/auth/credentials-flow.js +195 -0
  9. package/dist/auth/index.js +1 -6
  10. package/dist/auth/pairing/WaPairingFlow.js +39 -32
  11. package/dist/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +35 -17
  12. package/dist/client/WaClient.js +338 -174
  13. package/dist/client/WaClientFactory.js +399 -66
  14. package/dist/client/connection/WaConnectionManager.js +23 -11
  15. package/dist/client/coordinators/WaAbPropsCoordinator.js +141 -0
  16. package/dist/client/coordinators/WaBusinessCoordinator.js +232 -0
  17. package/dist/client/coordinators/WaEmailCoordinator.js +63 -0
  18. package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
  19. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +34 -8
  20. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +341 -118
  21. package/dist/client/coordinators/WaOfflineResumeCoordinator.js +114 -0
  22. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +97 -36
  23. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  24. package/dist/client/coordinators/WaProfileCoordinator.js +214 -0
  25. package/dist/client/coordinators/WaRetryCoordinator.js +184 -30
  26. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  27. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +184 -0
  28. package/dist/client/dirty.js +41 -21
  29. package/dist/client/events/abprops.js +43 -0
  30. package/dist/client/events/devices.js +72 -0
  31. package/dist/client/events/group.js +3 -11
  32. package/dist/client/events/identity.js +22 -0
  33. package/dist/client/events/privacy-token.js +38 -0
  34. package/dist/client/events/registration.js +42 -0
  35. package/dist/client/history-sync.js +50 -9
  36. package/dist/client/incoming.js +74 -7
  37. package/dist/client/mailbox.js +40 -23
  38. package/dist/client/media.js +243 -0
  39. package/dist/client/messages.js +245 -92
  40. package/dist/client/messaging/fanout.js +21 -11
  41. package/dist/client/messaging/participants.js +6 -4
  42. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  43. package/dist/client/tokens/cs-token.js +50 -0
  44. package/dist/client/tokens/tc-token.js +25 -0
  45. package/dist/crypto/core/index.js +5 -2
  46. package/dist/crypto/core/keys.js +4 -4
  47. package/dist/crypto/core/nonce.js +2 -0
  48. package/dist/crypto/core/primitives.js +0 -8
  49. package/dist/crypto/core/random.js +24 -8
  50. package/dist/crypto/core/xeddsa.js +57 -0
  51. package/dist/crypto/curves/X25519.js +43 -6
  52. package/dist/crypto/curves/constants.js +2 -1
  53. package/dist/crypto/index.js +3 -0
  54. package/dist/crypto/math/constants.js +13 -36
  55. package/dist/crypto/math/edwards.js +171 -44
  56. package/dist/crypto/math/fe.js +706 -0
  57. package/dist/crypto/math/mod.js +10 -3
  58. package/dist/esm/appstate/WaAppStateCrypto.js +40 -32
  59. package/dist/esm/appstate/WaAppStateSyncClient.js +206 -124
  60. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  61. package/dist/esm/appstate/index.js +2 -2
  62. package/dist/esm/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +1 -1
  63. package/dist/esm/appstate/utils.js +2 -5
  64. package/dist/esm/auth/WaAuthClient.js +52 -54
  65. package/dist/esm/auth/credentials-flow.js +190 -0
  66. package/dist/esm/auth/index.js +0 -2
  67. package/dist/esm/auth/pairing/WaPairingFlow.js +39 -32
  68. package/dist/esm/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +26 -10
  69. package/dist/esm/client/WaClient.js +339 -175
  70. package/dist/esm/client/WaClientFactory.js +401 -68
  71. package/dist/esm/client/connection/WaConnectionManager.js +23 -11
  72. package/dist/esm/client/coordinators/WaAbPropsCoordinator.js +137 -0
  73. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +229 -0
  74. package/dist/esm/client/coordinators/WaEmailCoordinator.js +60 -0
  75. package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
  76. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +36 -10
  77. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +337 -114
  78. package/dist/esm/client/coordinators/WaOfflineResumeCoordinator.js +110 -0
  79. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +97 -36
  80. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  81. package/dist/esm/client/coordinators/WaProfileCoordinator.js +211 -0
  82. package/dist/esm/client/coordinators/WaRetryCoordinator.js +186 -32
  83. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  84. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +180 -0
  85. package/dist/esm/client/dirty.js +41 -21
  86. package/dist/esm/client/events/abprops.js +40 -0
  87. package/dist/esm/client/events/devices.js +68 -0
  88. package/dist/esm/client/events/group.js +3 -11
  89. package/dist/esm/client/events/identity.js +19 -0
  90. package/dist/esm/client/events/privacy-token.js +35 -0
  91. package/dist/esm/client/events/registration.js +39 -0
  92. package/dist/esm/client/history-sync.js +50 -9
  93. package/dist/esm/client/incoming.js +74 -8
  94. package/dist/esm/client/mailbox.js +40 -23
  95. package/dist/esm/client/media.js +234 -0
  96. package/dist/esm/client/messages.js +244 -91
  97. package/dist/esm/client/messaging/fanout.js +22 -12
  98. package/dist/esm/client/messaging/participants.js +6 -4
  99. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  100. package/dist/esm/client/tokens/cs-token.js +46 -0
  101. package/dist/esm/client/tokens/tc-token.js +18 -0
  102. package/dist/esm/crypto/core/index.js +3 -2
  103. package/dist/esm/crypto/core/keys.js +1 -1
  104. package/dist/esm/crypto/core/nonce.js +2 -0
  105. package/dist/esm/crypto/core/primitives.js +0 -7
  106. package/dist/esm/crypto/core/random.js +23 -7
  107. package/dist/esm/crypto/core/xeddsa.js +53 -0
  108. package/dist/esm/crypto/curves/X25519.js +45 -8
  109. package/dist/esm/crypto/curves/constants.js +1 -0
  110. package/dist/esm/crypto/index.js +1 -0
  111. package/dist/esm/crypto/math/constants.js +12 -35
  112. package/dist/esm/crypto/math/edwards.js +174 -47
  113. package/dist/esm/crypto/math/fe.js +691 -0
  114. package/dist/esm/crypto/math/mod.js +10 -1
  115. package/dist/esm/index.js +1 -1
  116. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  117. package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
  118. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  119. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  120. package/dist/esm/infra/perf/StoreLock.js +80 -0
  121. package/dist/esm/media/WaMediaCrypto.js +332 -55
  122. package/dist/esm/media/WaMediaTransferClient.js +69 -220
  123. package/dist/esm/media/constants.js +4 -1
  124. package/dist/esm/media/processor.js +1 -0
  125. package/dist/esm/message/WaMessageClient.js +26 -19
  126. package/dist/esm/message/addon-crypto.js +130 -3
  127. package/dist/esm/message/content.js +206 -14
  128. package/dist/esm/message/icdc.js +76 -0
  129. package/dist/esm/message/incoming.js +38 -24
  130. package/dist/esm/message/phash.js +35 -13
  131. package/dist/esm/message/reporting-token.js +17 -30
  132. package/dist/esm/message/use-case-secret.js +1 -1
  133. package/dist/esm/protocol/abprops.js +159 -0
  134. package/dist/esm/protocol/appstate.js +9 -40
  135. package/dist/esm/protocol/browser.js +24 -18
  136. package/dist/esm/protocol/constants.js +8 -4
  137. package/dist/esm/protocol/defaults.js +6 -0
  138. package/dist/esm/protocol/email.js +30 -0
  139. package/dist/esm/protocol/index.js +1 -2
  140. package/dist/esm/protocol/jid.js +142 -39
  141. package/dist/esm/protocol/message.js +61 -1
  142. package/dist/esm/protocol/nodes.js +8 -2
  143. package/dist/esm/protocol/notification.js +9 -1
  144. package/dist/esm/protocol/privacy-token.js +17 -0
  145. package/dist/esm/protocol/privacy.js +55 -0
  146. package/dist/esm/protocol/stream.js +26 -1
  147. package/dist/esm/retry/codec.js +216 -0
  148. package/dist/esm/retry/constants.js +1 -1
  149. package/dist/esm/retry/index.js +2 -2
  150. package/dist/esm/retry/parse.js +50 -30
  151. package/dist/esm/retry/reason.js +1 -1
  152. package/dist/esm/retry/replay.js +11 -7
  153. package/dist/esm/retry/tracker.js +50 -12
  154. package/dist/esm/signal/api/SignalDeviceSyncApi.js +52 -32
  155. package/dist/esm/signal/api/SignalDigestSyncApi.js +21 -15
  156. package/dist/esm/signal/api/SignalIdentitySyncApi.js +30 -15
  157. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +19 -8
  158. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  159. package/dist/esm/signal/api/SignalSessionSyncApi.js +17 -8
  160. package/dist/esm/signal/api/result-map.js +10 -0
  161. package/dist/esm/signal/constants.js +0 -4
  162. package/dist/esm/signal/crypto/WaAdvSignature.js +5 -45
  163. package/dist/esm/signal/crypto/constants.js +0 -4
  164. package/dist/esm/signal/{store/sqlite.js → encoding.js} +40 -29
  165. package/dist/esm/signal/group/SenderKeyChain.js +3 -3
  166. package/dist/esm/signal/group/SenderKeyCodec.js +8 -8
  167. package/dist/esm/signal/group/SenderKeyManager.js +131 -109
  168. package/dist/esm/signal/index.js +1 -0
  169. package/dist/esm/signal/registration/keygen.js +8 -5
  170. package/dist/esm/signal/registration/utils.js +3 -2
  171. package/dist/esm/signal/session/SignalProtocol.js +158 -81
  172. package/dist/esm/signal/session/SignalRatchet.js +21 -10
  173. package/dist/esm/signal/session/SignalSerializer.js +5 -6
  174. package/dist/esm/signal/session/SignalSession.js +11 -9
  175. package/dist/esm/signal/session/resolver.js +140 -105
  176. package/dist/esm/store/contracts/identity.store.js +1 -0
  177. package/dist/esm/store/contracts/message-secret.store.js +1 -0
  178. package/dist/esm/store/contracts/pre-key.store.js +1 -0
  179. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  180. package/dist/esm/store/contracts/session.store.js +1 -0
  181. package/dist/esm/store/createStore.js +143 -193
  182. package/dist/esm/store/index.js +5 -10
  183. package/dist/esm/store/locks/appstate.lock.js +26 -0
  184. package/dist/esm/store/locks/auth.lock.js +15 -0
  185. package/dist/esm/store/locks/contact.lock.js +20 -0
  186. package/dist/esm/store/locks/device-list.lock.js +20 -0
  187. package/dist/esm/store/locks/identity.lock.js +16 -0
  188. package/dist/esm/store/locks/message-secret.lock.js +17 -0
  189. package/dist/esm/store/locks/message.lock.js +21 -0
  190. package/dist/esm/store/locks/participants.lock.js +20 -0
  191. package/dist/esm/store/locks/pre-key.lock.js +27 -0
  192. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  193. package/dist/esm/store/locks/retry.lock.js +29 -0
  194. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  195. package/dist/esm/store/locks/session.lock.js +19 -0
  196. package/dist/esm/store/locks/signal.lock.js +39 -0
  197. package/dist/esm/store/locks/thread.lock.js +21 -0
  198. package/dist/esm/store/noop.store.js +21 -1
  199. package/dist/esm/store/providers/memory/appstate.store.js +22 -24
  200. package/dist/esm/store/providers/memory/device-list.store.js +13 -5
  201. package/dist/esm/store/providers/memory/identity.store.js +31 -0
  202. package/dist/esm/store/providers/memory/message-secret.store.js +81 -0
  203. package/dist/esm/store/providers/memory/participants.store.js +3 -0
  204. package/dist/esm/store/providers/memory/pre-key.store.js +97 -0
  205. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  206. package/dist/esm/store/providers/memory/retry.store.js +99 -10
  207. package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
  208. package/dist/esm/store/providers/memory/session.store.js +45 -0
  209. package/dist/esm/store/providers/memory/signal.store.js +1 -147
  210. package/dist/esm/transport/WaComms.js +7 -4
  211. package/dist/esm/transport/WaWebSocket.js +9 -7
  212. package/dist/esm/transport/binary/constants.js +0 -30
  213. package/dist/esm/transport/binary/decoder.js +4 -4
  214. package/dist/esm/transport/binary/encoder.js +8 -15
  215. package/dist/esm/transport/binary/index.js +0 -1
  216. package/dist/esm/transport/index.js +6 -0
  217. package/dist/esm/transport/keepalive/WaKeepAlive.js +17 -8
  218. package/dist/esm/transport/node/WaMobileTcpSocket.js +114 -0
  219. package/dist/esm/transport/node/WaNodeOrchestrator.js +37 -22
  220. package/dist/esm/transport/node/builders/abprops.js +20 -0
  221. package/dist/esm/transport/node/builders/business.js +129 -0
  222. package/dist/esm/transport/node/builders/device.js +11 -0
  223. package/dist/esm/transport/node/builders/email.js +65 -0
  224. package/dist/esm/transport/node/builders/global.js +370 -0
  225. package/dist/esm/transport/node/builders/message.js +63 -239
  226. package/dist/esm/transport/node/builders/offline.js +14 -0
  227. package/dist/esm/transport/node/builders/pairing.js +0 -24
  228. package/dist/esm/transport/node/builders/prekeys.js +37 -40
  229. package/dist/esm/transport/node/builders/presence.js +13 -0
  230. package/dist/esm/transport/node/builders/privacy-token.js +37 -0
  231. package/dist/esm/transport/node/builders/privacy.js +48 -0
  232. package/dist/esm/transport/node/builders/profile.js +70 -0
  233. package/dist/esm/transport/node/builders/retry.js +11 -23
  234. package/dist/esm/transport/node/builders/usync.js +6 -2
  235. package/dist/esm/transport/node/helpers.js +43 -1
  236. package/dist/esm/transport/node/mex/argo-decoder.js +152 -0
  237. package/dist/esm/transport/node/mex/client.js +83 -0
  238. package/dist/esm/transport/node/mex/persist-ids.js +10 -0
  239. package/dist/esm/transport/node/usync.js +3 -33
  240. package/dist/esm/transport/node/xml.js +35 -14
  241. package/dist/esm/transport/noise/WaClientPayload.js +24 -19
  242. package/dist/esm/transport/noise/WaFrameCodec.js +2 -2
  243. package/dist/esm/transport/noise/WaMobileClientPayload.js +53 -0
  244. package/dist/esm/transport/noise/WaNoiseCert.js +9 -27
  245. package/dist/esm/transport/noise/WaNoiseSession.js +76 -34
  246. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  247. package/dist/esm/transport/stream/parse.js +8 -4
  248. package/dist/esm/util/bytes.js +22 -18
  249. package/dist/esm/util/index.js +5 -0
  250. package/dist/esm/util/primitives.js +3 -2
  251. package/dist/index.js +7 -1
  252. package/dist/infra/perf/BackgroundQueue.js +482 -0
  253. package/dist/infra/perf/BoundedTaskQueue.js +3 -1
  254. package/dist/infra/perf/PromiseDedup.js +24 -0
  255. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  256. package/dist/infra/perf/StoreLock.js +84 -0
  257. package/dist/media/WaMediaCrypto.js +328 -51
  258. package/dist/media/WaMediaTransferClient.js +72 -253
  259. package/dist/media/constants.js +5 -2
  260. package/dist/media/processor.js +2 -0
  261. package/dist/message/WaMessageClient.js +26 -19
  262. package/dist/message/addon-crypto.js +131 -0
  263. package/dist/message/content.js +211 -14
  264. package/dist/message/icdc.js +81 -0
  265. package/dist/message/incoming.js +38 -24
  266. package/dist/message/phash.js +35 -13
  267. package/dist/message/reporting-token.js +16 -30
  268. package/dist/message/use-case-secret.js +1 -1
  269. package/dist/protocol/abprops.js +163 -0
  270. package/dist/protocol/appstate.js +10 -41
  271. package/dist/protocol/browser.js +25 -18
  272. package/dist/protocol/constants.js +33 -2
  273. package/dist/protocol/defaults.js +6 -0
  274. package/dist/protocol/email.js +33 -0
  275. package/dist/protocol/index.js +8 -5
  276. package/dist/protocol/jid.js +149 -39
  277. package/dist/protocol/message.js +62 -2
  278. package/dist/protocol/nodes.js +8 -2
  279. package/dist/protocol/notification.js +10 -2
  280. package/dist/protocol/privacy-token.js +20 -0
  281. package/dist/protocol/privacy.js +58 -0
  282. package/dist/protocol/stream.js +27 -2
  283. package/dist/retry/codec.js +220 -0
  284. package/dist/retry/constants.js +1 -1
  285. package/dist/retry/index.js +5 -5
  286. package/dist/retry/parse.js +51 -30
  287. package/dist/retry/reason.js +1 -1
  288. package/dist/retry/replay.js +10 -6
  289. package/dist/retry/tracker.js +50 -12
  290. package/dist/signal/api/SignalDeviceSyncApi.js +51 -31
  291. package/dist/signal/api/SignalDigestSyncApi.js +21 -15
  292. package/dist/signal/api/SignalIdentitySyncApi.js +29 -14
  293. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
  294. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  295. package/dist/signal/api/SignalSessionSyncApi.js +16 -7
  296. package/dist/signal/api/result-map.js +13 -0
  297. package/dist/signal/constants.js +1 -5
  298. package/dist/signal/crypto/WaAdvSignature.js +2 -44
  299. package/dist/signal/crypto/constants.js +1 -5
  300. package/dist/signal/{store/sqlite.js → encoding.js} +41 -25
  301. package/dist/signal/group/SenderKeyChain.js +2 -2
  302. package/dist/signal/group/SenderKeyCodec.js +8 -8
  303. package/dist/signal/group/SenderKeyManager.js +130 -108
  304. package/dist/signal/index.js +13 -1
  305. package/dist/signal/registration/keygen.js +7 -4
  306. package/dist/signal/registration/utils.js +3 -2
  307. package/dist/signal/session/SignalProtocol.js +158 -81
  308. package/dist/signal/session/SignalRatchet.js +19 -8
  309. package/dist/signal/session/SignalSerializer.js +5 -6
  310. package/dist/signal/session/SignalSession.js +11 -9
  311. package/dist/signal/session/resolver.js +138 -103
  312. package/dist/store/contracts/identity.store.js +2 -0
  313. package/dist/store/contracts/message-secret.store.js +2 -0
  314. package/dist/store/contracts/pre-key.store.js +2 -0
  315. package/dist/store/contracts/privacy-token.store.js +2 -0
  316. package/dist/store/contracts/session.store.js +2 -0
  317. package/dist/store/createStore.js +142 -192
  318. package/dist/store/index.js +23 -33
  319. package/dist/store/locks/appstate.lock.js +29 -0
  320. package/dist/store/locks/auth.lock.js +18 -0
  321. package/dist/store/locks/contact.lock.js +23 -0
  322. package/dist/store/locks/device-list.lock.js +23 -0
  323. package/dist/store/locks/identity.lock.js +19 -0
  324. package/dist/store/locks/message-secret.lock.js +20 -0
  325. package/dist/store/locks/message.lock.js +24 -0
  326. package/dist/store/locks/participants.lock.js +23 -0
  327. package/dist/store/locks/pre-key.lock.js +30 -0
  328. package/dist/store/locks/privacy-token.lock.js +21 -0
  329. package/dist/store/locks/retry.lock.js +32 -0
  330. package/dist/store/locks/sender-key.lock.js +55 -0
  331. package/dist/store/locks/session.lock.js +22 -0
  332. package/dist/store/locks/signal.lock.js +42 -0
  333. package/dist/store/locks/thread.lock.js +24 -0
  334. package/dist/store/noop.store.js +22 -2
  335. package/dist/store/providers/memory/appstate.store.js +22 -24
  336. package/dist/store/providers/memory/device-list.store.js +13 -5
  337. package/dist/store/providers/memory/identity.store.js +35 -0
  338. package/dist/store/providers/memory/message-secret.store.js +85 -0
  339. package/dist/store/providers/memory/participants.store.js +3 -0
  340. package/dist/store/providers/memory/pre-key.store.js +101 -0
  341. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  342. package/dist/store/providers/memory/retry.store.js +98 -9
  343. package/dist/store/providers/memory/sender-key.store.js +6 -1
  344. package/dist/store/providers/memory/session.store.js +49 -0
  345. package/dist/store/providers/memory/signal.store.js +1 -147
  346. package/dist/transport/WaComms.js +7 -4
  347. package/dist/transport/WaWebSocket.js +9 -7
  348. package/dist/transport/binary/constants.js +1 -31
  349. package/dist/transport/binary/decoder.js +4 -4
  350. package/dist/transport/binary/encoder.js +8 -15
  351. package/dist/transport/binary/index.js +0 -4
  352. package/dist/transport/index.js +17 -1
  353. package/dist/transport/keepalive/WaKeepAlive.js +17 -8
  354. package/dist/transport/node/WaMobileTcpSocket.js +118 -0
  355. package/dist/transport/node/WaNodeOrchestrator.js +36 -21
  356. package/dist/transport/node/builders/abprops.js +23 -0
  357. package/dist/transport/node/builders/business.js +137 -0
  358. package/dist/transport/node/builders/device.js +14 -0
  359. package/dist/transport/node/builders/email.js +72 -0
  360. package/dist/transport/node/builders/global.js +375 -0
  361. package/dist/transport/node/builders/message.js +64 -245
  362. package/dist/transport/node/builders/offline.js +17 -0
  363. package/dist/transport/node/builders/pairing.js +0 -26
  364. package/dist/transport/node/builders/prekeys.js +36 -39
  365. package/dist/transport/node/builders/presence.js +16 -0
  366. package/dist/transport/node/builders/privacy-token.js +42 -0
  367. package/dist/transport/node/builders/privacy.js +55 -0
  368. package/dist/transport/node/builders/profile.js +78 -0
  369. package/dist/transport/node/builders/retry.js +10 -22
  370. package/dist/transport/node/builders/usync.js +6 -2
  371. package/dist/transport/node/helpers.js +46 -1
  372. package/dist/transport/node/mex/argo-decoder.js +189 -0
  373. package/dist/transport/node/mex/client.js +86 -0
  374. package/dist/transport/node/mex/persist-ids.js +13 -0
  375. package/dist/transport/node/usync.js +2 -32
  376. package/dist/transport/node/xml.js +35 -14
  377. package/dist/transport/noise/WaClientPayload.js +26 -21
  378. package/dist/transport/noise/WaFrameCodec.js +1 -1
  379. package/dist/transport/noise/WaMobileClientPayload.js +56 -0
  380. package/dist/transport/noise/WaNoiseCert.js +8 -26
  381. package/dist/transport/noise/WaNoiseSession.js +75 -33
  382. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  383. package/dist/transport/stream/parse.js +7 -3
  384. package/dist/types/appstate/WaAppStateCrypto.d.ts +11 -8
  385. package/dist/types/appstate/WaAppStateSyncClient.d.ts +6 -2
  386. package/dist/types/appstate/encoding.d.ts +7 -0
  387. package/dist/types/appstate/index.d.ts +3 -3
  388. package/dist/types/appstate/{WaAppStateSyncResponseParser.d.ts → response-parser.d.ts} +1 -1
  389. package/dist/types/appstate/types.d.ts +1 -1
  390. package/dist/types/appstate/utils.d.ts +0 -2
  391. package/dist/types/auth/WaAuthClient.d.ts +9 -3
  392. package/dist/types/auth/credentials-flow.d.ts +20 -0
  393. package/dist/types/auth/index.d.ts +0 -2
  394. package/dist/types/auth/pairing/WaPairingFlow.d.ts +3 -2
  395. package/dist/types/auth/pairing/{WaPairingCodeCrypto.d.ts → pairing-code-crypto.d.ts} +6 -1
  396. package/dist/types/auth/types.d.ts +41 -0
  397. package/dist/types/client/WaClient.d.ts +44 -18
  398. package/dist/types/client/WaClientFactory.d.ts +22 -8
  399. package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
  400. package/dist/types/client/coordinators/WaAbPropsCoordinator.d.ts +26 -0
  401. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  402. package/dist/types/client/coordinators/WaEmailCoordinator.d.ts +24 -0
  403. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +9 -2
  404. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +29 -2
  405. package/dist/types/client/coordinators/WaOfflineResumeCoordinator.d.ts +31 -0
  406. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +16 -1
  407. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  408. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +38 -0
  409. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +12 -0
  410. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  411. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +55 -0
  412. package/dist/types/client/dirty.d.ts +3 -1
  413. package/dist/types/client/events/abprops.d.ts +14 -0
  414. package/dist/types/client/events/devices.d.ts +20 -0
  415. package/dist/types/client/events/identity.d.ts +9 -0
  416. package/dist/types/client/events/privacy-token.d.ts +7 -0
  417. package/dist/types/client/events/registration.d.ts +17 -0
  418. package/dist/types/client/history-sync.d.ts +9 -6
  419. package/dist/types/client/incoming.d.ts +9 -2
  420. package/dist/types/client/index.d.ts +1 -1
  421. package/dist/types/client/mailbox.d.ts +5 -5
  422. package/dist/types/client/media.d.ts +31 -0
  423. package/dist/types/client/messages.d.ts +3 -2
  424. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  425. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  426. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  427. package/dist/types/client/types.d.ts +151 -4
  428. package/dist/types/crypto/core/index.d.ts +3 -2
  429. package/dist/types/crypto/core/nonce.d.ts +2 -0
  430. package/dist/types/crypto/core/primitives.d.ts +1 -2
  431. package/dist/types/crypto/core/random.d.ts +2 -1
  432. package/dist/types/crypto/core/xeddsa.d.ts +2 -0
  433. package/dist/types/crypto/curves/constants.d.ts +1 -0
  434. package/dist/types/crypto/index.d.ts +2 -0
  435. package/dist/types/crypto/math/constants.d.ts +4 -2
  436. package/dist/types/crypto/math/fe.d.ts +30 -0
  437. package/dist/types/crypto/math/mod.d.ts +0 -2
  438. package/dist/types/crypto/math/types.d.ts +11 -4
  439. package/dist/types/index.d.ts +6 -3
  440. package/dist/types/infra/log/ConsoleLogger.d.ts +1 -1
  441. package/dist/types/infra/log/PinoLogger.d.ts +1 -1
  442. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  443. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  444. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  445. package/dist/types/infra/perf/StoreLock.d.ts +11 -0
  446. package/dist/types/media/WaMediaCrypto.d.ts +16 -6
  447. package/dist/types/media/WaMediaTransferClient.d.ts +6 -23
  448. package/dist/types/media/constants.d.ts +3 -1
  449. package/dist/types/media/index.d.ts +2 -1
  450. package/dist/types/media/processor.d.ts +28 -0
  451. package/dist/types/media/types.d.ts +19 -5
  452. package/dist/types/message/addon-crypto.d.ts +34 -3
  453. package/dist/types/message/content.d.ts +11 -1
  454. package/dist/types/message/icdc.d.ts +13 -0
  455. package/dist/types/message/reporting-token.d.ts +0 -1
  456. package/dist/types/message/types.d.ts +42 -11
  457. package/dist/types/protocol/abprops.d.ts +142 -0
  458. package/dist/types/protocol/appstate.d.ts +0 -11
  459. package/dist/types/protocol/browser.d.ts +1 -0
  460. package/dist/types/protocol/constants.d.ts +12 -4
  461. package/dist/types/protocol/defaults.d.ts +6 -0
  462. package/dist/types/protocol/email.d.ts +32 -0
  463. package/dist/types/protocol/index.d.ts +1 -2
  464. package/dist/types/protocol/jid.d.ts +20 -2
  465. package/dist/types/protocol/message.d.ts +60 -0
  466. package/dist/types/protocol/nodes.d.ts +6 -0
  467. package/dist/types/protocol/notification.d.ts +8 -0
  468. package/dist/types/protocol/privacy-token.d.ts +17 -0
  469. package/dist/types/protocol/privacy.d.ts +75 -0
  470. package/dist/types/protocol/stream.d.ts +31 -0
  471. package/dist/types/retry/codec.d.ts +3 -0
  472. package/dist/types/retry/index.d.ts +3 -3
  473. package/dist/types/retry/parse.d.ts +5 -2
  474. package/dist/types/retry/reason.d.ts +1 -1
  475. package/dist/types/retry/tracker.d.ts +1 -0
  476. package/dist/types/retry/types.d.ts +6 -1
  477. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
  478. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +9 -0
  479. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +5 -3
  480. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  481. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  482. package/dist/types/signal/api/result-map.d.ts +1 -0
  483. package/dist/types/signal/constants.d.ts +0 -3
  484. package/dist/types/signal/crypto/WaAdvSignature.d.ts +0 -2
  485. package/dist/types/signal/crypto/constants.d.ts +0 -1
  486. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +9 -3
  487. package/dist/types/signal/group/SenderKeyChain.d.ts +1 -1
  488. package/dist/types/signal/group/SenderKeyManager.d.ts +17 -7
  489. package/dist/types/signal/index.d.ts +2 -0
  490. package/dist/types/signal/registration/utils.d.ts +2 -1
  491. package/dist/types/signal/session/SignalProtocol.d.ts +21 -6
  492. package/dist/types/signal/session/SignalSerializer.d.ts +2 -1
  493. package/dist/types/signal/session/resolver.d.ts +11 -4
  494. package/dist/types/signal/types.d.ts +16 -4
  495. package/dist/types/store/contracts/appstate.store.d.ts +1 -1
  496. package/dist/types/store/contracts/identity.store.d.ts +11 -0
  497. package/dist/types/store/contracts/message-secret.store.d.ts +16 -0
  498. package/dist/types/store/contracts/pre-key.store.d.ts +13 -0
  499. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  500. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  501. package/dist/types/store/contracts/session.store.d.ts +14 -0
  502. package/dist/types/store/contracts/signal.store.d.ts +1 -27
  503. package/dist/types/store/createStore.d.ts +1 -1
  504. package/dist/types/store/index.d.ts +12 -12
  505. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  506. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  507. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  508. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  509. package/dist/types/store/locks/identity.lock.d.ts +3 -0
  510. package/dist/types/store/locks/message-secret.lock.d.ts +3 -0
  511. package/dist/types/store/locks/message.lock.d.ts +3 -0
  512. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  513. package/dist/types/store/locks/pre-key.lock.d.ts +3 -0
  514. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  515. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  516. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  517. package/dist/types/store/locks/session.lock.d.ts +3 -0
  518. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  519. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  520. package/dist/types/store/noop.store.d.ts +4 -0
  521. package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
  522. package/dist/types/store/providers/memory/identity.store.d.ts +18 -0
  523. package/dist/types/store/providers/memory/message-secret.store.d.ts +21 -0
  524. package/dist/types/store/providers/memory/pre-key.store.d.ts +23 -0
  525. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  526. package/dist/types/store/providers/memory/retry.store.d.ts +15 -1
  527. package/dist/types/store/providers/memory/session.store.d.ts +21 -0
  528. package/dist/types/store/providers/memory/signal.store.d.ts +2 -43
  529. package/dist/types/store/providers/memory/thread.store.d.ts +1 -1
  530. package/dist/types/store/types.d.ts +69 -61
  531. package/dist/types/transport/WaWebSocket.d.ts +1 -1
  532. package/dist/types/transport/binary/constants.d.ts +0 -30
  533. package/dist/types/transport/binary/index.d.ts +0 -1
  534. package/dist/types/transport/index.d.ts +8 -1
  535. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +4 -1
  536. package/dist/types/transport/node/WaMobileTcpSocket.d.ts +18 -0
  537. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +9 -6
  538. package/dist/types/transport/node/builders/abprops.d.ts +5 -0
  539. package/dist/types/transport/node/builders/business.d.ts +29 -0
  540. package/dist/types/transport/node/builders/device.d.ts +2 -0
  541. package/dist/types/transport/node/builders/email.d.ts +11 -0
  542. package/dist/types/transport/node/builders/global.d.ts +102 -0
  543. package/dist/types/transport/node/builders/message.d.ts +8 -7
  544. package/dist/types/transport/node/builders/offline.d.ts +2 -0
  545. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  546. package/dist/types/transport/node/builders/prekeys.d.ts +4 -3
  547. package/dist/types/transport/node/builders/presence.d.ts +6 -0
  548. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  549. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  550. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  551. package/dist/types/transport/node/builders/retry.d.ts +0 -1
  552. package/dist/types/transport/node/helpers.d.ts +8 -0
  553. package/dist/types/transport/node/mex/argo-decoder.d.ts +11 -0
  554. package/dist/types/transport/node/mex/client.d.ts +18 -0
  555. package/dist/types/transport/node/mex/persist-ids.d.ts +14 -0
  556. package/dist/types/transport/noise/WaMobileClientPayload.d.ts +29 -0
  557. package/dist/types/transport/noise/WaNoiseCert.d.ts +7 -1
  558. package/dist/types/transport/noise/WaNoiseSession.d.ts +4 -2
  559. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  560. package/dist/types/transport/types.d.ts +8 -0
  561. package/dist/types/util/bytes.d.ts +1 -1
  562. package/dist/types/util/index.d.ts +5 -0
  563. package/dist/types/util/primitives.d.ts +0 -1
  564. package/dist/util/bytes.js +22 -18
  565. package/dist/util/index.js +23 -0
  566. package/dist/util/primitives.js +2 -2
  567. package/package.json +34 -10
  568. package/proto/index.js +1 -1
  569. package/dist/auth/flow/WaAuthCredentialsFlow.js +0 -130
  570. package/dist/auth/pairing/constants.js +0 -5
  571. package/dist/client/connection/WaKeyShareCoordinator.js +0 -63
  572. package/dist/crypto/core/constants.js +0 -4
  573. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +0 -125
  574. package/dist/esm/auth/pairing/constants.js +0 -2
  575. package/dist/esm/client/connection/WaKeyShareCoordinator.js +0 -59
  576. package/dist/esm/crypto/core/constants.js +0 -1
  577. package/dist/esm/retry/outbound.js +0 -82
  578. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  579. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
  580. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  581. package/dist/esm/store/providers/sqlite/connection.js +0 -245
  582. package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
  583. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
  584. package/dist/esm/store/providers/sqlite/message.store.js +0 -132
  585. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  586. package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
  587. package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
  588. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
  589. package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
  590. package/dist/esm/store/providers/sqlite/table-names.js +0 -107
  591. package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
  592. package/dist/esm/transport/node/builders/index.js +0 -8
  593. package/dist/retry/outbound.js +0 -87
  594. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  595. package/dist/store/providers/sqlite/appstate.store.js +0 -254
  596. package/dist/store/providers/sqlite/auth.store.js +0 -180
  597. package/dist/store/providers/sqlite/connection.js +0 -281
  598. package/dist/store/providers/sqlite/contact.store.js +0 -78
  599. package/dist/store/providers/sqlite/device-list.store.js +0 -131
  600. package/dist/store/providers/sqlite/message.store.js +0 -136
  601. package/dist/store/providers/sqlite/migrations.js +0 -350
  602. package/dist/store/providers/sqlite/participants.store.js +0 -81
  603. package/dist/store/providers/sqlite/retry.store.js +0 -145
  604. package/dist/store/providers/sqlite/sender-key.store.js +0 -202
  605. package/dist/store/providers/sqlite/signal.store.js +0 -439
  606. package/dist/store/providers/sqlite/table-names.js +0 -113
  607. package/dist/store/providers/sqlite/thread.store.js +0 -89
  608. package/dist/transport/node/builders/index.js +0 -42
  609. package/dist/types/appstate/store/sqlite.d.ts +0 -7
  610. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +0 -14
  611. package/dist/types/auth/pairing/constants.d.ts +0 -2
  612. package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +0 -14
  613. package/dist/types/crypto/core/constants.d.ts +0 -1
  614. package/dist/types/retry/outbound.d.ts +0 -4
  615. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  616. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
  617. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  618. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  619. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
  620. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
  621. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
  622. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  623. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
  624. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
  625. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
  626. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
  627. package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
  628. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
  629. package/dist/types/transport/node/builders/index.d.ts +0 -8
  630. /package/dist/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +0 -0
@@ -1,13 +1,14 @@
1
1
  import { generatePreKeyPair, generateRegistrationInfo, generateSignedPreKey } from '../registration/keygen.js';
2
- export async function createAndStoreInitialKeys(store) {
2
+ export async function createAndStoreInitialKeys(store, preKeyStore) {
3
3
  const [registrationInfo, firstPreKey] = await Promise.all([
4
4
  generateRegistrationInfo(),
5
5
  generatePreKeyPair(1)
6
6
  ]);
7
7
  const signedPreKey = await generateSignedPreKey(1, registrationInfo.identityKeyPair.privKey);
8
+ // Keep writes ordered so partial commit failures don't leave split registration bootstrap state.
8
9
  await store.setRegistrationInfo(registrationInfo);
9
10
  await store.setSignedPreKey(signedPreKey);
10
- await store.getOrGenSinglePreKey(async () => firstPreKey);
11
+ await preKeyStore.getOrGenSinglePreKey(async () => firstPreKey);
11
12
  return {
12
13
  registrationInfo,
13
14
  signedPreKey,
@@ -1,6 +1,8 @@
1
1
  import { toSerializedPubKey } from '../../crypto/index.js';
2
2
  import { ConsoleLogger } from '../../infra/log/ConsoleLogger.js';
3
+ import { StoreLock } from '../../infra/perf/StoreLock.js';
3
4
  import { MAX_PREV_SESSIONS } from '../constants.js';
5
+ import { encodeSignalSessionSnapshot } from '../encoding.js';
4
6
  import { decryptMsg, decryptMsgFromSession, encryptMsg } from '../session/SignalRatchet.js';
5
7
  import { deserializeMsg, deserializePkMsg, requirePreKey, requireSignedPreKey } from '../session/SignalSerializer.js';
6
8
  import { detachSession, findMatchingSession, generateSerializedKeyPair, initiateSessionIncoming, initiateSessionOutgoing, requireLocalIdentity, toSerializedKeyPair } from '../session/SignalSession.js';
@@ -8,26 +10,37 @@ import { uint8Equal } from '../../util/bytes.js';
8
10
  function signalAddressMapKey(address) {
9
11
  return `${address.user}\u0001${address.server ?? ''}\u0001${address.device}`;
10
12
  }
13
+ function signalAddressLockKey(address) {
14
+ return `signal:${signalAddressMapKey(address)}`;
15
+ }
11
16
  export class SignalProtocol {
12
- constructor(store, logger = new ConsoleLogger('info')) {
13
- this.store = store;
17
+ constructor(stores, logger = new ConsoleLogger('info')) {
18
+ this.stores = stores;
14
19
  this.logger = logger;
20
+ this.sessionMutationLock = new StoreLock();
15
21
  }
16
- async hasSession(address) {
17
- return this.store.hasSession(address);
18
- }
19
- async hasSessions(addresses) {
20
- return this.store.hasSessions(addresses);
21
- }
22
- async establishOutgoingSession(address, remoteBundle) {
23
- const [local, localOneTimeBase] = await Promise.all([
24
- requireLocalIdentity(this.store),
25
- generateSerializedKeyPair()
26
- ]);
27
- const session = await initiateSessionOutgoing(local, remoteBundle, localOneTimeBase);
28
- await this.store.setRemoteIdentity(address, session.remote.pubKey);
29
- await this.store.setSession(address, session);
30
- return session;
22
+ async establishOutgoingSession(address, remoteBundle, options = {}) {
23
+ return this.runWithAddressLock(address, async () => {
24
+ if (options.reuseExisting) {
25
+ const existing = await this.stores.session.getSession(address);
26
+ if (existing) {
27
+ const remoteIdentity = toSerializedPubKey(remoteBundle.identity);
28
+ if (!uint8Equal(existing.remote.pubKey, remoteIdentity)) {
29
+ throw new Error('identity mismatch');
30
+ }
31
+ return existing;
32
+ }
33
+ }
34
+ const [local, localOneTimeBase] = await Promise.all([
35
+ requireLocalIdentity(this.stores.signal),
36
+ generateSerializedKeyPair()
37
+ ]);
38
+ const session = await initiateSessionOutgoing(local, remoteBundle, localOneTimeBase);
39
+ // Keep writes ordered: a stored session without matching remote identity causes false mismatch checks.
40
+ await this.stores.identity.setRemoteIdentity(address, session.remote.pubKey);
41
+ await this.stores.session.setSession(address, session);
42
+ return session;
43
+ });
31
44
  }
32
45
  async encryptMessage(address, plaintext, expectedIdentity) {
33
46
  const [encrypted] = await this.encryptMessagesBatch([
@@ -35,77 +48,140 @@ export class SignalProtocol {
35
48
  ]);
36
49
  return encrypted;
37
50
  }
38
- async encryptMessagesBatch(requests) {
51
+ async encryptMessagesBatch(requests, prefetchedSessions) {
39
52
  if (requests.length === 0) {
40
53
  return [];
41
54
  }
42
- const addresses = requests.map((request) => request.address);
43
- const storedSessions = await this.store.getSessionsBatch(addresses);
44
- const latestSessionByAddress = new Map();
45
- const sessionUpdatesByAddress = new Map();
46
- const identityUpdatesByAddress = new Map();
47
- const results = new Array(requests.length);
48
- for (let index = 0; index < requests.length; index += 1) {
49
- const request = requests[index];
50
- const address = request.address;
51
- const addressKey = signalAddressMapKey(address);
52
- const session = latestSessionByAddress.get(addressKey) ?? storedSessions[index];
53
- if (!session) {
54
- throw new Error('signal session not found');
55
+ const lockKeySet = new Set();
56
+ for (let i = 0; i < requests.length; i += 1)
57
+ lockKeySet.add(signalAddressLockKey(requests[i].address));
58
+ const lockKeys = [...lockKeySet];
59
+ return this.sessionMutationLock.runMany(lockKeys, async () => {
60
+ const prefetchedByAddress = new Map();
61
+ if (prefetchedSessions && prefetchedSessions.length > 0) {
62
+ for (let index = 0; index < prefetchedSessions.length; index += 1) {
63
+ const entry = prefetchedSessions[index];
64
+ prefetchedByAddress.set(signalAddressMapKey(entry.address), entry.session);
65
+ }
55
66
  }
56
- if (request.expectedIdentity &&
57
- !uint8Equal(toSerializedPubKey(request.expectedIdentity), session.remote.pubKey)) {
58
- throw new Error('identity mismatch');
67
+ const uniqueAddressKeys = new Array(requests.length);
68
+ const uniqueAddresses = new Array(requests.length);
69
+ let uniqueAddressCount = 0;
70
+ for (let index = 0; index < requests.length; index += 1) {
71
+ const address = requests[index].address;
72
+ const addressKey = signalAddressMapKey(address);
73
+ let isDuplicate = false;
74
+ for (let dedupIndex = 0; dedupIndex < uniqueAddressCount; dedupIndex += 1) {
75
+ if (uniqueAddressKeys[dedupIndex] === addressKey) {
76
+ isDuplicate = true;
77
+ break;
78
+ }
79
+ }
80
+ if (isDuplicate) {
81
+ continue;
82
+ }
83
+ uniqueAddressKeys[uniqueAddressCount] = addressKey;
84
+ uniqueAddresses[uniqueAddressCount] = address;
85
+ uniqueAddressCount += 1;
59
86
  }
60
- const [updatedSession, encrypted] = await encryptMsg(session, request.plaintext);
61
- latestSessionByAddress.set(addressKey, updatedSession);
62
- sessionUpdatesByAddress.set(addressKey, {
63
- address,
64
- session: updatedSession
65
- });
66
- if (!uint8Equal(updatedSession.remote.pubKey, session.remote.pubKey)) {
67
- identityUpdatesByAddress.set(addressKey, {
87
+ uniqueAddressKeys.length = uniqueAddressCount;
88
+ uniqueAddresses.length = uniqueAddressCount;
89
+ const currentSessions = await this.stores.session.getSessionsBatch(uniqueAddresses);
90
+ const latestSessionByAddress = new Map();
91
+ for (let index = 0; index < uniqueAddressCount; index += 1) {
92
+ const addressKey = uniqueAddressKeys[index];
93
+ const current = currentSessions[index];
94
+ if (current) {
95
+ latestSessionByAddress.set(addressKey, current);
96
+ continue;
97
+ }
98
+ const prefetched = prefetchedByAddress.get(addressKey);
99
+ if (prefetched) {
100
+ latestSessionByAddress.set(addressKey, prefetched);
101
+ }
102
+ }
103
+ const sessionUpdatesByAddress = new Map();
104
+ const identityUpdatesByAddress = new Map();
105
+ const results = new Array(requests.length);
106
+ for (let index = 0; index < requests.length; index += 1) {
107
+ const request = requests[index];
108
+ const address = request.address;
109
+ const addressKey = signalAddressMapKey(address);
110
+ const session = latestSessionByAddress.get(addressKey);
111
+ if (!session) {
112
+ throw new Error('signal session not found');
113
+ }
114
+ if (request.expectedIdentity &&
115
+ !uint8Equal(toSerializedPubKey(request.expectedIdentity), session.remote.pubKey)) {
116
+ throw new Error('identity mismatch');
117
+ }
118
+ const [updatedSession, encrypted] = await encryptMsg(session, request.plaintext);
119
+ latestSessionByAddress.set(addressKey, updatedSession);
120
+ sessionUpdatesByAddress.set(addressKey, {
68
121
  address,
69
- identityKey: updatedSession.remote.pubKey
122
+ session: updatedSession
70
123
  });
124
+ if (!uint8Equal(updatedSession.remote.pubKey, session.remote.pubKey)) {
125
+ identityUpdatesByAddress.set(addressKey, {
126
+ address,
127
+ identityKey: updatedSession.remote.pubKey
128
+ });
129
+ }
130
+ results[index] = {
131
+ ...encrypted,
132
+ baseKey: updatedSession.aliceBaseKey
133
+ };
71
134
  }
72
- results[index] = {
73
- ...encrypted,
74
- baseKey: updatedSession.aliceBaseKey
75
- };
76
- }
77
- await this.store.setSessionsBatch([...sessionUpdatesByAddress.values()]);
78
- if (identityUpdatesByAddress.size > 0) {
79
- await this.store.setRemoteIdentities([...identityUpdatesByAddress.values()]);
80
- }
81
- return results;
135
+ // Persist remote identities first when needed so session writes never commit ahead of identity data.
136
+ if (identityUpdatesByAddress.size > 0) {
137
+ const identityUpdates = new Array(identityUpdatesByAddress.size);
138
+ let identityIndex = 0;
139
+ for (const update of identityUpdatesByAddress.values()) {
140
+ identityUpdates[identityIndex] = update;
141
+ identityIndex += 1;
142
+ }
143
+ await this.stores.identity.setRemoteIdentities(identityUpdates);
144
+ }
145
+ const sessionUpdates = new Array(sessionUpdatesByAddress.size);
146
+ let sessionIndex = 0;
147
+ for (const update of sessionUpdatesByAddress.values()) {
148
+ sessionUpdates[sessionIndex] = update;
149
+ sessionIndex += 1;
150
+ }
151
+ await this.stores.session.setSessionsBatch(sessionUpdates);
152
+ return results;
153
+ });
82
154
  }
83
155
  async decryptMessage(address, envelope) {
84
- const currentSession = await this.store.getSession(address);
85
- let outcome;
86
- if (envelope.type === 'pkmsg') {
87
- const parsedPk = deserializePkMsg(envelope.ciphertext);
88
- outcome = await this.decryptPkMsg(currentSession, parsedPk);
89
- }
90
- else {
91
- const parsed = deserializeMsg(envelope.ciphertext);
92
- outcome = await this.decryptMsgInternal(currentSession, parsed);
93
- }
94
- const nextRemoteIdentity = outcome.newSessionInfo?.newIdentity ?? outcome.updatedSession.remote.pubKey;
95
- if (!currentSession || !uint8Equal(currentSession.remote.pubKey, nextRemoteIdentity)) {
96
- await this.store.setRemoteIdentity(address, nextRemoteIdentity);
97
- }
98
- await this.store.setSession(address, outcome.updatedSession);
99
- return outcome.plaintext;
100
- }
101
- async decryptMsgInternal(session, parsed) {
102
- return decryptMsg(session, parsed, (error, previousSessionIndex) => {
103
- this.logger.debug('signal decrypt fallback session failed', {
104
- previousSessionIndex,
105
- message: error.message
106
- });
156
+ return this.runWithAddressLock(address, async () => {
157
+ const currentSession = await this.stores.session.getSession(address);
158
+ let outcome;
159
+ if (envelope.type === 'pkmsg') {
160
+ const parsedPk = deserializePkMsg(envelope.ciphertext);
161
+ outcome = await this.decryptPkMsg(currentSession, parsedPk);
162
+ }
163
+ else {
164
+ const parsed = deserializeMsg(envelope.ciphertext);
165
+ outcome = await decryptMsg(currentSession, parsed, (error, previousSessionIndex) => {
166
+ this.logger.debug('signal decrypt fallback session failed', {
167
+ previousSessionIndex,
168
+ message: error.message
169
+ });
170
+ });
171
+ }
172
+ const nextRemoteIdentity = outcome.newSessionInfo?.newIdentity ?? outcome.updatedSession.remote.pubKey;
173
+ const identityChanged = !currentSession || !uint8Equal(currentSession.remote.pubKey, nextRemoteIdentity);
174
+ // Keep writes ordered for consistency with resolver identity checks.
175
+ if (identityChanged) {
176
+ await this.stores.identity.setRemoteIdentity(address, nextRemoteIdentity);
177
+ }
178
+ await this.stores.session.setSession(address, outcome.updatedSession);
179
+ return outcome.plaintext;
107
180
  });
108
181
  }
182
+ runWithAddressLock(address, task) {
183
+ return this.sessionMutationLock.run(signalAddressLockKey(address), task);
184
+ }
109
185
  async decryptPkMsg(currentSession, parsed) {
110
186
  const matchingSession = findMatchingSession(currentSession, parsed.sessionBaseKey);
111
187
  if (matchingSession) {
@@ -117,11 +193,11 @@ export class SignalProtocol {
117
193
  };
118
194
  }
119
195
  const [local, signedPreKey, oneTimePreKey] = await Promise.all([
120
- requireLocalIdentity(this.store),
121
- requireSignedPreKey(this.store, parsed.localSignedPreKeyId),
196
+ requireLocalIdentity(this.stores.signal),
197
+ requireSignedPreKey(this.stores.signal, parsed.localSignedPreKeyId),
122
198
  parsed.localOneTimeKeyId === null || parsed.localOneTimeKeyId === undefined
123
199
  ? Promise.resolve(null)
124
- : requirePreKey(this.store, parsed.localOneTimeKeyId)
200
+ : requirePreKey(this.stores.preKey, parsed.localOneTimeKeyId)
125
201
  ]);
126
202
  const incoming = await initiateSessionIncoming(local, parsed.remote, parsed.sessionBaseKey, {
127
203
  signed: toSerializedKeyPair(signedPreKey.keyPair),
@@ -135,14 +211,15 @@ export class SignalProtocol {
135
211
  ? {
136
212
  ...incoming,
137
213
  prevSessions: [
138
- detachSession(currentSession),
214
+ encodeSignalSessionSnapshot(detachSession(currentSession)),
139
215
  ...currentSession.prevSessions.slice(0, MAX_PREV_SESSIONS - 1)
140
216
  ]
141
217
  }
142
218
  : incoming;
143
219
  const [updatedSession, plaintext] = await decryptMsgFromSession(baseSession, parsed);
220
+ // Only consume one-time prekeys after successful decrypt/session materialization.
144
221
  if (parsed.localOneTimeKeyId !== null && parsed.localOneTimeKeyId !== undefined) {
145
- await this.store.consumePreKeyById(parsed.localOneTimeKeyId);
222
+ await this.stores.preKey.consumePreKeyById(parsed.localOneTimeKeyId);
146
223
  }
147
224
  return {
148
225
  updatedSession,
@@ -1,7 +1,8 @@
1
- import { aesCbcDecrypt, aesCbcEncrypt, hkdf, importAesCbcKey, importHmacKey, hmacSign, prependVersion, toSerializedPubKey } from '../../crypto/index.js';
1
+ import { aesCbcDecrypt, aesCbcEncrypt, hkdf, hmacSign, importAesCbcKey, importHmacKey, prependVersion, toSerializedPubKey } from '../../crypto/index.js';
2
2
  import { proto } from '../../proto.js';
3
3
  import { CHAIN_KEY_LABEL, FUTURE_MESSAGES_MAX, MAX_UNUSED_KEYS, MESSAGE_KEY_LABEL, SIGNAL_MAC_SIZE, SIGNAL_VERSION } from '../constants.js';
4
- import { detachSession, calculateRatchet, generateSerializedKeyPair, snapshotToRecord } from '../session/SignalSession.js';
4
+ import { decodeSignalMessageKey, decodeSignalRecvChain, decodeSignalSessionSnapshot, encodeSignalRecvChain, encodeSignalSessionSnapshot } from '../encoding.js';
5
+ import { calculateRatchet, detachSession, generateSerializedKeyPair, snapshotToRecord } from '../session/SignalSession.js';
5
6
  import { concatBytes, removeAt, uint8Equal } from '../../util/bytes.js';
6
7
  import { toError } from '../../util/primitives.js';
7
8
  const MAX_TRACKED_RECV_CHAINS = 4;
@@ -35,7 +36,7 @@ export async function selectMessageKey(chain, targetCounter) {
35
36
  if (idx === -1) {
36
37
  throw new Error('duplicate message');
37
38
  }
38
- const messageKey = unused[idx];
39
+ const messageKey = decodeSignalMessageKey(unused[idx], `unusedMsgKeys[${idx}]`);
39
40
  const nextUnused = removeAt(unused, idx);
40
41
  return {
41
42
  messageKey,
@@ -73,7 +74,12 @@ export async function selectMessageKey(chain, targetCounter) {
73
74
  overflow -= 1;
74
75
  }
75
76
  else {
76
- nextUnused.push(currentMessageKey);
77
+ nextUnused.push({
78
+ index: currentMessageKey.index,
79
+ cipherKey: currentMessageKey.cipherKey,
80
+ macKey: currentMessageKey.macKey,
81
+ iv: currentMessageKey.iv
82
+ });
77
83
  }
78
84
  const derived = await deriveMsgKeyFromState(counter, chainState);
79
85
  currentMessageKey = derived.messageKey;
@@ -174,13 +180,14 @@ export async function decryptMsg(session, parsed, onPrevSessionDecryptError) {
174
180
  }
175
181
  catch (error) {
176
182
  for (let i = 0; i < session.prevSessions.length; i += 1) {
177
- const prevSession = snapshotToRecord(session.prevSessions[i]);
183
+ const decodedPrev = decodeSignalSessionSnapshot(session.prevSessions[i], `prevSessions[${i}]`);
184
+ const prevSession = snapshotToRecord(decodedPrev);
178
185
  try {
179
186
  const [updatedPrev, plaintext] = await decryptMsgFromSession(prevSession, parsed);
180
187
  const updatedSession = {
181
188
  ...updatedPrev,
182
189
  prevSessions: [
183
- detachSession(session),
190
+ encodeSignalSessionSnapshot(detachSession(session)),
184
191
  ...session.prevSessions.slice(0, i),
185
192
  ...session.prevSessions.slice(i + 1)
186
193
  ]
@@ -207,7 +214,10 @@ export async function decryptMsg(session, parsed, onPrevSessionDecryptError) {
207
214
  }
208
215
  export async function decryptMsgFromSession(session, message) {
209
216
  const ratchetPubKey = toSerializedPubKey(message.ratchetPubKey);
210
- const recvChainIndex = session.recvChains.findIndex((entry) => uint8Equal(entry.ratchetPubKey, ratchetPubKey));
217
+ const recvChainIndex = session.recvChains.findIndex((raw) => {
218
+ const key = raw.senderRatchetKey;
219
+ return key !== null && key !== undefined && uint8Equal(key, ratchetPubKey);
220
+ });
211
221
  let selectedMessageKey;
212
222
  let updatedSession;
213
223
  if (recvChainIndex === -1) {
@@ -225,7 +235,7 @@ export async function decryptMsgFromSession(session, message) {
225
235
  selectedMessageKey = selected.messageKey;
226
236
  const sendRatchet = await calculateRatchet(recvRatchet.rootKey, newSendRatchet, ratchetPubKey);
227
237
  const nextRecvChains = session.recvChains.slice(-MAX_TRACKED_RECV_CHAINS);
228
- nextRecvChains.push(selected.updatedChain);
238
+ nextRecvChains.push(encodeSignalRecvChain(selected.updatedChain));
229
239
  updatedSession = {
230
240
  ...session,
231
241
  rootKey: sendRatchet.rootKey,
@@ -240,10 +250,11 @@ export async function decryptMsgFromSession(session, message) {
240
250
  };
241
251
  }
242
252
  else {
243
- const selected = await selectMessageKey(session.recvChains[recvChainIndex], message.counter);
253
+ const decoded = decodeSignalRecvChain(session.recvChains[recvChainIndex], `recvChains[${recvChainIndex}]`);
254
+ const selected = await selectMessageKey(decoded, message.counter);
244
255
  selectedMessageKey = selected.messageKey;
245
256
  const nextRecvChains = session.recvChains.slice();
246
- nextRecvChains[recvChainIndex] = selected.updatedChain;
257
+ nextRecvChains[recvChainIndex] = encodeSignalRecvChain(selected.updatedChain);
247
258
  updatedSession = {
248
259
  ...session,
249
260
  recvChains: nextRecvChains
@@ -1,7 +1,6 @@
1
1
  import { readVersionedContent, toSerializedPubKey } from '../../crypto/index.js';
2
2
  import { proto } from '../../proto.js';
3
3
  import { SIGNAL_MAC_SIZE, SIGNAL_VERSION } from '../constants.js';
4
- import { toBytesView } from '../../util/bytes.js';
5
4
  export function deserializeMsg(versionContentMac) {
6
5
  const content = readVersionedContent(versionContentMac, SIGNAL_VERSION, SIGNAL_MAC_SIZE);
7
6
  const parsed = proto.SignalMessage.decode(content);
@@ -14,9 +13,9 @@ export function deserializeMsg(versionContentMac) {
14
13
  throw new Error('invalid signal message');
15
14
  }
16
15
  return {
17
- ratchetPubKey: toSerializedPubKey(toBytesView(parsed.ratchetKey)),
16
+ ratchetPubKey: toSerializedPubKey(parsed.ratchetKey),
18
17
  counter: parsed.counter,
19
- ciphertext: toBytesView(parsed.ciphertext),
18
+ ciphertext: parsed.ciphertext,
20
19
  versionContentMac
21
20
  };
22
21
  }
@@ -35,14 +34,14 @@ export function deserializePkMsg(versionContent) {
35
34
  parsed.message === undefined) {
36
35
  throw new Error('invalid prekey signal message');
37
36
  }
38
- const signal = deserializeMsg(toBytesView(parsed.message));
37
+ const signal = deserializeMsg(parsed.message);
39
38
  return {
40
39
  ...signal,
41
40
  remote: {
42
41
  regId: parsed.registrationId,
43
- pubKey: toSerializedPubKey(toBytesView(parsed.identityKey))
42
+ pubKey: toSerializedPubKey(parsed.identityKey)
44
43
  },
45
- sessionBaseKey: toSerializedPubKey(toBytesView(parsed.baseKey)),
44
+ sessionBaseKey: toSerializedPubKey(parsed.baseKey),
46
45
  localSignedPreKeyId: parsed.signedPreKeyId,
47
46
  localOneTimeKeyId: parsed.preKeyId ?? null
48
47
  };
@@ -1,5 +1,6 @@
1
1
  import { hkdfSplit, toRawPubKey, toSerializedPubKey, X25519 } from '../../crypto/index.js';
2
2
  import { SIGNAL_PREFIX } from '../constants.js';
3
+ import { decodeSignalSessionSnapshot, encodeSignalSessionSnapshot } from '../encoding.js';
3
4
  import { concatBytes, uint8Equal } from '../../util/bytes.js';
4
5
  export function snapshotToRecord(snapshot) {
5
6
  return {
@@ -21,19 +22,21 @@ export function findMatchingSession(session, sessionBaseKey) {
21
22
  return session;
22
23
  }
23
24
  for (let index = 0; index < session.prevSessions.length; index += 1) {
24
- const previousSession = session.prevSessions[index];
25
- if (!previousSession.aliceBaseKey ||
26
- !uint8Equal(previousSession.aliceBaseKey, serializedBaseKey)) {
25
+ const rawPrev = session.prevSessions[index];
26
+ if (!rawPrev.aliceBaseKey || !uint8Equal(rawPrev.aliceBaseKey, serializedBaseKey)) {
27
27
  continue;
28
28
  }
29
- const prevSessions = [detachSession(session)];
29
+ const decoded = decodeSignalSessionSnapshot(rawPrev, `prevSessions[${index}]`);
30
+ const prevSessions = [
31
+ encodeSignalSessionSnapshot(detachSession(session))
32
+ ];
30
33
  for (let i = 0; i < session.prevSessions.length; i += 1) {
31
34
  if (i !== index) {
32
35
  prevSessions.push(session.prevSessions[i]);
33
36
  }
34
37
  }
35
38
  return {
36
- ...previousSession,
39
+ ...decoded,
37
40
  prevSessions
38
41
  };
39
42
  }
@@ -73,10 +76,9 @@ export async function initiateSessionOutgoing(local, remoteBundle, localOneTimeB
73
76
  ]);
74
77
  const [rootKey, chainKey] = await hkdfSplit(secret, null, 'WhisperText');
75
78
  const recvChain = {
76
- ratchetPubKey: remoteRatchetKey,
77
- nextMsgIndex: 0,
78
- chainKey,
79
- unusedMsgKeys: []
79
+ senderRatchetKey: remoteRatchetKey,
80
+ chainKey: { index: 0, key: chainKey },
81
+ messageKeys: []
80
82
  };
81
83
  const sendRatchet = await generateSerializedKeyPair();
82
84
  const sendRatchetResult = await calculateRatchet(rootKey, sendRatchet, remoteRatchetKey);