zapo-js 0.2.0 → 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 (351) hide show
  1. package/README.md +7 -3
  2. package/dist/appstate/WaAppStateCrypto.js +49 -41
  3. package/dist/appstate/WaAppStateSyncClient.js +79 -42
  4. package/dist/appstate/index.js +2 -2
  5. package/dist/auth/WaAuthClient.js +20 -11
  6. package/dist/auth/{flow/WaAuthCredentialsFlow.js → credentials-flow.js} +83 -18
  7. package/dist/auth/pairing/WaPairingFlow.js +26 -29
  8. package/dist/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +29 -13
  9. package/dist/client/WaClient.js +115 -75
  10. package/dist/client/WaClientFactory.js +113 -30
  11. package/dist/client/connection/WaConnectionManager.js +4 -1
  12. package/dist/client/coordinators/WaAbPropsCoordinator.js +141 -0
  13. package/dist/client/coordinators/WaBusinessCoordinator.js +3 -12
  14. package/dist/client/coordinators/WaEmailCoordinator.js +63 -0
  15. package/dist/client/coordinators/WaIncomingNodeCoordinator.js +33 -8
  16. package/dist/client/coordinators/WaMessageDispatchCoordinator.js +55 -25
  17. package/dist/client/coordinators/WaOfflineResumeCoordinator.js +114 -0
  18. package/dist/client/coordinators/WaPassiveTasksCoordinator.js +38 -20
  19. package/dist/client/coordinators/WaProfileCoordinator.js +3 -1
  20. package/dist/client/coordinators/WaRetryCoordinator.js +11 -9
  21. package/dist/client/coordinators/WaTrustedContactTokenCoordinator.js +22 -4
  22. package/dist/client/dirty.js +1 -1
  23. package/dist/client/events/abprops.js +43 -0
  24. package/dist/client/events/privacy-token.js +1 -2
  25. package/dist/client/events/registration.js +42 -0
  26. package/dist/client/incoming.js +37 -0
  27. package/dist/client/mailbox.js +17 -1
  28. package/dist/client/media.js +243 -0
  29. package/dist/client/messages.js +163 -86
  30. package/dist/crypto/core/index.js +4 -1
  31. package/dist/crypto/core/random.js +3 -9
  32. package/dist/crypto/core/xeddsa.js +57 -0
  33. package/dist/crypto/curves/X25519.js +18 -0
  34. package/dist/crypto/curves/constants.js +2 -1
  35. package/dist/esm/appstate/WaAppStateCrypto.js +39 -31
  36. package/dist/esm/appstate/WaAppStateSyncClient.js +68 -31
  37. package/dist/esm/appstate/index.js +1 -1
  38. package/dist/esm/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +1 -1
  39. package/dist/esm/auth/WaAuthClient.js +17 -8
  40. package/dist/esm/auth/{flow/WaAuthCredentialsFlow.js → credentials-flow.js} +83 -18
  41. package/dist/esm/auth/pairing/WaPairingFlow.js +25 -28
  42. package/dist/esm/auth/pairing/{WaPairingCodeCrypto.js → pairing-code-crypto.js} +20 -6
  43. package/dist/esm/client/WaClient.js +116 -76
  44. package/dist/esm/client/WaClientFactory.js +114 -31
  45. package/dist/esm/client/connection/WaConnectionManager.js +4 -1
  46. package/dist/esm/client/coordinators/WaAbPropsCoordinator.js +137 -0
  47. package/dist/esm/client/coordinators/WaBusinessCoordinator.js +4 -13
  48. package/dist/esm/client/coordinators/WaEmailCoordinator.js +60 -0
  49. package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +35 -10
  50. package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +47 -17
  51. package/dist/esm/client/coordinators/WaOfflineResumeCoordinator.js +110 -0
  52. package/dist/esm/client/coordinators/WaPassiveTasksCoordinator.js +38 -20
  53. package/dist/esm/client/coordinators/WaProfileCoordinator.js +3 -1
  54. package/dist/esm/client/coordinators/WaRetryCoordinator.js +11 -9
  55. package/dist/esm/client/coordinators/WaTrustedContactTokenCoordinator.js +24 -6
  56. package/dist/esm/client/dirty.js +1 -1
  57. package/dist/esm/client/events/abprops.js +40 -0
  58. package/dist/esm/client/events/privacy-token.js +1 -2
  59. package/dist/esm/client/events/registration.js +39 -0
  60. package/dist/esm/client/incoming.js +36 -0
  61. package/dist/esm/client/mailbox.js +17 -1
  62. package/dist/esm/client/media.js +234 -0
  63. package/dist/esm/client/messages.js +162 -85
  64. package/dist/esm/crypto/core/index.js +1 -0
  65. package/dist/esm/crypto/core/random.js +2 -7
  66. package/dist/esm/crypto/core/xeddsa.js +53 -0
  67. package/dist/esm/crypto/curves/X25519.js +20 -2
  68. package/dist/esm/crypto/curves/constants.js +1 -0
  69. package/dist/esm/infra/perf/StoreLock.js +7 -4
  70. package/dist/esm/media/WaMediaCrypto.js +257 -62
  71. package/dist/esm/media/WaMediaTransferClient.js +47 -190
  72. package/dist/esm/media/constants.js +2 -0
  73. package/dist/esm/media/processor.js +1 -0
  74. package/dist/esm/message/addon-crypto.js +130 -3
  75. package/dist/esm/message/content.js +12 -6
  76. package/dist/esm/message/icdc.js +8 -8
  77. package/dist/esm/message/incoming.js +14 -12
  78. package/dist/esm/message/phash.js +32 -12
  79. package/dist/esm/message/reporting-token.js +3 -3
  80. package/dist/esm/message/use-case-secret.js +1 -1
  81. package/dist/esm/protocol/abprops.js +159 -0
  82. package/dist/esm/protocol/browser.js +14 -0
  83. package/dist/esm/protocol/constants.js +3 -1
  84. package/dist/esm/protocol/email.js +30 -0
  85. package/dist/esm/protocol/jid.js +44 -10
  86. package/dist/esm/protocol/nodes.js +6 -2
  87. package/dist/esm/protocol/notification.js +7 -1
  88. package/dist/esm/retry/reason.js +1 -1
  89. package/dist/esm/signal/api/SignalDeviceSyncApi.js +5 -2
  90. package/dist/esm/signal/api/SignalDigestSyncApi.js +8 -6
  91. package/dist/esm/signal/api/SignalIdentitySyncApi.js +4 -4
  92. package/dist/esm/signal/api/SignalMissingPreKeysSyncApi.js +1 -1
  93. package/dist/esm/signal/api/SignalSessionSyncApi.js +1 -1
  94. package/dist/esm/signal/crypto/WaAdvSignature.js +5 -51
  95. package/dist/esm/signal/crypto/constants.js +0 -4
  96. package/dist/esm/signal/encoding.js +11 -54
  97. package/dist/esm/signal/group/SenderKeyChain.js +3 -3
  98. package/dist/esm/signal/group/SenderKeyCodec.js +5 -6
  99. package/dist/esm/signal/group/SenderKeyManager.js +13 -10
  100. package/dist/esm/signal/registration/keygen.js +2 -3
  101. package/dist/esm/signal/registration/utils.js +2 -2
  102. package/dist/esm/signal/session/SignalProtocol.js +18 -17
  103. package/dist/esm/signal/session/SignalRatchet.js +21 -10
  104. package/dist/esm/signal/session/SignalSerializer.js +5 -6
  105. package/dist/esm/signal/session/SignalSession.js +11 -9
  106. package/dist/esm/signal/session/resolver.js +6 -6
  107. package/dist/esm/store/contracts/identity.store.js +1 -0
  108. package/dist/esm/store/contracts/message-secret.store.js +1 -0
  109. package/dist/esm/store/contracts/pre-key.store.js +1 -0
  110. package/dist/esm/store/contracts/session.store.js +1 -0
  111. package/dist/esm/store/createStore.js +48 -12
  112. package/dist/esm/store/index.js +4 -0
  113. package/dist/esm/store/locks/identity.lock.js +16 -0
  114. package/dist/esm/store/locks/message-secret.lock.js +17 -0
  115. package/dist/esm/store/locks/pre-key.lock.js +27 -0
  116. package/dist/esm/store/locks/session.lock.js +19 -0
  117. package/dist/esm/store/locks/signal.lock.js +0 -24
  118. package/dist/esm/store/noop.store.js +20 -0
  119. package/dist/esm/store/providers/memory/device-list.store.js +3 -0
  120. package/dist/esm/store/providers/memory/identity.store.js +31 -0
  121. package/dist/esm/store/providers/memory/message-secret.store.js +81 -0
  122. package/dist/esm/store/providers/memory/participants.store.js +3 -0
  123. package/dist/esm/store/providers/memory/pre-key.store.js +97 -0
  124. package/dist/esm/store/providers/memory/retry.store.js +25 -11
  125. package/dist/esm/store/providers/memory/session.store.js +45 -0
  126. package/dist/esm/store/providers/memory/signal.store.js +1 -164
  127. package/dist/esm/transport/WaComms.js +4 -3
  128. package/dist/esm/transport/WaWebSocket.js +9 -1
  129. package/dist/esm/transport/index.js +6 -0
  130. package/dist/esm/transport/keepalive/WaKeepAlive.js +17 -8
  131. package/dist/esm/transport/node/WaMobileTcpSocket.js +114 -0
  132. package/dist/esm/transport/node/WaNodeOrchestrator.js +17 -8
  133. package/dist/esm/transport/node/builders/abprops.js +20 -0
  134. package/dist/esm/transport/node/builders/device.js +11 -0
  135. package/dist/esm/transport/node/builders/email.js +65 -0
  136. package/dist/esm/transport/node/builders/offline.js +14 -0
  137. package/dist/esm/transport/node/builders/prekeys.js +37 -40
  138. package/dist/esm/transport/node/builders/presence.js +13 -0
  139. package/dist/esm/transport/node/builders/privacy-token.js +19 -23
  140. package/dist/esm/transport/node/builders/retry.js +1 -1
  141. package/dist/esm/transport/node/helpers.js +24 -0
  142. package/dist/esm/transport/node/mex/argo-decoder.js +152 -0
  143. package/dist/esm/transport/node/mex/client.js +83 -0
  144. package/dist/esm/transport/node/mex/persist-ids.js +10 -0
  145. package/dist/esm/transport/noise/WaClientPayload.js +15 -10
  146. package/dist/esm/transport/noise/WaFrameCodec.js +2 -2
  147. package/dist/esm/transport/noise/WaMobileClientPayload.js +53 -0
  148. package/dist/esm/transport/noise/WaNoiseCert.js +9 -27
  149. package/dist/esm/transport/noise/WaNoiseSession.js +12 -11
  150. package/dist/infra/perf/StoreLock.js +7 -4
  151. package/dist/media/WaMediaCrypto.js +253 -58
  152. package/dist/media/WaMediaTransferClient.js +50 -223
  153. package/dist/media/constants.js +3 -1
  154. package/dist/media/processor.js +2 -0
  155. package/dist/message/addon-crypto.js +131 -0
  156. package/dist/message/content.js +13 -5
  157. package/dist/message/icdc.js +8 -8
  158. package/dist/message/incoming.js +14 -12
  159. package/dist/message/phash.js +32 -12
  160. package/dist/message/reporting-token.js +2 -2
  161. package/dist/message/use-case-secret.js +1 -1
  162. package/dist/protocol/abprops.js +163 -0
  163. package/dist/protocol/browser.js +15 -0
  164. package/dist/protocol/constants.js +14 -2
  165. package/dist/protocol/email.js +33 -0
  166. package/dist/protocol/jid.js +45 -10
  167. package/dist/protocol/nodes.js +6 -2
  168. package/dist/protocol/notification.js +8 -2
  169. package/dist/retry/reason.js +1 -1
  170. package/dist/signal/api/SignalDeviceSyncApi.js +5 -2
  171. package/dist/signal/api/SignalDigestSyncApi.js +8 -6
  172. package/dist/signal/api/SignalIdentitySyncApi.js +4 -4
  173. package/dist/signal/crypto/WaAdvSignature.js +2 -50
  174. package/dist/signal/crypto/constants.js +1 -5
  175. package/dist/signal/encoding.js +11 -49
  176. package/dist/signal/group/SenderKeyChain.js +2 -2
  177. package/dist/signal/group/SenderKeyCodec.js +4 -5
  178. package/dist/signal/group/SenderKeyManager.js +12 -9
  179. package/dist/signal/registration/keygen.js +1 -2
  180. package/dist/signal/registration/utils.js +2 -2
  181. package/dist/signal/session/SignalProtocol.js +18 -17
  182. package/dist/signal/session/SignalRatchet.js +19 -8
  183. package/dist/signal/session/SignalSerializer.js +5 -6
  184. package/dist/signal/session/SignalSession.js +11 -9
  185. package/dist/signal/session/resolver.js +6 -6
  186. package/dist/store/contracts/identity.store.js +2 -0
  187. package/dist/store/contracts/message-secret.store.js +2 -0
  188. package/dist/store/contracts/pre-key.store.js +2 -0
  189. package/dist/store/contracts/session.store.js +2 -0
  190. package/dist/store/createStore.js +47 -11
  191. package/dist/store/index.js +9 -1
  192. package/dist/store/locks/identity.lock.js +19 -0
  193. package/dist/store/locks/message-secret.lock.js +20 -0
  194. package/dist/store/locks/pre-key.lock.js +30 -0
  195. package/dist/store/locks/session.lock.js +22 -0
  196. package/dist/store/locks/signal.lock.js +0 -24
  197. package/dist/store/noop.store.js +21 -1
  198. package/dist/store/providers/memory/device-list.store.js +3 -0
  199. package/dist/store/providers/memory/identity.store.js +35 -0
  200. package/dist/store/providers/memory/message-secret.store.js +85 -0
  201. package/dist/store/providers/memory/participants.store.js +3 -0
  202. package/dist/store/providers/memory/pre-key.store.js +101 -0
  203. package/dist/store/providers/memory/retry.store.js +24 -10
  204. package/dist/store/providers/memory/session.store.js +49 -0
  205. package/dist/store/providers/memory/signal.store.js +1 -164
  206. package/dist/transport/WaComms.js +4 -3
  207. package/dist/transport/WaWebSocket.js +9 -1
  208. package/dist/transport/index.js +17 -1
  209. package/dist/transport/keepalive/WaKeepAlive.js +17 -8
  210. package/dist/transport/node/WaMobileTcpSocket.js +118 -0
  211. package/dist/transport/node/WaNodeOrchestrator.js +16 -7
  212. package/dist/transport/node/builders/abprops.js +23 -0
  213. package/dist/transport/node/builders/device.js +14 -0
  214. package/dist/transport/node/builders/email.js +72 -0
  215. package/dist/transport/node/builders/offline.js +17 -0
  216. package/dist/transport/node/builders/prekeys.js +36 -39
  217. package/dist/transport/node/builders/presence.js +16 -0
  218. package/dist/transport/node/builders/privacy-token.js +18 -22
  219. package/dist/transport/node/builders/retry.js +1 -1
  220. package/dist/transport/node/helpers.js +26 -0
  221. package/dist/transport/node/mex/argo-decoder.js +189 -0
  222. package/dist/transport/node/mex/client.js +86 -0
  223. package/dist/transport/node/mex/persist-ids.js +13 -0
  224. package/dist/transport/noise/WaClientPayload.js +14 -9
  225. package/dist/transport/noise/WaFrameCodec.js +1 -1
  226. package/dist/transport/noise/WaMobileClientPayload.js +56 -0
  227. package/dist/transport/noise/WaNoiseCert.js +8 -26
  228. package/dist/transport/noise/WaNoiseSession.js +11 -10
  229. package/dist/types/appstate/WaAppStateCrypto.d.ts +11 -8
  230. package/dist/types/appstate/WaAppStateSyncClient.d.ts +6 -2
  231. package/dist/types/appstate/index.d.ts +1 -1
  232. package/dist/types/appstate/{WaAppStateSyncResponseParser.d.ts → response-parser.d.ts} +1 -1
  233. package/dist/types/appstate/types.d.ts +1 -1
  234. package/dist/types/auth/WaAuthClient.d.ts +9 -3
  235. package/dist/types/auth/credentials-flow.d.ts +20 -0
  236. package/dist/types/auth/pairing/WaPairingFlow.d.ts +3 -2
  237. package/dist/types/auth/pairing/{WaPairingCodeCrypto.d.ts → pairing-code-crypto.d.ts} +6 -1
  238. package/dist/types/auth/types.d.ts +40 -0
  239. package/dist/types/client/WaClient.d.ts +19 -8
  240. package/dist/types/client/WaClientFactory.d.ts +10 -4
  241. package/dist/types/client/coordinators/WaAbPropsCoordinator.d.ts +26 -0
  242. package/dist/types/client/coordinators/WaBusinessCoordinator.d.ts +1 -1
  243. package/dist/types/client/coordinators/WaEmailCoordinator.d.ts +24 -0
  244. package/dist/types/client/coordinators/WaIncomingNodeCoordinator.d.ts +6 -1
  245. package/dist/types/client/coordinators/WaMessageDispatchCoordinator.d.ts +15 -2
  246. package/dist/types/client/coordinators/WaOfflineResumeCoordinator.d.ts +31 -0
  247. package/dist/types/client/coordinators/WaPassiveTasksCoordinator.d.ts +13 -2
  248. package/dist/types/client/coordinators/WaPrivacyCoordinator.d.ts +1 -1
  249. package/dist/types/client/coordinators/WaProfileCoordinator.d.ts +4 -2
  250. package/dist/types/client/coordinators/WaRetryCoordinator.d.ts +6 -0
  251. package/dist/types/client/coordinators/WaTrustedContactTokenCoordinator.d.ts +11 -1
  252. package/dist/types/client/dirty.d.ts +3 -1
  253. package/dist/types/client/events/abprops.d.ts +14 -0
  254. package/dist/types/client/events/registration.d.ts +17 -0
  255. package/dist/types/client/incoming.d.ts +6 -1
  256. package/dist/types/client/mailbox.d.ts +2 -0
  257. package/dist/types/client/media.d.ts +31 -0
  258. package/dist/types/client/messages.d.ts +2 -0
  259. package/dist/types/client/persistence/WriteBehindPersistence.d.ts +1 -1
  260. package/dist/types/client/types.d.ts +100 -1
  261. package/dist/types/crypto/core/index.d.ts +1 -0
  262. package/dist/types/crypto/core/primitives.d.ts +1 -1
  263. package/dist/types/crypto/core/random.d.ts +1 -1
  264. package/dist/types/crypto/core/xeddsa.d.ts +2 -0
  265. package/dist/types/crypto/curves/constants.d.ts +1 -0
  266. package/dist/types/crypto/index.d.ts +1 -0
  267. package/dist/types/index.d.ts +2 -1
  268. package/dist/types/infra/log/ConsoleLogger.d.ts +1 -1
  269. package/dist/types/infra/log/PinoLogger.d.ts +1 -1
  270. package/dist/types/infra/perf/StoreLock.d.ts +1 -0
  271. package/dist/types/media/WaMediaCrypto.d.ts +15 -6
  272. package/dist/types/media/WaMediaTransferClient.d.ts +3 -11
  273. package/dist/types/media/constants.d.ts +2 -0
  274. package/dist/types/media/index.d.ts +1 -0
  275. package/dist/types/media/processor.d.ts +28 -0
  276. package/dist/types/media/types.d.ts +9 -3
  277. package/dist/types/message/addon-crypto.d.ts +34 -3
  278. package/dist/types/message/content.d.ts +3 -1
  279. package/dist/types/message/icdc.d.ts +4 -4
  280. package/dist/types/message/types.d.ts +16 -24
  281. package/dist/types/protocol/abprops.d.ts +142 -0
  282. package/dist/types/protocol/browser.d.ts +1 -0
  283. package/dist/types/protocol/constants.d.ts +5 -1
  284. package/dist/types/protocol/email.d.ts +32 -0
  285. package/dist/types/protocol/jid.d.ts +1 -0
  286. package/dist/types/protocol/nodes.d.ts +4 -0
  287. package/dist/types/protocol/notification.d.ts +6 -0
  288. package/dist/types/protocol/stream.d.ts +1 -0
  289. package/dist/types/retry/reason.d.ts +1 -1
  290. package/dist/types/signal/api/SignalDigestSyncApi.d.ts +3 -0
  291. package/dist/types/signal/api/SignalIdentitySyncApi.d.ts +3 -3
  292. package/dist/types/signal/crypto/WaAdvSignature.d.ts +0 -2
  293. package/dist/types/signal/crypto/constants.d.ts +0 -1
  294. package/dist/types/signal/encoding.d.ts +7 -1
  295. package/dist/types/signal/group/SenderKeyChain.d.ts +1 -1
  296. package/dist/types/signal/group/SenderKeyManager.d.ts +7 -2
  297. package/dist/types/signal/registration/utils.d.ts +2 -1
  298. package/dist/types/signal/session/SignalProtocol.d.ts +11 -2
  299. package/dist/types/signal/session/SignalSerializer.d.ts +2 -1
  300. package/dist/types/signal/session/resolver.d.ts +4 -2
  301. package/dist/types/signal/types.d.ts +16 -4
  302. package/dist/types/store/contracts/identity.store.d.ts +11 -0
  303. package/dist/types/store/contracts/message-secret.store.d.ts +16 -0
  304. package/dist/types/store/contracts/pre-key.store.d.ts +13 -0
  305. package/dist/types/store/contracts/session.store.d.ts +14 -0
  306. package/dist/types/store/contracts/signal.store.d.ts +1 -34
  307. package/dist/types/store/index.d.ts +9 -1
  308. package/dist/types/store/locks/identity.lock.d.ts +3 -0
  309. package/dist/types/store/locks/message-secret.lock.d.ts +3 -0
  310. package/dist/types/store/locks/pre-key.lock.d.ts +3 -0
  311. package/dist/types/store/locks/session.lock.d.ts +3 -0
  312. package/dist/types/store/noop.store.d.ts +4 -0
  313. package/dist/types/store/providers/memory/identity.store.d.ts +18 -0
  314. package/dist/types/store/providers/memory/message-secret.store.d.ts +21 -0
  315. package/dist/types/store/providers/memory/pre-key.store.d.ts +23 -0
  316. package/dist/types/store/providers/memory/retry.store.d.ts +7 -1
  317. package/dist/types/store/providers/memory/session.store.d.ts +21 -0
  318. package/dist/types/store/providers/memory/signal.store.d.ts +3 -45
  319. package/dist/types/store/providers/memory/thread.store.d.ts +1 -1
  320. package/dist/types/store/types.d.ts +21 -1
  321. package/dist/types/transport/WaWebSocket.d.ts +1 -0
  322. package/dist/types/transport/index.d.ts +8 -1
  323. package/dist/types/transport/keepalive/WaKeepAlive.d.ts +4 -1
  324. package/dist/types/transport/node/WaMobileTcpSocket.d.ts +18 -0
  325. package/dist/types/transport/node/WaNodeOrchestrator.d.ts +6 -2
  326. package/dist/types/transport/node/builders/abprops.d.ts +5 -0
  327. package/dist/types/transport/node/builders/device.d.ts +2 -0
  328. package/dist/types/transport/node/builders/email.d.ts +11 -0
  329. package/dist/types/transport/node/builders/offline.d.ts +2 -0
  330. package/dist/types/transport/node/builders/prekeys.d.ts +4 -3
  331. package/dist/types/transport/node/builders/presence.d.ts +6 -0
  332. package/dist/types/transport/node/helpers.d.ts +3 -0
  333. package/dist/types/transport/node/mex/argo-decoder.d.ts +11 -0
  334. package/dist/types/transport/node/mex/client.d.ts +18 -0
  335. package/dist/types/transport/node/mex/persist-ids.d.ts +14 -0
  336. package/dist/types/transport/noise/WaMobileClientPayload.d.ts +29 -0
  337. package/dist/types/transport/noise/WaNoiseCert.d.ts +7 -1
  338. package/dist/types/transport/noise/WaNoiseSession.d.ts +1 -0
  339. package/dist/types/transport/types.d.ts +8 -0
  340. package/package.json +6 -4
  341. package/dist/auth/pairing/constants.js +0 -5
  342. package/dist/client/connection/WaKeyShareCoordinator.js +0 -63
  343. package/dist/esm/auth/pairing/constants.js +0 -2
  344. package/dist/esm/client/connection/WaKeyShareCoordinator.js +0 -59
  345. package/dist/esm/transport/node/builders/index.js +0 -11
  346. package/dist/transport/node/builders/index.js +0 -51
  347. package/dist/types/auth/flow/WaAuthCredentialsFlow.d.ts +0 -14
  348. package/dist/types/auth/pairing/constants.d.ts +0 -2
  349. package/dist/types/client/connection/WaKeyShareCoordinator.d.ts +0 -14
  350. package/dist/types/transport/node/builders/index.d.ts +0 -11
  351. /package/dist/appstate/{WaAppStateSyncResponseParser.js → response-parser.js} +0 -0
@@ -1,12 +1,12 @@
1
- import { APP_STATE_DEFAULT_COLLECTIONS, APP_STATE_DEFAULT_COLLECTION_VERSION, APP_STATE_EMPTY_LT_HASH } from './constants.js';
1
+ import { APP_STATE_DEFAULT_COLLECTION_VERSION, APP_STATE_DEFAULT_COLLECTIONS, APP_STATE_EMPTY_LT_HASH } from './constants.js';
2
+ import { parseSyncResponse } from './response-parser.js';
2
3
  import { WaAppStateCrypto } from './WaAppStateCrypto.js';
3
- import { parseSyncResponse } from './WaAppStateSyncResponseParser.js';
4
+ import { randomBytesAsync, randomIntAsync } from '../crypto/index.js';
4
5
  import { proto } from '../proto.js';
5
6
  import { WA_APP_STATE_COLLECTION_STATES, WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../protocol/constants.js';
6
7
  import { parseSignalAddressFromJid } from '../protocol/jid.js';
7
8
  import { assertIqResult } from '../transport/node/query.js';
8
- import { decodeProtoBytes } from '../util/bytes.js';
9
- import { bytesToHex, uint8Equal } from '../util/bytes.js';
9
+ import { bytesToHex, decodeProtoBytes, uint8Equal } from '../util/bytes.js';
10
10
  import { longToNumber } from '../util/primitives.js';
11
11
  export class WaAppStateMissingKeyError extends Error {
12
12
  constructor(message, keyId, collection) {
@@ -25,7 +25,8 @@ export class WaAppStateSyncClient {
25
25
  this.hostDomain = options.hostDomain ?? WA_DEFAULTS.HOST_DOMAIN;
26
26
  this.defaultTimeoutMs = options.defaultTimeoutMs ?? WA_DEFAULTS.APP_STATE_SYNC_TIMEOUT_MS;
27
27
  this.onMissingKeys = options.onMissingKeys;
28
- this.crypto = new WaAppStateCrypto();
28
+ this.crypto = new WaAppStateCrypto(undefined, options.skipMacVerification === true);
29
+ this.mobilePrimary = options.mobilePrimary ?? false;
29
30
  this.syncContext = null;
30
31
  this.syncPromise = null;
31
32
  }
@@ -33,6 +34,28 @@ export class WaAppStateSyncClient {
33
34
  this.logger.trace('app-state export requested');
34
35
  return this.store.exportData();
35
36
  }
37
+ async ensureInitialSyncKey() {
38
+ const existing = await this.store.getActiveSyncKey();
39
+ if (existing) {
40
+ return existing;
41
+ }
42
+ const keyIdBytes = await randomBytesAsync(2);
43
+ const keyData = await randomBytesAsync(32);
44
+ const rawId = await randomIntAsync(0, 4294967295);
45
+ const key = {
46
+ keyId: keyIdBytes,
47
+ keyData,
48
+ timestamp: Date.now(),
49
+ fingerprint: { rawId, currentIndex: 0, deviceIndexes: [0] }
50
+ };
51
+ await this.store.upsertSyncKeys([key]);
52
+ this.crypto.clearCache();
53
+ this.logger.info('app-state initial sync key generated (mobile primary)', {
54
+ keyId: bytesToHex(keyIdBytes),
55
+ rawId
56
+ });
57
+ return key;
58
+ }
36
59
  async importSyncKeys(keys) {
37
60
  this.logger.debug('app-state importing sync keys', { count: keys.length });
38
61
  const inserted = await this.store.upsertSyncKeys(keys);
@@ -283,7 +306,7 @@ export class WaAppStateSyncClient {
283
306
  content: [
284
307
  {
285
308
  tag: WA_NODE_TAGS.SYNC,
286
- attrs: {},
309
+ attrs: this.mobilePrimary ? { data_namespace: '3' } : {},
287
310
  content: collectionNodes
288
311
  }
289
312
  ]
@@ -462,11 +485,13 @@ export class WaAppStateSyncClient {
462
485
  if (!snapshot.version?.version) {
463
486
  throw new Error(`snapshot for ${collection} is missing version`);
464
487
  }
465
- if (!snapshot.mac) {
466
- throw new Error(`snapshot for ${collection} is missing mac`);
467
- }
468
- if (!snapshot.keyId?.id) {
469
- throw new Error(`snapshot for ${collection} is missing keyId`);
488
+ if (!this.crypto.isMacVerificationSkipped) {
489
+ if (!snapshot.mac) {
490
+ throw new Error(`snapshot for ${collection} is missing mac`);
491
+ }
492
+ if (!snapshot.keyId?.id) {
493
+ throw new Error(`snapshot for ${collection} is missing keyId`);
494
+ }
470
495
  }
471
496
  return snapshot;
472
497
  }
@@ -481,14 +506,16 @@ export class WaAppStateSyncClient {
481
506
  if (!patch.version?.version) {
482
507
  throw new Error(`patch for ${collection} is missing version`);
483
508
  }
484
- if (!patch.snapshotMac) {
485
- throw new Error(`patch for ${collection} is missing snapshotMac`);
486
- }
487
- if (!patch.patchMac) {
488
- throw new Error(`patch for ${collection} is missing patchMac`);
489
- }
490
- if (!patch.keyId?.id) {
491
- throw new Error(`patch for ${collection} is missing keyId`);
509
+ if (!this.crypto.isMacVerificationSkipped) {
510
+ if (!patch.snapshotMac) {
511
+ throw new Error(`patch for ${collection} is missing snapshotMac`);
512
+ }
513
+ if (!patch.patchMac) {
514
+ throw new Error(`patch for ${collection} is missing patchMac`);
515
+ }
516
+ if (!patch.keyId?.id) {
517
+ throw new Error(`patch for ${collection} is missing keyId`);
518
+ }
492
519
  }
493
520
  if (patch.mutations && patch.mutations.length > 0 && patch.externalMutations) {
494
521
  throw new Error(`patch for ${collection} has inline and external mutations together`);
@@ -502,10 +529,13 @@ export class WaAppStateSyncClient {
502
529
  }
503
530
  async applySnapshot(collection, snapshot) {
504
531
  const version = this.normalizeProtoLong(snapshot.version?.version, `snapshot.version.version (${collection})`);
505
- const keyId = decodeProtoBytes(snapshot.keyId?.id, `snapshot.keyId.id (${collection})`);
506
- const keyData = await this.getKeyData(keyId);
507
- if (!keyData) {
508
- throw new WaAppStateMissingKeyError(`missing snapshot key ${bytesToHex(keyId)} for ${collection}`, keyId, collection);
532
+ let keyData = null;
533
+ if (!this.crypto.isMacVerificationSkipped) {
534
+ const keyId = decodeProtoBytes(snapshot.keyId?.id, `snapshot.keyId.id (${collection})`);
535
+ keyData = await this.getKeyData(keyId);
536
+ if (!keyData) {
537
+ throw new WaAppStateMissingKeyError(`missing snapshot key ${bytesToHex(keyId)} for ${collection}`, keyId, collection);
538
+ }
509
539
  }
510
540
  const indexValueMap = new Map();
511
541
  const mutations = [];
@@ -533,9 +563,11 @@ export class WaAppStateSyncClient {
533
563
  ltHashInputIndex += 1;
534
564
  }
535
565
  const ltHash = await this.crypto.ltHashAdd(APP_STATE_EMPTY_LT_HASH, ltHashInput);
536
- const expectedSnapshotMac = await this.crypto.generateSnapshotMac(keyData, ltHash, version, collection);
537
- if (!uint8Equal(expectedSnapshotMac, snapshot.mac)) {
538
- throw new Error(`snapshot MAC mismatch for ${collection}`);
566
+ if (keyData !== null) {
567
+ const expectedSnapshotMac = await this.crypto.generateSnapshotMac(keyData, ltHash, version, collection);
568
+ if (!uint8Equal(expectedSnapshotMac, snapshot.mac)) {
569
+ throw new Error(`snapshot MAC mismatch for ${collection}`);
570
+ }
539
571
  }
540
572
  this.setCollectionState(collection, version, ltHash, indexValueMap);
541
573
  return mutations;
@@ -546,10 +578,13 @@ export class WaAppStateSyncClient {
546
578
  if (current.version !== patchVersion - 1) {
547
579
  throw new Error(`patch version mismatch for ${collection}: local=${current.version}, incoming=${patchVersion}`);
548
580
  }
549
- const patchKeyId = decodeProtoBytes(patch.keyId?.id, `patch.keyId.id (${collection})`);
550
- const patchKeyData = await this.getKeyData(patchKeyId);
551
- if (!patchKeyData) {
552
- throw new WaAppStateMissingKeyError(`missing patch key ${bytesToHex(patchKeyId)} for ${collection}`, patchKeyId, collection);
581
+ let patchKeyData = null;
582
+ if (!this.crypto.isMacVerificationSkipped) {
583
+ const patchKeyId = decodeProtoBytes(patch.keyId?.id, `patch.keyId.id (${collection})`);
584
+ patchKeyData = await this.getKeyData(patchKeyId);
585
+ if (!patchKeyData) {
586
+ throw new WaAppStateMissingKeyError(`missing patch key ${bytesToHex(patchKeyId)} for ${collection}`, patchKeyId, collection);
587
+ }
553
588
  }
554
589
  const decryptedMutations = await this.decryptPatchMutations(collection, patch);
555
590
  const macMutations = new Array(decryptedMutations.length);
@@ -564,7 +599,9 @@ export class WaAppStateSyncClient {
564
599
  };
565
600
  }
566
601
  const nextState = await this.computeNextCollectionState(current.hash, current.indexValueMap, macMutations, collection);
567
- await this.assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextState.hash, valueMacs);
602
+ if (patchKeyData !== null) {
603
+ await this.assertPatchMacsMatch(patch, collection, patchKeyData, patchVersion, nextState.hash, valueMacs);
604
+ }
568
605
  this.setCollectionState(collection, patchVersion, nextState.hash, nextState.indexValueMap);
569
606
  return decryptedMutations;
570
607
  }
@@ -2,5 +2,5 @@ export * from './constants.js';
2
2
  export { encodeAppStateFingerprint, decodeAppStateFingerprint, decodeAppStateCollections, decodeAppStateSyncKeys } from './encoding.js';
3
3
  export * from './utils.js';
4
4
  export { WaAppStateCrypto } from './WaAppStateCrypto.js';
5
- export { parseSyncResponse } from './WaAppStateSyncResponseParser.js';
5
+ export { parseSyncResponse } from './response-parser.js';
6
6
  export { WaAppStateSyncClient } from './WaAppStateSyncClient.js';
@@ -1,7 +1,7 @@
1
1
  import { parseCollectionName } from './utils.js';
2
2
  import { proto } from '../proto.js';
3
3
  import { WA_APP_STATE_COLLECTION_STATES, WA_APP_STATE_ERROR_CODES, WA_IQ_TYPES, WA_NODE_TAGS } from '../protocol/constants.js';
4
- import { decodeNodeContentBase64OrBytes, findNodeChildrenByTags, findNodeChild, getNodeChildrenByTag } from '../transport/node/helpers.js';
4
+ import { decodeNodeContentBase64OrBytes, findNodeChild, findNodeChildrenByTags, getNodeChildrenByTag } from '../transport/node/helpers.js';
5
5
  export function parseSyncResponse(iqNode) {
6
6
  if (iqNode.tag !== WA_NODE_TAGS.IQ) {
7
7
  throw new Error(`invalid sync response tag ${iqNode.tag}`);
@@ -1,4 +1,4 @@
1
- import { buildCommsConfig, loadOrCreateCredentials, persistCredentials } from './flow/WaAuthCredentialsFlow.js';
1
+ import { buildCommsConfig, loadOrCreateCredentials, persistCredentials } from './credentials-flow.js';
2
2
  import { WaPairingFlow } from './pairing/WaPairingFlow.js';
3
3
  import { WaQrFlow } from './pairing/WaQrFlow.js';
4
4
  import { getWaCompanionPlatformId, WA_DEFAULTS } from '../protocol/constants.js';
@@ -24,6 +24,7 @@ export class WaAuthClient {
24
24
  this.callbacks = deps.callbacks ?? {};
25
25
  this.authStore = deps.authStore;
26
26
  this.signalStore = deps.signalStore;
27
+ this.preKeyStore = deps.preKeyStore;
27
28
  this.credentials = null;
28
29
  this.qrFlow = new WaQrFlow({
29
30
  logger: this.logger,
@@ -44,7 +45,8 @@ export class WaAuthClient {
44
45
  emitPairingCode: (code) => this.callbacks.onPairingCode?.(code),
45
46
  emitPairingRefresh: (forceManual) => this.callbacks.onPairingRefresh?.(forceManual),
46
47
  emitPaired: (credentials) => this.callbacks.onPaired?.(credentials)
47
- }
48
+ },
49
+ dangerous: options.dangerous
48
50
  });
49
51
  }
50
52
  getState(connected = false) {
@@ -64,7 +66,9 @@ export class WaAuthClient {
64
66
  this.credentials = await loadOrCreateCredentials({
65
67
  logger: this.logger,
66
68
  authStore: this.authStore,
67
- signalStore: this.signalStore
69
+ signalStore: this.signalStore,
70
+ preKeyStore: this.preKeyStore,
71
+ skipSignedPreKeySignatureVerification: this.options.dangerous?.disableSignedPreKeySignatureVerification
68
72
  });
69
73
  this.logger.info('auth client credentials ready', {
70
74
  registered: this.credentials?.meJid !== null && this.credentials?.meJid !== undefined
@@ -72,13 +76,17 @@ export class WaAuthClient {
72
76
  return this.credentials;
73
77
  });
74
78
  }
75
- buildCommsConfig(socketOptions) {
79
+ buildCommsConfig(socketOptions, overrides = {}) {
76
80
  this.logger.trace('auth client building comms config');
77
81
  return buildCommsConfig(this.logger, this.requireCredentials(), socketOptions, {
78
82
  deviceBrowser: this.options.deviceBrowser,
79
83
  deviceOsDisplayName: this.options.deviceOsDisplayName,
80
84
  requireFullSync: this.options.requireFullSync,
81
- version: this.options.version
85
+ version: this.options.version,
86
+ mobileTransport: this.options.mobileTransport,
87
+ noiseTrustedRootCa: overrides.noiseTrustedRootCa,
88
+ disableNoiseCertificateChainVerification: overrides.disableNoiseCertificateChainVerification ??
89
+ this.options.dangerous?.disableNoiseCertificateChainVerification
82
90
  });
83
91
  }
84
92
  async clearTransientState() {
@@ -177,10 +185,10 @@ export class WaAuthClient {
177
185
  }
178
186
  });
179
187
  }
180
- async requestPairingCode(phoneNumber, shouldShowPushNotification = false) {
188
+ async requestPairingCode(phoneNumber, shouldShowPushNotification = false, customCode) {
181
189
  this.requireCredentials();
182
190
  this.logger.info('auth client requesting pairing code');
183
- return this.runHandled(() => this.pairingFlow.requestPairingCode(phoneNumber, shouldShowPushNotification));
191
+ return this.runHandled(() => this.pairingFlow.requestPairingCode(phoneNumber, shouldShowPushNotification, customCode));
184
192
  }
185
193
  async fetchPairingCountryCodeIso() {
186
194
  this.requireCredentials();
@@ -228,7 +236,8 @@ export class WaAuthClient {
228
236
  await persistCredentials({
229
237
  logger: this.logger,
230
238
  authStore: this.authStore,
231
- signalStore: this.signalStore
239
+ signalStore: this.signalStore,
240
+ preKeyStore: this.preKeyStore
232
241
  }, credentials);
233
242
  }
234
243
  requireCredentials() {
@@ -1,11 +1,12 @@
1
- import { randomBytesAsync } from '../../crypto/index.js';
2
- import { toSerializedPubKey } from '../../crypto/core/keys.js';
3
- import { X25519 } from '../../crypto/curves/X25519.js';
4
- import { getLoginIdentity } from '../../protocol/jid.js';
5
- import { verifySignalSignature } from '../../signal/crypto/WaAdvSignature.js';
6
- import { createAndStoreInitialKeys } from '../../signal/registration/utils.js';
7
- import { toProxyAgent, toProxyDispatcher } from '../../transport/proxy.js';
8
- import { toError } from '../../util/primitives.js';
1
+ import { randomBytesAsync, toRawPubKey, xeddsaVerify } from '../crypto/index.js';
2
+ import { toSerializedPubKey } from '../crypto/core/keys.js';
3
+ import { X25519 } from '../crypto/curves/X25519.js';
4
+ import { getLoginIdentity } from '../protocol/jid.js';
5
+ import { createAndStoreInitialKeys } from '../signal/registration/utils.js';
6
+ import { WaMobileTcpSocketCtor } from '../transport/node/WaMobileTcpSocket.js';
7
+ import { buildMobileLoginPayload } from '../transport/noise/WaMobileClientPayload.js';
8
+ import { toProxyAgent, toProxyDispatcher } from '../transport/proxy.js';
9
+ import { toError } from '../util/primitives.js';
9
10
  export async function loadOrCreateCredentials(args) {
10
11
  args.logger.trace('auth credentials loadOrCreate start');
11
12
  const existing = await args.authStore.load();
@@ -18,13 +19,16 @@ export async function loadOrCreateCredentials(args) {
18
19
  registered: existing.meJid !== null && existing.meJid !== undefined,
19
20
  hasServerStaticKey: existing.serverStaticKey !== null && existing.serverStaticKey !== undefined
20
21
  });
21
- if (!existing.meJid && !(await hasValidSignedPreKey(args.logger, existing))) {
22
+ const skipSignedPreKeyCheck = args.skipSignedPreKeySignatureVerification === true;
23
+ if (!existing.meJid &&
24
+ !skipSignedPreKeyCheck &&
25
+ !(await hasValidSignedPreKey(args.logger, existing))) {
22
26
  args.logger.warn('signed pre-key is invalid, regenerating credentials');
23
27
  const fresh = await createFreshAndPersistCredentials(args);
24
28
  args.logger.info('regenerated credentials due to invalid signed pre-key');
25
29
  return fresh;
26
30
  }
27
- await restoreSignalStore(args.signalStore, existing);
31
+ await restoreSignalStore(args.signalStore, args.preKeyStore, existing);
28
32
  args.logger.trace('auth credentials restored into signal store');
29
33
  return existing;
30
34
  }
@@ -34,15 +38,72 @@ export async function persistCredentials(args, credentials) {
34
38
  });
35
39
  await args.authStore.save(credentials);
36
40
  }
41
+ function mobileTransportFromCredentials(credentials) {
42
+ if (!credentials.deviceInfo)
43
+ return undefined;
44
+ return {
45
+ deviceInfo: credentials.deviceInfo,
46
+ ...(credentials.pushName !== undefined ? { pushName: credentials.pushName } : {}),
47
+ ...(credentials.yearClass !== undefined ? { yearClass: credentials.yearClass } : {}),
48
+ ...(credentials.memClass !== undefined ? { memClass: credentials.memClass } : {})
49
+ };
50
+ }
37
51
  export function buildCommsConfig(logger, credentials, socketOptions, clientOptions) {
38
52
  const meJid = credentials.meJid;
39
53
  const registered = meJid !== null && meJid !== undefined;
40
54
  const loginIdentity = registered ? getLoginIdentity(meJid) : null;
41
55
  const wsProxy = socketOptions.proxy?.ws;
56
+ // Resolve the effective mobile transport: explicit option wins, otherwise
57
+ // synthesize one from persisted credentials.deviceInfo so a registered
58
+ // mobile session boots in mobile mode without the caller re-passing
59
+ // deviceInfo on every `new WaClient(...)` call.
60
+ const effectiveMobileTransport = clientOptions.mobileTransport ?? mobileTransportFromCredentials(credentials);
42
61
  logger.debug('building comms config from credentials', {
43
62
  registered,
44
- hasServerStaticKey: credentials.serverStaticKey !== null && credentials.serverStaticKey !== undefined
63
+ hasServerStaticKey: credentials.serverStaticKey !== null && credentials.serverStaticKey !== undefined,
64
+ mobile: Boolean(effectiveMobileTransport),
65
+ mobileSource: clientOptions.mobileTransport
66
+ ? 'option'
67
+ : effectiveMobileTransport
68
+ ? 'credentials'
69
+ : 'none'
45
70
  });
71
+ if (effectiveMobileTransport) {
72
+ if (wsProxy) {
73
+ throw new Error('mobileTransport does not support socketOptions.proxy.ws — remove the proxy option or open an issue to add TCP proxy support');
74
+ }
75
+ if (!loginIdentity) {
76
+ throw new Error('mobileTransport requires registered credentials (meJid) — run the mobile bridge flow first');
77
+ }
78
+ const loginPayload = buildMobileLoginPayload({
79
+ username: loginIdentity.username,
80
+ device: loginIdentity.device,
81
+ passive: effectiveMobileTransport.passive ?? false,
82
+ deviceInfo: effectiveMobileTransport.deviceInfo,
83
+ pushName: effectiveMobileTransport.pushName,
84
+ yearClass: effectiveMobileTransport.yearClass,
85
+ memClass: effectiveMobileTransport.memClass
86
+ });
87
+ return {
88
+ url: effectiveMobileTransport.tcpUrl ?? 'tcp://g.whatsapp.net:443',
89
+ rawWebSocketConstructor: WaMobileTcpSocketCtor,
90
+ connectTimeoutMs: socketOptions.connectTimeoutMs,
91
+ reconnectIntervalMs: socketOptions.reconnectIntervalMs,
92
+ timeoutIntervalMs: socketOptions.timeoutIntervalMs,
93
+ maxReconnectAttempts: socketOptions.maxReconnectAttempts,
94
+ noise: {
95
+ clientStaticKeyPair: credentials.noiseKeyPair,
96
+ isRegistered: true,
97
+ serverStaticKey: credentials.serverStaticKey,
98
+ routingInfo: credentials.routingInfo,
99
+ trustedRootCa: clientOptions.noiseTrustedRootCa,
100
+ verifyCertificateChain: clientOptions.disableNoiseCertificateChainVerification
101
+ ? false
102
+ : undefined,
103
+ loginPayload
104
+ }
105
+ };
106
+ }
46
107
  return {
47
108
  url: socketOptions.url,
48
109
  urls: socketOptions.urls,
@@ -58,6 +119,10 @@ export function buildCommsConfig(logger, credentials, socketOptions, clientOptio
58
119
  isRegistered: registered,
59
120
  serverStaticKey: credentials.serverStaticKey,
60
121
  routingInfo: credentials.routingInfo,
122
+ trustedRootCa: clientOptions.noiseTrustedRootCa,
123
+ verifyCertificateChain: clientOptions.disableNoiseCertificateChainVerification
124
+ ? false
125
+ : undefined,
61
126
  loginPayloadConfig: loginIdentity
62
127
  ? {
63
128
  username: loginIdentity.username,
@@ -80,11 +145,11 @@ export function buildCommsConfig(logger, credentials, socketOptions, clientOptio
80
145
  }
81
146
  };
82
147
  }
83
- async function createFreshCredentials(signalStore, logger) {
148
+ async function createFreshCredentials(signalStore, preKeyStore, logger) {
84
149
  logger.trace('creating fresh credentials');
85
150
  const [noiseKeyPair, registrationBundle, advSecretKey] = await Promise.all([
86
151
  X25519.generateKeyPair(),
87
- createAndStoreInitialKeys(signalStore),
152
+ createAndStoreInitialKeys(signalStore, preKeyStore),
88
153
  randomBytesAsync(32)
89
154
  ]);
90
155
  return {
@@ -96,16 +161,16 @@ async function createFreshCredentials(signalStore, logger) {
96
161
  };
97
162
  }
98
163
  async function createFreshAndPersistCredentials(args) {
99
- const credentials = await createFreshCredentials(args.signalStore, args.logger);
164
+ const credentials = await createFreshCredentials(args.signalStore, args.preKeyStore, args.logger);
100
165
  // Persist credentials first so signal restore never commits state for credentials that failed to save.
101
166
  await args.authStore.save(credentials);
102
- await restoreSignalStore(args.signalStore, credentials);
167
+ await restoreSignalStore(args.signalStore, args.preKeyStore, credentials);
103
168
  return credentials;
104
169
  }
105
170
  async function hasValidSignedPreKey(logger, credentials) {
106
171
  try {
107
172
  const serializedPubKey = toSerializedPubKey(credentials.signedPreKey.keyPair.pubKey);
108
- const valid = await verifySignalSignature(credentials.registrationInfo.identityKeyPair.pubKey, serializedPubKey, credentials.signedPreKey.signature);
173
+ const valid = await xeddsaVerify(toRawPubKey(credentials.registrationInfo.identityKeyPair.pubKey), serializedPubKey, credentials.signedPreKey.signature);
109
174
  logger.trace('signed pre-key validation completed', { valid });
110
175
  return valid;
111
176
  }
@@ -116,10 +181,10 @@ async function hasValidSignedPreKey(logger, credentials) {
116
181
  return false;
117
182
  }
118
183
  }
119
- async function restoreSignalStore(signalStore, credentials) {
184
+ async function restoreSignalStore(signalStore, preKeyStore, credentials) {
120
185
  await Promise.all([
121
186
  signalStore.setRegistrationInfo(credentials.registrationInfo),
122
187
  signalStore.setSignedPreKey(credentials.signedPreKey),
123
- signalStore.setServerHasPreKeys(credentials.serverHasPreKeys === true)
188
+ preKeyStore.setServerHasPreKeys(credentials.serverHasPreKeys === true)
124
189
  ]);
125
190
  }
@@ -1,14 +1,14 @@
1
- import { completeCompanionFinish, createCompanionHello } from '../pairing/WaPairingCodeCrypto.js';
1
+ import { completeCompanionFinish, createCompanionHello, normalizeCustomPairingCode } from '../pairing/pairing-code-crypto.js';
2
2
  import { randomBytesAsync } from '../../crypto/index.js';
3
3
  import { proto } from '../../proto.js';
4
+ import { getWaBrowserDisplayName } from '../../protocol/browser.js';
4
5
  import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_SIGNALING } from '../../protocol/constants.js';
5
6
  import { parsePhoneJid } from '../../protocol/jid.js';
6
7
  import { ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, computeAdvIdentityHmac, generateDeviceSignature, verifyDeviceIdentityAccountSignature } from '../../signal/crypto/WaAdvSignature.js';
7
8
  import { buildAckNode, buildIqResultNode } from '../../transport/node/builders/global.js';
8
9
  import { buildCompanionFinishRequestNode, buildCompanionHelloRequestNode, buildGetCountryCodeRequestNode } from '../../transport/node/builders/pairing.js';
9
- import { decodeNodeContentUtf8OrBytes, findNodeChildrenByTags, findNodeChild, getFirstNodeChild, getNodeChildrenNonEmptyUtf8ByTag, hasNodeChild } from '../../transport/node/helpers.js';
10
- import { decodeProtoBytes } from '../../util/bytes.js';
11
- import { concatBytes, uint8Equal } from '../../util/bytes.js';
10
+ import { decodeNodeContentUtf8OrBytes, findNodeChild, findNodeChildrenByTags, getFirstNodeChild, getNodeChildrenNonEmptyUtf8ByTag, hasNodeChild } from '../../transport/node/helpers.js';
11
+ import { concatBytes, decodeProtoBytes, uint8Equal } from '../../util/bytes.js';
12
12
  export class WaPairingFlow {
13
13
  constructor(options) {
14
14
  this.opts = options;
@@ -21,26 +21,19 @@ export class WaPairingFlow {
21
21
  this.opts.logger.trace('pairing flow session cleared');
22
22
  this.pairingSession = null;
23
23
  }
24
- async requestPairingCode(phoneNumber, shouldShowPushNotification = false) {
24
+ async requestPairingCode(phoneNumber, shouldShowPushNotification = false, customCode) {
25
25
  this.opts.logger.info('requesting pairing code', {
26
- shouldShowPushNotification
26
+ shouldShowPushNotification,
27
+ hasCustomCode: customCode !== undefined
27
28
  });
29
+ const normalizedCustomCode = customCode !== undefined ? normalizeCustomPairingCode(customCode) : undefined;
28
30
  const credentials = this.requireCredentials();
29
31
  const phoneJid = parsePhoneJid(phoneNumber);
30
32
  const [companionHello, refreshedCredentials] = await Promise.all([
31
- createCompanionHello(),
33
+ createCompanionHello({ customCode: normalizedCustomCode }),
32
34
  this.rotateAdvSecret(credentials)
33
35
  ]);
34
- const browser = this.opts.device.browser;
35
- const browserDisplayName = {
36
- chrome: 'Chrome',
37
- firefox: 'Firefox',
38
- ie: 'IE',
39
- opera: 'Opera',
40
- safari: 'Safari',
41
- edge: 'Edge',
42
- chromium: 'Chromium'
43
- }[browser.trim().toLowerCase()] ?? browser;
36
+ const browserDisplayName = getWaBrowserDisplayName(this.opts.device.browser);
44
37
  const response = await this.opts.socket.query(buildCompanionHelloRequestNode({
45
38
  phoneJid,
46
39
  shouldShowPushNotification,
@@ -186,13 +179,15 @@ export class WaPairingFlow {
186
179
  const wrappedHmac = decodeProtoBytes(wrappedIdentity.hmac, 'ADVSignedDeviceIdentityHMAC.hmac');
187
180
  const accountType = wrappedIdentity.accountType ?? proto.ADVEncryptionType.E2EE;
188
181
  const isHosted = accountType === proto.ADVEncryptionType.HOSTED;
189
- const hmacInput = isHosted
190
- ? concatBytes([ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, wrappedDetails])
191
- : wrappedDetails;
192
- const expectedHmac = await computeAdvIdentityHmac(credentials.advSecretKey, hmacInput);
193
- if (!uint8Equal(expectedHmac, wrappedHmac)) {
194
- this.opts.logger.error('pair-success hmac mismatch');
195
- throw new Error('pair-success HMAC validation failed');
182
+ if (this.opts.dangerous?.disablePairSuccessHmacVerification !== true) {
183
+ const hmacInput = isHosted
184
+ ? concatBytes([ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, wrappedDetails])
185
+ : wrappedDetails;
186
+ const expectedHmac = await computeAdvIdentityHmac(credentials.advSecretKey, hmacInput);
187
+ if (!uint8Equal(expectedHmac, wrappedHmac)) {
188
+ this.opts.logger.error('pair-success hmac mismatch');
189
+ throw new Error('pair-success HMAC validation failed');
190
+ }
196
191
  }
197
192
  const { signedIdentity, keyIndex, responseIdentityBytes } = await this.buildPairSuccessResponseIdentity(credentials, wrappedDetails, isHosted);
198
193
  const nextCredentials = {
@@ -241,10 +236,12 @@ export class WaPairingFlow {
241
236
  const accountSignature = decodeProtoBytes(signedIdentity.accountSignature, 'ADVSignedDeviceIdentity.accountSignature');
242
237
  const accountSignatureKey = decodeProtoBytes(signedIdentity.accountSignatureKey, 'ADVSignedDeviceIdentity.accountSignatureKey');
243
238
  const localIdentity = credentials.registrationInfo.identityKeyPair;
244
- const validAccountSignature = await verifyDeviceIdentityAccountSignature(details, accountSignature, localIdentity.pubKey, accountSignatureKey, isHosted);
245
- if (!validAccountSignature) {
246
- this.opts.logger.error('pair-success account signature invalid');
247
- throw new Error('pair-success account signature validation failed');
239
+ if (this.opts.dangerous?.disableAdvSignatureVerification !== true) {
240
+ const validAccountSignature = await verifyDeviceIdentityAccountSignature(details, accountSignature, localIdentity.pubKey, accountSignatureKey, isHosted);
241
+ if (!validAccountSignature) {
242
+ this.opts.logger.error('pair-success account signature invalid');
243
+ throw new Error('pair-success account signature validation failed');
244
+ }
248
245
  }
249
246
  signedIdentity.deviceSignature = await generateDeviceSignature(details, localIdentity, accountSignatureKey, isHosted);
250
247
  const advDeviceIdentity = proto.ADVDeviceIdentity.decode(details);
@@ -1,8 +1,9 @@
1
- import { CROCKFORD_ALPHABET, PBKDF2_ITERATIONS } from '../pairing/constants.js';
2
1
  import { aesCtrDecrypt, aesCtrEncrypt, aesGcmEncrypt, hkdf, importAesGcmKey, pbkdf2DeriveAesCtrKey, randomBytesAsync } from '../../crypto/index.js';
3
2
  import { X25519 } from '../../crypto/curves/X25519.js';
4
3
  import { WA_PAIRING_KDF_INFO } from '../../protocol/constants.js';
5
4
  import { concatBytes, TEXT_ENCODER } from '../../util/bytes.js';
5
+ export const CROCKFORD_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTVWXYZ';
6
+ export const PBKDF2_ITERATIONS = 2 << 16;
6
7
  function bytesToCrockford(bytes) {
7
8
  let bitCount = 0;
8
9
  let value = 0;
@@ -20,14 +21,27 @@ function bytesToCrockford(bytes) {
20
21
  }
21
22
  return out;
22
23
  }
23
- export async function createCompanionHello() {
24
- const [codeBytes, companionEphemeralKeyPair, salt, counter] = await Promise.all([
25
- randomBytesAsync(5),
24
+ export function normalizeCustomPairingCode(input) {
25
+ const stripped = input.replace(/-/g, '').toUpperCase();
26
+ if (stripped.length !== 8) {
27
+ throw new Error(`custom pairing code must be 8 characters, got ${stripped.length}`);
28
+ }
29
+ for (let i = 0; i < stripped.length; i += 1) {
30
+ if (CROCKFORD_ALPHABET.indexOf(stripped[i]) < 0) {
31
+ throw new Error(`custom pairing code contains invalid character "${stripped[i]}" (allowed: ${CROCKFORD_ALPHABET})`);
32
+ }
33
+ }
34
+ return stripped;
35
+ }
36
+ export async function createCompanionHello(options = {}) {
37
+ const normalizedCustomCode = options.customCode !== undefined ? normalizeCustomPairingCode(options.customCode) : null;
38
+ const [companionEphemeralKeyPair, salt, counter, codeBytes] = await Promise.all([
26
39
  X25519.generateKeyPair(),
27
40
  randomBytesAsync(32),
28
- randomBytesAsync(16)
41
+ randomBytesAsync(16),
42
+ normalizedCustomCode !== null ? Promise.resolve(null) : randomBytesAsync(5)
29
43
  ]);
30
- const pairingCode = bytesToCrockford(codeBytes);
44
+ const pairingCode = normalizedCustomCode ?? bytesToCrockford(codeBytes);
31
45
  const cipher = await pbkdf2DeriveAesCtrKey(TEXT_ENCODER.encode(pairingCode), salt, PBKDF2_ITERATIONS);
32
46
  const encrypted = await aesCtrEncrypt(cipher, counter, companionEphemeralKeyPair.pubKey);
33
47
  return {