zapo-js 0.1.2 → 0.2.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 (468) hide show
  1. package/README.md +12 -4
  2. package/dist/appstate/WaAppStateCrypto.js +1 -1
  3. package/dist/appstate/WaAppStateSyncClient.js +138 -93
  4. package/dist/appstate/{store/sqlite.js → encoding.js} +13 -8
  5. package/dist/appstate/index.js +8 -6
  6. package/dist/appstate/utils.js +0 -5
  7. package/dist/auth/WaAuthClient.js +36 -47
  8. package/dist/auth/flow/WaAuthCredentialsFlow.js +7 -7
  9. package/dist/auth/index.js +1 -6
  10. package/dist/auth/pairing/WaPairingCodeCrypto.js +6 -4
  11. package/dist/auth/pairing/WaPairingFlow.js +13 -3
  12. package/dist/client/WaClient.js +225 -101
  13. package/dist/client/WaClientFactory.js +294 -44
  14. package/dist/client/connection/WaConnectionManager.js +19 -10
  15. package/dist/client/coordinators/WaBusinessCoordinator.js +241 -0
  16. package/dist/client/coordinators/WaGroupCoordinator.js +11 -7
  17. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  18. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +292 -99
  19. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  20. package/dist/client/coordinators/WaPrivacyCoordinator.js +134 -0
  21. package/dist/client/coordinators/WaProfileCoordinator.js +212 -0
  22. package/dist/client/coordinators/WaRetryCoordinator.js +179 -27
  23. package/dist/client/coordinators/WaStreamControlCoordinator.js +18 -11
  24. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +166 -0
  25. package/dist/client/dirty.js +40 -20
  26. package/dist/client/events/devices.js +72 -0
  27. package/dist/client/events/group.js +3 -11
  28. package/dist/client/events/identity.js +22 -0
  29. package/dist/client/events/privacy-token.js +39 -0
  30. package/dist/client/history-sync.js +50 -9
  31. package/dist/client/incoming.js +37 -7
  32. package/dist/client/mailbox.js +24 -23
  33. package/dist/client/messages.js +107 -31
  34. package/dist/client/messaging/fanout.js +21 -11
  35. package/dist/client/messaging/participants.js +6 -4
  36. package/dist/client/persistence/WriteBehindPersistence.js +129 -0
  37. package/dist/client/tokens/cs-token.js +50 -0
  38. package/dist/client/tokens/tc-token.js +25 -0
  39. package/dist/crypto/core/index.js +2 -2
  40. package/dist/crypto/core/keys.js +4 -4
  41. package/dist/crypto/core/nonce.js +2 -0
  42. package/dist/crypto/core/primitives.js +0 -8
  43. package/dist/crypto/core/random.js +22 -0
  44. package/dist/crypto/curves/X25519.js +25 -6
  45. package/dist/crypto/index.js +3 -0
  46. package/dist/crypto/math/constants.js +13 -36
  47. package/dist/crypto/math/edwards.js +171 -44
  48. package/dist/crypto/math/fe.js +706 -0
  49. package/dist/crypto/math/mod.js +10 -3
  50. package/dist/esm/appstate/WaAppStateCrypto.js +1 -1
  51. package/dist/esm/appstate/WaAppStateSyncClient.js +138 -93
  52. package/dist/esm/appstate/{store/sqlite.js → encoding.js} +13 -8
  53. package/dist/esm/appstate/index.js +2 -2
  54. package/dist/esm/appstate/utils.js +2 -5
  55. package/dist/esm/auth/WaAuthClient.js +36 -47
  56. package/dist/esm/auth/flow/WaAuthCredentialsFlow.js +7 -7
  57. package/dist/esm/auth/index.js +0 -2
  58. package/dist/esm/auth/pairing/WaPairingCodeCrypto.js +6 -4
  59. package/dist/esm/auth/pairing/WaPairingFlow.js +14 -4
  60. package/dist/esm/client/WaClient.js +225 -101
  61. package/dist/esm/client/WaClientFactory.js +295 -45
  62. package/dist/esm/client/connection/WaConnectionManager.js +19 -10
  63. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +238 -0
  64. package/dist/esm/client/coordinators/WaGroupCoordinator.js +11 -7
  65. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -0
  66. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +295 -102
  67. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +74 -31
  68. package/dist/esm/client/coordinators/WaPrivacyCoordinator.js +131 -0
  69. package/dist/esm/client/coordinators/WaProfileCoordinator.js +209 -0
  70. package/dist/esm/client/coordinators/WaRetryCoordinator.js +181 -29
  71. package/dist/esm/client/coordinators/WaStreamControlCoordinator.js +19 -12
  72. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +162 -0
  73. package/dist/esm/client/dirty.js +40 -20
  74. package/dist/esm/client/events/devices.js +68 -0
  75. package/dist/esm/client/events/group.js +3 -11
  76. package/dist/esm/client/events/identity.js +19 -0
  77. package/dist/esm/client/events/privacy-token.js +36 -0
  78. package/dist/esm/client/history-sync.js +50 -9
  79. package/dist/esm/client/incoming.js +38 -8
  80. package/dist/esm/client/mailbox.js +24 -23
  81. package/dist/esm/client/messages.js +108 -32
  82. package/dist/esm/client/messaging/fanout.js +22 -12
  83. package/dist/esm/client/messaging/participants.js +6 -4
  84. package/dist/esm/client/persistence/WriteBehindPersistence.js +125 -0
  85. package/dist/esm/client/tokens/cs-token.js +46 -0
  86. package/dist/esm/client/tokens/tc-token.js +18 -0
  87. package/dist/esm/crypto/core/index.js +2 -2
  88. package/dist/esm/crypto/core/keys.js +1 -1
  89. package/dist/esm/crypto/core/nonce.js +2 -0
  90. package/dist/esm/crypto/core/primitives.js +0 -7
  91. package/dist/esm/crypto/core/random.js +22 -1
  92. package/dist/esm/crypto/curves/X25519.js +25 -6
  93. package/dist/esm/crypto/index.js +1 -0
  94. package/dist/esm/crypto/math/constants.js +12 -35
  95. package/dist/esm/crypto/math/edwards.js +174 -47
  96. package/dist/esm/crypto/math/fe.js +691 -0
  97. package/dist/esm/crypto/math/mod.js +10 -1
  98. package/dist/esm/index.js +1 -1
  99. package/dist/esm/infra/perf/BackgroundQueue.js +478 -0
  100. package/dist/esm/infra/perf/BoundedTaskQueue.js +3 -1
  101. package/dist/esm/infra/perf/PromiseDedup.js +20 -0
  102. package/dist/esm/infra/perf/SharedExclusiveGate.js +109 -0
  103. package/dist/esm/infra/perf/StoreLock.js +77 -0
  104. package/dist/esm/media/WaMediaCrypto.js +95 -13
  105. package/dist/esm/media/WaMediaTransferClient.js +39 -47
  106. package/dist/esm/media/constants.js +2 -1
  107. package/dist/esm/message/WaMessageClient.js +26 -19
  108. package/dist/esm/message/content.js +195 -9
  109. package/dist/esm/message/icdc.js +76 -0
  110. package/dist/esm/message/incoming.js +24 -12
  111. package/dist/esm/message/phash.js +3 -1
  112. package/dist/esm/message/reporting-token.js +14 -27
  113. package/dist/esm/protocol/appstate.js +9 -40
  114. package/dist/esm/protocol/browser.js +10 -18
  115. package/dist/esm/protocol/constants.js +5 -3
  116. package/dist/esm/protocol/defaults.js +6 -0
  117. package/dist/esm/protocol/index.js +1 -2
  118. package/dist/esm/protocol/jid.js +105 -36
  119. package/dist/esm/protocol/message.js +61 -1
  120. package/dist/esm/protocol/nodes.js +2 -0
  121. package/dist/esm/protocol/notification.js +3 -1
  122. package/dist/esm/protocol/privacy-token.js +17 -0
  123. package/dist/esm/protocol/privacy.js +55 -0
  124. package/dist/esm/protocol/stream.js +26 -1
  125. package/dist/esm/retry/codec.js +216 -0
  126. package/dist/esm/retry/constants.js +1 -1
  127. package/dist/esm/retry/index.js +2 -2
  128. package/dist/esm/retry/parse.js +50 -30
  129. package/dist/esm/retry/replay.js +11 -7
  130. package/dist/esm/retry/tracker.js +50 -12
  131. package/dist/esm/signal/api/SignalDeviceSyncApi.js +49 -32
  132. package/dist/esm/signal/api/SignalDigestSyncApi.js +13 -9
  133. package/dist/esm/signal/api/SignalIdentitySyncApi.js +26 -11
  134. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +18 -7
  135. package/dist/esm/signal/api/SignalRotateKeyApi.js +4 -2
  136. package/dist/esm/signal/api/SignalSessionSyncApi.js +16 -7
  137. package/dist/esm/signal/api/result-map.js +10 -0
  138. package/dist/esm/signal/constants.js +0 -4
  139. package/dist/esm/signal/crypto/WaAdvSignature.js +12 -6
  140. package/dist/esm/signal/{store/sqlite.js → encoding.js} +78 -24
  141. package/dist/esm/signal/group/SenderKeyCodec.js +3 -2
  142. package/dist/esm/signal/group/SenderKeyManager.js +125 -106
  143. package/dist/esm/signal/index.js +1 -0
  144. package/dist/esm/signal/registration/keygen.js +6 -2
  145. package/dist/esm/signal/registration/utils.js +1 -0
  146. package/dist/esm/signal/session/SignalProtocol.js +150 -74
  147. package/dist/esm/signal/session/resolver.js +137 -102
  148. package/dist/esm/store/contracts/privacy-token.store.js +1 -0
  149. package/dist/esm/store/createStore.js +101 -187
  150. package/dist/esm/store/index.js +1 -10
  151. package/dist/esm/store/locks/appstate.lock.js +26 -0
  152. package/dist/esm/store/locks/auth.lock.js +15 -0
  153. package/dist/esm/store/locks/contact.lock.js +20 -0
  154. package/dist/esm/store/locks/device-list.lock.js +20 -0
  155. package/dist/esm/store/locks/message.lock.js +21 -0
  156. package/dist/esm/store/locks/participants.lock.js +20 -0
  157. package/dist/esm/store/locks/privacy-token.lock.js +18 -0
  158. package/dist/esm/store/locks/retry.lock.js +29 -0
  159. package/dist/esm/store/locks/sender-key.lock.js +52 -0
  160. package/dist/esm/store/locks/signal.lock.js +63 -0
  161. package/dist/esm/store/locks/thread.lock.js +21 -0
  162. package/dist/esm/store/noop.store.js +1 -1
  163. package/dist/esm/store/providers/memory/appstate.store.js +22 -24
  164. package/dist/esm/store/providers/memory/device-list.store.js +10 -5
  165. package/dist/esm/store/providers/memory/privacy-token.store.js +43 -0
  166. package/dist/esm/store/providers/memory/retry.store.js +77 -2
  167. package/dist/esm/store/providers/memory/sender-key.store.js +6 -1
  168. package/dist/esm/store/providers/memory/signal.store.js +36 -19
  169. package/dist/esm/transport/WaComms.js +3 -1
  170. package/dist/esm/transport/WaWebSocket.js +0 -6
  171. package/dist/esm/transport/binary/constants.js +0 -30
  172. package/dist/esm/transport/binary/decoder.js +4 -4
  173. package/dist/esm/transport/binary/encoder.js +8 -15
  174. package/dist/esm/transport/binary/index.js +0 -1
  175. package/dist/esm/transport/node/WaNodeOrchestrator.js +25 -19
  176. package/dist/esm/transport/node/builders/business.js +129 -0
  177. package/dist/esm/transport/node/builders/global.js +370 -0
  178. package/dist/esm/transport/node/builders/index.js +5 -2
  179. package/dist/esm/transport/node/builders/message.js +63 -239
  180. package/dist/esm/transport/node/builders/pairing.js +0 -24
  181. package/dist/esm/transport/node/builders/privacy-token.js +41 -0
  182. package/dist/esm/transport/node/builders/privacy.js +48 -0
  183. package/dist/esm/transport/node/builders/profile.js +70 -0
  184. package/dist/esm/transport/node/builders/retry.js +10 -22
  185. package/dist/esm/transport/node/builders/usync.js +6 -2
  186. package/dist/esm/transport/node/helpers.js +19 -1
  187. package/dist/esm/transport/node/usync.js +3 -33
  188. package/dist/esm/transport/node/xml.js +35 -14
  189. package/dist/esm/transport/noise/WaClientPayload.js +10 -10
  190. package/dist/esm/transport/noise/WaNoiseCert.js +3 -3
  191. package/dist/esm/transport/noise/WaNoiseSession.js +64 -23
  192. package/dist/esm/transport/noise/WaNoiseSocket.js +8 -4
  193. package/dist/esm/transport/stream/parse.js +8 -4
  194. package/dist/esm/util/bytes.js +22 -18
  195. package/dist/esm/util/index.js +5 -0
  196. package/dist/esm/util/primitives.js +3 -2
  197. package/dist/index.js +7 -1
  198. package/dist/infra/perf/BackgroundQueue.js +482 -0
  199. package/dist/infra/perf/BoundedTaskQueue.js +3 -1
  200. package/dist/infra/perf/PromiseDedup.js +24 -0
  201. package/dist/infra/perf/SharedExclusiveGate.js +113 -0
  202. package/dist/infra/perf/StoreLock.js +81 -0
  203. package/dist/media/WaMediaCrypto.js +94 -12
  204. package/dist/media/WaMediaTransferClient.js +39 -47
  205. package/dist/media/constants.js +2 -1
  206. package/dist/message/WaMessageClient.js +26 -19
  207. package/dist/message/content.js +198 -9
  208. package/dist/message/icdc.js +81 -0
  209. package/dist/message/incoming.js +24 -12
  210. package/dist/message/phash.js +3 -1
  211. package/dist/message/reporting-token.js +14 -28
  212. package/dist/protocol/appstate.js +10 -41
  213. package/dist/protocol/browser.js +10 -18
  214. package/dist/protocol/constants.js +21 -2
  215. package/dist/protocol/defaults.js +6 -0
  216. package/dist/protocol/index.js +8 -5
  217. package/dist/protocol/jid.js +111 -36
  218. package/dist/protocol/message.js +62 -2
  219. package/dist/protocol/nodes.js +2 -0
  220. package/dist/protocol/notification.js +3 -1
  221. package/dist/protocol/privacy-token.js +20 -0
  222. package/dist/protocol/privacy.js +58 -0
  223. package/dist/protocol/stream.js +27 -2
  224. package/dist/retry/codec.js +220 -0
  225. package/dist/retry/constants.js +1 -1
  226. package/dist/retry/index.js +5 -5
  227. package/dist/retry/parse.js +51 -30
  228. package/dist/retry/replay.js +10 -6
  229. package/dist/retry/tracker.js +50 -12
  230. package/dist/signal/api/SignalDeviceSyncApi.js +48 -31
  231. package/dist/signal/api/SignalDigestSyncApi.js +13 -9
  232. package/dist/signal/api/SignalIdentitySyncApi.js +25 -10
  233. package/dist/signal/api/SignalMissingPreKeysSyncApi.js +17 -6
  234. package/dist/signal/api/SignalRotateKeyApi.js +4 -2
  235. package/dist/signal/api/SignalSessionSyncApi.js +16 -7
  236. package/dist/signal/api/result-map.js +13 -0
  237. package/dist/signal/constants.js +1 -5
  238. package/dist/signal/crypto/WaAdvSignature.js +11 -5
  239. package/dist/signal/{store/sqlite.js → encoding.js} +79 -25
  240. package/dist/signal/group/SenderKeyCodec.js +4 -3
  241. package/dist/signal/group/SenderKeyManager.js +125 -106
  242. package/dist/signal/index.js +13 -1
  243. package/dist/signal/registration/keygen.js +6 -2
  244. package/dist/signal/registration/utils.js +1 -0
  245. package/dist/signal/session/SignalProtocol.js +150 -74
  246. package/dist/signal/session/resolver.js +135 -100
  247. package/dist/store/contracts/privacy-token.store.js +2 -0
  248. package/dist/store/createStore.js +101 -187
  249. package/dist/store/index.js +15 -33
  250. package/dist/store/locks/appstate.lock.js +29 -0
  251. package/dist/store/locks/auth.lock.js +18 -0
  252. package/dist/store/locks/contact.lock.js +23 -0
  253. package/dist/store/locks/device-list.lock.js +23 -0
  254. package/dist/store/locks/message.lock.js +24 -0
  255. package/dist/store/locks/participants.lock.js +23 -0
  256. package/dist/store/locks/privacy-token.lock.js +21 -0
  257. package/dist/store/locks/retry.lock.js +32 -0
  258. package/dist/store/locks/sender-key.lock.js +55 -0
  259. package/dist/store/locks/signal.lock.js +66 -0
  260. package/dist/store/locks/thread.lock.js +24 -0
  261. package/dist/store/noop.store.js +1 -1
  262. package/dist/store/providers/memory/appstate.store.js +22 -24
  263. package/dist/store/providers/memory/device-list.store.js +10 -5
  264. package/dist/store/providers/memory/privacy-token.store.js +47 -0
  265. package/dist/store/providers/memory/retry.store.js +77 -2
  266. package/dist/store/providers/memory/sender-key.store.js +6 -1
  267. package/dist/store/providers/memory/signal.store.js +36 -19
  268. package/dist/transport/WaComms.js +3 -1
  269. package/dist/transport/WaWebSocket.js +0 -6
  270. package/dist/transport/binary/constants.js +1 -31
  271. package/dist/transport/binary/decoder.js +4 -4
  272. package/dist/transport/binary/encoder.js +8 -15
  273. package/dist/transport/binary/index.js +0 -4
  274. package/dist/transport/node/WaNodeOrchestrator.js +24 -18
  275. package/dist/transport/node/builders/business.js +137 -0
  276. package/dist/transport/node/builders/global.js +375 -0
  277. package/dist/transport/node/builders/index.js +18 -9
  278. package/dist/transport/node/builders/message.js +64 -245
  279. package/dist/transport/node/builders/pairing.js +0 -26
  280. package/dist/transport/node/builders/privacy-token.js +46 -0
  281. package/dist/transport/node/builders/privacy.js +55 -0
  282. package/dist/transport/node/builders/profile.js +78 -0
  283. package/dist/transport/node/builders/retry.js +9 -21
  284. package/dist/transport/node/builders/usync.js +6 -2
  285. package/dist/transport/node/helpers.js +20 -1
  286. package/dist/transport/node/usync.js +2 -32
  287. package/dist/transport/node/xml.js +35 -14
  288. package/dist/transport/noise/WaClientPayload.js +13 -13
  289. package/dist/transport/noise/WaNoiseCert.js +2 -2
  290. package/dist/transport/noise/WaNoiseSession.js +64 -23
  291. package/dist/transport/noise/WaNoiseSocket.js +8 -4
  292. package/dist/transport/stream/parse.js +7 -3
  293. package/dist/types/appstate/encoding.d.ts +7 -0
  294. package/dist/types/appstate/index.d.ts +3 -3
  295. package/dist/types/appstate/utils.d.ts +0 -2
  296. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +1 -1
  297. package/dist/types/auth/index.d.ts +0 -2
  298. package/dist/types/auth/types.d.ts +1 -0
  299. package/dist/types/client/WaClient.d.ts +27 -12
  300. package/dist/types/client/WaClientFactory.d.ts +12 -4
  301. package/dist/types/client/connection/WaConnectionManager.d.ts +2 -0
  302. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +57 -0
  303. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +3 -1
  304. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +14 -0
  305. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +4 -0
  306. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +26 -0
  307. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +36 -0
  308. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
  309. package/dist/types/client/coordinators/WaStreamControlCoordinator.d.ts +3 -2
  310. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +45 -0
  311. package/dist/types/client/events/devices.d.ts +20 -0
  312. package/dist/types/client/events/identity.d.ts +9 -0
  313. package/dist/types/client/events/privacy-token.d.ts +7 -0
  314. package/dist/types/client/history-sync.d.ts +9 -6
  315. package/dist/types/client/incoming.d.ts +3 -1
  316. package/dist/types/client/index.d.ts +1 -1
  317. package/dist/types/client/mailbox.d.ts +3 -5
  318. package/dist/types/client/messages.d.ts +1 -2
  319. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +34 -0
  320. package/dist/types/client/tokens/cs-token.d.ts +10 -0
  321. package/dist/types/client/tokens/tc-token.d.ts +5 -0
  322. package/dist/types/client/types.d.ts +51 -3
  323. package/dist/types/crypto/core/index.d.ts +2 -2
  324. package/dist/types/crypto/core/nonce.d.ts +2 -0
  325. package/dist/types/crypto/core/primitives.d.ts +0 -1
  326. package/dist/types/crypto/core/random.d.ts +1 -0
  327. package/dist/types/crypto/index.d.ts +1 -0
  328. package/dist/types/crypto/math/constants.d.ts +4 -2
  329. package/dist/types/crypto/math/fe.d.ts +30 -0
  330. package/dist/types/crypto/math/mod.d.ts +0 -2
  331. package/dist/types/crypto/math/types.d.ts +11 -4
  332. package/dist/types/index.d.ts +5 -3
  333. package/dist/types/infra/perf/BackgroundQueue.d.ts +58 -0
  334. package/dist/types/infra/perf/PromiseDedup.d.ts +4 -0
  335. package/dist/types/infra/perf/SharedExclusiveGate.d.ts +17 -0
  336. package/dist/types/infra/perf/StoreLock.d.ts +10 -0
  337. package/dist/types/media/WaMediaCrypto.d.ts +3 -2
  338. package/dist/types/media/WaMediaTransferClient.d.ts +3 -12
  339. package/dist/types/media/constants.d.ts +1 -1
  340. package/dist/types/media/index.d.ts +1 -1
  341. package/dist/types/media/types.d.ts +10 -2
  342. package/dist/types/message/content.d.ts +8 -0
  343. package/dist/types/message/icdc.d.ts +13 -0
  344. package/dist/types/message/reporting-token.d.ts +0 -1
  345. package/dist/types/message/types.d.ts +45 -6
  346. package/dist/types/protocol/appstate.d.ts +0 -11
  347. package/dist/types/protocol/constants.d.ts +7 -3
  348. package/dist/types/protocol/defaults.d.ts +6 -0
  349. package/dist/types/protocol/index.d.ts +1 -2
  350. package/dist/types/protocol/jid.d.ts +19 -2
  351. package/dist/types/protocol/message.d.ts +60 -0
  352. package/dist/types/protocol/nodes.d.ts +2 -0
  353. package/dist/types/protocol/notification.d.ts +2 -0
  354. package/dist/types/protocol/privacy-token.d.ts +17 -0
  355. package/dist/types/protocol/privacy.d.ts +75 -0
  356. package/dist/types/protocol/stream.d.ts +30 -0
  357. package/dist/types/retry/codec.d.ts +3 -0
  358. package/dist/types/retry/index.d.ts +3 -3
  359. package/dist/types/retry/parse.d.ts +5 -2
  360. package/dist/types/retry/tracker.d.ts +1 -0
  361. package/dist/types/retry/types.d.ts +6 -1
  362. package/dist/types/signal/api/SignalDeviceSyncApi.d.ts +2 -1
  363. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +6 -0
  364. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +2 -0
  365. package/dist/types/signal/api/SignalRotateKeyApi.d.ts +4 -5
  366. package/dist/types/signal/api/SignalSessionSyncApi.d.ts +8 -6
  367. package/dist/types/signal/api/result-map.d.ts +1 -0
  368. package/dist/types/signal/constants.d.ts +0 -3
  369. package/dist/types/signal/{store/sqlite.d.ts → encoding.d.ts} +3 -3
  370. package/dist/types/signal/group/SenderKeyManager.d.ts +10 -5
  371. package/dist/types/signal/index.d.ts +2 -0
  372. package/dist/types/signal/session/SignalProtocol.d.ts +10 -4
  373. package/dist/types/signal/session/resolver.d.ts +7 -2
  374. package/dist/types/store/contracts/appstate.store.d.ts +1 -1
  375. package/dist/types/store/contracts/privacy-token.store.d.ts +16 -0
  376. package/dist/types/store/contracts/retry.store.d.ts +7 -0
  377. package/dist/types/store/contracts/signal.store.d.ts +7 -0
  378. package/dist/types/store/createStore.d.ts +1 -1
  379. package/dist/types/store/index.d.ts +5 -13
  380. package/dist/types/store/locks/appstate.lock.d.ts +3 -0
  381. package/dist/types/store/locks/auth.lock.d.ts +3 -0
  382. package/dist/types/store/locks/contact.lock.d.ts +3 -0
  383. package/dist/types/store/locks/device-list.lock.d.ts +2 -0
  384. package/dist/types/store/locks/message.lock.d.ts +3 -0
  385. package/dist/types/store/locks/participants.lock.d.ts +2 -0
  386. package/dist/types/store/locks/privacy-token.lock.d.ts +2 -0
  387. package/dist/types/store/locks/retry.lock.d.ts +2 -0
  388. package/dist/types/store/locks/sender-key.lock.d.ts +3 -0
  389. package/dist/types/store/locks/signal.lock.d.ts +3 -0
  390. package/dist/types/store/locks/thread.lock.d.ts +3 -0
  391. package/dist/types/store/providers/memory/appstate.store.d.ts +1 -1
  392. package/dist/types/store/providers/memory/privacy-token.store.d.ts +13 -0
  393. package/dist/types/store/providers/memory/retry.store.d.ts +8 -0
  394. package/dist/types/store/providers/memory/signal.store.d.ts +2 -1
  395. package/dist/types/store/types.d.ts +49 -61
  396. package/dist/types/transport/WaWebSocket.d.ts +0 -1
  397. package/dist/types/transport/binary/constants.d.ts +0 -30
  398. package/dist/types/transport/binary/index.d.ts +0 -1
  399. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +3 -4
  400. package/dist/types/transport/node/builders/business.d.ts +29 -0
  401. package/dist/types/transport/node/builders/global.d.ts +102 -0
  402. package/dist/types/transport/node/builders/index.d.ts +5 -2
  403. package/dist/types/transport/node/builders/message.d.ts +8 -7
  404. package/dist/types/transport/node/builders/pairing.d.ts +0 -2
  405. package/dist/types/transport/node/builders/privacy-token.d.ts +9 -0
  406. package/dist/types/transport/node/builders/privacy.d.ts +7 -0
  407. package/dist/types/transport/node/builders/profile.d.ts +8 -0
  408. package/dist/types/transport/node/builders/retry.d.ts +0 -1
  409. package/dist/types/transport/node/helpers.d.ts +5 -0
  410. package/dist/types/transport/noise/WaNoiseSession.d.ts +3 -2
  411. package/dist/types/transport/noise/WaNoiseSocket.d.ts +4 -2
  412. package/dist/types/util/bytes.d.ts +1 -1
  413. package/dist/types/util/index.d.ts +5 -0
  414. package/dist/types/util/primitives.d.ts +0 -1
  415. package/dist/util/bytes.js +22 -18
  416. package/dist/util/index.js +23 -0
  417. package/dist/util/primitives.js +2 -2
  418. package/package.json +29 -7
  419. package/proto/index.js +1 -1
  420. package/dist/crypto/core/constants.js +0 -4
  421. package/dist/esm/crypto/core/constants.js +0 -1
  422. package/dist/esm/retry/outbound.js +0 -82
  423. package/dist/esm/store/providers/sqlite/BaseSqliteStore.js +0 -37
  424. package/dist/esm/store/providers/sqlite/appstate.store.js +0 -250
  425. package/dist/esm/store/providers/sqlite/auth.store.js +0 -176
  426. package/dist/esm/store/providers/sqlite/connection.js +0 -245
  427. package/dist/esm/store/providers/sqlite/contact.store.js +0 -74
  428. package/dist/esm/store/providers/sqlite/device-list.store.js +0 -127
  429. package/dist/esm/store/providers/sqlite/message.store.js +0 -132
  430. package/dist/esm/store/providers/sqlite/migrations.js +0 -347
  431. package/dist/esm/store/providers/sqlite/participants.store.js +0 -77
  432. package/dist/esm/store/providers/sqlite/retry.store.js +0 -141
  433. package/dist/esm/store/providers/sqlite/sender-key.store.js +0 -198
  434. package/dist/esm/store/providers/sqlite/signal.store.js +0 -435
  435. package/dist/esm/store/providers/sqlite/table-names.js +0 -107
  436. package/dist/esm/store/providers/sqlite/thread.store.js +0 -85
  437. package/dist/retry/outbound.js +0 -87
  438. package/dist/store/providers/sqlite/BaseSqliteStore.js +0 -41
  439. package/dist/store/providers/sqlite/appstate.store.js +0 -254
  440. package/dist/store/providers/sqlite/auth.store.js +0 -180
  441. package/dist/store/providers/sqlite/connection.js +0 -281
  442. package/dist/store/providers/sqlite/contact.store.js +0 -78
  443. package/dist/store/providers/sqlite/device-list.store.js +0 -131
  444. package/dist/store/providers/sqlite/message.store.js +0 -136
  445. package/dist/store/providers/sqlite/migrations.js +0 -350
  446. package/dist/store/providers/sqlite/participants.store.js +0 -81
  447. package/dist/store/providers/sqlite/retry.store.js +0 -145
  448. package/dist/store/providers/sqlite/sender-key.store.js +0 -202
  449. package/dist/store/providers/sqlite/signal.store.js +0 -439
  450. package/dist/store/providers/sqlite/table-names.js +0 -113
  451. package/dist/store/providers/sqlite/thread.store.js +0 -89
  452. package/dist/types/appstate/store/sqlite.d.ts +0 -7
  453. package/dist/types/crypto/core/constants.d.ts +0 -1
  454. package/dist/types/retry/outbound.d.ts +0 -4
  455. package/dist/types/store/providers/sqlite/BaseSqliteStore.d.ts +0 -12
  456. package/dist/types/store/providers/sqlite/appstate.store.d.ts +0 -17
  457. package/dist/types/store/providers/sqlite/auth.store.d.ts +0 -10
  458. package/dist/types/store/providers/sqlite/connection.d.ts +0 -10
  459. package/dist/types/store/providers/sqlite/contact.store.d.ts +0 -12
  460. package/dist/types/store/providers/sqlite/device-list.store.d.ts +0 -15
  461. package/dist/types/store/providers/sqlite/message.store.d.ts +0 -13
  462. package/dist/types/store/providers/sqlite/migrations.d.ts +0 -3
  463. package/dist/types/store/providers/sqlite/participants.store.d.ts +0 -12
  464. package/dist/types/store/providers/sqlite/retry.store.d.ts +0 -15
  465. package/dist/types/store/providers/sqlite/sender-key.store.d.ts +0 -24
  466. package/dist/types/store/providers/sqlite/signal.store.d.ts +0 -53
  467. package/dist/types/store/providers/sqlite/table-names.d.ts +0 -5
  468. package/dist/types/store/providers/sqlite/thread.store.d.ts +0 -13
@@ -1,7 +1,7 @@
1
- import { proto } from '../../proto.js';
2
- import { WA_DEFAULTS } from '../../protocol/constants.js';
3
- import { assertByteLength } from '../../util/bytes.js';
4
- import { asBytes, asNumber, asOptionalBytes, asOptionalNumber, asString, toBoolOrUndef } from '../../util/coercion.js';
1
+ import { proto } from '../proto.js';
2
+ import { WA_DEFAULTS } from '../protocol/constants.js';
3
+ import { assertByteLength } from '../util/bytes.js';
4
+ import { asBytes, asNumber, asOptionalBytes, asOptionalNumber, asString, toBoolOrUndef } from '../util/coercion.js';
5
5
  export function toSignalAddressParts(address) {
6
6
  return {
7
7
  user: address.user,
@@ -56,7 +56,13 @@ function encodeSignalSessionSnapshot(session) {
56
56
  rootKey: session.rootKey,
57
57
  previousCounter: session.prevSendChainHighestIndex,
58
58
  senderChain: encodeSignalSendChain(session.sendChain),
59
- receiverChains: session.recvChains.map((chain) => encodeSignalRecvChain(chain)),
59
+ receiverChains: (() => {
60
+ const src = session.recvChains;
61
+ const arr = new Array(src.length);
62
+ for (let i = 0; i < src.length; i += 1)
63
+ arr[i] = encodeSignalRecvChain(src[i]);
64
+ return arr;
65
+ })(),
60
66
  pendingPreKey: session.initialExchangeInfo
61
67
  ? {
62
68
  preKeyId: session.initialExchangeInfo.remoteOneTimeId ?? undefined,
@@ -85,12 +91,20 @@ function encodeSignalRecvChain(chain) {
85
91
  index: chain.nextMsgIndex,
86
92
  key: chain.chainKey
87
93
  },
88
- messageKeys: (chain.unusedMsgKeys ?? []).map((messageKey) => ({
89
- index: messageKey.index,
90
- cipherKey: messageKey.cipherKey,
91
- macKey: messageKey.macKey,
92
- iv: messageKey.iv
93
- }))
94
+ messageKeys: (() => {
95
+ const src = chain.unusedMsgKeys ?? [];
96
+ const arr = new Array(src.length);
97
+ for (let i = 0; i < src.length; i += 1) {
98
+ const messageKey = src[i];
99
+ arr[i] = {
100
+ index: messageKey.index,
101
+ cipherKey: messageKey.cipherKey,
102
+ macKey: messageKey.macKey,
103
+ iv: messageKey.iv
104
+ };
105
+ }
106
+ return arr;
107
+ })()
94
108
  };
95
109
  }
96
110
  function decodeSignalMessageKey(messageKey, field) {
@@ -120,7 +134,13 @@ function decodeSignalRecvChain(chain, field) {
120
134
  ratchetPubKey,
121
135
  nextMsgIndex: asNumber(chainKey.index, `${field}.chainKey.index`),
122
136
  chainKey: chainKeyBytes,
123
- unusedMsgKeys: (chain.messageKeys ?? []).map((messageKey, index) => decodeSignalMessageKey(messageKey, `${field}.messageKeys[${index}]`))
137
+ unusedMsgKeys: (() => {
138
+ const src = chain.messageKeys ?? [];
139
+ const arr = new Array(src.length);
140
+ for (let i = 0; i < src.length; i += 1)
141
+ arr[i] = decodeSignalMessageKey(src[i], `${field}.messageKeys[${i}]`);
142
+ return arr;
143
+ })()
124
144
  };
125
145
  }
126
146
  function decodeSignalSendChain(chain, field) {
@@ -179,7 +199,13 @@ function decodeSignalSessionSnapshot(session, field) {
179
199
  },
180
200
  rootKey,
181
201
  sendChain: decodeSignalSendChain(senderChain, `${field}.senderChain`),
182
- recvChains: (session.receiverChains ?? []).map((chain, index) => decodeSignalRecvChain(chain, `${field}.receiverChains[${index}]`)),
202
+ recvChains: (() => {
203
+ const src = session.receiverChains ?? [];
204
+ const arr = new Array(src.length);
205
+ for (let i = 0; i < src.length; i += 1)
206
+ arr[i] = decodeSignalRecvChain(src[i], `${field}.receiverChains[${i}]`);
207
+ return arr;
208
+ })(),
183
209
  initialExchangeInfo: pendingPreKey
184
210
  ? {
185
211
  remoteOneTimeId: asOptionalNumber(pendingPreKey.preKeyId, `${field}.pendingPreKey.preKeyId`) ??
@@ -195,7 +221,13 @@ function decodeSignalSessionSnapshot(session, field) {
195
221
  export function encodeSignalSessionRecord(record) {
196
222
  return proto.RecordStructure.encode({
197
223
  currentSession: encodeSignalSessionSnapshot(record),
198
- previousSessions: record.prevSessions.map((session) => encodeSignalSessionSnapshot(session))
224
+ previousSessions: (() => {
225
+ const src = record.prevSessions;
226
+ const arr = new Array(src.length);
227
+ for (let i = 0; i < src.length; i += 1)
228
+ arr[i] = encodeSignalSessionSnapshot(src[i]);
229
+ return arr;
230
+ })()
199
231
  }).finish();
200
232
  }
201
233
  export function decodeSignalSessionRecord(raw) {
@@ -206,7 +238,13 @@ export function decodeSignalSessionRecord(raw) {
206
238
  const current = decodeSignalSessionSnapshot(decoded.currentSession, 'signal_sessions.currentSession');
207
239
  return {
208
240
  ...current,
209
- prevSessions: (decoded.previousSessions ?? []).map((session, index) => decodeSignalSessionSnapshot(session, `signal_sessions.previousSessions[${index}]`))
241
+ prevSessions: (() => {
242
+ const src = decoded.previousSessions ?? [];
243
+ const arr = new Array(src.length);
244
+ for (let i = 0; i < src.length; i += 1)
245
+ arr[i] = decodeSignalSessionSnapshot(src[i], `signal_sessions.previousSessions[${i}]`);
246
+ return arr;
247
+ })()
210
248
  };
211
249
  }
212
250
  export function encodeSenderKeyRecord(record) {
@@ -222,10 +260,18 @@ export function encodeSenderKeyRecord(record) {
222
260
  public: record.signingPublicKey,
223
261
  private: record.signingPrivateKey
224
262
  },
225
- senderMessageKeys: (record.unusedMessageKeys ?? []).map((messageKey) => ({
226
- iteration: messageKey.iteration,
227
- seed: messageKey.seed
228
- }))
263
+ senderMessageKeys: (() => {
264
+ const src = record.unusedMessageKeys ?? [];
265
+ const arr = new Array(src.length);
266
+ for (let i = 0; i < src.length; i += 1) {
267
+ const messageKey = src[i];
268
+ arr[i] = {
269
+ iteration: messageKey.iteration,
270
+ seed: messageKey.seed
271
+ };
272
+ }
273
+ return arr;
274
+ })()
229
275
  }
230
276
  ]
231
277
  }).finish();
@@ -245,10 +291,18 @@ function decodeSenderKeyState(state, field) {
245
291
  signingPrivateKey: state.senderSigningKey.private !== null && state.senderSigningKey.private !== undefined
246
292
  ? asBytes(state.senderSigningKey.private, `${field}.senderSigningKey.private`)
247
293
  : undefined,
248
- unusedMessageKeys: (state.senderMessageKeys ?? []).map((messageKey, index) => ({
249
- iteration: asNumber(messageKey.iteration, `${field}.senderMessageKeys[${index}].iteration`),
250
- seed: asBytes(messageKey.seed, `${field}.senderMessageKeys[${index}].seed`)
251
- }))
294
+ unusedMessageKeys: (() => {
295
+ const src = state.senderMessageKeys ?? [];
296
+ const arr = new Array(src.length);
297
+ for (let i = 0; i < src.length; i += 1) {
298
+ const messageKey = src[i];
299
+ arr[i] = {
300
+ iteration: asNumber(messageKey.iteration, `${field}.senderMessageKeys[${i}].iteration`),
301
+ seed: asBytes(messageKey.seed, `${field}.senderMessageKeys[${i}].seed`)
302
+ };
303
+ }
304
+ return arr;
305
+ })()
252
306
  };
253
307
  }
254
308
  export function decodeSenderKeyRecord(raw, groupId, sender) {
@@ -281,7 +335,7 @@ export function decodeSenderKeyDistributionRow(row) {
281
335
  timestampMs: asNumber(row.timestamp_ms, 'sender_key_distribution.timestamp_ms')
282
336
  };
283
337
  }
284
- export function decodeSqliteCount(row, field) {
338
+ export function decodeStoreCount(row, field) {
285
339
  return row ? asNumber(row.count, field) : 0;
286
340
  }
287
341
  export function decodeSignalRemoteIdentity(raw) {
@@ -1,6 +1,7 @@
1
1
  import { readVersionedContent, toSerializedPubKey } from '../../crypto/index.js';
2
2
  import { proto } from '../../proto.js';
3
- import { SIGNATURE_SIZE, SIGNAL_GROUP_VERSION } from '../constants.js';
3
+ import { SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
4
+ import { SIGNAL_GROUP_VERSION } from '../constants.js';
4
5
  import { assertByteLength, toBytesView } from '../../util/bytes.js';
5
6
  export function parseDistributionPayload(payload) {
6
7
  const body = readVersionedContent(payload, SIGNAL_GROUP_VERSION, 0);
@@ -25,7 +26,7 @@ export function parseDistributionPayload(payload) {
25
26
  };
26
27
  }
27
28
  export function parseSenderKeyMessage(versionContentMac) {
28
- const body = readVersionedContent(versionContentMac, SIGNAL_GROUP_VERSION, SIGNATURE_SIZE);
29
+ const body = readVersionedContent(versionContentMac, SIGNAL_GROUP_VERSION, SIGNAL_SIGNATURE_LENGTH);
29
30
  const decoded = proto.SenderKeyMessage.decode(body);
30
31
  if (decoded.id === null ||
31
32
  decoded.id === undefined ||
@@ -1,6 +1,9 @@
1
1
  import { aesCbcDecrypt, aesCbcEncrypt, importAesCbcKey, toSerializedPubKey, prependVersion, randomBytesAsync, randomIntAsync, X25519 } from '../../crypto/index.js';
2
+ import { StoreLock } from '../../infra/perf/StoreLock.js';
2
3
  import { proto } from '../../proto.js';
3
- import { SIGNAL_GROUP_VERSION, SIGNATURE_SIZE } from '../constants.js';
4
+ import { signalAddressKey } from '../../protocol/jid.js';
5
+ import { SIGNAL_SIGNATURE_LENGTH } from '../api/constants.js';
6
+ import { SIGNAL_GROUP_VERSION } from '../constants.js';
4
7
  import { signSignalMessage, verifySignalSignature } from '../crypto/WaAdvSignature.js';
5
8
  import { deriveSenderKeyMsgKey, selectMessageKey } from '../group/SenderKeyChain.js';
6
9
  import { parseDistributionPayload, parseSenderKeyMessage } from '../group/SenderKeyCodec.js';
@@ -24,143 +27,156 @@ async function aesCbcDecryptFromSeed(seed, ciphertext) {
24
27
  }
25
28
  export class SenderKeyManager {
26
29
  constructor(store) {
30
+ this.senderLock = new StoreLock();
27
31
  this.store = store;
28
32
  }
29
- async createSenderKeyDistributionMessage(groupId, sender) {
30
- const senderKey = await this.ensureSenderKey(groupId, sender);
31
- const distributionProto = proto.SenderKeyDistributionMessage.encode({
32
- id: senderKey.keyId,
33
- iteration: senderKey.iteration,
34
- chainKey: senderKey.chainKey,
35
- signingKey: senderKey.signingPublicKey
36
- }).finish();
37
- const payload = prependVersion(distributionProto, SIGNAL_GROUP_VERSION);
38
- await this.store.upsertSenderKeyDistribution({
39
- groupId,
40
- sender,
41
- keyId: senderKey.keyId,
42
- timestampMs: Date.now()
33
+ async prepareGroupEncryption(groupId, sender, plaintext) {
34
+ return this.runWithSenderLock(groupId, sender, async () => {
35
+ const senderKey = await this.ensureSenderKeyInternal(groupId, sender);
36
+ if (!senderKey.signingPrivateKey) {
37
+ throw new Error('sender private signing key is missing');
38
+ }
39
+ const derived = await deriveSenderKeyMsgKey(senderKey.iteration, senderKey.chainKey);
40
+ await this.store.upsertSenderKey({
41
+ ...senderKey,
42
+ chainKey: derived.nextChainKey,
43
+ iteration: derived.messageKey.iteration + 1
44
+ });
45
+ const distributionProto = proto.SenderKeyDistributionMessage.encode({
46
+ id: senderKey.keyId,
47
+ iteration: senderKey.iteration,
48
+ chainKey: senderKey.chainKey,
49
+ signingKey: senderKey.signingPublicKey
50
+ }).finish();
51
+ const distributionMessage = {
52
+ groupId,
53
+ axolotlSenderKeyDistributionMessage: prependVersion(distributionProto, SIGNAL_GROUP_VERSION)
54
+ };
55
+ const messagePayload = await aesCbcEncryptFromSeed(derived.messageKey.seed, plaintext);
56
+ const senderKeyMessage = proto.SenderKeyMessage.encode({
57
+ id: senderKey.keyId,
58
+ iteration: derived.messageKey.iteration,
59
+ ciphertext: messagePayload
60
+ }).finish();
61
+ const versionedContent = prependVersion(senderKeyMessage, SIGNAL_GROUP_VERSION);
62
+ const signature = await signSignalMessage(senderKey.signingPrivateKey, versionedContent);
63
+ if (signature.length !== SIGNAL_SIGNATURE_LENGTH) {
64
+ throw new Error(`invalid sender key signature length ${signature.length}`);
65
+ }
66
+ const ciphertext = {
67
+ groupId,
68
+ sender,
69
+ keyId: senderKey.keyId,
70
+ iteration: derived.messageKey.iteration,
71
+ ciphertext: concatBytes([versionedContent, signature])
72
+ };
73
+ await this.store.upsertSenderKeyDistribution({
74
+ groupId,
75
+ sender,
76
+ keyId: senderKey.keyId,
77
+ timestampMs: Date.now()
78
+ });
79
+ return {
80
+ distributionMessage,
81
+ ciphertext,
82
+ keyId: senderKey.keyId
83
+ };
43
84
  });
44
- return {
45
- groupId,
46
- axolotlSenderKeyDistributionMessage: payload
47
- };
48
85
  }
49
- async filterParticipantsNeedingDistribution(groupId, sender, participants) {
86
+ async filterParticipantsNeedingDistribution(groupId, senderKeyId, participants) {
50
87
  if (participants.length === 0) {
51
88
  return [];
52
89
  }
53
- const senderKey = await this.ensureSenderKey(groupId, sender);
54
90
  const distributed = await this.store.getDeviceSenderKeyDistributions(groupId, participants);
55
- return participants.filter((_, index) => {
91
+ const pendingParticipants = new Array(participants.length);
92
+ let pendingCount = 0;
93
+ for (let index = 0; index < participants.length; index += 1) {
56
94
  const record = distributed[index];
57
- return !record || record.keyId !== senderKey.keyId;
58
- });
95
+ if (!record || record.keyId !== senderKeyId) {
96
+ pendingParticipants[pendingCount] = participants[index];
97
+ pendingCount += 1;
98
+ }
99
+ }
100
+ pendingParticipants.length = pendingCount;
101
+ return pendingParticipants;
59
102
  }
60
- async markSenderKeyDistributed(groupId, sender, participants) {
103
+ async markSenderKeyDistributed(groupId, senderKeyId, participants) {
61
104
  if (participants.length === 0) {
62
105
  return;
63
106
  }
64
- const senderKey = await this.ensureSenderKey(groupId, sender);
65
107
  const timestampMs = Date.now();
66
108
  const distributions = new Array(participants.length);
67
109
  for (let index = 0; index < participants.length; index += 1) {
68
110
  distributions[index] = {
69
111
  groupId,
70
112
  sender: participants[index],
71
- keyId: senderKey.keyId,
113
+ keyId: senderKeyId,
72
114
  timestampMs
73
115
  };
74
116
  }
75
117
  await this.store.upsertSenderKeyDistributions(distributions);
76
118
  }
77
119
  async processSenderKeyDistributionPayload(groupId, sender, payload) {
78
- if (groupId.length === 0) {
79
- throw new Error('sender key distribution missing groupId');
80
- }
81
- const parsed = parseDistributionPayload(payload);
82
- const record = {
83
- groupId,
84
- sender,
85
- keyId: parsed.keyId,
86
- iteration: parsed.iteration,
87
- chainKey: parsed.chainKey,
88
- signingPublicKey: parsed.signingPublicKey,
89
- unusedMessageKeys: []
90
- };
91
- await Promise.all([
92
- this.store.upsertSenderKey(record),
93
- this.store.upsertSenderKeyDistribution({
120
+ return this.runWithSenderLock(groupId, sender, async () => {
121
+ if (groupId.length === 0) {
122
+ throw new Error('sender key distribution missing groupId');
123
+ }
124
+ const parsed = parseDistributionPayload(payload);
125
+ const record = {
94
126
  groupId,
95
127
  sender,
96
128
  keyId: parsed.keyId,
97
- timestampMs: Date.now()
98
- })
99
- ]);
100
- return record;
101
- }
102
- async encryptGroupMessage(groupId, sender, plaintext) {
103
- const senderKey = await this.ensureSenderKey(groupId, sender);
104
- if (!senderKey.signingPrivateKey) {
105
- throw new Error('sender private signing key is missing');
106
- }
107
- const derived = await deriveSenderKeyMsgKey(senderKey.iteration, senderKey.chainKey);
108
- const messagePayload = await aesCbcEncryptFromSeed(derived.messageKey.seed, plaintext);
109
- const senderKeyMessage = proto.SenderKeyMessage.encode({
110
- id: senderKey.keyId,
111
- iteration: derived.messageKey.iteration,
112
- ciphertext: messagePayload
113
- }).finish();
114
- const versionedContent = prependVersion(senderKeyMessage, SIGNAL_GROUP_VERSION);
115
- const signature = await signSignalMessage(senderKey.signingPrivateKey, versionedContent);
116
- if (signature.length !== SIGNATURE_SIZE) {
117
- throw new Error(`invalid sender key signature length ${signature.length}`);
118
- }
119
- const ciphertext = concatBytes([versionedContent, signature]);
120
- await this.store.upsertSenderKey({
121
- ...senderKey,
122
- chainKey: derived.nextChainKey,
123
- iteration: derived.messageKey.iteration + 1
129
+ iteration: parsed.iteration,
130
+ chainKey: parsed.chainKey,
131
+ signingPublicKey: parsed.signingPublicKey,
132
+ unusedMessageKeys: []
133
+ };
134
+ await Promise.all([
135
+ this.store.upsertSenderKey(record),
136
+ this.store.upsertSenderKeyDistribution({
137
+ groupId,
138
+ sender,
139
+ keyId: parsed.keyId,
140
+ timestampMs: Date.now()
141
+ })
142
+ ]);
143
+ return record;
124
144
  });
125
- return {
126
- groupId,
127
- sender,
128
- keyId: senderKey.keyId,
129
- iteration: derived.messageKey.iteration,
130
- ciphertext
131
- };
132
145
  }
133
146
  async decryptGroupMessage(payload) {
134
- const parsed = parseSenderKeyMessage(payload.ciphertext);
135
- const senderKey = await this.store.getDeviceSenderKey(payload.groupId, payload.sender);
136
- if (!senderKey) {
137
- throw new Error('missing sender key');
138
- }
139
- if (senderKey.keyId !== parsed.keyId) {
140
- throw new Error('sender key id mismatch');
141
- }
142
- if (payload.keyId !== undefined &&
143
- payload.keyId !== null &&
144
- parsed.keyId !== payload.keyId) {
145
- throw new Error('sender key id mismatch');
146
- }
147
- if (payload.iteration !== undefined &&
148
- payload.iteration !== null &&
149
- parsed.iteration !== payload.iteration) {
150
- throw new Error('sender key iteration mismatch');
151
- }
152
- const signedContent = parsed.versionContentMac.subarray(0, parsed.versionContentMac.length - SIGNATURE_SIZE);
153
- const signature = parsed.versionContentMac.subarray(parsed.versionContentMac.length - SIGNATURE_SIZE);
154
- const validSignature = await verifySignalSignature(senderKey.signingPublicKey, signedContent, signature);
155
- if (!validSignature) {
156
- throw new Error('invalid sender key signature');
157
- }
158
- const selected = await selectMessageKey(senderKey, parsed.iteration);
159
- const plaintext = await aesCbcDecryptFromSeed(selected.messageKey.seed, parsed.ciphertext);
160
- await this.store.upsertSenderKey(selected.updatedRecord);
161
- return plaintext;
147
+ return this.runWithSenderLock(payload.groupId, payload.sender, async () => {
148
+ const parsed = parseSenderKeyMessage(payload.ciphertext);
149
+ const senderKey = await this.store.getDeviceSenderKey(payload.groupId, payload.sender);
150
+ if (!senderKey) {
151
+ throw new Error('missing sender key');
152
+ }
153
+ if (senderKey.keyId !== parsed.keyId) {
154
+ throw new Error('sender key id mismatch');
155
+ }
156
+ if (payload.keyId !== undefined &&
157
+ payload.keyId !== null &&
158
+ parsed.keyId !== payload.keyId) {
159
+ throw new Error('sender key id mismatch');
160
+ }
161
+ if (payload.iteration !== undefined &&
162
+ payload.iteration !== null &&
163
+ parsed.iteration !== payload.iteration) {
164
+ throw new Error('sender key iteration mismatch');
165
+ }
166
+ const signedContent = parsed.versionContentMac.subarray(0, parsed.versionContentMac.length - SIGNAL_SIGNATURE_LENGTH);
167
+ const signature = parsed.versionContentMac.subarray(parsed.versionContentMac.length - SIGNAL_SIGNATURE_LENGTH);
168
+ const validSignature = await verifySignalSignature(senderKey.signingPublicKey, signedContent, signature);
169
+ if (!validSignature) {
170
+ throw new Error('invalid sender key signature');
171
+ }
172
+ const selected = await selectMessageKey(senderKey, parsed.iteration);
173
+ // Keep decrypt + persist ordered: failed decrypt must not advance sender-key state.
174
+ const plaintext = await aesCbcDecryptFromSeed(selected.messageKey.seed, parsed.ciphertext);
175
+ await this.store.upsertSenderKey(selected.updatedRecord);
176
+ return plaintext;
177
+ });
162
178
  }
163
- async ensureSenderKey(groupId, sender) {
179
+ async ensureSenderKeyInternal(groupId, sender) {
164
180
  const existing = await this.store.getDeviceSenderKey(groupId, sender);
165
181
  if (existing) {
166
182
  return existing;
@@ -183,4 +199,7 @@ export class SenderKeyManager {
183
199
  await this.store.upsertSenderKey(created);
184
200
  return created;
185
201
  }
202
+ runWithSenderLock(groupId, sender, task) {
203
+ return this.senderLock.run(`senderKey:${groupId}:${signalAddressKey(sender)}`, task);
204
+ }
186
205
  }
@@ -1,3 +1,4 @@
1
+ export { decodeSignalPreKeyRow, decodeSignalRegistrationRow, decodeSignalRemoteIdentity, decodeSignalSessionRecord, decodeSignalSignedPreKeyRow, decodeSenderKeyDistributionRow, decodeSenderKeyRecord, decodeStoreCount, encodeSenderKeyRecord, encodeSignalSessionRecord, toSignalAddressParts } from './encoding.js';
1
2
  export { generatePreKeyPair, generateRegistrationId, generateRegistrationInfo, generateSignedPreKey } from './registration/keygen.js';
2
3
  export { buildPreKeyUploadIq, parsePreKeyUploadFailure } from './api/prekeys.js';
3
4
  export { SignalDigestSyncApi } from './api/SignalDigestSyncApi.js';
@@ -3,9 +3,13 @@ import { toSerializedPubKey } from '../../crypto/core/keys.js';
3
3
  import { X25519 } from '../../crypto/curves/X25519.js';
4
4
  import { signSignalMessage } from '../crypto/WaAdvSignature.js';
5
5
  export async function generateRegistrationInfo() {
6
+ const [registrationId, identityKeyPair] = await Promise.all([
7
+ generateRegistrationId(),
8
+ X25519.generateKeyPair()
9
+ ]);
6
10
  return {
7
- registrationId: await generateRegistrationId(),
8
- identityKeyPair: await X25519.generateKeyPair()
11
+ registrationId,
12
+ identityKeyPair
9
13
  };
10
14
  }
11
15
  export async function generatePreKeyPair(keyId) {
@@ -5,6 +5,7 @@ export async function createAndStoreInitialKeys(store) {
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
11
  await store.getOrGenSinglePreKey(async () => firstPreKey);