@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.
- package/README.md +1 -1
- package/WAProto/WAProto.proto +75 -1256
- package/WAProto/index.d.ts +19729 -36122
- package/WAProto/index.js +132193 -178538
- package/engine-requirements.js +15 -7
- package/lib/Defaults/index.js +14 -22
- package/lib/Signal/Group/group_cipher.js +5 -5
- package/lib/Signal/Group/keyhelper.js +4 -4
- package/lib/Signal/Group/sender-chain-key.js +2 -2
- package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
- package/lib/Signal/Group/sender-key-message.js +3 -3
- package/lib/Signal/Group/sender-key-record.js +1 -1
- package/lib/Signal/Group/sender-message-key.js +5 -5
- package/lib/Signal/libsignal.js +28 -39
- package/lib/Signal/lid-mapping.js +8 -28
- package/lib/Socket/aigroups.js +5 -5
- package/lib/Socket/business.js +11 -3
- package/lib/Socket/chats.js +319 -668
- package/lib/Socket/communities.js +89 -85
- package/lib/Socket/graphql.js +228 -435
- package/lib/Socket/groups.js +211 -132
- package/lib/Socket/index.js +7 -9
- package/lib/Socket/interactive-handler.js +60 -117
- package/lib/Socket/interop.js +175 -56
- package/lib/Socket/luxu.js +387 -0
- package/lib/Socket/managed-account.js +48 -79
- package/lib/Socket/messages-recv.js +340 -898
- package/lib/Socket/messages-send.js +160 -462
- package/lib/Socket/mex.js +53 -40
- package/lib/Socket/newsletter.js +295 -291
- package/lib/Socket/privacy.js +265 -77
- package/lib/Socket/registration.js +157 -164
- package/lib/Socket/socket.js +199 -181
- package/lib/Socket/text-router.js +83 -0
- package/lib/Socket/username.js +227 -144
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +2 -2
- package/lib/Store/make-in-memory-store.js +141 -25
- package/lib/Types/Auth.js +3 -3
- package/lib/Types/Label.js +1 -1
- package/lib/Types/LabelAssociation.js +1 -1
- package/lib/Types/Mex.js +112 -0
- package/lib/Types/Newsletter.js +65 -96
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +57 -52
- package/lib/Utils/browser-utils.js +1 -1
- package/lib/Utils/business.js +6 -2
- package/lib/Utils/chat-utils.js +38 -102
- package/lib/Utils/command-loader.d.ts +31 -0
- package/lib/Utils/command-loader.js +100 -0
- package/lib/Utils/companion-reg-client-utils.js +42 -0
- package/lib/Utils/crypto.js +84 -54
- package/lib/Utils/curve25519-js.js +275 -0
- package/lib/Utils/decode-wa-message.js +83 -316
- package/lib/Utils/event-buffer.js +61 -37
- package/lib/Utils/generics.js +103 -157
- package/lib/Utils/group-history.js +12 -3
- package/lib/Utils/history.js +15 -15
- package/lib/Utils/index.js +5 -1
- package/lib/Utils/link-preview.js +8 -3
- package/lib/Utils/lt-hash.js +35 -2
- package/lib/Utils/make-mutex.js +1 -1
- package/lib/Utils/message-retry-manager.js +92 -27
- package/lib/Utils/messages-media.js +130 -159
- package/lib/Utils/messages.js +566 -144
- package/lib/Utils/meta-ai-msmsg.js +202 -62
- package/lib/Utils/native-bridge.js +82 -0
- package/lib/Utils/noise-handler.js +21 -19
- package/lib/Utils/offline-node-processor.js +8 -3
- package/lib/Utils/pre-key-manager.js +23 -13
- package/lib/Utils/process-message.js +106 -197
- package/lib/Utils/reporting-utils.js +2 -2
- package/lib/Utils/session-pool.d.ts +16 -0
- package/lib/Utils/session-pool.js +94 -0
- package/lib/Utils/signal.js +63 -28
- package/lib/Utils/stanza-ack.js +12 -39
- package/lib/Utils/sticker.d.ts +17 -0
- package/lib/Utils/sticker.js +145 -0
- package/lib/Utils/sync-action-utils.js +7 -4
- package/lib/Utils/tc-token-utils.js +25 -20
- package/lib/Utils/use-multi-file-auth-state.js +14 -30
- package/lib/Utils/validate-connection.js +19 -59
- package/lib/Utils/view-once-cache.d.ts +9 -0
- package/lib/Utils/view-once-cache.js +79 -0
- package/lib/WABinary/decode.js +16 -50
- package/lib/WABinary/encode.js +224 -54
- package/lib/WABinary/generic-utils.js +97 -7
- package/lib/WABinary/jid-utils.js +14 -27
- package/lib/WAM/encode.js +7 -7
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
- package/lib/WAUSync/Protocols/index.js +0 -1
- package/lib/WAUSync/USyncQuery.js +6 -77
- package/lib/WAUSync/USyncUser.js +8 -16
- package/lib/WAUSync/index.js +0 -1
- package/lib/antiban.js +854 -608
- package/lib/index.js +1 -1
- package/package.json +20 -16
package/engine-requirements.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
const major = parseInt(process.versions.node.split(
|
|
1
|
+
const major = parseInt(process.versions.node.split(".")[0], 10);
|
|
2
2
|
|
|
3
3
|
if (major < 20) {
|
|
4
|
-
console.error(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
`);
|
|
9
17
|
process.exit(1);
|
|
10
|
-
}
|
|
18
|
+
}
|
package/lib/Defaults/index.js
CHANGED
|
@@ -26,8 +26,6 @@ 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 =
|
|
31
29
|
exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX =
|
|
32
30
|
exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX =
|
|
33
31
|
exports.WA_ADV_DEVICE_SIG_PREFIX =
|
|
@@ -44,8 +42,7 @@ const index_js_1 = require('../../WAProto/index.js')
|
|
|
44
42
|
const libsignal_1 = require('../Signal/libsignal')
|
|
45
43
|
const browser_utils_1 = require('../Utils/browser-utils')
|
|
46
44
|
const logger_1 = __importDefault(require('../Utils/logger'))
|
|
47
|
-
|
|
48
|
-
const version = [2, 3000, 1044798975]
|
|
45
|
+
const version = [2, 3000, 1041467552]
|
|
49
46
|
exports.VERSION = version
|
|
50
47
|
exports.UNAUTHORIZED_CODES = [401, 403, 419]
|
|
51
48
|
exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com'
|
|
@@ -58,19 +55,13 @@ exports.WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0])
|
|
|
58
55
|
exports.WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1])
|
|
59
56
|
exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5])
|
|
60
57
|
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])
|
|
64
58
|
exports.WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60
|
|
65
|
-
|
|
66
59
|
exports.STATUS_EXPIRY_SECONDS = 24 * 60 * 60
|
|
67
|
-
|
|
68
60
|
exports.PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60
|
|
69
61
|
exports.NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0'
|
|
70
62
|
exports.DICT_VERSION = 3
|
|
71
63
|
exports.KEY_BUNDLE_TYPE = Buffer.from([5])
|
|
72
|
-
exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION])
|
|
73
|
-
|
|
64
|
+
exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION])
|
|
74
65
|
exports.URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g
|
|
75
66
|
exports.WA_CERT_DETAILS = {
|
|
76
67
|
SERIAL: 0,
|
|
@@ -89,10 +80,11 @@ exports.PROCESSABLE_HISTORY_TYPES = [
|
|
|
89
80
|
]
|
|
90
81
|
exports.DEFAULT_CONNECTION_CONFIG = {
|
|
91
82
|
version: version,
|
|
92
|
-
browser: browser_utils_1.Browsers.windows('
|
|
83
|
+
browser: browser_utils_1.Browsers.windows('Firefox'),
|
|
93
84
|
waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
|
|
94
85
|
connectTimeoutMs: 20000,
|
|
95
86
|
keepAliveIntervalMs: 30000,
|
|
87
|
+
aiLabel: true,
|
|
96
88
|
logger: logger_1.default.child({ class: 'baileys' }),
|
|
97
89
|
emitOwnEvents: true,
|
|
98
90
|
defaultQueryTimeoutMs: 60000,
|
|
@@ -173,17 +165,17 @@ exports.MEDIA_HKDF_KEY_MAPPING = {
|
|
|
173
165
|
exports.MEDIA_KEYS = Object.keys(exports.MEDIA_PATH_MAP)
|
|
174
166
|
exports.MIN_PREKEY_COUNT = 5
|
|
175
167
|
exports.INITIAL_PREKEY_COUNT = 812
|
|
176
|
-
exports.UPLOAD_TIMEOUT = 30000
|
|
177
|
-
exports.MIN_UPLOAD_INTERVAL = 5000
|
|
168
|
+
exports.UPLOAD_TIMEOUT = 30000
|
|
169
|
+
exports.MIN_UPLOAD_INTERVAL = 5000
|
|
178
170
|
exports.DEFAULT_CACHE_TTLS = {
|
|
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
|
|
171
|
+
SIGNAL_STORE: 5 * 60,
|
|
172
|
+
MSG_RETRY: 60 * 60,
|
|
173
|
+
CALL_OFFER: 5 * 60,
|
|
174
|
+
USER_DEVICES: 5 * 60,
|
|
175
|
+
GROUP_METADATA: 30 * 60,
|
|
176
|
+
CALL_SESSION: 10 * 60,
|
|
177
|
+
USYNC_RESULTS: 10 * 60,
|
|
178
|
+
IDENTITY_PROOF: 60 * 60
|
|
187
179
|
}
|
|
188
180
|
exports.TimeMs = {
|
|
189
181
|
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
|
|
4
|
+
const Crypto_1 = require('../../Utils/crypto')
|
|
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(
|
|
77
|
-
} catch {
|
|
76
|
+
return Buffer.from(Crypto_1.aesDecryptWithIV(ciphertext, key, iv))
|
|
77
|
+
} catch (e) {
|
|
78
78
|
throw new Error('InvalidMessageException')
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
async getCipherText(iv, key, plaintext) {
|
|
82
82
|
try {
|
|
83
|
-
return Buffer.from(
|
|
84
|
-
} catch {
|
|
83
|
+
return Buffer.from(Crypto_1.aesEncrypWithIV(plaintext, key, iv))
|
|
84
|
+
} catch (e) {
|
|
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
|
|
58
|
+
const Crypto_1 = require('../../Utils/crypto')
|
|
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 =
|
|
67
|
+
key = Crypto_1.Curve.generateKeyPair()
|
|
68
68
|
}
|
|
69
69
|
return {
|
|
70
|
-
public:
|
|
71
|
-
private: Buffer.from(key.
|
|
70
|
+
public: Crypto_1.generateSignalPubKey(key.public),
|
|
71
|
+
private: Buffer.from(key.private)
|
|
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
|
|
4
|
+
const Crypto_1 = require('../../Utils/crypto')
|
|
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(
|
|
29
|
+
return Buffer.from(Crypto_1.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
|
|
25
|
+
throw 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
|
|
4
|
+
const Crypto_1 = require('../../Utils/crypto')
|
|
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 =
|
|
56
|
+
const res = Crypto_1.Curve.verify(signatureKey, part1, part2)
|
|
57
57
|
if (!res) throw new Error('Invalid signature!')
|
|
58
58
|
}
|
|
59
59
|
getSignature(signatureKey, serialized) {
|
|
60
|
-
return Buffer.from(
|
|
60
|
+
return Buffer.from(Crypto_1.Curve.sign(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('
|
|
39
|
+
const str = Buffer.from(data).toString('utf-8')
|
|
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
|
|
4
|
+
const Crypto_1 = require('../../Utils/crypto')
|
|
5
5
|
class SenderMessageKey {
|
|
6
6
|
constructor(iteration, seed) {
|
|
7
|
-
|
|
8
|
-
const derived = Buffer.from(
|
|
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' }))
|
|
9
9
|
const keys = new Uint8Array(32)
|
|
10
|
-
keys.set(new Uint8Array(derived.slice(16, 32)))
|
|
11
|
-
keys.set(new Uint8Array(derived.slice(32, 48)), 16)
|
|
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
12
|
this.iv = Buffer.from(derived.slice(0, 16))
|
|
13
13
|
this.cipherKey = Buffer.from(keys.buffer)
|
|
14
14
|
this.iteration = iteration
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -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('
|
|
55
|
+
const rb = require('../Utils/native-bridge').loadRustBridge()
|
|
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,15 @@ 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
|
-
|
|
64
63
|
function extractIdentityFromPkmsg(ciphertext) {
|
|
65
64
|
try {
|
|
66
65
|
if (!ciphertext || ciphertext.length < 2) {
|
|
67
66
|
return undefined
|
|
68
67
|
}
|
|
69
|
-
|
|
70
68
|
const version = ciphertext[0]
|
|
71
69
|
if ((version & 0xf) !== 3) {
|
|
72
70
|
return undefined
|
|
73
71
|
}
|
|
74
|
-
|
|
75
72
|
const identityKeyArr = rb.getPreKeyMessageIdentityKey(ciphertext)
|
|
76
73
|
if (identityKeyArr) {
|
|
77
74
|
return identityKeyArr
|
|
@@ -82,11 +79,17 @@ function extractIdentityFromPkmsg(ciphertext) {
|
|
|
82
79
|
}
|
|
83
80
|
}
|
|
84
81
|
function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
82
|
+
if (!rb) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
'The Signal session (Double Ratchet encryption) requires the "whatsapp-rust-bridge" native ' +
|
|
85
|
+
'module, which failed to load. Make sure it is installed: npm install whatsapp-rust-bridge@0.5.4'
|
|
86
|
+
)
|
|
87
|
+
}
|
|
85
88
|
const lidMapping = new lid_mapping_1.LIDMappingStore(auth.keys, logger, pnToLIDFunc)
|
|
86
89
|
const storage = signalStorage(auth, lidMapping)
|
|
87
90
|
const parsedKeys = auth.keys
|
|
88
91
|
const migratedSessionCache = new lru_cache_1.LRUCache({
|
|
89
|
-
ttl: 3 * 24 * 60 * 60 * 1000,
|
|
92
|
+
ttl: 3 * 24 * 60 * 60 * 1000,
|
|
90
93
|
ttlAutopurge: true,
|
|
91
94
|
updateAgeOnGet: true
|
|
92
95
|
})
|
|
@@ -94,7 +97,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
94
97
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
95
98
|
const senderName = jidToSignalSenderKeyName(group, authorJid)
|
|
96
99
|
const cipher = new Group_1.GroupCipher(storage, senderName)
|
|
97
|
-
|
|
98
100
|
return parsedKeys.transaction(async () => {
|
|
99
101
|
return cipher.decrypt(msg)
|
|
100
102
|
}, group)
|
|
@@ -128,7 +130,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
128
130
|
async decryptMessage({ jid, type, ciphertext }) {
|
|
129
131
|
const addr = jidToSignalProtocolAddress(jid)
|
|
130
132
|
const session = new rb.SessionCipher(storage, addr)
|
|
131
|
-
|
|
132
133
|
if (type === 'pkmsg') {
|
|
133
134
|
const identityKey = extractIdentityFromPkmsg(ciphertext)
|
|
134
135
|
if (identityKey) {
|
|
@@ -151,8 +152,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
151
152
|
}
|
|
152
153
|
return result
|
|
153
154
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
155
|
return parsedKeys.transaction(async () => {
|
|
157
156
|
return await doDecrypt()
|
|
158
157
|
}, jid)
|
|
@@ -160,7 +159,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
160
159
|
async encryptMessage({ jid, data }) {
|
|
161
160
|
const addr = jidToSignalProtocolAddress(jid)
|
|
162
161
|
const cipher = new rb.SessionCipher(storage, addr)
|
|
163
|
-
|
|
164
162
|
return parsedKeys.transaction(async () => {
|
|
165
163
|
const { type: sigType, body } = await cipher.encrypt(data)
|
|
166
164
|
const type = sigType === 3 ? 'pkmsg' : 'msg'
|
|
@@ -192,10 +190,24 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
192
190
|
await cipher.initOutgoing(session)
|
|
193
191
|
}, jid)
|
|
194
192
|
},
|
|
193
|
+
async getSessionInfo(jid) {
|
|
194
|
+
try {
|
|
195
|
+
const addr = jidToSignalProtocolAddress(jid)
|
|
196
|
+
const sessBytes = await storage.loadSession(addr.toString())
|
|
197
|
+
if (!sessBytes) return null
|
|
198
|
+
const session = rb.SessionRecord.deserialize(sessBytes)
|
|
199
|
+
const open = session.getOpenSession?.()
|
|
200
|
+
const baseKey = open?.indexInfo?.baseKey
|
|
201
|
+
const registrationId = open?.registrationId
|
|
202
|
+
if (!baseKey || typeof registrationId !== 'number') return null
|
|
203
|
+
return { baseKey: new Uint8Array(baseKey), registrationId }
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return null
|
|
206
|
+
}
|
|
207
|
+
},
|
|
195
208
|
jidToSignalProtocolAddress(jid) {
|
|
196
209
|
return jidToSignalProtocolAddress(jid).toString()
|
|
197
210
|
},
|
|
198
|
-
|
|
199
211
|
lidMapping,
|
|
200
212
|
async validateSession(jid) {
|
|
201
213
|
try {
|
|
@@ -211,28 +223,23 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
211
223
|
},
|
|
212
224
|
async deleteSession(jids) {
|
|
213
225
|
if (!jids.length) return
|
|
214
|
-
|
|
215
226
|
const sessionUpdates = {}
|
|
216
227
|
jids.forEach(jid => {
|
|
217
228
|
const addr = jidToSignalProtocolAddress(jid)
|
|
218
229
|
sessionUpdates[addr.toString()] = null
|
|
219
230
|
})
|
|
220
|
-
|
|
221
231
|
return parsedKeys.transaction(async () => {
|
|
222
232
|
await auth.keys.set({ session: sessionUpdates })
|
|
223
233
|
}, `delete-${jids.length}-sessions`)
|
|
224
234
|
},
|
|
225
235
|
async migrateSession(fromJid, toJid) {
|
|
226
|
-
|
|
227
236
|
if (!fromJid || (!(0, WABinary_1.isLidUser)(toJid) && !(0, WABinary_1.isHostedLidUser)(toJid)))
|
|
228
237
|
return { migrated: 0, skipped: 0, total: 0 }
|
|
229
|
-
|
|
230
238
|
if (!(0, WABinary_1.isPnUser)(fromJid) && !(0, WABinary_1.isHostedPnUser)(fromJid)) {
|
|
231
239
|
return { migrated: 0, skipped: 0, total: 1 }
|
|
232
240
|
}
|
|
233
241
|
const { user } = (0, WABinary_1.jidDecode)(fromJid)
|
|
234
242
|
logger.debug({ fromJid }, 'bulk device migration - loading all user devices')
|
|
235
|
-
|
|
236
243
|
const { [user]: userDevices } = await parsedKeys.get('device-list', [user])
|
|
237
244
|
if (!userDevices) {
|
|
238
245
|
return { migrated: 0, skipped: 0, total: 0 }
|
|
@@ -242,22 +249,18 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
242
249
|
if (!userDevices.includes(fromDeviceStr)) {
|
|
243
250
|
userDevices.push(fromDeviceStr)
|
|
244
251
|
}
|
|
245
|
-
|
|
246
252
|
const uncachedDevices = userDevices.filter(device => {
|
|
247
253
|
const deviceKey = `${user}.${device}`
|
|
248
254
|
return !migratedSessionCache.has(deviceKey)
|
|
249
255
|
})
|
|
250
|
-
|
|
251
256
|
const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`)
|
|
252
257
|
const existingSessions = await parsedKeys.get('session', deviceSessionKeys)
|
|
253
|
-
|
|
254
258
|
const deviceJids = []
|
|
255
259
|
for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
|
|
256
260
|
if (sessionData) {
|
|
257
|
-
|
|
258
261
|
const deviceStr = sessionKey.split('.')[1]
|
|
259
262
|
if (!deviceStr) continue
|
|
260
|
-
const deviceNum = parseInt(deviceStr
|
|
263
|
+
const deviceNum = parseInt(deviceStr)
|
|
261
264
|
let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`
|
|
262
265
|
if (deviceNum === 99) {
|
|
263
266
|
jid = `${user}:99@hosted`
|
|
@@ -274,7 +277,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
274
277
|
},
|
|
275
278
|
'bulk device migration complete - all user devices processed'
|
|
276
279
|
)
|
|
277
|
-
|
|
278
280
|
return parsedKeys.transaction(
|
|
279
281
|
async () => {
|
|
280
282
|
const migrationOps = deviceJids.map(jid => {
|
|
@@ -293,31 +295,25 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
293
295
|
})
|
|
294
296
|
const totalOps = migrationOps.length
|
|
295
297
|
let migratedCount = 0
|
|
296
|
-
|
|
297
298
|
const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())))
|
|
298
299
|
const pnSessions = await parsedKeys.get('session', pnAddrStrings)
|
|
299
|
-
|
|
300
300
|
const sessionUpdates = {}
|
|
301
301
|
for (const op of migrationOps) {
|
|
302
302
|
const pnAddrStr = op.fromAddr.toString()
|
|
303
303
|
const lidAddrStr = op.toAddr.toString()
|
|
304
304
|
const pnSession = pnSessions[pnAddrStr]
|
|
305
305
|
if (pnSession) {
|
|
306
|
-
|
|
307
306
|
const fromSession = rb.SessionRecord.deserialize(pnSession)
|
|
308
307
|
if (fromSession.haveOpenSession()) {
|
|
309
|
-
|
|
310
308
|
sessionUpdates[lidAddrStr] = fromSession.serialize()
|
|
311
309
|
sessionUpdates[pnAddrStr] = null
|
|
312
310
|
migratedCount++
|
|
313
311
|
}
|
|
314
312
|
}
|
|
315
313
|
}
|
|
316
|
-
|
|
317
314
|
if (Object.keys(sessionUpdates).length > 0) {
|
|
318
315
|
await parsedKeys.set({ session: sessionUpdates })
|
|
319
316
|
logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete')
|
|
320
|
-
|
|
321
317
|
for (const op of migrationOps) {
|
|
322
318
|
if (sessionUpdates[op.toAddr.toString()]) {
|
|
323
319
|
const deviceKey = `${op.pnUser}.${op.deviceId}`
|
|
@@ -353,12 +349,11 @@ const jidToSignalSenderKeyName = (group, user) => {
|
|
|
353
349
|
return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user))
|
|
354
350
|
}
|
|
355
351
|
function signalStorage({ creds, keys }, lidMapping) {
|
|
356
|
-
|
|
357
352
|
const resolveLIDSignalAddress = async id => {
|
|
358
353
|
if (id.includes('.')) {
|
|
359
354
|
const [deviceId, device] = id.split('.')
|
|
360
355
|
const [user, domainType_] = deviceId.split('_')
|
|
361
|
-
const domainType = parseInt(domainType_ || '0'
|
|
356
|
+
const domainType = parseInt(domainType_ || '0')
|
|
362
357
|
if (
|
|
363
358
|
domainType === WABinary_1.WAJIDDomains.LID ||
|
|
364
359
|
domainType === WABinary_1.WAJIDDomains.HOSTED_LID ||
|
|
@@ -382,22 +377,19 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
382
377
|
const fetched = await keys.get('session', keysToFetch)
|
|
383
378
|
const sess = fetched[wireJid] || fetched[id]
|
|
384
379
|
if (!sess) return null
|
|
385
|
-
|
|
386
380
|
if (typeof sess === 'object' && !Buffer.isBuffer(sess) && !ArrayBuffer.isView(sess) && sess._sessions) {
|
|
387
381
|
return null
|
|
388
382
|
}
|
|
389
|
-
|
|
390
383
|
return Buffer.isBuffer(sess) ? sess : Buffer.from(sess)
|
|
391
|
-
} catch {
|
|
384
|
+
} catch (e) {
|
|
392
385
|
return null
|
|
393
386
|
}
|
|
394
387
|
},
|
|
395
388
|
storeSession: async (id, session) => {
|
|
396
|
-
|
|
397
389
|
await keys.set({ session: { [id]: session.serialize() } })
|
|
398
390
|
},
|
|
399
391
|
isTrustedIdentity: () => {
|
|
400
|
-
return true
|
|
392
|
+
return true
|
|
401
393
|
},
|
|
402
394
|
loadIdentityKey: async id => {
|
|
403
395
|
const wireJid = await resolveLIDSignalAddress(id)
|
|
@@ -412,7 +404,6 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
412
404
|
existingKey.length === identityKey.length &&
|
|
413
405
|
existingKey.every((byte, i) => byte === identityKey[i])
|
|
414
406
|
if (existingKey && !keysMatch) {
|
|
415
|
-
|
|
416
407
|
await keys.set({
|
|
417
408
|
session: { [wireJid]: null },
|
|
418
409
|
'identity-key': { [wireJid]: identityKey }
|
|
@@ -420,7 +411,6 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
420
411
|
return true
|
|
421
412
|
}
|
|
422
413
|
if (!existingKey) {
|
|
423
|
-
|
|
424
414
|
await keys.set({ 'identity-key': { [wireJid]: identityKey } })
|
|
425
415
|
return true
|
|
426
416
|
}
|
|
@@ -441,8 +431,7 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
441
431
|
const key = creds.signedPreKey
|
|
442
432
|
return {
|
|
443
433
|
privKey: Buffer.from(key.keyPair.private),
|
|
444
|
-
pubKey: Buffer.from(key.keyPair.public)
|
|
445
|
-
signature: key.signature ? Buffer.from(key.signature) : undefined
|
|
434
|
+
pubKey: Buffer.from(key.keyPair.public)
|
|
446
435
|
}
|
|
447
436
|
},
|
|
448
437
|
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,
|
|
9
|
+
ttl: 3 * 24 * 60 * 60 * 1000,
|
|
10
10
|
ttlAutopurge: true,
|
|
11
11
|
updateAgeOnGet: true
|
|
12
12
|
})
|
|
@@ -20,10 +20,12 @@ 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
|
-
|
|
26
|
-
|
|
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
|
+
) {
|
|
27
29
|
this.logger.warn(`Invalid LID-PN mapping: ${lid}, ${pn}`)
|
|
28
30
|
continue
|
|
29
31
|
}
|
|
@@ -75,7 +77,6 @@ class LIDMappingStore {
|
|
|
75
77
|
await this.keys.transaction(async () => {
|
|
76
78
|
await this.keys.set({ 'lid-mapping': batchData })
|
|
77
79
|
}, 'lid-mapping')
|
|
78
|
-
|
|
79
80
|
for (const [pnUser, lidUser] of Object.entries(pairMap)) {
|
|
80
81
|
this.mappingCache.set(`pn:${pnUser}`, lidUser)
|
|
81
82
|
this.mappingCache.set(`lid:${lidUser}`, pnUser)
|
|
@@ -84,26 +85,6 @@ class LIDMappingStore {
|
|
|
84
85
|
async getLIDForPN(pn) {
|
|
85
86
|
return (await this.getLIDsForPNs([pn]))?.[0]?.lid || null
|
|
86
87
|
}
|
|
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
|
-
}
|
|
107
88
|
async getLIDsForPNs(pns) {
|
|
108
89
|
if (pns.length === 0) return null
|
|
109
90
|
const sortedPns = [...new Set(pns)].sort()
|
|
@@ -131,7 +112,6 @@ class LIDMappingStore {
|
|
|
131
112
|
this.logger.warn(`Invalid or empty LID user for PN ${pn}: lidUser = "${lidUser}"`)
|
|
132
113
|
return false
|
|
133
114
|
}
|
|
134
|
-
|
|
135
115
|
const pnDevice = decoded.device !== undefined ? decoded.device : 0
|
|
136
116
|
const deviceSpecificLid = `${normalizedLidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
|
|
137
117
|
this.logger.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`)
|
|
@@ -186,7 +166,7 @@ class LIDMappingStore {
|
|
|
186
166
|
}
|
|
187
167
|
}
|
|
188
168
|
if (Object.keys(usyncFetch).length > 0) {
|
|
189
|
-
const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch))
|
|
169
|
+
const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch))
|
|
190
170
|
if (result && result.length > 0) {
|
|
191
171
|
await this.storeLIDPNMappings(result)
|
|
192
172
|
for (const pair of result) {
|
package/lib/Socket/aigroups.js
CHANGED
|
@@ -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
|
-
|
|
13
|
+
/** Query helper for AI groups (w:gp2 namespace) */
|
|
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
|
-
|
|
30
|
+
// Handle incoming w:gp2 notifications (create, promote, remove, add)
|
|
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
|
-
|
|
47
|
+
// New AI group created — emit groups.upsert
|
|
48
48
|
try {
|
|
49
49
|
const meta = await aiGroupMetadata(groupId)
|
|
50
50
|
ev.emit('groups.upsert', [meta])
|
|
51
51
|
} catch {
|
|
52
|
-
|
|
52
|
+
// metadata fetch may fail; emit minimal info
|
|
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
|
-
|
|
192
|
+
// IQ response nests group inside create node: result → create → group
|
|
193
193
|
const createNode = (0, WABinary_1.getBinaryNodeChild)(result, 'create')
|
|
194
194
|
const group =
|
|
195
195
|
(0, WABinary_1.getBinaryNodeChild)(createNode || result, 'group') ||
|
package/lib/Socket/business.js
CHANGED
|
@@ -268,7 +268,11 @@ const makeBusinessSocket = config => {
|
|
|
268
268
|
})
|
|
269
269
|
return (0, business_1.parseOrderDetailsNode)(result)
|
|
270
270
|
}
|
|
271
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Get linked Facebook/Instagram accounts (WhatsApp-as-a-page linking).
|
|
273
|
+
* Ported from WhatsApp Web's WASmaxBizLinkingGetLinkedAccountsRPC.
|
|
274
|
+
* @returns {Promise<{ pageInfo: object, linkState?: string, node: object } | undefined>}
|
|
275
|
+
*/
|
|
272
276
|
const getLinkedAccounts = async () => {
|
|
273
277
|
const result = await query({
|
|
274
278
|
tag: 'iq',
|
|
@@ -280,7 +284,11 @@ const makeBusinessSocket = config => {
|
|
|
280
284
|
const button = (0, WABinary_1.getBinaryNodeChild)(fbPage, 'whatsapp_as_page_button')
|
|
281
285
|
return { pageInfo: fbPage.attrs, linkState: button?.attrs?.state, node: fbPage }
|
|
282
286
|
}
|
|
283
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Get business eligibility for the given features (meta_verified / marketing_messages / genai).
|
|
289
|
+
* Ported from WhatsApp Web's WASmaxBizMarketingMessageGetBusinessEligibilityRPC.
|
|
290
|
+
* @param {{ metaVerified?: any, marketingMessages?: any, genai?: any }} [features]
|
|
291
|
+
*/
|
|
284
292
|
const getBusinessEligibility = async (features = {}) => {
|
|
285
293
|
const attrs = {}
|
|
286
294
|
if (features.metaVerified !== undefined) attrs.meta_verified = String(features.metaVerified)
|
|
@@ -329,7 +337,7 @@ const makeBusinessSocket = config => {
|
|
|
329
337
|
return (0, business_1.parseProductNode)(productNode)
|
|
330
338
|
}
|
|
331
339
|
const productCreate = async create => {
|
|
332
|
-
|
|
340
|
+
// ensure isHidden is defined
|
|
333
341
|
create.isHidden = !!create.isHidden
|
|
334
342
|
create = await (0, business_1.uploadingNecessaryImagesOfProduct)(create, waUploadToServer)
|
|
335
343
|
const createNode = (0, business_1.toProductNode)(undefined, create)
|