@nerxa/socketon 0.0.0-stage → 1.21.1

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 (289) hide show
  1. package/EXPERIMENTAL.md +350 -0
  2. package/LICENSE +24 -0
  3. package/README.md +6317 -2
  4. package/WAProto/index.d.ts +17301 -0
  5. package/WAProto/index.js +125088 -0
  6. package/engine-requirements.js +14 -0
  7. package/package.json +125 -4
  8. package/src/Defaults/index.d.ts +152 -0
  9. package/src/Defaults/index.js +164 -0
  10. package/src/MessageBuilder/bot-signature.d.ts +22 -0
  11. package/src/MessageBuilder/bot-signature.js +122 -0
  12. package/src/MessageBuilder/extras.d.ts +449 -0
  13. package/src/MessageBuilder/extras.js +1356 -0
  14. package/src/MessageBuilder/index.d.ts +210 -0
  15. package/src/MessageBuilder/index.js +3594 -0
  16. package/src/MessageBuilder/metaai.d.ts +438 -0
  17. package/src/MessageBuilder/metaai.js +890 -0
  18. package/src/Signal/Group/ciphertext-message.d.ts +9 -0
  19. package/src/Signal/Group/ciphertext-message.js +11 -0
  20. package/src/Signal/Group/group-session-builder.d.ts +7 -0
  21. package/src/Signal/Group/group-session-builder.js +27 -0
  22. package/src/Signal/Group/group_cipher.d.ts +11 -0
  23. package/src/Signal/Group/group_cipher.js +78 -0
  24. package/src/Signal/Group/index.d.ts +11 -0
  25. package/src/Signal/Group/index.js +11 -0
  26. package/src/Signal/Group/keyhelper.d.ts +6 -0
  27. package/src/Signal/Group/keyhelper.js +17 -0
  28. package/src/Signal/Group/sender-chain-key.d.ts +13 -0
  29. package/src/Signal/Group/sender-chain-key.js +25 -0
  30. package/src/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  31. package/src/Signal/Group/sender-key-distribution-message.js +62 -0
  32. package/src/Signal/Group/sender-key-message.d.ts +18 -0
  33. package/src/Signal/Group/sender-key-message.js +65 -0
  34. package/src/Signal/Group/sender-key-name.d.ts +11 -0
  35. package/src/Signal/Group/sender-key-name.js +47 -0
  36. package/src/Signal/Group/sender-key-record.d.ts +12 -0
  37. package/src/Signal/Group/sender-key-record.js +40 -0
  38. package/src/Signal/Group/sender-key-state.d.ts +16 -0
  39. package/src/Signal/Group/sender-key-state.js +83 -0
  40. package/src/Signal/Group/sender-message-key.d.ts +11 -0
  41. package/src/Signal/Group/sender-message-key.js +25 -0
  42. package/src/Signal/libsignal.d.ts +54 -0
  43. package/src/Signal/libsignal.js +427 -0
  44. package/src/Signal/lid-mapping.d.ts +20 -0
  45. package/src/Signal/lid-mapping.js +274 -0
  46. package/src/Socket/Client/index.d.ts +2 -0
  47. package/src/Socket/Client/index.js +3 -0
  48. package/src/Socket/Client/tcp.js +177 -0
  49. package/src/Socket/Client/types.d.ts +5 -0
  50. package/src/Socket/Client/types.js +9 -0
  51. package/src/Socket/Client/websocket.d.ts +12 -0
  52. package/src/Socket/Client/websocket.js +53 -0
  53. package/src/Socket/business.d.ts +431 -0
  54. package/src/Socket/business.js +379 -0
  55. package/src/Socket/chats.d.ts +247 -0
  56. package/src/Socket/chats.js +1484 -0
  57. package/src/Socket/communities.d.ts +598 -0
  58. package/src/Socket/communities.js +421 -0
  59. package/src/Socket/email.js +145 -0
  60. package/src/Socket/groups.d.ts +298 -0
  61. package/src/Socket/groups.js +339 -0
  62. package/src/Socket/index.d.ts +581 -0
  63. package/src/Socket/index.js +77 -0
  64. package/src/Socket/messages-recv.d.ts +370 -0
  65. package/src/Socket/messages-recv.js +1864 -0
  66. package/src/Socket/messages-send.d.ts +390 -0
  67. package/src/Socket/messages-send.js +1574 -0
  68. package/src/Socket/mex.d.ts +1 -0
  69. package/src/Socket/mex.js +44 -0
  70. package/src/Socket/mobile-builders.js +72 -0
  71. package/src/Socket/mobile.js +424 -0
  72. package/src/Socket/newsletter.d.ts +468 -0
  73. package/src/Socket/newsletter.js +671 -0
  74. package/src/Socket/socket.d.ts +77 -0
  75. package/src/Socket/socket.js +1106 -0
  76. package/src/Store/index.d.ts +3 -0
  77. package/src/Store/index.js +3 -0
  78. package/src/Store/make-in-memory-store.d.ts +62 -0
  79. package/src/Store/make-in-memory-store.js +396 -0
  80. package/src/Store/make-ordered-dictionary.d.ts +12 -0
  81. package/src/Store/make-ordered-dictionary.js +78 -0
  82. package/src/Store/object-repository.d.ts +10 -0
  83. package/src/Store/object-repository.js +23 -0
  84. package/src/Types/Auth.d.ts +1 -0
  85. package/src/Types/Auth.js +1 -0
  86. package/src/Types/Bussines.d.ts +1 -0
  87. package/src/Types/Bussines.js +1 -0
  88. package/src/Types/Call.d.ts +1 -0
  89. package/src/Types/Call.js +1 -0
  90. package/src/Types/Chat.d.ts +2 -0
  91. package/src/Types/Chat.js +24 -0
  92. package/src/Types/Contact.d.ts +1 -0
  93. package/src/Types/Contact.js +1 -0
  94. package/src/Types/Events.d.ts +1 -0
  95. package/src/Types/Events.js +0 -0
  96. package/src/Types/GroupMetadata.d.ts +5 -0
  97. package/src/Types/GroupMetadata.js +6 -0
  98. package/src/Types/Label.d.ts +2 -0
  99. package/src/Types/Label.js +24 -0
  100. package/src/Types/LabelAssociation.d.ts +2 -0
  101. package/src/Types/LabelAssociation.js +6 -0
  102. package/src/Types/Message.d.ts +13 -0
  103. package/src/Types/Message.js +23 -0
  104. package/src/Types/Mex.d.ts +2 -0
  105. package/src/Types/Mex.js +95 -0
  106. package/src/Types/Product.d.ts +1 -0
  107. package/src/Types/Product.js +1 -0
  108. package/src/Types/Signal.d.ts +1 -0
  109. package/src/Types/Signal.js +0 -0
  110. package/src/Types/Socket.d.ts +1 -0
  111. package/src/Types/Socket.js +0 -0
  112. package/src/Types/State.d.ts +5 -0
  113. package/src/Types/State.js +54 -0
  114. package/src/Types/USync.d.ts +1 -0
  115. package/src/Types/USync.js +0 -0
  116. package/src/Types/index.d.ts +13 -0
  117. package/src/Types/index.js +25 -0
  118. package/src/Utils/auth-store.d.ts +29 -0
  119. package/src/Utils/auth-store.js +76 -0
  120. package/src/Utils/auth-utils.d.ts +58 -0
  121. package/src/Utils/auth-utils.js +273 -0
  122. package/src/Utils/browser-utils.d.ts +9 -0
  123. package/src/Utils/browser-utils.js +28 -0
  124. package/src/Utils/business.d.ts +49 -0
  125. package/src/Utils/business.js +226 -0
  126. package/src/Utils/chat-utils.d.ts +408 -0
  127. package/src/Utils/chat-utils.js +846 -0
  128. package/src/Utils/companion-reg-client-utils.d.ts +4 -0
  129. package/src/Utils/companion-reg-client-utils.js +39 -0
  130. package/src/Utils/crypto.d.ts +39 -0
  131. package/src/Utils/crypto.js +110 -0
  132. package/src/Utils/decode-wa-message.d.ts +99 -0
  133. package/src/Utils/decode-wa-message.js +373 -0
  134. package/src/Utils/event-buffer.d.ts +22 -0
  135. package/src/Utils/event-buffer.js +624 -0
  136. package/src/Utils/generics.d.ts +63 -0
  137. package/src/Utils/generics.js +375 -0
  138. package/src/Utils/group-metadata-cache.d.ts +4 -0
  139. package/src/Utils/group-metadata-cache.js +25 -0
  140. package/src/Utils/history.d.ts +75 -0
  141. package/src/Utils/history.js +131 -0
  142. package/src/Utils/html-app.d.ts +19 -0
  143. package/src/Utils/html-app.js +96 -0
  144. package/src/Utils/html-multiplayer.d.ts +10 -0
  145. package/src/Utils/html-multiplayer.js +94 -0
  146. package/src/Utils/identity-change-handler.d.ts +13 -0
  147. package/src/Utils/identity-change-handler.js +48 -0
  148. package/src/Utils/index.d.ts +44 -0
  149. package/src/Utils/index.js +44 -0
  150. package/src/Utils/link-preview-metadata.d.ts +47 -0
  151. package/src/Utils/link-preview-metadata.js +88 -0
  152. package/src/Utils/link-preview.d.ts +12 -0
  153. package/src/Utils/link-preview.js +79 -0
  154. package/src/Utils/logger.d.ts +2 -0
  155. package/src/Utils/logger.js +2 -0
  156. package/src/Utils/lt-hash.d.ts +6 -0
  157. package/src/Utils/lt-hash.js +3 -0
  158. package/src/Utils/make-mutex.d.ts +6 -0
  159. package/src/Utils/make-mutex.js +32 -0
  160. package/src/Utils/message-retry-manager.d.ts +79 -0
  161. package/src/Utils/message-retry-manager.js +255 -0
  162. package/src/Utils/messages-media.d.ts +136 -0
  163. package/src/Utils/messages-media.js +814 -0
  164. package/src/Utils/messages.d.ts +62 -0
  165. package/src/Utils/messages.js +2223 -0
  166. package/src/Utils/mobile-companion-crypto.js +191 -0
  167. package/src/Utils/modern-messages.d.ts +150 -0
  168. package/src/Utils/modern-messages.js +496 -0
  169. package/src/Utils/native-flow.d.ts +11 -0
  170. package/src/Utils/native-flow.js +115 -0
  171. package/src/Utils/newsletter-status.d.ts +158 -0
  172. package/src/Utils/newsletter-status.js +651 -0
  173. package/src/Utils/noise-handler.d.ts +20 -0
  174. package/src/Utils/noise-handler.js +200 -0
  175. package/src/Utils/offline-node-processor.d.ts +9 -0
  176. package/src/Utils/offline-node-processor.js +33 -0
  177. package/src/Utils/optional-media.d.ts +3 -0
  178. package/src/Utils/optional-media.js +45 -0
  179. package/src/Utils/payment-messages.d.ts +66 -0
  180. package/src/Utils/payment-messages.js +160 -0
  181. package/src/Utils/pre-key-manager.d.ts +25 -0
  182. package/src/Utils/pre-key-manager.js +95 -0
  183. package/src/Utils/process-message.d.ts +60 -0
  184. package/src/Utils/process-message.js +688 -0
  185. package/src/Utils/reporting-utils.d.ts +12 -0
  186. package/src/Utils/reporting-utils.js +256 -0
  187. package/src/Utils/scheduled-message.d.ts +51 -0
  188. package/src/Utils/scheduled-message.js +112 -0
  189. package/src/Utils/sender-key-memory.d.ts +19 -0
  190. package/src/Utils/sender-key-memory.js +51 -0
  191. package/src/Utils/signal.d.ts +82 -0
  192. package/src/Utils/signal.js +193 -0
  193. package/src/Utils/stanza-ack.d.ts +16 -0
  194. package/src/Utils/stanza-ack.js +30 -0
  195. package/src/Utils/status-stickers.d.ts +127 -0
  196. package/src/Utils/status-stickers.js +260 -0
  197. package/src/Utils/sync-action-utils.d.ts +2 -0
  198. package/src/Utils/sync-action-utils.js +44 -0
  199. package/src/Utils/tc-token-utils.d.ts +29 -0
  200. package/src/Utils/tc-token-utils.js +155 -0
  201. package/src/Utils/ttl-cache.d.ts +28 -0
  202. package/src/Utils/ttl-cache.js +120 -0
  203. package/src/Utils/use-mongo-auth-state.d.ts +21 -0
  204. package/src/Utils/use-mongo-auth-state.js +67 -0
  205. package/src/Utils/use-multi-file-auth-state.d.ts +11 -0
  206. package/src/Utils/use-multi-file-auth-state.js +106 -0
  207. package/src/Utils/use-mysql-auth-state.d.ts +19 -0
  208. package/src/Utils/use-mysql-auth-state.js +79 -0
  209. package/src/Utils/use-postgres-auth-state.d.ts +19 -0
  210. package/src/Utils/use-postgres-auth-state.js +79 -0
  211. package/src/Utils/use-redis-auth-state.d.ts +19 -0
  212. package/src/Utils/use-redis-auth-state.js +89 -0
  213. package/src/Utils/use-single-file-auth-state.d.ts +10 -0
  214. package/src/Utils/use-single-file-auth-state.js +108 -0
  215. package/src/Utils/use-sqlite-auth-state.d.ts +12 -0
  216. package/src/Utils/use-sqlite-auth-state.js +120 -0
  217. package/src/Utils/useNekoDBAuth.d.ts +19 -0
  218. package/src/Utils/useNekoDBAuth.js +111 -0
  219. package/src/Utils/username.d.ts +12 -0
  220. package/src/Utils/username.js +58 -0
  221. package/src/Utils/validate-connection.d.ts +43 -0
  222. package/src/Utils/validate-connection.js +277 -0
  223. package/src/Utils/voice-recognition.d.ts +53 -0
  224. package/src/Utils/voice-recognition.js +219 -0
  225. package/src/Voip/audio-feeder.d.ts +24 -0
  226. package/src/Voip/audio-feeder.js +268 -0
  227. package/src/Voip/index.d.ts +88 -0
  228. package/src/Voip/index.js +936 -0
  229. package/src/Voip/relay-transport.d.ts +5 -0
  230. package/src/Voip/relay-transport.js +824 -0
  231. package/src/Voip/signaling.d.ts +11 -0
  232. package/src/Voip/signaling.js +1099 -0
  233. package/src/Voip/types.d.ts +2 -0
  234. package/src/Voip/types.js +12 -0
  235. package/src/Voip/video-feeder.d.ts +24 -0
  236. package/src/Voip/video-feeder.js +268 -0
  237. package/src/Voip/wasm-engine.d.ts +26 -0
  238. package/src/Voip/wasm-engine.js +1307 -0
  239. package/src/Voip/worker-bootstrap.js +1023 -0
  240. package/src/WABinary/constants.d.ts +22 -0
  241. package/src/WABinary/constants.js +1300 -0
  242. package/src/WABinary/decode.d.ts +9 -0
  243. package/src/WABinary/decode.js +261 -0
  244. package/src/WABinary/encode.d.ts +2 -0
  245. package/src/WABinary/encode.js +219 -0
  246. package/src/WABinary/generic-utils.d.ts +76 -0
  247. package/src/WABinary/generic-utils.js +214 -0
  248. package/src/WABinary/index.d.ts +5 -0
  249. package/src/WABinary/index.js +5 -0
  250. package/src/WABinary/jid-utils.d.ts +30 -0
  251. package/src/WABinary/jid-utils.js +97 -0
  252. package/src/WABinary/types.d.ts +1 -0
  253. package/src/WABinary/types.js +0 -0
  254. package/src/WAM/BinaryInfo.d.ts +7 -0
  255. package/src/WAM/BinaryInfo.js +9 -0
  256. package/src/WAM/constants.d.ts +34926 -0
  257. package/src/WAM/constants.js +22852 -0
  258. package/src/WAM/encode.d.ts +1 -0
  259. package/src/WAM/encode.js +148 -0
  260. package/src/WAM/index.d.ts +3 -0
  261. package/src/WAM/index.js +3 -0
  262. package/src/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
  263. package/src/WAUSync/Protocols/USyncContactProtocol.js +50 -0
  264. package/src/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
  265. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +51 -0
  266. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  267. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
  268. package/src/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  269. package/src/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
  270. package/src/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
  271. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
  272. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
  273. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.js +49 -0
  274. package/src/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
  275. package/src/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
  276. package/src/WAUSync/Protocols/index.d.ts +5 -0
  277. package/src/WAUSync/Protocols/index.js +5 -0
  278. package/src/WAUSync/USyncQuery.d.ts +20 -0
  279. package/src/WAUSync/USyncQuery.js +93 -0
  280. package/src/WAUSync/USyncUser.d.ts +16 -0
  281. package/src/WAUSync/USyncUser.js +30 -0
  282. package/src/WAUSync/index.d.ts +3 -0
  283. package/src/WAUSync/index.js +3 -0
  284. package/src/assets/wasm/README.md +76 -0
  285. package/src/assets/wasm/loader.js +5 -0
  286. package/src/assets/wasm/whatsapp.wasm +0 -0
  287. package/src/assets/wasm/worker-modules.js +273 -0
  288. package/src/index.d.ts +43 -0
  289. package/src/index.js +48 -0
@@ -0,0 +1,4 @@
1
+ export const CompanionWebClientType: any;
2
+ export function getCompanionWebClientType([os, browserName]: [any, any]): any;
3
+ export function getCompanionPlatformId(browser: any): any;
4
+ export function buildPairingQRData(ref: any, noiseKeyB64: any, identityKeyB64: any, advB64: any, browser: any): string;
@@ -0,0 +1,39 @@
1
+ export var CompanionWebClientType;
2
+ (function (CompanionWebClientType) {
3
+ CompanionWebClientType[CompanionWebClientType["UNKNOWN"] = 0] = "UNKNOWN";
4
+ CompanionWebClientType[CompanionWebClientType["CHROME"] = 1] = "CHROME";
5
+ CompanionWebClientType[CompanionWebClientType["EDGE"] = 2] = "EDGE";
6
+ CompanionWebClientType[CompanionWebClientType["FIREFOX"] = 3] = "FIREFOX";
7
+ CompanionWebClientType[CompanionWebClientType["IE"] = 4] = "IE";
8
+ CompanionWebClientType[CompanionWebClientType["OPERA"] = 5] = "OPERA";
9
+ CompanionWebClientType[CompanionWebClientType["SAFARI"] = 6] = "SAFARI";
10
+ CompanionWebClientType[CompanionWebClientType["ELECTRON"] = 7] = "ELECTRON";
11
+ CompanionWebClientType[CompanionWebClientType["UWP"] = 8] = "UWP";
12
+ CompanionWebClientType[CompanionWebClientType["OTHER_WEB_CLIENT"] = 9] = "OTHER_WEB_CLIENT";
13
+ })(CompanionWebClientType || (CompanionWebClientType = {}));
14
+ const BROWSER_TO_COMPANION_WEB_CLIENT = {
15
+ Chrome: CompanionWebClientType.CHROME,
16
+ Edge: CompanionWebClientType.EDGE,
17
+ Firefox: CompanionWebClientType.FIREFOX,
18
+ IE: CompanionWebClientType.IE,
19
+ Opera: CompanionWebClientType.OPERA,
20
+ Safari: CompanionWebClientType.SAFARI
21
+ };
22
+ export const getCompanionWebClientType = ([os, browserName]) => {
23
+ if (browserName === 'Desktop') {
24
+ return os === 'Windows' ? CompanionWebClientType.UWP : CompanionWebClientType.ELECTRON;
25
+ }
26
+ return BROWSER_TO_COMPANION_WEB_CLIENT[browserName] || CompanionWebClientType.OTHER_WEB_CLIENT;
27
+ };
28
+ export const getCompanionPlatformId = (browser) => {
29
+ return getCompanionWebClientType(browser).toString();
30
+ };
31
+ export const buildPairingQRData = (ref, noiseKeyB64, identityKeyB64, advB64, browser) => {
32
+ return 'https://wa.me/settings/linked_devices#' + [
33
+ ref,
34
+ noiseKeyB64,
35
+ identityKeyB64,
36
+ advB64,
37
+ getCompanionPlatformId(browser)
38
+ ].join(',');
39
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * encrypt AES 256 GCM;
3
+ * where the tag tag is suffixed to the ciphertext
4
+ * */
5
+ export function aesEncryptGCM(plaintext: any, key: any, iv: any, additionalData: any): any;
6
+ /**
7
+ * decrypt AES 256 GCM;
8
+ * where the auth tag is suffixed to the ciphertext
9
+ * */
10
+ export function aesDecryptGCM(ciphertext: any, key: any, iv: any, additionalData: any): any;
11
+ export function aesEncryptCTR(plaintext: any, key: any, iv: any): any;
12
+ export function aesDecryptCTR(ciphertext: any, key: any, iv: any): any;
13
+ /** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
14
+ export function aesDecrypt(buffer: any, key: any): any;
15
+ /** decrypt AES 256 CBC */
16
+ export function aesDecryptWithIV(buffer: any, key: any, IV: any): any;
17
+ export function aesEncrypt(buffer: any, key: any): any;
18
+ export function aesEncrypWithIV(buffer: any, key: any, IV: any): any;
19
+ export function hmacSign(buffer: any, key: any, variant?: string): any;
20
+ export function sha256(buffer: any): any;
21
+ export function derivePairingCodeKey(pairingCode: any, salt: any): Promise<any>;
22
+ export function generateSignalPubKey(pubKey: any): any;
23
+ export namespace Curve {
24
+ function generateKeyPair(): {
25
+ private: any;
26
+ public: any;
27
+ };
28
+ function sharedKey(privateKey: any, publicKey: any): any;
29
+ function sign(privateKey: any, buf: any): any;
30
+ function verify(pubKey: any, message: any, signature: any): boolean;
31
+ }
32
+ export function signedKeyPair(identityKeyPair: any, keyId: any): {
33
+ keyPair: {
34
+ private: any;
35
+ public: any;
36
+ };
37
+ signature: any;
38
+ keyId: any;
39
+ };
@@ -0,0 +1,110 @@
1
+ import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto';
2
+ import * as curve from 'libsignal/src/curve.js';
3
+ import { KEY_BUNDLE_TYPE } from '../Defaults/index.js';
4
+ export { md5, hkdf } from '@rexxhayanasi/wangcap-id-bridge';
5
+
6
+ const { subtle } = globalThis.crypto;
7
+
8
+ export const generateSignalPubKey = (pubKey) => pubKey.length === 33 ? pubKey : Buffer.concat([KEY_BUNDLE_TYPE, pubKey]);
9
+ export const Curve = {
10
+ generateKeyPair: () => {
11
+ const { pubKey, privKey } = curve.generateKeyPair();
12
+ return {
13
+ private: Buffer.from(privKey),
14
+
15
+ public: Buffer.from(pubKey.slice(1))
16
+ };
17
+ },
18
+ sharedKey: (privateKey, publicKey) => {
19
+ const shared = curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey);
20
+ return Buffer.from(shared);
21
+ },
22
+ sign: (privateKey, buf) => curve.calculateSignature(privateKey, buf),
23
+ verify: (pubKey, message, signature) => {
24
+ try {
25
+ curve.verifySignature(generateSignalPubKey(pubKey), message, signature);
26
+ return true;
27
+ }
28
+ catch (error) {
29
+ return false;
30
+ }
31
+ }
32
+ };
33
+ export const signedKeyPair = (identityKeyPair, keyId) => {
34
+ const preKey = Curve.generateKeyPair();
35
+ const pubKey = generateSignalPubKey(preKey.public);
36
+ const signature = Curve.sign(identityKeyPair.private, pubKey);
37
+ return { keyPair: preKey, signature, keyId };
38
+ };
39
+ const GCM_TAG_LENGTH = 128 >> 3;
40
+
41
+ export function aesEncryptGCM(plaintext, key, iv, additionalData) {
42
+ const cipher = createCipheriv('aes-256-gcm', key, iv);
43
+ cipher.setAAD(additionalData);
44
+ return Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);
45
+ }
46
+
47
+ export function aesDecryptGCM(ciphertext, key, iv, additionalData) {
48
+ const decipher = createDecipheriv('aes-256-gcm', key, iv);
49
+
50
+ const enc = ciphertext.slice(0, ciphertext.length - GCM_TAG_LENGTH);
51
+ const tag = ciphertext.slice(ciphertext.length - GCM_TAG_LENGTH);
52
+
53
+ decipher.setAAD(additionalData);
54
+ decipher.setAuthTag(tag);
55
+ return Buffer.concat([decipher.update(enc), decipher.final()]);
56
+ }
57
+ export function aesEncryptCTR(plaintext, key, iv) {
58
+ const cipher = createCipheriv('aes-256-ctr', key, iv);
59
+ return Buffer.concat([cipher.update(plaintext), cipher.final()]);
60
+ }
61
+ export function aesDecryptCTR(ciphertext, key, iv) {
62
+ const decipher = createDecipheriv('aes-256-ctr', key, iv);
63
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
64
+ }
65
+
66
+ export function aesDecrypt(buffer, key) {
67
+ return aesDecryptWithIV(buffer.subarray(16), key, buffer.subarray(0, 16));
68
+ }
69
+
70
+ export function aesDecryptWithIV(buffer, key, IV) {
71
+ const aes = createDecipheriv('aes-256-cbc', key, IV);
72
+ return Buffer.concat([aes.update(buffer), aes.final()]);
73
+ }
74
+
75
+ export function aesEncrypt(buffer, key) {
76
+ const IV = randomBytes(16);
77
+ const aes = createCipheriv('aes-256-cbc', key, IV);
78
+ return Buffer.concat([IV, aes.update(buffer), aes.final()]);
79
+ }
80
+
81
+ export function aesEncrypWithIV(buffer, key, IV) {
82
+ const aes = createCipheriv('aes-256-cbc', key, IV);
83
+ return Buffer.concat([aes.update(buffer), aes.final()]);
84
+ }
85
+
86
+ export function hmacSign(buffer, key, variant = 'sha256') {
87
+ return createHmac(variant, key).update(buffer).digest();
88
+ }
89
+ export function sha256(buffer) {
90
+ return createHash('sha256').update(buffer).digest();
91
+ }
92
+ export async function derivePairingCodeKey(pairingCode, salt) {
93
+
94
+ const encoder = new TextEncoder();
95
+ const pairingCodeBuffer = encoder.encode(pairingCode);
96
+ const saltBuffer = new Uint8Array(salt instanceof Uint8Array ? salt : new Uint8Array(salt));
97
+
98
+ const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer, { name: 'PBKDF2' }, false, [
99
+ 'deriveBits'
100
+ ]);
101
+
102
+ const derivedBits = await subtle.deriveBits({
103
+ name: 'PBKDF2',
104
+ salt: saltBuffer,
105
+ iterations: 2 << 16,
106
+ hash: 'SHA-256'
107
+ }, keyMaterial, 32 * 8
108
+ );
109
+ return Buffer.from(derivedBits);
110
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Decode the received node as a message.
3
+ * @note this will only parse the message, not decrypt it
4
+ */
5
+ export function decodeMessageNode(stanza: any, meId: any, meLid: any): {
6
+ fullMessage: {
7
+ key: {
8
+ server_id?: any;
9
+ remoteJid: any;
10
+ remoteJidAlt: any;
11
+ remoteJidUsername: any;
12
+ fromMe: boolean;
13
+ id: any;
14
+ participant: any;
15
+ participantAlt: any;
16
+ participantUsername: any;
17
+ addressingMode: any;
18
+ };
19
+ category: any;
20
+ messageTimestamp: number;
21
+ pushName: any;
22
+ broadcast: any;
23
+ };
24
+ author: any;
25
+ sender: any;
26
+ };
27
+ export function getDecryptionJid(sender: any, repository: any): Promise<any>;
28
+ export function extractNewsletterMessageMeta(stanza: any): {
29
+ adminProfile?: {
30
+ id?: string;
31
+ name?: string;
32
+ pictureId?: string;
33
+ pictureDirectPath?: string;
34
+ };
35
+ paidPartnership?: boolean;
36
+ aiContent?: boolean;
37
+ editTimestamp?: number;
38
+ originalTimestamp?: number;
39
+ } | undefined;
40
+ export const NO_MESSAGE_FOUND_ERROR_TEXT: "Message absent from node";
41
+ export const MISSING_KEYS_ERROR_TEXT: "Key used already or never filled";
42
+ export const ACCOUNT_RESTRICTED_TEXT: "Your account has been restricted";
43
+ export namespace DECRYPTION_RETRY_CONFIG {
44
+ let maxRetries: number;
45
+ let baseDelayMs: number;
46
+ let sessionRecordErrors: string[];
47
+ }
48
+ export namespace NACK_REASONS {
49
+ let StaleGroupAddressingMode: number;
50
+ let SenderReachoutTimelocked: number;
51
+ let NewChatMessagesCapped: number;
52
+ let ParsingError: number;
53
+ let UnrecognizedStanza: number;
54
+ let UnrecognizedStanzaClass: number;
55
+ let UnrecognizedStanzaType: number;
56
+ let InvalidProtobuf: number;
57
+ let InvalidHostedCompanionStanza: number;
58
+ let MissingMessageSecret: number;
59
+ let SignalErrorOldCounter: number;
60
+ let MessageDeletedOnPeer: number;
61
+ let UnhandledError: number;
62
+ let UnsupportedAdminRevoke: number;
63
+ let UnsupportedLIDGroup: number;
64
+ let DBOperationFailed: number;
65
+ }
66
+ export namespace SERVER_ERROR_CODES {
67
+ let MessageAccountRestriction: string;
68
+ let SmaxInvalid: string;
69
+ let NewChatMessagesCapped: string;
70
+ }
71
+ export const RETRYABLE_ACK_CODES: Set<string>;
72
+ export function extractAddressingContext(stanza: any): {
73
+ addressingMode: any;
74
+ senderAlt: any;
75
+ recipientAlt: any;
76
+ };
77
+ export function decryptMessageNode(stanza: any, meId: any, meLid: any, repository: any, logger: any): {
78
+ fullMessage: {
79
+ key: {
80
+ server_id?: any;
81
+ remoteJid: any;
82
+ remoteJidAlt: any;
83
+ remoteJidUsername: any;
84
+ fromMe: boolean;
85
+ id: any;
86
+ participant: any;
87
+ participantAlt: any;
88
+ participantUsername: any;
89
+ addressingMode: any;
90
+ };
91
+ category: any;
92
+ messageTimestamp: number;
93
+ pushName: any;
94
+ broadcast: any;
95
+ };
96
+ category: any;
97
+ author: any;
98
+ decrypt(): Promise<void>;
99
+ };
@@ -0,0 +1,373 @@
1
+ import { Boom } from '@hapi/boom';
2
+ import { proto } from '../../WAProto/index.js';
3
+ import { areJidsSameUser, isHostedLidUser, isHostedPnUser, isJidBroadcast, isJidGroup, isJidMetaAI, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser
4
+
5
+ } from '../WABinary/index.js';
6
+ import { unpadRandomMax16 } from './generics.js';
7
+ const findChildByTag = (node, tag) => {
8
+ if (!node || !Array.isArray(node.content)) {
9
+ return undefined;
10
+ }
11
+ return node.content.find(child => child?.tag === tag);
12
+ };
13
+ const readIntAttr = (attrs, key) => {
14
+ const raw = attrs?.[key];
15
+ if (raw === undefined || raw === null || raw === '') {
16
+ return undefined;
17
+ }
18
+ const parsed = Number.parseInt(String(raw), 10);
19
+ return Number.isFinite(parsed) ? parsed : undefined;
20
+ };
21
+ export const extractNewsletterMessageMeta = (stanza) => {
22
+ const meta = findChildByTag(stanza, 'meta');
23
+ if (!meta) {
24
+ return undefined;
25
+ }
26
+ const result = {};
27
+ const adminProfile = findChildByTag(meta, 'admin_profile');
28
+ if (adminProfile) {
29
+ const name = findChildByTag(adminProfile, 'name');
30
+ const picture = findChildByTag(adminProfile, 'picture');
31
+ const content = name?.content;
32
+ result.adminProfile = {
33
+ id: adminProfile.attrs?.id,
34
+ name: typeof content === 'string'
35
+ ? content
36
+ : content instanceof Uint8Array
37
+ ? Buffer.from(content).toString('utf-8')
38
+ : undefined,
39
+ pictureId: picture?.attrs?.id,
40
+ pictureDirectPath: picture?.attrs?.direct_path
41
+ };
42
+ }
43
+ if (findChildByTag(meta, 'paid_partnership')) {
44
+ result.paidPartnership = true;
45
+ }
46
+ if (findChildByTag(meta, 'ai_content')) {
47
+ result.aiContent = true;
48
+ }
49
+ const editTimestamp = readIntAttr(meta.attrs, 'msg_edit_t');
50
+ if (editTimestamp !== undefined) {
51
+ result.editTimestamp = editTimestamp;
52
+ }
53
+ const originalTimestamp = readIntAttr(meta.attrs, 'original_msg_t');
54
+ if (originalTimestamp !== undefined) {
55
+ result.originalTimestamp = originalTimestamp;
56
+ }
57
+ return Object.keys(result).length ? result : undefined;
58
+ };
59
+ export const getDecryptionJid = async (sender, repository) => {
60
+ if (isLidUser(sender) || isHostedLidUser(sender)) {
61
+ return sender;
62
+ }
63
+ const mapped = await repository.lidMapping.getLIDForPN(sender);
64
+ return mapped || sender;
65
+ };
66
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
67
+
68
+ const { senderAlt } = extractAddressingContext(stanza);
69
+ if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
70
+ try {
71
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }]);
72
+ await repository.migrateSession(sender, senderAlt);
73
+ logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope');
74
+ }
75
+ catch (error) {
76
+ logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping');
77
+ }
78
+ }
79
+ };
80
+ export const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
81
+ export const MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
82
+ export const ACCOUNT_RESTRICTED_TEXT = 'Your account has been restricted';
83
+
84
+ export const DECRYPTION_RETRY_CONFIG = {
85
+ maxRetries: 3,
86
+ baseDelayMs: 100,
87
+ sessionRecordErrors: ['No session record', 'SessionError: No session record']
88
+ };
89
+
90
+ export const NACK_REASONS = {
91
+ StaleGroupAddressingMode: 421,
92
+ SenderReachoutTimelocked: 463,
93
+ NewChatMessagesCapped: 475,
94
+ ParsingError: 487,
95
+ UnrecognizedStanza: 488,
96
+ UnrecognizedStanzaClass: 489,
97
+ UnrecognizedStanzaType: 490,
98
+ InvalidProtobuf: 491,
99
+ InvalidHostedCompanionStanza: 493,
100
+ MissingMessageSecret: 495,
101
+ SignalErrorOldCounter: 496,
102
+ MessageDeletedOnPeer: 499,
103
+ UnhandledError: 500,
104
+ UnsupportedAdminRevoke: 550,
105
+ UnsupportedLIDGroup: 551,
106
+ DBOperationFailed: 552
107
+ };
108
+
109
+ export const SERVER_ERROR_CODES = {
110
+
111
+ MessageAccountRestriction: '463',
112
+
113
+ SmaxInvalid: '479',
114
+
115
+ NewChatMessagesCapped: '475'
116
+ };
117
+
118
+ export const RETRYABLE_ACK_CODES = new Set(['408', '429', '500', '503']);
119
+ export const extractAddressingContext = (stanza) => {
120
+ let senderAlt;
121
+ let recipientAlt;
122
+ const sender = stanza.attrs.participant || stanza.attrs.from;
123
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn');
124
+ if (addressingMode === 'lid') {
125
+
126
+ senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn;
127
+ recipientAlt = stanza.attrs.recipient_pn;
128
+
129
+ }
130
+ else {
131
+
132
+ senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid;
133
+ recipientAlt = stanza.attrs.recipient_lid;
134
+
135
+ }
136
+ return {
137
+ addressingMode,
138
+ senderAlt,
139
+ recipientAlt
140
+ };
141
+ };
142
+
143
+ export function decodeMessageNode(stanza, meId, meLid) {
144
+ let msgType;
145
+ let chatId;
146
+ let author;
147
+ let fromMe = false;
148
+ const msgId = stanza.attrs.id;
149
+ const from = stanza.attrs.from;
150
+ const participant = stanza.attrs.participant;
151
+ const recipient = stanza.attrs.recipient;
152
+ if (!msgId) {
153
+ throw new Boom('Invalid message stanza: missing id attribute', { data: stanza });
154
+ }
155
+ if (!from) {
156
+ throw new Boom('Invalid message stanza: missing from attribute', { data: stanza });
157
+ }
158
+ const addressingContext = extractAddressingContext(stanza);
159
+ const isMe = (jid) => areJidsSameUser(jid, meId);
160
+ const isMeLid = (jid) => areJidsSameUser(jid, meLid);
161
+ if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) {
162
+ if (recipient && !isJidMetaAI(recipient)) {
163
+ if (!isMe(from) && !isMeLid(from)) {
164
+ throw new Boom('receipient present, but msg not from me', { data: stanza });
165
+ }
166
+ if (isMe(from) || isMeLid(from)) {
167
+ fromMe = true;
168
+ }
169
+ chatId = recipient;
170
+ }
171
+ else {
172
+
173
+ if (isMe(from) || isMeLid(from)) {
174
+ fromMe = true;
175
+ }
176
+ chatId = from;
177
+ }
178
+ msgType = 'chat';
179
+ author = from;
180
+ }
181
+ else if (isJidGroup(from)) {
182
+ if (!participant) {
183
+ throw new Boom('No participant in group message');
184
+ }
185
+ if (isMe(participant) || isMeLid(participant)) {
186
+ fromMe = true;
187
+ }
188
+ msgType = 'group';
189
+ author = participant;
190
+ chatId = from;
191
+ }
192
+ else if (isJidBroadcast(from)) {
193
+ if (!participant) {
194
+ throw new Boom('No participant in group message');
195
+ }
196
+ const isParticipantMe = isMe(participant);
197
+ if (isJidStatusBroadcast(from)) {
198
+ msgType = isParticipantMe ? 'direct_peer_status' : 'other_status';
199
+ }
200
+ else {
201
+ msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast';
202
+ }
203
+ fromMe = isParticipantMe;
204
+ chatId = from;
205
+ author = participant;
206
+ }
207
+ else if (isJidNewsletter(from)) {
208
+ msgType = 'newsletter';
209
+ chatId = from;
210
+ author = from;
211
+ if (isMe(from) || isMeLid(from)) {
212
+ fromMe = true;
213
+ }
214
+ }
215
+ else {
216
+ throw new Boom('Unknown message type', { data: stanza });
217
+ }
218
+ const pushname = stanza?.attrs?.notify;
219
+ const key = {
220
+ remoteJid: chatId,
221
+ remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
222
+ remoteJidUsername: !isJidGroup(chatId)
223
+ ? stanza.attrs.peer_recipient_username || stanza.attrs.recipient_username
224
+ : undefined,
225
+ fromMe,
226
+ id: msgId,
227
+ participant,
228
+ participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
229
+ participantUsername: stanza.attrs.participant ? stanza.attrs.participant_username : undefined,
230
+ addressingMode: addressingContext.addressingMode,
231
+ ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
232
+ };
233
+ const fullMessage = {
234
+ key,
235
+ category: stanza.attrs.category,
236
+ messageTimestamp: +stanza.attrs.t,
237
+ pushName: pushname,
238
+ broadcast: isJidBroadcast(from)
239
+ };
240
+ if (msgType === 'newsletter') {
241
+ const meta = extractNewsletterMessageMeta(stanza);
242
+ if (meta) {
243
+ fullMessage.newsletterMeta = meta;
244
+ if (meta.adminProfile?.name) {
245
+ fullMessage.pushName = fullMessage.pushName || meta.adminProfile.name;
246
+ }
247
+ }
248
+ if (stanza.attrs.is_sender === 'true') {
249
+ fullMessage.key.fromMe = true;
250
+ fullMessage.key.isNewsletterSender = true;
251
+ }
252
+ }
253
+ if (key.fromMe) {
254
+ fullMessage.status = proto.WebMessageInfo.Status.SERVER_ACK;
255
+ }
256
+ return {
257
+ fullMessage,
258
+ author,
259
+ sender: msgType === 'chat' ? author : chatId
260
+ };
261
+ }
262
+ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
263
+ const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid);
264
+ return {
265
+ fullMessage,
266
+ category: stanza.attrs.category,
267
+ author,
268
+ async decrypt() {
269
+ let decryptables = 0;
270
+ if (Array.isArray(stanza.content)) {
271
+ for (const { tag, attrs, content } of stanza.content) {
272
+ if (tag === 'verified_name' && content instanceof Uint8Array) {
273
+ try {
274
+ const cert = proto.VerifiedNameCertificate.decode(content);
275
+ const details = proto.VerifiedNameCertificate.Details.decode(cert.details);
276
+ fullMessage.verifiedBizName = details.verifiedName;
277
+ }
278
+ catch (err) {
279
+ logger?.warn?.({ err, key: fullMessage.key }, 'could not read the verified business name, leaving it unset');
280
+ }
281
+ }
282
+ if (tag === 'unavailable' && attrs.type === 'view_once') {
283
+ fullMessage.key.isViewOnce = true;
284
+ }
285
+ if (attrs.count && tag === 'enc') {
286
+ fullMessage.retryCount = Number(attrs.count);
287
+ }
288
+ if (tag !== 'enc' && tag !== 'plaintext') {
289
+ continue;
290
+ }
291
+ if (!(content instanceof Uint8Array)) {
292
+ continue;
293
+ }
294
+ decryptables += 1;
295
+ let msgBuffer;
296
+ const decryptionJid = await getDecryptionJid(author, repository);
297
+ if (tag !== 'plaintext') {
298
+
299
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger);
300
+ }
301
+ try {
302
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type;
303
+ switch (e2eType) {
304
+ case 'skmsg':
305
+ msgBuffer = await repository.decryptGroupMessage({
306
+ group: sender,
307
+ authorJid: author,
308
+ msg: content
309
+ });
310
+ break;
311
+ case 'pkmsg':
312
+ case 'msg':
313
+ msgBuffer = await repository.decryptMessage({
314
+ jid: decryptionJid,
315
+ type: e2eType,
316
+ ciphertext: content
317
+ });
318
+ break;
319
+ case 'plaintext':
320
+ msgBuffer = content;
321
+ break;
322
+ default:
323
+ throw new Error(`Unknown e2e type: ${e2eType}`);
324
+ }
325
+ let msg = proto.Message.decode(e2eType !== 'plaintext' ? unpadRandomMax16(msgBuffer) : msgBuffer);
326
+ msg = msg.deviceSentMessage?.message || msg;
327
+ if (msg.senderKeyDistributionMessage) {
328
+
329
+ try {
330
+ await repository.processSenderKeyDistributionMessage({
331
+ authorJid: author,
332
+ item: msg.senderKeyDistributionMessage
333
+ });
334
+ }
335
+ catch (err) {
336
+ logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message');
337
+ }
338
+ }
339
+ if (fullMessage.message) {
340
+ Object.assign(fullMessage.message, msg);
341
+ }
342
+ else {
343
+ fullMessage.message = msg;
344
+ }
345
+ }
346
+ catch (err) {
347
+ const errorContext = {
348
+ key: fullMessage.key,
349
+ err,
350
+ messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
351
+ sender,
352
+ author,
353
+ isSessionRecordError: isSessionRecordError(err)
354
+ };
355
+ logger.error(errorContext, 'failed to decrypt message');
356
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
357
+ fullMessage.messageStubParameters = [err.message.toString()];
358
+ }
359
+ }
360
+ }
361
+
362
+ if (!decryptables && !fullMessage.key?.isViewOnce) {
363
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
364
+ fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT];
365
+ }
366
+ }
367
+ };
368
+ };
369
+
370
+ function isSessionRecordError(error) {
371
+ const errorMessage = error?.message || error?.toString() || '';
372
+ return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern));
373
+ }
@@ -0,0 +1,22 @@
1
+ export const DEFAULT_MAX_EVENT_LISTENERS: number;
2
+ export function makeEventBuffer(logger: any, maxListeners?: number): {
3
+ process(handler: any): () => void;
4
+ emit(event: any, evData: any): any;
5
+ isBuffering(): boolean;
6
+ buffer: () => void;
7
+ flush: () => boolean;
8
+ createBufferedFunction(work: any): (...args: any[]) => Promise<any>;
9
+ on: (...args: any[]) => any;
10
+ off: (...args: any[]) => any;
11
+ removeAllListeners: (...args: any[]) => any;
12
+ once: (...args: any[]) => any;
13
+ addListener: (...args: any[]) => any;
14
+ removeListener: (...args: any[]) => any;
15
+ listeners: (...args: any[]) => Function[];
16
+ rawListeners: (...args: any[]) => Function[];
17
+ eventNames: () => (string | symbol)[];
18
+ setMaxListeners: (count: number) => any;
19
+ getMaxListeners: () => number;
20
+ listenerCount: (...args: any[]) => number;
21
+ destroy(): void;
22
+ };