@badzz88/baileys 8.4.6 → 8.4.9

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 (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1055 -337
  3. package/WAProto/WAProto.proto +850 -32
  4. package/WAProto/index.d.ts +4913 -25
  5. package/WAProto/index.js +14074 -98
  6. package/package.json +96 -131
  7. package/src/Defaults/index.js +201 -0
  8. package/src/Defaults/phonenumber-mcc.json +223 -0
  9. package/src/Signal/Group/ciphertext-message.js +15 -0
  10. package/src/Signal/Group/group-session-builder.js +92 -0
  11. package/src/Signal/Group/group_cipher.js +89 -0
  12. package/src/Signal/Group/index.js +136 -0
  13. package/src/Signal/Group/keyhelper.js +73 -0
  14. package/src/Signal/Group/sender-chain-key.js +32 -0
  15. package/src/Signal/Group/sender-key-distribution-message.js +66 -0
  16. package/src/Signal/Group/sender-key-message.js +69 -0
  17. package/src/Signal/Group/sender-key-name.js +50 -0
  18. package/src/Signal/Group/sender-key-record.js +44 -0
  19. package/src/Signal/Group/sender-key-state.js +97 -0
  20. package/src/Signal/Group/sender-message-key.js +30 -0
  21. package/src/Signal/libsignal.js +470 -0
  22. package/src/Signal/lid-mapping.js +262 -0
  23. package/src/Socket/Client/index.js +30 -0
  24. package/src/Socket/Client/types.js +13 -0
  25. package/src/Socket/Client/websocket.js +62 -0
  26. package/src/Socket/aigroups.js +240 -0
  27. package/src/Socket/business.js +422 -0
  28. package/src/Socket/chats.js +2374 -0
  29. package/src/Socket/communities.js +580 -0
  30. package/src/Socket/graphql.js +915 -0
  31. package/src/Socket/groups.js +812 -0
  32. package/src/Socket/index.js +37 -0
  33. package/src/Socket/interactive-handler.js +579 -0
  34. package/src/Socket/interop.js +566 -0
  35. package/src/Socket/managed-account.js +214 -0
  36. package/src/Socket/messages-recv.js +3012 -0
  37. package/src/Socket/messages-send.js +2163 -0
  38. package/{lib → src}/Socket/mex.js +11 -5
  39. package/src/Socket/newsletter.js +1057 -0
  40. package/src/Socket/privacy.js +452 -0
  41. package/src/Socket/registration.js +434 -0
  42. package/src/Socket/socket.js +1079 -0
  43. package/src/Socket/text-router.js +67 -0
  44. package/src/Socket/username.js +234 -0
  45. package/src/Store/index.js +36 -0
  46. package/src/Store/make-cache-manager-store.js +90 -0
  47. package/src/Store/make-in-memory-store.js +506 -0
  48. package/src/Store/make-ordered-dictionary.js +81 -0
  49. package/src/Store/object-repository.js +29 -0
  50. package/src/Types/Auth.js +38 -0
  51. package/src/Types/Bussines.js +2 -0
  52. package/src/Types/Call.js +2 -0
  53. package/src/Types/Chat.js +4 -0
  54. package/src/Types/Contact.js +2 -0
  55. package/src/Types/Events.js +2 -0
  56. package/src/Types/GroupMetadata.js +2 -0
  57. package/src/Types/Label.js +27 -0
  58. package/src/Types/LabelAssociation.js +9 -0
  59. package/src/Types/Message.js +95 -0
  60. package/src/Types/Newsletter.js +152 -0
  61. package/src/Types/Product.js +2 -0
  62. package/src/Types/Signal.js +2 -0
  63. package/src/Types/Socket.js +2 -0
  64. package/src/Types/State.js +70 -0
  65. package/src/Types/USync.js +2 -0
  66. package/src/Types/index.js +54 -0
  67. package/src/Utils/auth-utils.js +306 -0
  68. package/src/Utils/browser-utils.js +114 -0
  69. package/src/Utils/business.js +247 -0
  70. package/src/Utils/chat-utils.js +1272 -0
  71. package/src/Utils/consumer-application.js +107 -0
  72. package/src/Utils/crypto.js +125 -0
  73. package/src/Utils/decode-wa-message.js +808 -0
  74. package/src/Utils/event-buffer.js +586 -0
  75. package/src/Utils/generics.js +640 -0
  76. package/src/Utils/group-history.js +60 -0
  77. package/src/Utils/history.js +244 -0
  78. package/src/Utils/identity-change-handler.js +52 -0
  79. package/src/Utils/index.js +53 -0
  80. package/src/Utils/jid-display-normalization.js +218 -0
  81. package/src/Utils/link-preview.js +143 -0
  82. package/src/Utils/logger.js +9 -0
  83. package/src/Utils/lt-hash.js +10 -0
  84. package/src/Utils/make-mutex.js +36 -0
  85. package/src/Utils/message-composer.js +479 -0
  86. package/src/Utils/message-inspect.js +400 -0
  87. package/src/Utils/message-retry-manager.js +231 -0
  88. package/src/Utils/messages-media.js +943 -0
  89. package/src/Utils/messages.js +2490 -0
  90. package/src/Utils/meta-ai-msmsg.js +133 -0
  91. package/src/Utils/noise-handler.js +194 -0
  92. package/src/Utils/offline-node-processor.js +42 -0
  93. package/src/Utils/pre-key-manager.js +107 -0
  94. package/src/Utils/process-message.js +1047 -0
  95. package/src/Utils/reporting-utils.js +262 -0
  96. package/src/Utils/signal.js +192 -0
  97. package/src/Utils/stanza-ack.js +74 -0
  98. package/src/Utils/sync-action-utils.js +54 -0
  99. package/src/Utils/tc-token-utils.js +161 -0
  100. package/src/Utils/use-multi-file-auth-state.js +121 -0
  101. package/src/Utils/validate-connection.js +248 -0
  102. package/src/Utils/voip-rekey.js +22 -0
  103. package/src/WABinary/constants.js +1304 -0
  104. package/src/WABinary/decode.js +377 -0
  105. package/src/WABinary/encode.js +58 -0
  106. package/src/WABinary/generic-utils.js +148 -0
  107. package/src/WABinary/index.js +33 -0
  108. package/src/WABinary/jid-utils.js +374 -0
  109. package/src/WABinary/types.js +2 -0
  110. package/src/WAM/BinaryInfo.js +13 -0
  111. package/src/WAM/constants.js +39486 -0
  112. package/src/WAM/encode.js +142 -0
  113. package/src/WAM/index.js +31 -0
  114. package/src/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  115. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +100 -0
  116. package/src/WAUSync/Protocols/USyncContactProtocol.js +60 -0
  117. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +65 -0
  118. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
  119. package/src/WAUSync/Protocols/USyncFeatureProtocol.js +74 -0
  120. package/src/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  121. package/src/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  122. package/src/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  123. package/src/WAUSync/Protocols/USyncStatusProtocol.js +44 -0
  124. package/src/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  125. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +28 -0
  126. package/src/WAUSync/Protocols/index.js +40 -0
  127. package/src/WAUSync/USyncBackoff.js +31 -0
  128. package/src/WAUSync/USyncQuery.js +204 -0
  129. package/src/WAUSync/USyncUser.js +58 -0
  130. package/src/WAUSync/index.js +32 -0
  131. package/src/antiban.js +4726 -0
  132. package/{lib → src}/index.js +48 -16
  133. package/lib/Defaults/baileys-version.json +0 -3
  134. package/lib/Defaults/index.js +0 -137
  135. package/lib/Defaults/phonenumber-mcc.json +0 -223
  136. package/lib/Signal/Group/Protocols.js +0 -269
  137. package/lib/Signal/Group/ciphertext-message.js +0 -12
  138. package/lib/Signal/Group/group-session-builder.js +0 -30
  139. package/lib/Signal/Group/group_cipher.js +0 -82
  140. package/lib/Signal/Group/index.js +0 -12
  141. package/lib/Signal/Group/keyhelper.js +0 -18
  142. package/lib/Signal/Group/queue-job.js +0 -57
  143. package/lib/Signal/Group/sender-chain-key.js +0 -26
  144. package/lib/Signal/Group/sender-key-distribution-message.js +0 -63
  145. package/lib/Signal/Group/sender-key-message.js +0 -66
  146. package/lib/Signal/Group/sender-key-name.js +0 -48
  147. package/lib/Signal/Group/sender-key-record.js +0 -41
  148. package/lib/Signal/Group/sender-key-state.js +0 -84
  149. package/lib/Signal/Group/sender-message-key.js +0 -26
  150. package/lib/Signal/libsignal.js +0 -432
  151. package/lib/Signal/lid-mapping.js +0 -277
  152. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  153. package/lib/Socket/Client/index.js +0 -3
  154. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  155. package/lib/Socket/Client/types.js +0 -11
  156. package/lib/Socket/Client/web-socket-client.js +0 -62
  157. package/lib/Socket/Client/websocket.js +0 -54
  158. package/lib/Socket/business.js +0 -379
  159. package/lib/Socket/chats.js +0 -1193
  160. package/lib/Socket/communities.js +0 -431
  161. package/lib/Socket/community.js +0 -392
  162. package/lib/Socket/dugong.js +0 -637
  163. package/lib/Socket/groups.js +0 -374
  164. package/lib/Socket/index.js +0 -12
  165. package/lib/Socket/luxu.js +0 -387
  166. package/lib/Socket/messages-recv.js +0 -1916
  167. package/lib/Socket/messages-send.js +0 -1459
  168. package/lib/Socket/newsletter.js +0 -253
  169. package/lib/Socket/registration.js +0 -167
  170. package/lib/Socket/socket.js +0 -950
  171. package/lib/Socket/username.js +0 -146
  172. package/lib/Socket/usync.js +0 -69
  173. package/lib/Store/index.js +0 -10
  174. package/lib/Store/keyed-db.js +0 -108
  175. package/lib/Store/make-cache-manager-store.js +0 -85
  176. package/lib/Store/make-in-memory-store.js +0 -198
  177. package/lib/Store/make-ordered-dictionary.js +0 -75
  178. package/lib/Store/object-repository.js +0 -32
  179. package/lib/Types/Auth.js +0 -2
  180. package/lib/Types/Bussines.js +0 -2
  181. package/lib/Types/Call.js +0 -2
  182. package/lib/Types/Chat.js +0 -8
  183. package/lib/Types/Contact.js +0 -2
  184. package/lib/Types/Events.js +0 -2
  185. package/lib/Types/GroupMetadata.js +0 -2
  186. package/lib/Types/Label.js +0 -25
  187. package/lib/Types/LabelAssociation.js +0 -7
  188. package/lib/Types/Message.js +0 -11
  189. package/lib/Types/Mex.js +0 -37
  190. package/lib/Types/Newsletter.js +0 -38
  191. package/lib/Types/Product.js +0 -2
  192. package/lib/Types/Signal.js +0 -2
  193. package/lib/Types/Socket.js +0 -3
  194. package/lib/Types/State.js +0 -56
  195. package/lib/Types/USync.js +0 -2
  196. package/lib/Types/index.js +0 -26
  197. package/lib/Utils/auth-utils.js +0 -302
  198. package/lib/Utils/baileys-event-stream.js +0 -63
  199. package/lib/Utils/browser-utils.js +0 -48
  200. package/lib/Utils/business.js +0 -231
  201. package/lib/Utils/chat-utils.js +0 -873
  202. package/lib/Utils/companion-reg-client-utils.js +0 -35
  203. package/lib/Utils/crypto.js +0 -118
  204. package/lib/Utils/decode-wa-message.js +0 -350
  205. package/lib/Utils/event-buffer.js +0 -622
  206. package/lib/Utils/generics.js +0 -399
  207. package/lib/Utils/history.js +0 -134
  208. package/lib/Utils/identity-change-handler.js +0 -50
  209. package/lib/Utils/index.js +0 -23
  210. package/lib/Utils/link-preview.js +0 -85
  211. package/lib/Utils/logger.js +0 -3
  212. package/lib/Utils/lt-hash.js +0 -8
  213. package/lib/Utils/make-mutex.js +0 -33
  214. package/lib/Utils/message-composer.js +0 -273
  215. package/lib/Utils/message-retry-manager.js +0 -265
  216. package/lib/Utils/messages-media.js +0 -788
  217. package/lib/Utils/messages.js +0 -1260
  218. package/lib/Utils/noise-handler.js +0 -201
  219. package/lib/Utils/offline-node-processor.js +0 -40
  220. package/lib/Utils/pre-key-manager.js +0 -106
  221. package/lib/Utils/process-message.js +0 -630
  222. package/lib/Utils/reporting-utils.js +0 -258
  223. package/lib/Utils/signal.js +0 -202
  224. package/lib/Utils/stanza-ack.js +0 -38
  225. package/lib/Utils/sync-action-utils.js +0 -49
  226. package/lib/Utils/tc-token-utils.js +0 -163
  227. package/lib/Utils/use-multi-file-auth-state.js +0 -121
  228. package/lib/Utils/validate-connection.js +0 -204
  229. package/lib/WABinary/constants.js +0 -1301
  230. package/lib/WABinary/decode.js +0 -262
  231. package/lib/WABinary/encode.js +0 -220
  232. package/lib/WABinary/generic-utils.js +0 -204
  233. package/lib/WABinary/index.js +0 -6
  234. package/lib/WABinary/jid-utils.js +0 -98
  235. package/lib/WABinary/types.js +0 -2
  236. package/lib/WAM/BinaryInfo.js +0 -10
  237. package/lib/WAM/constants.js +0 -22853
  238. package/lib/WAM/encode.js +0 -150
  239. package/lib/WAM/index.js +0 -4
  240. package/lib/WAUSync/Protocols/USyncContactProtocol.js +0 -52
  241. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +0 -54
  242. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -27
  243. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +0 -38
  244. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +0 -25
  245. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -51
  246. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -29
  247. package/lib/WAUSync/Protocols/index.js +0 -6
  248. package/lib/WAUSync/USyncQuery.js +0 -98
  249. package/lib/WAUSync/USyncUser.js +0 -31
  250. package/lib/WAUSync/index.js +0 -4
@@ -0,0 +1,97 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.SenderKeyState = void 0
4
+ const sender_chain_key_1 = require('./sender-chain-key')
5
+ const sender_message_key_1 = require('./sender-message-key')
6
+ class SenderKeyState {
7
+ constructor(
8
+ id,
9
+ iteration,
10
+ chainKey,
11
+ signatureKeyPair,
12
+ signatureKeyPublic,
13
+ signatureKeyPrivate,
14
+ senderKeyStateStructure
15
+ ) {
16
+ this.MAX_MESSAGE_KEYS = 2000
17
+ if (senderKeyStateStructure) {
18
+ this.senderKeyStateStructure = {
19
+ ...senderKeyStateStructure,
20
+ senderMessageKeys: Array.isArray(senderKeyStateStructure.senderMessageKeys)
21
+ ? senderKeyStateStructure.senderMessageKeys
22
+ : []
23
+ }
24
+ } else {
25
+ if (signatureKeyPair) {
26
+ signatureKeyPublic = signatureKeyPair.public
27
+ signatureKeyPrivate = signatureKeyPair.private
28
+ }
29
+ this.senderKeyStateStructure = {
30
+ senderKeyId: id || 0,
31
+ senderChainKey: {
32
+ iteration: iteration || 0,
33
+ seed: Buffer.from(chainKey || [])
34
+ },
35
+ senderSigningKey: {
36
+ public: Buffer.from(signatureKeyPublic || []),
37
+ private: Buffer.from(signatureKeyPrivate || [])
38
+ },
39
+ senderMessageKeys: []
40
+ }
41
+ }
42
+ }
43
+ getKeyId() {
44
+ return this.senderKeyStateStructure.senderKeyId
45
+ }
46
+ getSenderChainKey() {
47
+ return new sender_chain_key_1.SenderChainKey(
48
+ this.senderKeyStateStructure.senderChainKey.iteration,
49
+ this.senderKeyStateStructure.senderChainKey.seed
50
+ )
51
+ }
52
+ setSenderChainKey(chainKey) {
53
+ this.senderKeyStateStructure.senderChainKey = {
54
+ iteration: chainKey.getIteration(),
55
+ seed: chainKey.getSeed()
56
+ }
57
+ }
58
+ getSigningKeyPublic() {
59
+ const publicKey = Buffer.from(this.senderKeyStateStructure.senderSigningKey.public)
60
+ if (publicKey.length === 32) {
61
+ const fixed = Buffer.alloc(33)
62
+ fixed[0] = 0x05
63
+ publicKey.copy(fixed, 1)
64
+ return fixed
65
+ }
66
+ return publicKey
67
+ }
68
+ getSigningKeyPrivate() {
69
+ const privateKey = this.senderKeyStateStructure.senderSigningKey.private
70
+ return Buffer.from(privateKey || [])
71
+ }
72
+ hasSenderMessageKey(iteration) {
73
+ return this.senderKeyStateStructure.senderMessageKeys.some(key => key.iteration === iteration)
74
+ }
75
+ addSenderMessageKey(senderMessageKey) {
76
+ this.senderKeyStateStructure.senderMessageKeys.push({
77
+ iteration: senderMessageKey.getIteration(),
78
+ seed: senderMessageKey.getSeed()
79
+ })
80
+ if (this.senderKeyStateStructure.senderMessageKeys.length > this.MAX_MESSAGE_KEYS) {
81
+ this.senderKeyStateStructure.senderMessageKeys.shift()
82
+ }
83
+ }
84
+ removeSenderMessageKey(iteration) {
85
+ const index = this.senderKeyStateStructure.senderMessageKeys.findIndex(key => key.iteration === iteration)
86
+ if (index !== -1) {
87
+ const messageKey = this.senderKeyStateStructure.senderMessageKeys[index]
88
+ this.senderKeyStateStructure.senderMessageKeys.splice(index, 1)
89
+ return new sender_message_key_1.SenderMessageKey(messageKey.iteration, messageKey.seed)
90
+ }
91
+ return null
92
+ }
93
+ getStructure() {
94
+ return this.senderKeyStateStructure
95
+ }
96
+ }
97
+ exports.SenderKeyState = SenderKeyState
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.SenderMessageKey = void 0
4
+ const rb = require('whatsapp-rust-bridge-baron')
5
+ class SenderMessageKey {
6
+ constructor(iteration, seed) {
7
+ // HKDF(seed, 96, salt=0x00*32, info='WhisperGroup') → split into 3×32 byte chunks
8
+ const derived = Buffer.from(rb.hkdf(seed, 96, { salt: Buffer.alloc(32), info: 'WhisperGroup' }))
9
+ const keys = new Uint8Array(32)
10
+ keys.set(new Uint8Array(derived.slice(16, 32))) // bytes 16-31 of chunk 0
11
+ keys.set(new Uint8Array(derived.slice(32, 48)), 16) // bytes 0-15 of chunk 1
12
+ this.iv = Buffer.from(derived.slice(0, 16))
13
+ this.cipherKey = Buffer.from(keys.buffer)
14
+ this.iteration = iteration
15
+ this.seed = seed
16
+ }
17
+ getIteration() {
18
+ return this.iteration
19
+ }
20
+ getIv() {
21
+ return this.iv
22
+ }
23
+ getCipherKey() {
24
+ return this.cipherKey
25
+ }
26
+ getSeed() {
27
+ return this.seed
28
+ }
29
+ }
30
+ exports.SenderMessageKey = SenderMessageKey
@@ -0,0 +1,470 @@
1
+ 'use strict'
2
+ var __createBinding =
3
+ (this && this.__createBinding) ||
4
+ (Object.create
5
+ ? function (o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k
7
+ var desc = Object.getOwnPropertyDescriptor(m, k)
8
+ if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = {
10
+ enumerable: true,
11
+ get: function () {
12
+ return m[k]
13
+ }
14
+ }
15
+ }
16
+ Object.defineProperty(o, k2, desc)
17
+ }
18
+ : function (o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k
20
+ o[k2] = m[k]
21
+ })
22
+ var __setModuleDefault =
23
+ (this && this.__setModuleDefault) ||
24
+ (Object.create
25
+ ? function (o, v) {
26
+ Object.defineProperty(o, 'default', { enumerable: true, value: v })
27
+ }
28
+ : function (o, v) {
29
+ o['default'] = v
30
+ })
31
+ var __importStar =
32
+ (this && this.__importStar) ||
33
+ (function () {
34
+ var ownKeys = function (o) {
35
+ ownKeys =
36
+ Object.getOwnPropertyNames ||
37
+ function (o) {
38
+ var ar = []
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k
40
+ return ar
41
+ }
42
+ return ownKeys(o)
43
+ }
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod
46
+ var result = {}
47
+ if (mod != null)
48
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== 'default') __createBinding(result, mod, k[i])
49
+ __setModuleDefault(result, mod)
50
+ return result
51
+ }
52
+ })()
53
+ Object.defineProperty(exports, '__esModule', { value: true })
54
+ exports.makeLibSignalRepository = makeLibSignalRepository
55
+ const rb = require('whatsapp-rust-bridge-baron')
56
+ const lru_cache_1 = require('lru-cache')
57
+ const Utils_1 = require('../Utils')
58
+ const WABinary_1 = require('../WABinary')
59
+ const sender_key_name_1 = require('./Group/sender-key-name')
60
+ const sender_key_record_1 = require('./Group/sender-key-record')
61
+ const Group_1 = require('./Group')
62
+ const lid_mapping_1 = require('./lid-mapping')
63
+ /** Extract identity key from PreKeyWhisperMessage for identity change detection */
64
+ function extractIdentityFromPkmsg(ciphertext) {
65
+ try {
66
+ if (!ciphertext || ciphertext.length < 2) {
67
+ return undefined
68
+ }
69
+ // Version byte check (version 3)
70
+ const version = ciphertext[0]
71
+ if ((version & 0xf) !== 3) {
72
+ return undefined
73
+ }
74
+ // Parse protobuf (skip version byte)
75
+ const identityKeyArr = rb.getPreKeyMessageIdentityKey(ciphertext)
76
+ if (identityKeyArr) {
77
+ return identityKeyArr
78
+ }
79
+ return undefined
80
+ } catch {
81
+ return undefined
82
+ }
83
+ }
84
+ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
85
+ const lidMapping = new lid_mapping_1.LIDMappingStore(auth.keys, logger, pnToLIDFunc)
86
+ const storage = signalStorage(auth, lidMapping)
87
+ const parsedKeys = auth.keys
88
+ const migratedSessionCache = new lru_cache_1.LRUCache({
89
+ ttl: 3 * 24 * 60 * 60 * 1000, // 7 days
90
+ ttlAutopurge: true,
91
+ updateAgeOnGet: true
92
+ })
93
+ const repository = {
94
+ decryptGroupMessage({ group, authorJid, msg }) {
95
+ const senderName = jidToSignalSenderKeyName(group, authorJid)
96
+ const cipher = new Group_1.GroupCipher(storage, senderName)
97
+ // Use transaction to ensure atomicity
98
+ return parsedKeys.transaction(async () => {
99
+ return cipher.decrypt(msg)
100
+ }, group)
101
+ },
102
+ async processSenderKeyDistributionMessage({ item, authorJid }) {
103
+ const builder = new Group_1.GroupSessionBuilder(storage)
104
+ if (!item.groupId) {
105
+ throw new Error('Group ID is required for sender key distribution message')
106
+ }
107
+ const senderName = jidToSignalSenderKeyName(item.groupId, authorJid)
108
+ const senderMsg = new Group_1.SenderKeyDistributionMessage(
109
+ null,
110
+ null,
111
+ null,
112
+ null,
113
+ item.axolotlSenderKeyDistributionMessage
114
+ )
115
+ const senderNameStr = senderName.toString()
116
+ const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
117
+ if (!senderKey) {
118
+ await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord())
119
+ }
120
+ return parsedKeys.transaction(async () => {
121
+ const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
122
+ if (!senderKey) {
123
+ await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord())
124
+ }
125
+ await builder.process(senderName, senderMsg)
126
+ }, item.groupId)
127
+ },
128
+ async decryptMessage({ jid, type, ciphertext }) {
129
+ const addr = jidToSignalProtocolAddress(jid)
130
+ const session = new rb.SessionCipher(storage, addr)
131
+ // Extract and save sender's identity key before decryption for identity change detection
132
+ if (type === 'pkmsg') {
133
+ const identityKey = extractIdentityFromPkmsg(ciphertext)
134
+ if (identityKey) {
135
+ const addrStr = addr.toString()
136
+ const identityChanged = await storage.saveIdentity(addrStr, identityKey)
137
+ if (identityChanged) {
138
+ logger.info({ jid, addr: addrStr }, 'identity key changed or new contact, session will be re-established')
139
+ }
140
+ }
141
+ }
142
+ async function doDecrypt() {
143
+ let result
144
+ switch (type) {
145
+ case 'pkmsg':
146
+ result = await session.decryptPreKeyWhisperMessage(ciphertext)
147
+ break
148
+ case 'msg':
149
+ result = await session.decryptWhisperMessage(ciphertext)
150
+ break
151
+ }
152
+ return result
153
+ }
154
+ // If it's not a sync message, we need to ensure atomicity
155
+ // For regular messages, we use a transaction to ensure atomicity
156
+ return parsedKeys.transaction(async () => {
157
+ return await doDecrypt()
158
+ }, jid)
159
+ },
160
+ async encryptMessage({ jid, data }) {
161
+ const addr = jidToSignalProtocolAddress(jid)
162
+ const cipher = new rb.SessionCipher(storage, addr)
163
+ // Use transaction to ensure atomicity
164
+ return parsedKeys.transaction(async () => {
165
+ const { type: sigType, body } = await cipher.encrypt(data)
166
+ const type = sigType === 3 ? 'pkmsg' : 'msg'
167
+ return { type, ciphertext: Buffer.from(body, 'binary') }
168
+ }, jid)
169
+ },
170
+ async encryptGroupMessage({ group, meId, data }) {
171
+ const senderName = jidToSignalSenderKeyName(group, meId)
172
+ const builder = new Group_1.GroupSessionBuilder(storage)
173
+ const senderNameStr = senderName.toString()
174
+ return parsedKeys.transaction(async () => {
175
+ const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
176
+ if (!senderKey) {
177
+ await storage.storeSenderKey(senderName, new sender_key_record_1.SenderKeyRecord())
178
+ }
179
+ const senderKeyDistributionMessage = await builder.create(senderName)
180
+ const session = new Group_1.GroupCipher(storage, senderName)
181
+ const ciphertext = await session.encrypt(data)
182
+ return {
183
+ ciphertext,
184
+ senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
185
+ }
186
+ }, group)
187
+ },
188
+ async injectE2ESession({ jid, session }) {
189
+ logger.trace({ jid }, 'injecting E2EE session')
190
+ const cipher = new rb.SessionBuilder(storage, jidToSignalProtocolAddress(jid))
191
+ return parsedKeys.transaction(async () => {
192
+ await cipher.initOutgoing(session)
193
+ }, jid)
194
+ },
195
+ jidToSignalProtocolAddress(jid) {
196
+ return jidToSignalProtocolAddress(jid).toString()
197
+ },
198
+ // Optimized direct access to LID mapping store
199
+ lidMapping,
200
+ async validateSession(jid) {
201
+ try {
202
+ const addr = jidToSignalProtocolAddress(jid)
203
+ const sessBytes = await storage.loadSession(addr.toString())
204
+ if (!sessBytes) return { exists: false, reason: 'no session' }
205
+ const session = rb.SessionRecord.deserialize(sessBytes)
206
+ if (!session.haveOpenSession()) return { exists: false, reason: 'no open session' }
207
+ return { exists: true }
208
+ } catch (error) {
209
+ return { exists: false, reason: 'validation error' }
210
+ }
211
+ },
212
+ async deleteSession(jids) {
213
+ if (!jids.length) return
214
+ // Convert JIDs to signal addresses and prepare for bulk deletion
215
+ const sessionUpdates = {}
216
+ jids.forEach(jid => {
217
+ const addr = jidToSignalProtocolAddress(jid)
218
+ sessionUpdates[addr.toString()] = null
219
+ })
220
+ // Single transaction for all deletions
221
+ return parsedKeys.transaction(async () => {
222
+ await auth.keys.set({ session: sessionUpdates })
223
+ }, `delete-${jids.length}-sessions`)
224
+ },
225
+ async migrateSession(fromJid, toJid) {
226
+ // TODO: use usync to handle this entire mess
227
+ if (!fromJid || (!(0, WABinary_1.isLidUser)(toJid) && !(0, WABinary_1.isHostedLidUser)(toJid)))
228
+ return { migrated: 0, skipped: 0, total: 0 }
229
+ // Only support PN to LID migration
230
+ if (!(0, WABinary_1.isPnUser)(fromJid) && !(0, WABinary_1.isHostedPnUser)(fromJid)) {
231
+ return { migrated: 0, skipped: 0, total: 1 }
232
+ }
233
+ const { user } = (0, WABinary_1.jidDecode)(fromJid)
234
+ logger.debug({ fromJid }, 'bulk device migration - loading all user devices')
235
+ // Get user's device list from storage
236
+ const { [user]: userDevices } = await parsedKeys.get('device-list', [user])
237
+ if (!userDevices) {
238
+ return { migrated: 0, skipped: 0, total: 0 }
239
+ }
240
+ const { device: fromDevice } = (0, WABinary_1.jidDecode)(fromJid)
241
+ const fromDeviceStr = fromDevice?.toString() || '0'
242
+ if (!userDevices.includes(fromDeviceStr)) {
243
+ userDevices.push(fromDeviceStr)
244
+ }
245
+ // Filter out cached devices before database fetch
246
+ const uncachedDevices = userDevices.filter(device => {
247
+ const deviceKey = `${user}.${device}`
248
+ return !migratedSessionCache.has(deviceKey)
249
+ })
250
+ // Bulk check session existence only for uncached devices
251
+ const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`)
252
+ const existingSessions = await parsedKeys.get('session', deviceSessionKeys)
253
+ // Step 3: Convert existing sessions to JIDs (only migrate sessions that exist)
254
+ const deviceJids = []
255
+ for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
256
+ if (sessionData) {
257
+ // Session exists in storage
258
+ const deviceStr = sessionKey.split('.')[1]
259
+ if (!deviceStr) continue
260
+ const deviceNum = parseInt(deviceStr, 10)
261
+ let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`
262
+ if (deviceNum === 99) {
263
+ jid = `${user}:99@hosted`
264
+ }
265
+ deviceJids.push(jid)
266
+ }
267
+ }
268
+ logger.debug(
269
+ {
270
+ fromJid,
271
+ totalDevices: userDevices.length,
272
+ devicesWithSessions: deviceJids.length,
273
+ devices: deviceJids
274
+ },
275
+ 'bulk device migration complete - all user devices processed'
276
+ )
277
+ // Single transaction for all migrations
278
+ return parsedKeys.transaction(
279
+ async () => {
280
+ const migrationOps = deviceJids.map(jid => {
281
+ const lidWithDevice = (0, WABinary_1.transferDevice)(jid, toJid)
282
+ const fromDecoded = (0, WABinary_1.jidDecode)(jid)
283
+ const toDecoded = (0, WABinary_1.jidDecode)(lidWithDevice)
284
+ return {
285
+ fromJid: jid,
286
+ toJid: lidWithDevice,
287
+ pnUser: fromDecoded.user,
288
+ lidUser: toDecoded.user,
289
+ deviceId: fromDecoded.device || 0,
290
+ fromAddr: jidToSignalProtocolAddress(jid),
291
+ toAddr: jidToSignalProtocolAddress(lidWithDevice)
292
+ }
293
+ })
294
+ const totalOps = migrationOps.length
295
+ let migratedCount = 0
296
+ // Bulk fetch PN sessions - already exist (verified during device discovery)
297
+ const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())))
298
+ const pnSessions = await parsedKeys.get('session', pnAddrStrings)
299
+ // Prepare bulk session updates (PN → LID migration + deletion)
300
+ const sessionUpdates = {}
301
+ for (const op of migrationOps) {
302
+ const pnAddrStr = op.fromAddr.toString()
303
+ const lidAddrStr = op.toAddr.toString()
304
+ const pnSession = pnSessions[pnAddrStr]
305
+ if (pnSession) {
306
+ // Session exists (guaranteed from device discovery)
307
+ const fromSession = rb.SessionRecord.deserialize(pnSession)
308
+ if (fromSession.haveOpenSession()) {
309
+ // Queue for bulk update: copy to LID, delete from PN
310
+ sessionUpdates[lidAddrStr] = fromSession.serialize()
311
+ sessionUpdates[pnAddrStr] = null
312
+ migratedCount++
313
+ }
314
+ }
315
+ }
316
+ // Single bulk session update for all migrations
317
+ if (Object.keys(sessionUpdates).length > 0) {
318
+ await parsedKeys.set({ session: sessionUpdates })
319
+ logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete')
320
+ // Cache device-level migrations
321
+ for (const op of migrationOps) {
322
+ if (sessionUpdates[op.toAddr.toString()]) {
323
+ const deviceKey = `${op.pnUser}.${op.deviceId}`
324
+ migratedSessionCache.set(deviceKey, true)
325
+ }
326
+ }
327
+ }
328
+ const skippedCount = totalOps - migratedCount
329
+ return { migrated: migratedCount, skipped: skippedCount, total: totalOps }
330
+ },
331
+ `migrate-${deviceJids.length}-sessions-${(0, WABinary_1.jidDecode)(toJid)?.user}`
332
+ )
333
+ }
334
+ }
335
+ return repository
336
+ }
337
+ const jidToSignalProtocolAddress = jid => {
338
+ const decoded = (0, WABinary_1.jidDecode)(jid)
339
+ const { user, device, server, domainType } = decoded
340
+ if (!user) {
341
+ throw new Error(
342
+ `JID decoded but user is empty: "${jid}" -> user: "${user}", server: "${server}", device: ${device}`
343
+ )
344
+ }
345
+ const signalUser = domainType !== WABinary_1.WAJIDDomains.WHATSAPP ? `${user}_${domainType}` : user
346
+ const finalDevice = device || 0
347
+ if (device === 99 && decoded.server !== 'hosted' && decoded.server !== 'hosted.lid') {
348
+ throw new Error('Unexpected non-hosted device JID with device 99. This ID seems invalid. ID:' + jid)
349
+ }
350
+ return new rb.ProtocolAddress(signalUser, finalDevice)
351
+ }
352
+ const jidToSignalSenderKeyName = (group, user) => {
353
+ return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user))
354
+ }
355
+ function signalStorage({ creds, keys }, lidMapping) {
356
+ // Shared function to resolve PN signal address to LID if mapping exists
357
+ const resolveLIDSignalAddress = async id => {
358
+ if (id.includes('.')) {
359
+ const [deviceId, device] = id.split('.')
360
+ const [user, domainType_] = deviceId.split('_')
361
+ const domainType = parseInt(domainType_ || '0', 10)
362
+ if (
363
+ domainType === WABinary_1.WAJIDDomains.LID ||
364
+ domainType === WABinary_1.WAJIDDomains.HOSTED_LID ||
365
+ user.includes('-')
366
+ )
367
+ return id
368
+ const pnJid = `${user}${device !== '0' ? `:${device}` : ''}@${domainType === WABinary_1.WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}`
369
+ const lidForPN = await lidMapping.getLIDForPN(pnJid)
370
+ if (lidForPN) {
371
+ const lidAddr = jidToSignalProtocolAddress(lidForPN)
372
+ return lidAddr.toString()
373
+ }
374
+ }
375
+ return id
376
+ }
377
+ return {
378
+ loadSession: async id => {
379
+ try {
380
+ const wireJid = await resolveLIDSignalAddress(id)
381
+ const keysToFetch = wireJid !== id ? [wireJid, id] : [id]
382
+ const fetched = await keys.get('session', keysToFetch)
383
+ const sess = fetched[wireJid] || fetched[id]
384
+ if (!sess) return null
385
+ // Detect old libsignal-node JSON format → treat as no session
386
+ if (typeof sess === 'object' && !Buffer.isBuffer(sess) && !ArrayBuffer.isView(sess) && sess._sessions) {
387
+ return null
388
+ }
389
+ // Return raw bytes — Rust storage adapter expects Uint8Array, not SessionRecord object
390
+ return Buffer.isBuffer(sess) ? sess : Buffer.from(sess)
391
+ } catch {
392
+ return null
393
+ }
394
+ },
395
+ storeSession: async (id, session) => {
396
+ // Store under raw ID so it's always findable regardless of LID mapping state
397
+ await keys.set({ session: { [id]: session.serialize() } })
398
+ },
399
+ isTrustedIdentity: () => {
400
+ return true // TOFU - Trust on First Use (same as WhatsApp Web)
401
+ },
402
+ loadIdentityKey: async id => {
403
+ const wireJid = await resolveLIDSignalAddress(id)
404
+ const { [wireJid]: key } = await keys.get('identity-key', [wireJid])
405
+ return key || undefined
406
+ },
407
+ saveIdentity: async (id, identityKey) => {
408
+ const wireJid = await resolveLIDSignalAddress(id)
409
+ const { [wireJid]: existingKey } = await keys.get('identity-key', [wireJid])
410
+ const keysMatch =
411
+ existingKey &&
412
+ existingKey.length === identityKey.length &&
413
+ existingKey.every((byte, i) => byte === identityKey[i])
414
+ if (existingKey && !keysMatch) {
415
+ // Identity changed - clear session and update key
416
+ await keys.set({
417
+ session: { [wireJid]: null },
418
+ 'identity-key': { [wireJid]: identityKey }
419
+ })
420
+ return true
421
+ }
422
+ if (!existingKey) {
423
+ // New contact - Trust on First Use (TOFU)
424
+ await keys.set({ 'identity-key': { [wireJid]: identityKey } })
425
+ return true
426
+ }
427
+ return false
428
+ },
429
+ loadPreKey: async id => {
430
+ const keyId = id.toString()
431
+ const { [keyId]: key } = await keys.get('pre-key', [keyId])
432
+ if (key) {
433
+ return {
434
+ privKey: Buffer.from(key.private),
435
+ pubKey: Buffer.from(key.public)
436
+ }
437
+ }
438
+ },
439
+ removePreKey: id => keys.set({ 'pre-key': { [id]: null } }),
440
+ loadSignedPreKey: () => {
441
+ const key = creds.signedPreKey
442
+ return {
443
+ privKey: Buffer.from(key.keyPair.private),
444
+ pubKey: Buffer.from(key.keyPair.public),
445
+ signature: key.signature ? Buffer.from(key.signature) : undefined
446
+ }
447
+ },
448
+ loadSenderKey: async senderKeyName => {
449
+ const keyId = senderKeyName.toString()
450
+ const { [keyId]: key } = await keys.get('sender-key', [keyId])
451
+ if (key) {
452
+ return sender_key_record_1.SenderKeyRecord.deserialize(key)
453
+ }
454
+ return new sender_key_record_1.SenderKeyRecord()
455
+ },
456
+ storeSenderKey: async (senderKeyName, key) => {
457
+ const keyId = senderKeyName.toString()
458
+ const serialized = JSON.stringify(key.serialize())
459
+ await keys.set({ 'sender-key': { [keyId]: Buffer.from(serialized, 'utf-8') } })
460
+ },
461
+ getOurRegistrationId: () => creds.registrationId,
462
+ getOurIdentity: () => {
463
+ const { signedIdentityKey } = creds
464
+ return {
465
+ privKey: Buffer.from(signedIdentityKey.private),
466
+ pubKey: Buffer.from((0, Utils_1.generateSignalPubKey)(signedIdentityKey.public))
467
+ }
468
+ }
469
+ }
470
+ }