@badzz88/baileys 8.5.4 → 8.5.5

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 (107) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +75 -1256
  3. package/WAProto/index.d.ts +19729 -36122
  4. package/WAProto/index.js +132193 -178538
  5. package/engine-requirements.js +15 -7
  6. package/lib/Defaults/index.js +14 -22
  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 +28 -39
  15. package/lib/Signal/lid-mapping.js +8 -28
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +11 -3
  18. package/lib/Socket/chats.js +319 -668
  19. package/lib/Socket/communities.js +89 -85
  20. package/lib/Socket/graphql.js +228 -435
  21. package/lib/Socket/groups.js +211 -132
  22. package/lib/Socket/index.js +7 -9
  23. package/lib/Socket/interactive-handler.js +60 -117
  24. package/lib/Socket/interop.js +175 -56
  25. package/lib/Socket/luxu.js +387 -0
  26. package/lib/Socket/managed-account.js +48 -79
  27. package/lib/Socket/messages-recv.js +340 -898
  28. package/lib/Socket/messages-send.js +160 -462
  29. package/lib/Socket/mex.js +53 -40
  30. package/lib/Socket/newsletter.js +295 -291
  31. package/lib/Socket/privacy.js +265 -77
  32. package/lib/Socket/registration.js +157 -164
  33. package/lib/Socket/socket.js +199 -181
  34. package/lib/Socket/text-router.js +83 -0
  35. package/lib/Socket/username.js +227 -144
  36. package/lib/Store/keyed-db.js +108 -0
  37. package/lib/Store/make-cache-manager-store.js +2 -2
  38. package/lib/Store/make-in-memory-store.js +141 -25
  39. package/lib/Types/Auth.js +3 -3
  40. package/lib/Types/Label.js +1 -1
  41. package/lib/Types/LabelAssociation.js +1 -1
  42. package/lib/Types/Mex.js +112 -0
  43. package/lib/Types/Newsletter.js +65 -96
  44. package/lib/Types/State.js +4 -4
  45. package/lib/Types/index.js +1 -1
  46. package/lib/Utils/auth-utils.js +57 -52
  47. package/lib/Utils/browser-utils.js +1 -1
  48. package/lib/Utils/business.js +6 -2
  49. package/lib/Utils/chat-utils.js +38 -102
  50. package/lib/Utils/command-loader.d.ts +31 -0
  51. package/lib/Utils/command-loader.js +100 -0
  52. package/lib/Utils/companion-reg-client-utils.js +42 -0
  53. package/lib/Utils/crypto.js +84 -54
  54. package/lib/Utils/curve25519-js.js +275 -0
  55. package/lib/Utils/decode-wa-message.js +83 -316
  56. package/lib/Utils/event-buffer.js +61 -37
  57. package/lib/Utils/generics.js +103 -157
  58. package/lib/Utils/group-history.js +12 -3
  59. package/lib/Utils/history.js +15 -15
  60. package/lib/Utils/index.js +5 -1
  61. package/lib/Utils/link-preview.js +8 -3
  62. package/lib/Utils/lt-hash.js +35 -2
  63. package/lib/Utils/make-mutex.js +1 -1
  64. package/lib/Utils/message-retry-manager.js +92 -27
  65. package/lib/Utils/messages-media.js +130 -159
  66. package/lib/Utils/messages.js +566 -144
  67. package/lib/Utils/meta-ai-msmsg.js +202 -62
  68. package/lib/Utils/native-bridge.js +82 -0
  69. package/lib/Utils/noise-handler.js +21 -19
  70. package/lib/Utils/offline-node-processor.js +8 -3
  71. package/lib/Utils/pre-key-manager.js +23 -13
  72. package/lib/Utils/process-message.js +106 -197
  73. package/lib/Utils/reporting-utils.js +2 -2
  74. package/lib/Utils/session-pool.d.ts +16 -0
  75. package/lib/Utils/session-pool.js +94 -0
  76. package/lib/Utils/signal.js +63 -28
  77. package/lib/Utils/stanza-ack.js +12 -39
  78. package/lib/Utils/sticker.d.ts +17 -0
  79. package/lib/Utils/sticker.js +145 -0
  80. package/lib/Utils/sync-action-utils.js +7 -4
  81. package/lib/Utils/tc-token-utils.js +25 -20
  82. package/lib/Utils/use-multi-file-auth-state.js +14 -30
  83. package/lib/Utils/validate-connection.js +19 -59
  84. package/lib/Utils/view-once-cache.d.ts +9 -0
  85. package/lib/Utils/view-once-cache.js +79 -0
  86. package/lib/WABinary/decode.js +16 -50
  87. package/lib/WABinary/encode.js +224 -54
  88. package/lib/WABinary/generic-utils.js +97 -7
  89. package/lib/WABinary/jid-utils.js +14 -27
  90. package/lib/WAM/encode.js +7 -7
  91. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
  92. package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
  93. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
  94. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
  95. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
  96. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  97. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  98. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
  99. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  100. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
  101. package/lib/WAUSync/Protocols/index.js +0 -1
  102. package/lib/WAUSync/USyncQuery.js +6 -77
  103. package/lib/WAUSync/USyncUser.js +8 -16
  104. package/lib/WAUSync/index.js +0 -1
  105. package/lib/antiban.js +854 -608
  106. package/lib/index.js +1 -1
  107. package/package.json +20 -16
@@ -7,48 +7,24 @@ exports.encodeSignedDeviceIdentity =
7
7
  void 0
8
8
  const boom_1 = require('@hapi/boom')
9
9
  const crypto_1 = require('crypto')
10
- const rb = require('whatsapp-rust-bridge')
10
+ const Crypto_1 = require('./crypto')
11
11
  const index_js_1 = require('../../WAProto/index.js')
12
12
  const Defaults_1 = require('../Defaults')
13
13
  const WABinary_1 = require('../WABinary')
14
14
  const crypto_2 = require('./crypto')
15
15
  const generics_1 = require('./generics')
16
16
  const signal_1 = require('./signal')
17
- const MOBILE_PLATFORMS = new Set(['Android', 'iOS'])
18
17
  const getUserAgent = config => {
19
- const os = config.browser[0]
20
- let platform, device, osVersion
21
- if (os === 'Android') {
22
- platform = index_js_1.proto.ClientPayload.UserAgent.Platform.ANDROID
23
- device = 'Android'
24
- osVersion = config.browser[2] || '15.0.0'
25
- } else if (os === 'iOS') {
26
- platform = index_js_1.proto.ClientPayload.UserAgent.Platform.IOS
27
- device = 'iPhone'
28
- osVersion = config.browser[2] || '18.0'
29
- } else if (config.syncFullHistory && os === 'Mac OS' && config.browser[1] === 'Desktop') {
30
-
31
-
32
- platform = index_js_1.proto.ClientPayload.UserAgent.Platform.MACOS
33
- device = 'Desktop'
34
- osVersion = '0.1'
35
- } else {
36
- platform = index_js_1.proto.ClientPayload.UserAgent.Platform.WEB
37
- device = 'Desktop'
38
- osVersion = '0.1'
39
- }
40
18
  return {
41
19
  appVersion: {
42
20
  primary: config.version[0],
43
21
  secondary: config.version[1],
44
22
  tertiary: config.version[2]
45
23
  },
46
- platform,
47
-
48
-
24
+ platform: index_js_1.proto.ClientPayload.UserAgent.Platform.WEB,
49
25
  releaseChannel: index_js_1.proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
50
- osVersion,
51
- device,
26
+ osVersion: '0.1',
27
+ device: 'Desktop',
52
28
  osBuildNumber: '0.1',
53
29
  localeLanguageIso6391: 'en',
54
30
  mnc: '000',
@@ -58,9 +34,7 @@ const getUserAgent = config => {
58
34
  }
59
35
  const PLATFORM_MAP = {
60
36
  'Mac OS': index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.DARWIN,
61
- Windows: index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.WIN_HYBRID,
62
- Android: index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER,
63
- iOS: index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER
37
+ Windows: index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.WIN32
64
38
  }
65
39
  const getWebInfo = config => {
66
40
  let webSubPlatform = index_js_1.proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER
@@ -75,16 +49,14 @@ const getClientPayload = config => {
75
49
  connectReason: index_js_1.proto.ClientPayload.ConnectReason.USER_ACTIVATED,
76
50
  userAgent: getUserAgent(config)
77
51
  }
78
- if (!MOBILE_PLATFORMS.has(config.browser[0])) {
79
- payload.webInfo = getWebInfo(config)
80
- }
52
+ payload.webInfo = getWebInfo(config)
81
53
  return payload
82
54
  }
83
55
  const generateLoginNode = (userJid, config, creds) => {
84
56
  const { user, device } = (0, WABinary_1.jidDecode)(userJid)
85
-
86
-
87
-
57
+ // masqueradeAsPrimary: connect as device 0 so the WA server (and interop bridges)
58
+ // route primary-device traffic — including interop messages — to this session.
59
+ // Trade-off: the real phone (device 0 on TCP) may be kicked or see a conflict.
88
60
  const effectiveDevice = config.masqueradeAsPrimary ? 0 : device
89
61
  const payload = {
90
62
  ...getClientPayload(config),
@@ -94,8 +66,8 @@ const generateLoginNode = (userJid, config, creds) => {
94
66
  device: effectiveDevice,
95
67
  lidDbMigrated: false
96
68
  }
97
-
98
-
69
+ // InteropData is required for Meta/FB-linked accounts (AccountType = HOSTED).
70
+ // Populated from creds when present so the server routes interop traffic correctly.
99
71
  if (creds?.interopData?.accountId) {
100
72
  payload.interopData = {
101
73
  accountId: creds.interopData.accountId,
@@ -111,23 +83,18 @@ const getPlatformType = platform => {
111
83
  return index_js_1.proto.DeviceProps.PlatformType[platformType] || index_js_1.proto.DeviceProps.PlatformType.CHROME
112
84
  }
113
85
  const generateRegistrationNode = ({ registrationId, signedPreKey, signedIdentityKey }, config) => {
114
-
115
-
116
- const appVersionBuf = Buffer.from(rb.md5(Buffer.from(config.version.join('.'))))
86
+ // the app version needs to be md5 hashed
87
+ // and passed in
88
+ const appVersionBuf = Buffer.from(Crypto_1.md5(Buffer.from(config.version.join('.'))))
117
89
  const companion = {
118
90
  os: config.browser[0],
119
91
  platformType: getPlatformType(config.browser[1]),
120
92
  requireFullSync: config.syncFullHistory,
121
93
  historySyncConfig: {
122
- fullSyncDaysLimit: 30,
123
- fullSyncSizeMbLimit: undefined,
124
94
  storageQuotaMb: 10240,
125
95
  inlineInitialPayloadInE2EeMsg: true,
126
96
  recentSyncDaysLimit: undefined,
127
-
128
-
129
-
130
- supportCallLogHistory: config.browser[0] === 'Windows',
97
+ supportCallLogHistory: false,
131
98
  supportBotUserAgentChatHistory: true,
132
99
  supportCagReactionsAndPolls: true,
133
100
  supportBizHostedMsg: true,
@@ -136,16 +103,9 @@ const generateRegistrationNode = ({ registrationId, signedPreKey, signedIdentity
136
103
  supportFbidBotChatHistory: true,
137
104
  supportAddOnHistorySyncMigration: undefined,
138
105
  supportMessageAssociation: true,
139
- supportGroupHistory: true,
106
+ supportGroupHistory: false,
140
107
  onDemandReady: undefined,
141
- supportGuestChat: true,
142
- completeOnDemandReady: undefined,
143
- thumbnailSyncDaysLimit: undefined,
144
- initialSyncMaxMessagesPerChat: undefined,
145
- supportManusHistory: true,
146
- supportHatchHistory: true,
147
- supportedBotChannelFbids: undefined,
148
- supportInlineContacts: true
108
+ supportGuestChat: undefined
149
109
  },
150
110
  version: {
151
111
  primary: 10,
@@ -249,8 +209,8 @@ const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, s
249
209
  exports.configureSuccessfulPairing = configureSuccessfulPairing
250
210
  const encodeSignedDeviceIdentity = (account, includeSignatureKey) => {
251
211
  account = { ...account }
252
-
253
-
212
+ // set to null if we are not to include the signature key
213
+ // or if we are including the signature key but it is empty
254
214
  if (!includeSignatureKey || !account.accountSignatureKey?.length) {
255
215
  account.accountSignatureKey = null
256
216
  }
@@ -0,0 +1,9 @@
1
+ export interface AutoCacheViewOnceOptions {
2
+ cacheDir?: string
3
+ logger?: any
4
+ onCached?: (info: { id: string; jid: string; filePath: string; type: string }) => void
5
+ }
6
+
7
+ export function getViewOnceContent(message: any): Record<string, any> | null
8
+
9
+ export function autoCacheViewOnceMedia(sock: any, options?: AutoCacheViewOnceOptions): () => void
@@ -0,0 +1,79 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.autoCacheViewOnceMedia = void 0
4
+ const path = require('path')
5
+ const fs = require('fs')
6
+ const Messages_1 = require('./messages')
7
+ const MessagesMedia_1 = require('./messages-media')
8
+
9
+ const VIEW_ONCE_WRAPPER_KEYS = ['viewOnceMessage', 'viewOnceMessageV2', 'viewOnceMessageV2Extension']
10
+ const VIEW_ONCE_INNER_KEYS = ['imageMessage', 'videoMessage', 'audioMessage']
11
+
12
+ /**
13
+ * Unwraps a message and returns the inner view-once media content if present, otherwise null.
14
+ * Handles both the wrapper style (viewOnceMessage[V2/V2Extension] -> message -> ...)
15
+ * and the inline style (imageMessage/videoMessage with viewOnce: true set directly).
16
+ */
17
+ const getViewOnceContent = message => {
18
+ if (!message) return null
19
+ const content = (0, Messages_1.extractMessageContent)(message)
20
+ if (!content) return null
21
+ for (const wrapperKey of VIEW_ONCE_WRAPPER_KEYS) {
22
+ const wrapper = content[wrapperKey]
23
+ if (wrapper?.message) {
24
+ const inner = (0, Messages_1.extractMessageContent)(wrapper.message)
25
+ if (inner) return inner
26
+ }
27
+ }
28
+ for (const key of VIEW_ONCE_INNER_KEYS) {
29
+ if (content[key]?.viewOnce) {
30
+ return { [key]: content[key] }
31
+ }
32
+ }
33
+ return null
34
+ }
35
+
36
+ /**
37
+ * Registers a `messages.upsert` listener on the given socket that automatically
38
+ * downloads and saves view-once media (image/video/audio) to `cacheDir` as soon
39
+ * as it arrives, before the sender's app can mark it as opened/consumed.
40
+ *
41
+ * @param {ReturnType<typeof import('../Socket').default>} sock - an active Baileys socket
42
+ * @param {{ cacheDir?: string, logger?: any, onCached?: (info: { id: string, jid: string, filePath: string, type: string }) => void }} [options]
43
+ * @returns {() => void} a function that removes the listener
44
+ */
45
+ const autoCacheViewOnceMedia = (sock, options = {}) => {
46
+ const cacheDir = options.cacheDir || './viewonce-cache'
47
+ const logger = options.logger || sock.logger
48
+ if (!fs.existsSync(cacheDir)) {
49
+ fs.mkdirSync(cacheDir, { recursive: true })
50
+ }
51
+ const handler = async ({ messages, type }) => {
52
+ if (type !== 'notify' && type !== 'append') return
53
+ for (const msg of messages) {
54
+ try {
55
+ const viewOnceContent = getViewOnceContent(msg.message)
56
+ if (!viewOnceContent) continue
57
+ const mediaType = Object.keys(viewOnceContent)[0]
58
+ const buffer = await (0, Messages_1.downloadMediaMessage)(
59
+ msg,
60
+ 'buffer',
61
+ {},
62
+ { logger, reuploadRequest: sock.updateMediaMessage }
63
+ )
64
+ const extension = (0, MessagesMedia_1.extensionForMediaMessage)(viewOnceContent) || 'bin'
65
+ const fileName = `${msg.key.id}.${extension}`
66
+ const filePath = path.join(cacheDir, fileName)
67
+ fs.writeFileSync(filePath, buffer)
68
+ logger?.debug?.({ id: msg.key.id, filePath, mediaType }, 'cached view-once media')
69
+ options.onCached?.({ id: msg.key.id, jid: msg.key.remoteJid, filePath, type: mediaType })
70
+ } catch (error) {
71
+ logger?.warn?.({ error, id: msg.key?.id }, 'failed to cache view-once media')
72
+ }
73
+ }
74
+ }
75
+ sock.ev.on('messages.upsert', handler)
76
+ return () => sock.ev.off('messages.upsert', handler)
77
+ }
78
+ exports.autoCacheViewOnceMedia = autoCacheViewOnceMedia
79
+ exports.getViewOnceContent = getViewOnceContent
@@ -56,37 +56,17 @@ const util_1 = require('util')
56
56
  const zlib_1 = require('zlib')
57
57
  const constants = __importStar(require('./constants'))
58
58
  const jid_utils_1 = require('./jid-utils')
59
- const rb = require('whatsapp-rust-bridge')
60
59
  const inflatePromise = (0, util_1.promisify)(zlib_1.inflate)
61
60
  const decompressingIfRequired = async buffer => {
62
61
  if (2 & buffer.readUInt8()) {
63
62
  buffer = await inflatePromise(buffer.slice(1))
64
63
  } else {
65
-
64
+ // nodes with no compression have a 0x00 prefix, we remove that
66
65
  buffer = buffer.slice(1)
67
66
  }
68
67
  return buffer
69
68
  }
70
69
  exports.decompressingIfRequired = decompressingIfRequired
71
-
72
-
73
- const rustNodeToJs = node => {
74
- if (!node || typeof node !== 'object') return node
75
- const result = { tag: node.tag, attrs: node.attrs || {} }
76
- const content = node.content
77
- if (content === undefined || content === null) {
78
-
79
- } else if (content instanceof Uint8Array) {
80
- result.content = Buffer.from(content)
81
- } else if (typeof content === 'string') {
82
- result.content = content
83
- } else if (Array.isArray(content)) {
84
- result.content = content.map(rustNodeToJs)
85
- } else {
86
- result.content = content
87
- }
88
- return result
89
- }
90
70
  const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) => {
91
71
  const { DOUBLE_BYTE_TOKENS, SINGLE_BYTE_TOKENS, TAGS } = opts
92
72
  const checkEOS = length => {
@@ -110,7 +90,7 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
110
90
  return value
111
91
  }
112
92
  const readStringFromChars = length => {
113
- return readBytes(length).toString('utf8')
93
+ return readBytes(length).toString('utf-8')
114
94
  }
115
95
  const readInt = (n, littleEndian = false) => {
116
96
  checkEOS(n)
@@ -196,7 +176,7 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
196
176
  const domainType = Number(rawDomainType)
197
177
  const device = readByte()
198
178
  const user = readString(readByte())
199
- let server = 's.whatsapp.net'
179
+ let server = 's.whatsapp.net' // default whatsapp server
200
180
  if (domainType === jid_utils_1.WAJIDDomains.LID) {
201
181
  server = 'lid'
202
182
  } else if (domainType === jid_utils_1.WAJIDDomains.HOSTED) {
@@ -217,13 +197,13 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
217
197
  const device = readInt(2)
218
198
  const integrator = readInt(2)
219
199
  let server = 'interop'
220
-
221
-
222
-
200
+ // Only attempt to read the optional server field if at least 1 byte remains
201
+ // and the next byte is a valid string tag (avoids corrupting the stream on
202
+ // unknown tags that readString would swallow silently after a catch).
223
203
  if (indexRef.index < buffer.length) {
224
204
  const serverTag = buffer[indexRef.index]
225
-
226
-
205
+ // BINARY_8 / BINARY_20 / BINARY_32 or a single-byte token (1–235) are
206
+ // valid string tags; LIST_EMPTY (0) means no server string follows.
227
207
  const isValidStringTag =
228
208
  (serverTag >= 1 && serverTag <= 235) ||
229
209
  serverTag === TAGS.BINARY_8 ||
@@ -232,7 +212,7 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
232
212
  serverTag === TAGS.NIBBLE_8 ||
233
213
  serverTag === TAGS.HEX_8
234
214
  if (isValidStringTag) {
235
- indexRef.index++
215
+ indexRef.index++ // consume the tag byte
236
216
  server = readString(serverTag)
237
217
  }
238
218
  }
@@ -281,7 +261,7 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
281
261
  case TAGS.NIBBLE_8:
282
262
  return readPacked8(tag)
283
263
  default:
284
-
264
+ // Unknown tag — token table may be outdated (new WA protocol version)
285
265
  process.stderr.write(`[WABinary] unknown string tag 0x${tag.toString(16)} — token table outdated?\n`)
286
266
  return ''
287
267
  }
@@ -297,16 +277,14 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
297
277
  const getTokenDouble = (index1, index2) => {
298
278
  const dict = DOUBLE_BYTE_TOKENS[index1]
299
279
  if (!dict) {
300
-
280
+ // Unknown dictionary — token table may be outdated (new WA protocol version)
301
281
  process.stderr.write(`[WABinary] unknown double-byte token dict ${index1} — token table outdated?\n`)
302
282
  return ''
303
283
  }
304
284
  const value = dict[index2]
305
285
  if (typeof value === 'undefined') {
306
-
307
- process.stderr.write(
308
- `[WABinary] unknown double-byte token dict=${index1} idx=${index2} — token table outdated?\n`
309
- )
286
+ // Unknown token in known dictionary — token table may be outdated
287
+ process.stderr.write(`[WABinary] unknown double-byte token dict=${index1} idx=${index2} — token table outdated?\n`)
310
288
  return ''
311
289
  }
312
290
  return value
@@ -321,7 +299,7 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
321
299
  if (listSize === 0 || !header) {
322
300
  throw new Error('invalid node')
323
301
  }
324
-
302
+ // read the attributes in
325
303
  const attributesLength = (listSize - 1) >> 1
326
304
  for (let i = 0; i < attributesLength; i++) {
327
305
  const key = readString(readByte())
@@ -358,20 +336,8 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
358
336
  }
359
337
  }
360
338
  exports.decodeDecompressedBinaryNode = decodeDecompressedBinaryNode
361
- const JS_DECODE_OPTS = {
362
- TAGS: constants.TAGS,
363
- SINGLE_BYTE_TOKENS: constants.SINGLE_BYTE_TOKENS,
364
- DOUBLE_BYTE_TOKENS: constants.DOUBLE_BYTE_TOKENS,
365
- }
366
339
  const decodeBinaryNode = buff => {
367
- const u8 = buff instanceof Uint8Array ? buff : new Uint8Array(buff.buffer, buff.byteOffset, buff.byteLength)
368
- try {
369
- const internal = rb.decodeNode(u8)
370
- return rustNodeToJs(internal.toJSON())
371
- } catch (_) {
372
-
373
-
374
- return (0, exports.decodeDecompressedBinaryNode)(buff, JS_DECODE_OPTS)
375
- }
340
+ const buffer = Buffer.isBuffer(buff) ? buff : Buffer.from(buff)
341
+ return decodeDecompressedBinaryNode(buffer, constants)
376
342
  }
377
343
  exports.decodeBinaryNode = decodeBinaryNode
@@ -1,58 +1,228 @@
1
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
2
  Object.defineProperty(exports, '__esModule', { value: true })
54
3
  exports.encodeBinaryNode = void 0
55
- const rb = require('whatsapp-rust-bridge')
56
- const encodeBinaryNode = node => Buffer.from(rb.encodeNode(node))
57
- exports.encodeBinaryNode = encodeBinaryNode
4
+ const constants = require('./constants')
5
+ const { jidDecode } = require('./jid-utils')
6
+
7
+ const encodeBinaryNodeJS = (node, opts = constants, buffer = [0]) => {
8
+ const encoded = encodeBinaryNodeInner(node, opts, buffer);
9
+ return Buffer.from(encoded);
10
+ };
11
+ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
12
+ const { TAGS, TOKEN_MAP } = opts;
13
+ const pushByte = (value) => buffer.push(value & 0xff);
14
+ const pushInt = (value, n, littleEndian = false) => {
15
+ for (let i = 0; i < n; i++) {
16
+ const curShift = littleEndian ? i : n - 1 - i;
17
+ buffer.push((value >> (curShift * 8)) & 0xff);
18
+ }
19
+ };
20
+ const pushBytes = (bytes) => {
21
+ for (const b of bytes) {
22
+ buffer.push(b);
23
+ }
24
+ };
25
+ const pushInt16 = (value) => {
26
+ pushBytes([(value >> 8) & 0xff, value & 0xff]);
27
+ };
28
+ const pushInt20 = (value) => pushBytes([(value >> 16) & 0x0f, (value >> 8) & 0xff, value & 0xff]);
29
+ const writeByteLength = (length) => {
30
+ if (length >= 4294967296) {
31
+ throw new Error('string too large to encode: ' + length);
32
+ }
33
+ if (length >= 1 << 20) {
34
+ pushByte(TAGS.BINARY_32);
35
+ pushInt(length, 4); // 32 bit integer
36
+ }
37
+ else if (length >= 256) {
38
+ pushByte(TAGS.BINARY_20);
39
+ pushInt20(length);
40
+ }
41
+ else {
42
+ pushByte(TAGS.BINARY_8);
43
+ pushByte(length);
44
+ }
45
+ };
46
+ const writeStringRaw = (str) => {
47
+ const bytes = Buffer.from(str, 'utf-8');
48
+ writeByteLength(bytes.length);
49
+ pushBytes(bytes);
50
+ };
51
+ const writeJid = ({ domainType, device, user, server }) => {
52
+ if (typeof device !== 'undefined') {
53
+ pushByte(TAGS.AD_JID);
54
+ pushByte(domainType || 0);
55
+ pushByte(device || 0);
56
+ writeString(user);
57
+ }
58
+ else {
59
+ pushByte(TAGS.JID_PAIR);
60
+ if (user.length) {
61
+ writeString(user);
62
+ }
63
+ else {
64
+ pushByte(TAGS.LIST_EMPTY);
65
+ }
66
+ writeString(server);
67
+ }
68
+ };
69
+ const packNibble = (char) => {
70
+ switch (char) {
71
+ case '-':
72
+ return 10;
73
+ case '.':
74
+ return 11;
75
+ case '\0':
76
+ return 15;
77
+ default:
78
+ if (char >= '0' && char <= '9') {
79
+ return char.charCodeAt(0) - '0'.charCodeAt(0);
80
+ }
81
+ throw new Error(`invalid byte for nibble "${char}"`);
82
+ }
83
+ };
84
+ const packHex = (char) => {
85
+ if (char >= '0' && char <= '9') {
86
+ return char.charCodeAt(0) - '0'.charCodeAt(0);
87
+ }
88
+ if (char >= 'A' && char <= 'F') {
89
+ return 10 + char.charCodeAt(0) - 'A'.charCodeAt(0);
90
+ }
91
+ if (char >= 'a' && char <= 'f') {
92
+ return 10 + char.charCodeAt(0) - 'a'.charCodeAt(0);
93
+ }
94
+ if (char === '\0') {
95
+ return 15;
96
+ }
97
+ throw new Error(`Invalid hex char "${char}"`);
98
+ };
99
+ const writePackedBytes = (str, type) => {
100
+ if (str.length > TAGS.PACKED_MAX) {
101
+ throw new Error('Too many bytes to pack');
102
+ }
103
+ pushByte(type === 'nibble' ? TAGS.NIBBLE_8 : TAGS.HEX_8);
104
+ let roundedLength = Math.ceil(str.length / 2.0);
105
+ if (str.length % 2 !== 0) {
106
+ roundedLength |= 128;
107
+ }
108
+ pushByte(roundedLength);
109
+ const packFunction = type === 'nibble' ? packNibble : packHex;
110
+ const packBytePair = (v1, v2) => {
111
+ const result = (packFunction(v1) << 4) | packFunction(v2);
112
+ return result;
113
+ };
114
+ const strLengthHalf = Math.floor(str.length / 2);
115
+ for (let i = 0; i < strLengthHalf; i++) {
116
+ pushByte(packBytePair(str[2 * i], str[2 * i + 1]));
117
+ }
118
+ if (str.length % 2 !== 0) {
119
+ pushByte(packBytePair(str[str.length - 1], '\x00'));
120
+ }
121
+ };
122
+ const isNibble = (str) => {
123
+ if (!str || str.length > TAGS.PACKED_MAX) {
124
+ return false;
125
+ }
126
+ for (const char of str) {
127
+ const isInNibbleRange = char >= '0' && char <= '9';
128
+ if (!isInNibbleRange && char !== '-' && char !== '.') {
129
+ return false;
130
+ }
131
+ }
132
+ return true;
133
+ };
134
+ const isHex = (str) => {
135
+ if (!str || str.length > TAGS.PACKED_MAX) {
136
+ return false;
137
+ }
138
+ for (const char of str) {
139
+ const isInNibbleRange = char >= '0' && char <= '9';
140
+ if (!isInNibbleRange && !(char >= 'A' && char <= 'F')) {
141
+ return false;
142
+ }
143
+ }
144
+ return true;
145
+ };
146
+ const writeString = (str) => {
147
+ if (str === undefined || str === null) {
148
+ pushByte(TAGS.LIST_EMPTY);
149
+ return;
150
+ }
151
+ if (str === '') {
152
+ writeStringRaw(str);
153
+ return;
154
+ }
155
+ const tokenIndex = TOKEN_MAP[str];
156
+ if (tokenIndex) {
157
+ if (typeof tokenIndex.dict === 'number') {
158
+ pushByte(TAGS.DICTIONARY_0 + tokenIndex.dict);
159
+ }
160
+ pushByte(tokenIndex.index);
161
+ }
162
+ else if (isNibble(str)) {
163
+ writePackedBytes(str, 'nibble');
164
+ }
165
+ else if (isHex(str)) {
166
+ writePackedBytes(str, 'hex');
167
+ }
168
+ else {
169
+ const decodedJid = jidDecode(str);
170
+ if (decodedJid) {
171
+ writeJid(decodedJid);
172
+ }
173
+ else {
174
+ writeStringRaw(str);
175
+ }
176
+ }
177
+ };
178
+ const writeListStart = (listSize) => {
179
+ if (listSize === 0) {
180
+ pushByte(TAGS.LIST_EMPTY);
181
+ }
182
+ else if (listSize < 256) {
183
+ pushBytes([TAGS.LIST_8, listSize]);
184
+ }
185
+ else {
186
+ pushByte(TAGS.LIST_16);
187
+ pushInt16(listSize);
188
+ }
189
+ };
190
+ if (!tag) {
191
+ throw new Error('Invalid node: tag cannot be undefined');
192
+ }
193
+ const validAttributes = Object.keys(attrs || {}).filter(k => typeof attrs[k] !== 'undefined' && attrs[k] !== null);
194
+ writeListStart(2 * validAttributes.length + 1 + (typeof content !== 'undefined' ? 1 : 0));
195
+ writeString(tag);
196
+ for (const key of validAttributes) {
197
+ if (typeof attrs[key] === 'string') {
198
+ writeString(key);
199
+ writeString(attrs[key]);
200
+ }
201
+ }
202
+ if (typeof content === 'string') {
203
+ writeString(content);
204
+ }
205
+ else if (Buffer.isBuffer(content) || content instanceof Uint8Array) {
206
+ writeByteLength(content.length);
207
+ pushBytes(content);
208
+ }
209
+ else if (Array.isArray(content)) {
210
+ const validContent = content.filter(item => item && (item.tag || Buffer.isBuffer(item) || item instanceof Uint8Array || typeof item === 'string'));
211
+ writeListStart(validContent.length);
212
+ for (const item of validContent) {
213
+ encodeBinaryNodeInner(item, opts, buffer);
214
+ }
215
+ }
216
+ else if (typeof content === 'undefined') {
217
+ // do nothing
218
+ }
219
+ else {
220
+ throw new Error(`invalid children for header "${tag}": ${content} (${typeof content})`);
221
+ }
222
+ return buffer;
223
+ };
58
224
 
225
+ const encodeBinaryNode = (node, opts, buffer) => {
226
+ return encodeBinaryNodeJS(node, opts || constants, buffer || [0])
227
+ }
228
+ exports.encodeBinaryNode = encodeBinaryNode