@badzz88/baileys 8.5.3 → 8.5.4

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 (110) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +1256 -75
  3. package/WAProto/index.d.ts +36042 -19649
  4. package/WAProto/index.js +181990 -135645
  5. package/engine-requirements.js +7 -15
  6. package/lib/Defaults/index.js +22 -17
  7. package/lib/Signal/Group/group_cipher.js +5 -5
  8. package/lib/Signal/Group/keyhelper.js +4 -4
  9. package/lib/Signal/Group/sender-chain-key.js +2 -2
  10. package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/lib/Signal/Group/sender-key-message.js +3 -3
  12. package/lib/Signal/Group/sender-key-record.js +1 -1
  13. package/lib/Signal/Group/sender-message-key.js +5 -5
  14. package/lib/Signal/libsignal.js +39 -59
  15. package/lib/Signal/lid-mapping.js +28 -10
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +3 -11
  18. package/lib/Socket/chats.js +668 -319
  19. package/lib/Socket/communities.js +85 -89
  20. package/lib/Socket/graphql.js +435 -228
  21. package/lib/Socket/groups.js +132 -211
  22. package/lib/Socket/index.js +9 -7
  23. package/lib/Socket/interactive-handler.js +117 -60
  24. package/lib/Socket/interop.js +56 -175
  25. package/lib/Socket/managed-account.js +79 -48
  26. package/lib/Socket/messages-recv.js +898 -340
  27. package/lib/Socket/messages-send.js +462 -160
  28. package/lib/Socket/mex.js +40 -53
  29. package/lib/Socket/newsletter.js +291 -295
  30. package/lib/Socket/privacy.js +77 -265
  31. package/lib/Socket/registration.js +164 -157
  32. package/lib/Socket/socket.js +181 -199
  33. package/lib/Socket/username.js +144 -227
  34. package/lib/Store/make-cache-manager-store.js +2 -2
  35. package/lib/Store/make-in-memory-store.js +25 -141
  36. package/lib/Types/Auth.js +3 -3
  37. package/lib/Types/Label.js +1 -1
  38. package/lib/Types/LabelAssociation.js +1 -1
  39. package/lib/Types/Newsletter.js +96 -65
  40. package/lib/Types/State.js +4 -4
  41. package/lib/Types/index.js +1 -1
  42. package/lib/Utils/auth-utils.js +52 -57
  43. package/lib/Utils/browser-utils.js +1 -1
  44. package/lib/Utils/business.js +2 -6
  45. package/lib/Utils/chat-utils.js +102 -38
  46. package/lib/Utils/crypto.js +54 -84
  47. package/lib/Utils/decode-wa-message.js +316 -83
  48. package/lib/Utils/event-buffer.js +37 -61
  49. package/lib/Utils/generics.js +157 -103
  50. package/lib/Utils/group-history.js +3 -12
  51. package/lib/Utils/history.js +15 -15
  52. package/lib/Utils/index.js +1 -5
  53. package/lib/Utils/link-preview.js +3 -8
  54. package/lib/Utils/lt-hash.js +2 -35
  55. package/lib/Utils/make-mutex.js +1 -1
  56. package/lib/Utils/message-inspect.js +393 -0
  57. package/lib/Utils/message-retry-manager.js +27 -92
  58. package/lib/Utils/messages-media.js +159 -130
  59. package/lib/Utils/messages.js +144 -566
  60. package/lib/Utils/meta-ai-msmsg.js +62 -202
  61. package/lib/Utils/noise-handler.js +19 -21
  62. package/lib/Utils/offline-node-processor.js +3 -8
  63. package/lib/Utils/pre-key-manager.js +13 -23
  64. package/lib/Utils/process-message.js +197 -106
  65. package/lib/Utils/reporting-utils.js +2 -2
  66. package/lib/Utils/signal.js +28 -63
  67. package/lib/Utils/stanza-ack.js +39 -12
  68. package/lib/Utils/sync-action-utils.js +4 -7
  69. package/lib/Utils/tc-token-utils.js +20 -25
  70. package/lib/Utils/use-multi-file-auth-state.js +30 -14
  71. package/lib/Utils/validate-connection.js +59 -19
  72. package/lib/WABinary/decode.js +50 -16
  73. package/lib/WABinary/encode.js +54 -224
  74. package/lib/WABinary/generic-utils.js +7 -97
  75. package/lib/WABinary/jid-utils.js +27 -14
  76. package/lib/WAM/encode.js +7 -7
  77. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +58 -1
  78. package/lib/WAUSync/Protocols/USyncContactProtocol.js +7 -1
  79. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +13 -5
  80. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +1 -4
  81. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +20 -7
  82. package/lib/WAUSync/Protocols/USyncNewsletterProtocol.js +865 -0
  83. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  84. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  85. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -2
  86. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  87. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +2 -1
  88. package/lib/WAUSync/Protocols/index.js +1 -0
  89. package/lib/WAUSync/USyncBackoff.js +26 -0
  90. package/lib/WAUSync/USyncQuery.js +77 -6
  91. package/lib/WAUSync/USyncUser.js +16 -8
  92. package/lib/WAUSync/index.js +1 -0
  93. package/lib/antiban.js +608 -854
  94. package/lib/index.js +1 -1
  95. package/package.json +16 -20
  96. package/lib/Socket/luxu.js +0 -387
  97. package/lib/Socket/text-router.js +0 -83
  98. package/lib/Store/keyed-db.js +0 -108
  99. package/lib/Types/Mex.js +0 -112
  100. package/lib/Utils/command-loader.d.ts +0 -31
  101. package/lib/Utils/command-loader.js +0 -100
  102. package/lib/Utils/companion-reg-client-utils.js +0 -42
  103. package/lib/Utils/curve25519-js.js +0 -275
  104. package/lib/Utils/native-bridge.js +0 -82
  105. package/lib/Utils/session-pool.d.ts +0 -16
  106. package/lib/Utils/session-pool.js +0 -94
  107. package/lib/Utils/sticker.d.ts +0 -17
  108. package/lib/Utils/sticker.js +0 -145
  109. package/lib/Utils/view-once-cache.d.ts +0 -9
  110. package/lib/Utils/view-once-cache.js +0 -79
@@ -1,18 +1,10 @@
1
- const major = parseInt(process.versions.node.split(".")[0], 10);
1
+ const major = parseInt(process.versions.node.split('.')[0], 10);
2
2
 
3
3
  if (major < 20) {
4
- console.error(`
5
- ━━━━━━━━━━━━━━━━━━━━━━━━━━
6
- 🚫 Unsupported Node.js Version
7
-
8
- • Current : v${process.versions.node}
9
- • Required : v20.0.0+
10
-
11
- This package uses features available only in
12
- Node.js 20 or newer.
13
-
14
- Please update Node.js and try again.
15
- ━━━━━━━━━━━━━━━━━━━━━━━━━━
16
- `);
4
+ console.error(
5
+ `\n❌ This package requires Node.js 20+ to run reliably.\n` +
6
+ ` You are using Node.js ${process.versions.node}.\n` +
7
+ ` Please upgrade to Node.js 20+ to proceed.\n`
8
+ );
17
9
  process.exit(1);
18
- }
10
+ }
@@ -26,6 +26,8 @@ exports.VERSION =
26
26
  exports.PLACEHOLDER_MAX_AGE_SECONDS =
27
27
  exports.STATUS_EXPIRY_SECONDS =
28
28
  exports.WA_DEFAULT_EPHEMERAL =
29
+ exports.WA_ADV_HOSTED_KEY_INDEX_LIST_SIG_PREFIX =
30
+ exports.WA_ADV_KEY_INDEX_LIST_SIG_PREFIX =
29
31
  exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX =
30
32
  exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX =
31
33
  exports.WA_ADV_DEVICE_SIG_PREFIX =
@@ -42,7 +44,8 @@ const index_js_1 = require('../../WAProto/index.js')
42
44
  const libsignal_1 = require('../Signal/libsignal')
43
45
  const browser_utils_1 = require('../Utils/browser-utils')
44
46
  const logger_1 = __importDefault(require('../Utils/logger'))
45
- const version = [2, 3000, 1041467552]
47
+
48
+ const version = [2, 3000, 1044798975]
46
49
  exports.VERSION = version
47
50
  exports.UNAUTHORIZED_CODES = [401, 403, 419]
48
51
  exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com'
@@ -55,16 +58,19 @@ exports.WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0])
55
58
  exports.WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1])
56
59
  exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5])
57
60
  exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6])
61
+
62
+ exports.WA_ADV_KEY_INDEX_LIST_SIG_PREFIX = Buffer.from([6, 2])
63
+ exports.WA_ADV_HOSTED_KEY_INDEX_LIST_SIG_PREFIX = Buffer.from([6, 7])
58
64
  exports.WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60
59
- /** Status messages older than 24 hours are considered expired */
65
+
60
66
  exports.STATUS_EXPIRY_SECONDS = 24 * 60 * 60
61
- /** WA Web enforces a 14-day maximum age for placeholder resend requests */
67
+
62
68
  exports.PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60
63
69
  exports.NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0'
64
70
  exports.DICT_VERSION = 3
65
71
  exports.KEY_BUNDLE_TYPE = Buffer.from([5])
66
- exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION]) // last is "DICT_VERSION"
67
- /** from: https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url */
72
+ exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION])
73
+
68
74
  exports.URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g
69
75
  exports.WA_CERT_DETAILS = {
70
76
  SERIAL: 0,
@@ -83,11 +89,10 @@ exports.PROCESSABLE_HISTORY_TYPES = [
83
89
  ]
84
90
  exports.DEFAULT_CONNECTION_CONFIG = {
85
91
  version: version,
86
- browser: browser_utils_1.Browsers.windows('Firefox'),
92
+ browser: browser_utils_1.Browsers.windows('Desktop'),
87
93
  waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
88
94
  connectTimeoutMs: 20000,
89
95
  keepAliveIntervalMs: 30000,
90
- aiLabel: true,
91
96
  logger: logger_1.default.child({ class: 'baileys' }),
92
97
  emitOwnEvents: true,
93
98
  defaultQueryTimeoutMs: 60000,
@@ -168,17 +173,17 @@ exports.MEDIA_HKDF_KEY_MAPPING = {
168
173
  exports.MEDIA_KEYS = Object.keys(exports.MEDIA_PATH_MAP)
169
174
  exports.MIN_PREKEY_COUNT = 5
170
175
  exports.INITIAL_PREKEY_COUNT = 812
171
- exports.UPLOAD_TIMEOUT = 30000 // 30 seconds
172
- exports.MIN_UPLOAD_INTERVAL = 5000 // 5 seconds minimum between uploads
176
+ exports.UPLOAD_TIMEOUT = 30000
177
+ exports.MIN_UPLOAD_INTERVAL = 5000
173
178
  exports.DEFAULT_CACHE_TTLS = {
174
- SIGNAL_STORE: 5 * 60, // 5 minutes
175
- MSG_RETRY: 60 * 60, // 1 hour
176
- CALL_OFFER: 5 * 60, // 5 minutes
177
- USER_DEVICES: 5 * 60, // 5 minutes
178
- GROUP_METADATA: 30 * 60, // 30 minutes
179
- CALL_SESSION: 10 * 60, // 10 minutes
180
- USYNC_RESULTS: 10 * 60, // 10 minutes
181
- IDENTITY_PROOF: 60 * 60 // 1 hour
179
+ SIGNAL_STORE: 5 * 60,
180
+ MSG_RETRY: 60 * 60,
181
+ CALL_OFFER: 5 * 60,
182
+ USER_DEVICES: 5 * 60,
183
+ GROUP_METADATA: 30 * 60,
184
+ CALL_SESSION: 10 * 60,
185
+ USYNC_RESULTS: 10 * 60,
186
+ IDENTITY_PROOF: 60 * 60
182
187
  }
183
188
  exports.TimeMs = {
184
189
  Second: 1000,
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.GroupCipher = void 0
4
- const Crypto_1 = require('../../Utils/crypto')
4
+ const rb = require('whatsapp-rust-bridge')
5
5
  const sender_key_message_1 = require('./sender-key-message')
6
6
  class GroupCipher {
7
7
  constructor(senderKeyStore, senderKeyName) {
@@ -73,15 +73,15 @@ class GroupCipher {
73
73
  }
74
74
  async getPlainText(iv, key, ciphertext) {
75
75
  try {
76
- return Buffer.from(Crypto_1.aesDecryptWithIV(ciphertext, key, iv))
77
- } catch (e) {
76
+ return Buffer.from(rb.aesDecryptWithIV(ciphertext, key, iv))
77
+ } catch {
78
78
  throw new Error('InvalidMessageException')
79
79
  }
80
80
  }
81
81
  async getCipherText(iv, key, plaintext) {
82
82
  try {
83
- return Buffer.from(Crypto_1.aesEncrypWithIV(plaintext, key, iv))
84
- } catch (e) {
83
+ return Buffer.from(rb.aesEncrypWithIV(plaintext, key, iv))
84
+ } catch {
85
85
  throw new Error('InvalidMessageException')
86
86
  }
87
87
  }
@@ -55,7 +55,7 @@ exports.generateSenderKey = generateSenderKey
55
55
  exports.generateSenderKeyId = generateSenderKeyId
56
56
  exports.generateSenderSigningKey = generateSenderSigningKey
57
57
  const nodeCrypto = __importStar(require('crypto'))
58
- const Crypto_1 = require('../../Utils/crypto')
58
+ const rb = require('whatsapp-rust-bridge')
59
59
  function generateSenderKey() {
60
60
  return nodeCrypto.randomBytes(32)
61
61
  }
@@ -64,10 +64,10 @@ function generateSenderKeyId() {
64
64
  }
65
65
  function generateSenderSigningKey(key) {
66
66
  if (!key) {
67
- key = Crypto_1.Curve.generateKeyPair()
67
+ key = rb.generateKeyPair()
68
68
  }
69
69
  return {
70
- public: Crypto_1.generateSignalPubKey(key.public),
71
- private: Buffer.from(key.private)
70
+ public: Buffer.from(key.pubKey),
71
+ private: Buffer.from(key.privKey)
72
72
  }
73
73
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderChainKey = void 0
4
- const Crypto_1 = require('../../Utils/crypto')
4
+ const rb = require('whatsapp-rust-bridge')
5
5
  const sender_message_key_1 = require('./sender-message-key')
6
6
  class SenderChainKey {
7
7
  constructor(iteration, chainKey) {
@@ -26,7 +26,7 @@ class SenderChainKey {
26
26
  return this.chainKey
27
27
  }
28
28
  getDerivative(seed, key) {
29
- return Buffer.from(Crypto_1.hmacSign(seed, key))
29
+ return Buffer.from(rb.hmacSign(seed, key))
30
30
  }
31
31
  }
32
32
  exports.SenderChainKey = SenderChainKey
@@ -22,7 +22,7 @@ class SenderKeyDistributionMessage extends ciphertext_message_1.CiphertextMessag
22
22
  ? Buffer.from(distributionMessage.signingKey, 'base64')
23
23
  : distributionMessage.signingKey
24
24
  } catch (e) {
25
- throw new Error(String(e))
25
+ throw e instanceof Error ? e : new Error(String(e))
26
26
  }
27
27
  } else {
28
28
  const version = this.intsToByteHighAndLow(this.CURRENT_VERSION, this.CURRENT_VERSION)
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderKeyMessage = void 0
4
- const Crypto_1 = require('../../Utils/crypto')
4
+ const rb = require('whatsapp-rust-bridge')
5
5
  const index_js_1 = require('../../../WAProto/index.js')
6
6
  const ciphertext_message_1 = require('./ciphertext-message')
7
7
  class SenderKeyMessage extends ciphertext_message_1.CiphertextMessage {
@@ -53,11 +53,11 @@ class SenderKeyMessage extends ciphertext_message_1.CiphertextMessage {
53
53
  verifySignature(signatureKey) {
54
54
  const part1 = this.serialized.slice(0, this.serialized.length - this.SIGNATURE_LENGTH)
55
55
  const part2 = this.serialized.slice(-1 * this.SIGNATURE_LENGTH)
56
- const res = Crypto_1.Curve.verify(signatureKey, part1, part2)
56
+ const res = rb.verifySignature(signatureKey, part1, part2)
57
57
  if (!res) throw new Error('Invalid signature!')
58
58
  }
59
59
  getSignature(signatureKey, serialized) {
60
- return Buffer.from(Crypto_1.Curve.sign(signatureKey, serialized))
60
+ return Buffer.from(rb.calculateSignature(signatureKey, serialized))
61
61
  }
62
62
  serialize() {
63
63
  return this.serialized
@@ -36,7 +36,7 @@ class SenderKeyRecord {
36
36
  return this.senderKeyStates.map(state => state.getStructure())
37
37
  }
38
38
  static deserialize(data) {
39
- const str = Buffer.from(data).toString('utf-8')
39
+ const str = Buffer.from(data).toString('utf8')
40
40
  const parsed = JSON.parse(str, generics_1.BufferJSON.reviver)
41
41
  return new SenderKeyRecord(parsed)
42
42
  }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderMessageKey = void 0
4
- const Crypto_1 = require('../../Utils/crypto')
4
+ const rb = require('whatsapp-rust-bridge')
5
5
  class SenderMessageKey {
6
6
  constructor(iteration, seed) {
7
- // HKDF(seed, 96, salt=0x00*32, info='WhisperGroup') → split into 3×32 byte chunks
8
- const derived = Buffer.from(Crypto_1.hkdf(seed, 96, { salt: Buffer.alloc(32), info: 'WhisperGroup' }))
7
+
8
+ const derived = Buffer.from(rb.hkdf(seed, 96, { salt: Buffer.alloc(32), info: 'WhisperGroup' }))
9
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
10
+ keys.set(new Uint8Array(derived.slice(16, 32)))
11
+ keys.set(new Uint8Array(derived.slice(32, 48)), 16)
12
12
  this.iv = Buffer.from(derived.slice(0, 16))
13
13
  this.cipherKey = Buffer.from(keys.buffer)
14
14
  this.iteration = iteration
@@ -52,7 +52,7 @@ var __importStar =
52
52
  })()
53
53
  Object.defineProperty(exports, '__esModule', { value: true })
54
54
  exports.makeLibSignalRepository = makeLibSignalRepository
55
- const rb = require('../Utils/native-bridge').loadRustBridge()
55
+ const rb = require('whatsapp-rust-bridge')
56
56
  const lru_cache_1 = require('lru-cache')
57
57
  const Utils_1 = require('../Utils')
58
58
  const WABinary_1 = require('../WABinary')
@@ -60,18 +60,18 @@ const sender_key_name_1 = require('./Group/sender-key-name')
60
60
  const sender_key_record_1 = require('./Group/sender-key-record')
61
61
  const Group_1 = require('./Group')
62
62
  const lid_mapping_1 = require('./lid-mapping')
63
- /** Extract identity key from PreKeyWhisperMessage for identity change detection */
63
+
64
64
  function extractIdentityFromPkmsg(ciphertext) {
65
65
  try {
66
66
  if (!ciphertext || ciphertext.length < 2) {
67
67
  return undefined
68
68
  }
69
- // Version byte check (version 3)
69
+
70
70
  const version = ciphertext[0]
71
71
  if ((version & 0xf) !== 3) {
72
72
  return undefined
73
73
  }
74
- // Parse protobuf (skip version byte)
74
+
75
75
  const identityKeyArr = rb.getPreKeyMessageIdentityKey(ciphertext)
76
76
  if (identityKeyArr) {
77
77
  return identityKeyArr
@@ -82,17 +82,11 @@ function extractIdentityFromPkmsg(ciphertext) {
82
82
  }
83
83
  }
84
84
  function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
85
- if (!rb) {
86
- throw new Error(
87
- 'The Signal session (Double Ratchet encryption) requires the "whatsapp-rust-bridge" native ' +
88
- 'module, which failed to load. Make sure it is installed: npm install whatsapp-rust-bridge@0.5.4'
89
- )
90
- }
91
85
  const lidMapping = new lid_mapping_1.LIDMappingStore(auth.keys, logger, pnToLIDFunc)
92
86
  const storage = signalStorage(auth, lidMapping)
93
87
  const parsedKeys = auth.keys
94
88
  const migratedSessionCache = new lru_cache_1.LRUCache({
95
- ttl: 3 * 24 * 60 * 60 * 1000, // 7 days
89
+ ttl: 3 * 24 * 60 * 60 * 1000,
96
90
  ttlAutopurge: true,
97
91
  updateAgeOnGet: true
98
92
  })
@@ -100,7 +94,7 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
100
94
  decryptGroupMessage({ group, authorJid, msg }) {
101
95
  const senderName = jidToSignalSenderKeyName(group, authorJid)
102
96
  const cipher = new Group_1.GroupCipher(storage, senderName)
103
- // Use transaction to ensure atomicity
97
+
104
98
  return parsedKeys.transaction(async () => {
105
99
  return cipher.decrypt(msg)
106
100
  }, group)
@@ -134,7 +128,7 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
134
128
  async decryptMessage({ jid, type, ciphertext }) {
135
129
  const addr = jidToSignalProtocolAddress(jid)
136
130
  const session = new rb.SessionCipher(storage, addr)
137
- // Extract and save sender's identity key before decryption for identity change detection
131
+
138
132
  if (type === 'pkmsg') {
139
133
  const identityKey = extractIdentityFromPkmsg(ciphertext)
140
134
  if (identityKey) {
@@ -157,8 +151,8 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
157
151
  }
158
152
  return result
159
153
  }
160
- // If it's not a sync message, we need to ensure atomicity
161
- // For regular messages, we use a transaction to ensure atomicity
154
+
155
+
162
156
  return parsedKeys.transaction(async () => {
163
157
  return await doDecrypt()
164
158
  }, jid)
@@ -166,7 +160,7 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
166
160
  async encryptMessage({ jid, data }) {
167
161
  const addr = jidToSignalProtocolAddress(jid)
168
162
  const cipher = new rb.SessionCipher(storage, addr)
169
- // Use transaction to ensure atomicity
163
+
170
164
  return parsedKeys.transaction(async () => {
171
165
  const { type: sigType, body } = await cipher.encrypt(data)
172
166
  const type = sigType === 3 ? 'pkmsg' : 'msg'
@@ -198,25 +192,10 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
198
192
  await cipher.initOutgoing(session)
199
193
  }, jid)
200
194
  },
201
- async getSessionInfo(jid) {
202
- try {
203
- const addr = jidToSignalProtocolAddress(jid)
204
- const sessBytes = await storage.loadSession(addr.toString())
205
- if (!sessBytes) return null
206
- const session = rb.SessionRecord.deserialize(sessBytes)
207
- const open = session.getOpenSession?.()
208
- const baseKey = open?.indexInfo?.baseKey
209
- const registrationId = open?.registrationId
210
- if (!baseKey || typeof registrationId !== 'number') return null
211
- return { baseKey: new Uint8Array(baseKey), registrationId }
212
- } catch (error) {
213
- return null
214
- }
215
- },
216
195
  jidToSignalProtocolAddress(jid) {
217
196
  return jidToSignalProtocolAddress(jid).toString()
218
197
  },
219
- // Optimized direct access to LID mapping store
198
+
220
199
  lidMapping,
221
200
  async validateSession(jid) {
222
201
  try {
@@ -232,28 +211,28 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
232
211
  },
233
212
  async deleteSession(jids) {
234
213
  if (!jids.length) return
235
- // Convert JIDs to signal addresses and prepare for bulk deletion
214
+
236
215
  const sessionUpdates = {}
237
216
  jids.forEach(jid => {
238
217
  const addr = jidToSignalProtocolAddress(jid)
239
218
  sessionUpdates[addr.toString()] = null
240
219
  })
241
- // Single transaction for all deletions
220
+
242
221
  return parsedKeys.transaction(async () => {
243
222
  await auth.keys.set({ session: sessionUpdates })
244
223
  }, `delete-${jids.length}-sessions`)
245
224
  },
246
225
  async migrateSession(fromJid, toJid) {
247
- // TODO: use usync to handle this entire mess
226
+
248
227
  if (!fromJid || (!(0, WABinary_1.isLidUser)(toJid) && !(0, WABinary_1.isHostedLidUser)(toJid)))
249
228
  return { migrated: 0, skipped: 0, total: 0 }
250
- // Only support PN to LID migration
229
+
251
230
  if (!(0, WABinary_1.isPnUser)(fromJid) && !(0, WABinary_1.isHostedPnUser)(fromJid)) {
252
231
  return { migrated: 0, skipped: 0, total: 1 }
253
232
  }
254
233
  const { user } = (0, WABinary_1.jidDecode)(fromJid)
255
234
  logger.debug({ fromJid }, 'bulk device migration - loading all user devices')
256
- // Get user's device list from storage
235
+
257
236
  const { [user]: userDevices } = await parsedKeys.get('device-list', [user])
258
237
  if (!userDevices) {
259
238
  return { migrated: 0, skipped: 0, total: 0 }
@@ -263,22 +242,22 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
263
242
  if (!userDevices.includes(fromDeviceStr)) {
264
243
  userDevices.push(fromDeviceStr)
265
244
  }
266
- // Filter out cached devices before database fetch
245
+
267
246
  const uncachedDevices = userDevices.filter(device => {
268
247
  const deviceKey = `${user}.${device}`
269
248
  return !migratedSessionCache.has(deviceKey)
270
249
  })
271
- // Bulk check session existence only for uncached devices
250
+
272
251
  const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`)
273
252
  const existingSessions = await parsedKeys.get('session', deviceSessionKeys)
274
- // Step 3: Convert existing sessions to JIDs (only migrate sessions that exist)
253
+
275
254
  const deviceJids = []
276
255
  for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
277
256
  if (sessionData) {
278
- // Session exists in storage
257
+
279
258
  const deviceStr = sessionKey.split('.')[1]
280
259
  if (!deviceStr) continue
281
- const deviceNum = parseInt(deviceStr)
260
+ const deviceNum = parseInt(deviceStr, 10)
282
261
  let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`
283
262
  if (deviceNum === 99) {
284
263
  jid = `${user}:99@hosted`
@@ -295,7 +274,7 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
295
274
  },
296
275
  'bulk device migration complete - all user devices processed'
297
276
  )
298
- // Single transaction for all migrations
277
+
299
278
  return parsedKeys.transaction(
300
279
  async () => {
301
280
  const migrationOps = deviceJids.map(jid => {
@@ -314,31 +293,31 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
314
293
  })
315
294
  const totalOps = migrationOps.length
316
295
  let migratedCount = 0
317
- // Bulk fetch PN sessions - already exist (verified during device discovery)
296
+
318
297
  const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())))
319
298
  const pnSessions = await parsedKeys.get('session', pnAddrStrings)
320
- // Prepare bulk session updates (PN → LID migration + deletion)
299
+
321
300
  const sessionUpdates = {}
322
301
  for (const op of migrationOps) {
323
302
  const pnAddrStr = op.fromAddr.toString()
324
303
  const lidAddrStr = op.toAddr.toString()
325
304
  const pnSession = pnSessions[pnAddrStr]
326
305
  if (pnSession) {
327
- // Session exists (guaranteed from device discovery)
306
+
328
307
  const fromSession = rb.SessionRecord.deserialize(pnSession)
329
308
  if (fromSession.haveOpenSession()) {
330
- // Queue for bulk update: copy to LID, delete from PN
309
+
331
310
  sessionUpdates[lidAddrStr] = fromSession.serialize()
332
311
  sessionUpdates[pnAddrStr] = null
333
312
  migratedCount++
334
313
  }
335
314
  }
336
315
  }
337
- // Single bulk session update for all migrations
316
+
338
317
  if (Object.keys(sessionUpdates).length > 0) {
339
318
  await parsedKeys.set({ session: sessionUpdates })
340
319
  logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete')
341
- // Cache device-level migrations
320
+
342
321
  for (const op of migrationOps) {
343
322
  if (sessionUpdates[op.toAddr.toString()]) {
344
323
  const deviceKey = `${op.pnUser}.${op.deviceId}`
@@ -374,12 +353,12 @@ const jidToSignalSenderKeyName = (group, user) => {
374
353
  return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user))
375
354
  }
376
355
  function signalStorage({ creds, keys }, lidMapping) {
377
- // Shared function to resolve PN signal address to LID if mapping exists
356
+
378
357
  const resolveLIDSignalAddress = async id => {
379
358
  if (id.includes('.')) {
380
359
  const [deviceId, device] = id.split('.')
381
360
  const [user, domainType_] = deviceId.split('_')
382
- const domainType = parseInt(domainType_ || '0')
361
+ const domainType = parseInt(domainType_ || '0', 10)
383
362
  if (
384
363
  domainType === WABinary_1.WAJIDDomains.LID ||
385
364
  domainType === WABinary_1.WAJIDDomains.HOSTED_LID ||
@@ -403,22 +382,22 @@ function signalStorage({ creds, keys }, lidMapping) {
403
382
  const fetched = await keys.get('session', keysToFetch)
404
383
  const sess = fetched[wireJid] || fetched[id]
405
384
  if (!sess) return null
406
- // Detect old libsignal-node JSON format → treat as no session
385
+
407
386
  if (typeof sess === 'object' && !Buffer.isBuffer(sess) && !ArrayBuffer.isView(sess) && sess._sessions) {
408
387
  return null
409
388
  }
410
- // Return raw bytes — Rust storage adapter expects Uint8Array, not SessionRecord object
389
+
411
390
  return Buffer.isBuffer(sess) ? sess : Buffer.from(sess)
412
- } catch (e) {
391
+ } catch {
413
392
  return null
414
393
  }
415
394
  },
416
395
  storeSession: async (id, session) => {
417
- // Store under raw ID so it's always findable regardless of LID mapping state
396
+
418
397
  await keys.set({ session: { [id]: session.serialize() } })
419
398
  },
420
399
  isTrustedIdentity: () => {
421
- return true // TOFU - Trust on First Use (same as WhatsApp Web)
400
+ return true
422
401
  },
423
402
  loadIdentityKey: async id => {
424
403
  const wireJid = await resolveLIDSignalAddress(id)
@@ -433,7 +412,7 @@ function signalStorage({ creds, keys }, lidMapping) {
433
412
  existingKey.length === identityKey.length &&
434
413
  existingKey.every((byte, i) => byte === identityKey[i])
435
414
  if (existingKey && !keysMatch) {
436
- // Identity changed - clear session and update key
415
+
437
416
  await keys.set({
438
417
  session: { [wireJid]: null },
439
418
  'identity-key': { [wireJid]: identityKey }
@@ -441,7 +420,7 @@ function signalStorage({ creds, keys }, lidMapping) {
441
420
  return true
442
421
  }
443
422
  if (!existingKey) {
444
- // New contact - Trust on First Use (TOFU)
423
+
445
424
  await keys.set({ 'identity-key': { [wireJid]: identityKey } })
446
425
  return true
447
426
  }
@@ -462,7 +441,8 @@ function signalStorage({ creds, keys }, lidMapping) {
462
441
  const key = creds.signedPreKey
463
442
  return {
464
443
  privKey: Buffer.from(key.keyPair.private),
465
- pubKey: Buffer.from(key.keyPair.public)
444
+ pubKey: Buffer.from(key.keyPair.public),
445
+ signature: key.signature ? Buffer.from(key.signature) : undefined
466
446
  }
467
447
  },
468
448
  loadSenderKey: async senderKeyName => {
@@ -6,7 +6,7 @@ const WABinary_1 = require('../WABinary')
6
6
  class LIDMappingStore {
7
7
  constructor(keys, logger, pnToLIDFunc) {
8
8
  this.mappingCache = new lru_cache_1.LRUCache({
9
- ttl: 3 * 24 * 60 * 60 * 1000, // 7 days
9
+ ttl: 3 * 24 * 60 * 60 * 1000,
10
10
  ttlAutopurge: true,
11
11
  updateAgeOnGet: true
12
12
  })
@@ -20,12 +20,10 @@ class LIDMappingStore {
20
20
  if (pairs.length === 0) return
21
21
  const validatedPairs = []
22
22
  for (const { lid, pn } of pairs) {
23
- if (
24
- !(
25
- ((0, WABinary_1.isLidUser)(lid) && (0, WABinary_1.isPnUser)(pn)) ||
26
- ((0, WABinary_1.isPnUser)(lid) && (0, WABinary_1.isLidUser)(pn))
27
- )
28
- ) {
23
+ if (!(
24
+ ((0, WABinary_1.isLidUser)(lid) && (0, WABinary_1.isPnUser)(pn)) ||
25
+ ((0, WABinary_1.isPnUser)(lid) && (0, WABinary_1.isLidUser)(pn))
26
+ )) {
29
27
  this.logger.warn(`Invalid LID-PN mapping: ${lid}, ${pn}`)
30
28
  continue
31
29
  }
@@ -77,7 +75,7 @@ class LIDMappingStore {
77
75
  await this.keys.transaction(async () => {
78
76
  await this.keys.set({ 'lid-mapping': batchData })
79
77
  }, 'lid-mapping')
80
- // Update cache after successful DB write
78
+
81
79
  for (const [pnUser, lidUser] of Object.entries(pairMap)) {
82
80
  this.mappingCache.set(`pn:${pnUser}`, lidUser)
83
81
  this.mappingCache.set(`lid:${lidUser}`, pnUser)
@@ -86,6 +84,26 @@ class LIDMappingStore {
86
84
  async getLIDForPN(pn) {
87
85
  return (await this.getLIDsForPNs([pn]))?.[0]?.lid || null
88
86
  }
87
+
88
+
89
+ async getStoredLIDForPN(pn) {
90
+ if (!(0, WABinary_1.isPnUser)(pn) && !(0, WABinary_1.isHostedPnUser)(pn)) return null
91
+ const decoded = (0, WABinary_1.jidDecode)(pn)
92
+ if (!decoded) return null
93
+ const pnUser = decoded.user
94
+ let lidUser = this.mappingCache.get(`pn:${pnUser}`)
95
+ if (!lidUser || typeof lidUser !== 'string') {
96
+ const stored = await this.keys.get('lid-mapping', [pnUser])
97
+ lidUser = stored[pnUser]
98
+ if (lidUser && typeof lidUser === 'string') {
99
+ this.mappingCache.set(`pn:${pnUser}`, lidUser)
100
+ this.mappingCache.set(`lid:${lidUser}`, pnUser)
101
+ }
102
+ }
103
+ if (!lidUser || typeof lidUser !== 'string') return null
104
+ const pnDevice = decoded.device !== undefined ? decoded.device : 0
105
+ return `${lidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
106
+ }
89
107
  async getLIDsForPNs(pns) {
90
108
  if (pns.length === 0) return null
91
109
  const sortedPns = [...new Set(pns)].sort()
@@ -113,7 +131,7 @@ class LIDMappingStore {
113
131
  this.logger.warn(`Invalid or empty LID user for PN ${pn}: lidUser = "${lidUser}"`)
114
132
  return false
115
133
  }
116
- // Push the PN device ID to the LID to maintain device separation
134
+
117
135
  const pnDevice = decoded.device !== undefined ? decoded.device : 0
118
136
  const deviceSpecificLid = `${normalizedLidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
119
137
  this.logger.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`)
@@ -168,7 +186,7 @@ class LIDMappingStore {
168
186
  }
169
187
  }
170
188
  if (Object.keys(usyncFetch).length > 0) {
171
- const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch)) // this function already adds LIDs to mapping
189
+ const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch))
172
190
  if (result && result.length > 0) {
173
191
  await this.storeLIDPNMappings(result)
174
192
  for (const pair of result) {
@@ -10,7 +10,7 @@ const makeAIGroupsSocket = config => {
10
10
  const sock = (0, groups_1.makeGroupsSocket)(config)
11
11
  const { ev, query } = sock
12
12
 
13
- /** Query helper for AI groups (w:gp2 namespace) */
13
+
14
14
  const aiGroupQuery = async (jid, type, content) =>
15
15
  query({
16
16
  tag: 'iq',
@@ -27,7 +27,7 @@ const makeAIGroupsSocket = config => {
27
27
  return (0, exports.extractAIGroupMetadata)(result)
28
28
  }
29
29
 
30
- // Handle incoming w:gp2 notifications (create, promote, remove, add)
30
+
31
31
  sock.ws.on('CB:notification,w:gp2', async node => {
32
32
  const { attrs, content } = node
33
33
  if (!Array.isArray(content) || content.length === 0) return
@@ -44,12 +44,12 @@ const makeAIGroupsSocket = config => {
44
44
  if (!groupId) return
45
45
 
46
46
  if (tag === 'create') {
47
- // New AI group created — emit groups.upsert
47
+
48
48
  try {
49
49
  const meta = await aiGroupMetadata(groupId)
50
50
  ev.emit('groups.upsert', [meta])
51
51
  } catch {
52
- // metadata fetch may fail; emit minimal info
52
+
53
53
  ev.emit('groups.upsert', [{ id: groupId }])
54
54
  }
55
55
  } else if (tag === 'promote' || tag === 'demote' || tag === 'remove' || tag === 'add') {
@@ -189,7 +189,7 @@ const makeAIGroupsSocket = config => {
189
189
  exports.makeAIGroupsSocket = makeAIGroupsSocket
190
190
 
191
191
  const extractAIGroupMetadata = result => {
192
- // IQ response nests group inside create node: result → create → group
192
+
193
193
  const createNode = (0, WABinary_1.getBinaryNodeChild)(result, 'create')
194
194
  const group =
195
195
  (0, WABinary_1.getBinaryNodeChild)(createNode || result, 'group') ||