whalibmob 5.1.21 → 5.5.22

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.
@@ -38,7 +38,9 @@ async function httpPostViaSocks(path, body, waVersion, proxyUrl) {
38
38
  });
39
39
 
40
40
  const _dev = getDeviceConfig();
41
- const userAgent = `WhatsApp/${waVersion} iOS/${_dev.osVersion} Device/${_dev.model}`;
41
+ const userAgent = _dev.os === 'android'
42
+ ? `WhatsApp/${waVersion} A`
43
+ : `WhatsApp/${waVersion} iOS/${_dev.osVersion} Device/${_dev.model}`;
42
44
  const req = [
43
45
  `POST /v2${path} HTTP/1.1`,
44
46
  `Host: ${dHost}`,
@@ -88,7 +90,9 @@ const {
88
90
  REGISTRATION_ENDPOINT,
89
91
  REGISTRATION_PUBLIC_KEY,
90
92
  IOS_STATIC_TOKEN,
93
+ ANDROID_STATIC_TOKEN,
91
94
  IOS_VERSION_FALLBACK,
95
+ ANDROID_VERSION_FALLBACK,
92
96
  IOS_USER_AGENT,
93
97
  IOS_DEVICE,
94
98
  SIGNAL_KEY_TYPE,
@@ -227,93 +231,93 @@ function parsePhone(phoneNumber) {
227
231
  return { cc: cc1, national: String(BigInt(str.slice(1))) };
228
232
  }
229
233
 
230
- // ---------- WhatsApp version fetch (from Apple App Store / iTunes) ----------
234
+ // ---------- WhatsApp version fetch (iOS from iTunes, Android from Play Store) ----------
231
235
 
232
- // Version cache with TTL — re-fetches every 6 hours so long-running processes
233
- // always use the current App Store version, not a stale one from startup.
234
- const VERSION_CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
235
- let _versionCache = { version: null, fetchedAt: 0 };
236
+ let _cachedIosVersion = null;
237
+ let _cachedAndroidVersion = null;
236
238
 
237
- // Fetch JSON from a single iTunes API URL. Resolves to a version string or null.
238
- function _fetchFromUrl(url) {
239
+ async function fetchIosVersion() {
240
+ if (_cachedIosVersion) return _cachedIosVersion;
239
241
  return new Promise((resolve) => {
240
- const req = https.get(url, { headers: { 'User-Agent': IOS_USER_AGENT } }, (res) => {
241
- // Follow one redirect (iTunes sometimes 301 → 200)
242
- if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location) {
243
- resolve(_fetchFromUrl(res.headers.location));
244
- return;
242
+ const req = https.get(
243
+ 'https://itunes.apple.com/lookup?bundleId=net.whatsapp.WhatsApp',
244
+ { headers: { 'User-Agent': IOS_USER_AGENT } },
245
+ (res) => {
246
+ const chunks = [];
247
+ res.on('data', d => chunks.push(d));
248
+ res.on('end', () => {
249
+ try {
250
+ const json = JSON.parse(Buffer.concat(chunks).toString('utf8'));
251
+ let ver = (json.results && json.results[0] && json.results[0].version) || IOS_VERSION_FALLBACK;
252
+ if (!ver.startsWith('2.')) ver = '2.' + ver;
253
+ _cachedIosVersion = ver;
254
+ resolve(ver);
255
+ } catch (_) {
256
+ resolve(IOS_VERSION_FALLBACK);
257
+ }
258
+ });
245
259
  }
246
- const chunks = [];
247
- res.on('data', d => chunks.push(d));
248
- res.on('end', () => {
249
- try {
250
- const json = JSON.parse(Buffer.concat(chunks).toString('utf8'));
251
- const raw = json.results && json.results[0] && json.results[0].version;
252
- if (!raw) return resolve(null);
253
- let ver = String(raw).trim();
254
- if (!ver.startsWith('2.')) ver = '2.' + ver;
255
- resolve(ver);
256
- } catch (_) {
257
- resolve(null);
258
- }
259
- });
260
- });
261
- req.on('error', () => resolve(null));
262
- req.setTimeout(8000, () => { req.destroy(); resolve(null); });
260
+ );
261
+ req.on('error', () => resolve(IOS_VERSION_FALLBACK));
262
+ req.setTimeout(8000, () => { req.destroy(); resolve(IOS_VERSION_FALLBACK); });
263
263
  });
264
264
  }
265
265
 
266
- // Live App Store sources, tried in order until one succeeds.
267
- // Multiple endpoints provide resilience against CDN hiccups and region blocks.
268
- const IOS_VERSION_SOURCES = [
269
- 'https://itunes.apple.com/lookup?bundleId=net.whatsapp.WhatsApp&country=us',
270
- 'https://itunes.apple.com/lookup?bundleId=net.whatsapp.WhatsApp',
271
- 'https://itunes.apple.com/lookup?bundleId=net.whatsapp.WhatsApp&country=gb',
272
- ];
273
-
274
- // Fetch and return the latest WhatsApp iOS version from the Apple App Store.
275
- // Results are cached for VERSION_CACHE_TTL_MS (6 hours) so long-running
276
- // servers automatically pick up new releases without a restart.
277
- // Set WA_VERSION env var to pin a specific version and skip the live fetch.
278
- async function fetchIosVersion() {
279
- const now = Date.now();
280
- if (_versionCache.version && (now - _versionCache.fetchedAt) < VERSION_CACHE_TTL_MS) {
281
- return _versionCache.version;
282
- }
283
-
284
- // Try each source in order — return the first successful result
285
- for (const url of IOS_VERSION_SOURCES) {
286
- const ver = await _fetchFromUrl(url);
287
- if (ver) {
288
- _versionCache = { version: ver, fetchedAt: now };
289
- console.error(`[DBG] fetchIosVersion: ${ver} (source: ${url})`);
290
- return ver;
266
+ // Fetch latest WhatsApp Android version from Google Play Store.
267
+ // Parses the 4-part "2.x.x.x" version string embedded in the page JSON data.
268
+ // Falls back to ANDROID_VERSION_FALLBACK on any error.
269
+ async function fetchAndroidVersion() {
270
+ if (_cachedAndroidVersion) return _cachedAndroidVersion;
271
+ try {
272
+ const axios = require('axios');
273
+ const resp = await axios.get(
274
+ 'https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=us',
275
+ {
276
+ headers: {
277
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
278
+ 'Accept-Language': 'en-US,en;q=0.9'
279
+ },
280
+ timeout: 12000
281
+ }
282
+ );
283
+ const html = String(resp.data);
284
+
285
+ // Primary: first quoted 4-part version string matching WhatsApp's "2.x.x.x" scheme.
286
+ // In Play Store JSON the current stable version appears first, before beta/history entries.
287
+ const primary = html.match(/"(2\.\d+\.\d+\.\d+)"/);
288
+ if (primary) {
289
+ _cachedAndroidVersion = primary[1];
290
+ return primary[1];
291
291
  }
292
- }
293
292
 
294
- // All sources failed use fallback constant (and don't cache it so next call retries)
295
- console.error(`[DBG] fetchIosVersion: all sources failed, using fallback ${IOS_VERSION_FALLBACK}`);
296
- return IOS_VERSION_FALLBACK;
293
+ // Secondary: unquoted version adjacent to "WhatsApp" text (catches alternate HTML structures).
294
+ const secondary = html.match(/WhatsApp[^<"]{0,200}?(2\.\d+\.\d+\.\d+)/);
295
+ if (secondary) {
296
+ _cachedAndroidVersion = secondary[1];
297
+ return secondary[1];
298
+ }
299
+ } catch (_) {}
300
+ return ANDROID_VERSION_FALLBACK;
297
301
  }
298
302
 
299
- // Return the latest WhatsApp iOS version.
300
- // If WA_VERSION is set in the environment, that value is always used (no fetch).
301
- async function fetchWaVersion() {
303
+ // Return the appropriate WhatsApp version for the active device.
304
+ // If WA_VERSION is set in the environment, that value is always used.
305
+ async function fetchWaVersion(device) {
302
306
  if (process.env.WA_VERSION) return process.env.WA_VERSION;
303
- return fetchIosVersion();
307
+ return (device && device.os === 'android') ? fetchAndroidVersion() : fetchIosVersion();
304
308
  }
305
309
 
306
310
  // ---------- Token computation ----------
307
- //
308
- // iOS token formula:
309
- // token = MD5( staticSecret + MD5hex(waVersion) + nationalNumber )
310
- // The staticSecret is IOS_STATIC_TOKEN unless WA_STATIC_TOKEN is set.
311
- // This algorithm is accepted by WhatsApp servers as of 2.26.x.
311
+ // token = MD5( staticToken + MD5hex(waVersion) + nationalNumber )
312
+ // The static token depends on the platform (iOS vs Android).
313
+ // Override with WA_STATIC_TOKEN in .env if the bundled token becomes stale.
312
314
 
313
315
  function computeToken(waVersion, national) {
314
- const secret = process.env.WA_STATIC_TOKEN || IOS_STATIC_TOKEN;
316
+ const device = getDeviceConfig();
317
+ const staticToken = process.env.WA_STATIC_TOKEN
318
+ || (device.os === 'android' ? ANDROID_STATIC_TOKEN : IOS_STATIC_TOKEN);
315
319
  const versionHashHex = md5Bytes(waVersion).toString('hex');
316
- return md5Hex(secret + versionHashHex + national);
320
+ return md5Hex(staticToken + versionHashHex + national);
317
321
  }
318
322
 
319
323
  // ---------- Byte helpers ----------
@@ -368,31 +372,24 @@ function buildPayload(store, waVersion, useToken, extraPairs) {
368
372
  const { cc, national } = parsePhone(store.phoneNumber);
369
373
  const token = useToken ? computeToken(waVersion, national) : null;
370
374
  const fdid = store.fdid.toUpperCase();
371
- const meta = getCountryMeta(cc);
372
375
 
373
376
  return buildForm([
374
- 'cc', cc,
375
- 'in', national,
376
- 'rc', String(RELEASE_CHANNEL),
377
- 'lg', meta.lg || 'en',
378
- 'lc', meta.lc || 'US',
379
- 'mcc', meta.mcc,
380
- 'mnc', meta.mnc,
381
- 'sim_mcc', meta.mcc,
382
- 'sim_mnc', meta.mnc,
383
- 'platform', '1',
384
- 'hasinrc', '0',
385
- 'authkey', toBase64Url(stripKeyPrefix(store.noiseKeyPair.public)),
386
- 'e_regid', toBase64Url(intToBytes(store.registrationId, 4)),
387
- 'e_keytype', toBase64Url(Buffer.from([SIGNAL_KEY_TYPE])),
388
- 'e_ident', toBase64Url(stripKeyPrefix(store.identityKeyPair.public)),
389
- 'e_skey_id', toBase64Url(intToBytes(store.signedPreKey.id, 3)),
377
+ 'cc', cc,
378
+ 'in', national,
379
+ 'rc', String(RELEASE_CHANNEL),
380
+ 'lg', 'en',
381
+ 'lc', 'US',
382
+ 'authkey', toBase64Url(stripKeyPrefix(store.noiseKeyPair.public)),
383
+ 'e_regid', toBase64Url(intToBytes(store.registrationId, 4)),
384
+ 'e_keytype', toBase64Url(Buffer.from([SIGNAL_KEY_TYPE])),
385
+ 'e_ident', toBase64Url(stripKeyPrefix(store.identityKeyPair.public)),
386
+ 'e_skey_id', toBase64Url(intToBytes(store.signedPreKey.id, 3)),
390
387
  'e_skey_val', toBase64Url(stripKeyPrefix(store.signedPreKey.public)),
391
388
  'e_skey_sig', toBase64Url(store.signedPreKey.signature),
392
- 'fdid', fdid,
393
- 'expid', toBase64Url(store.deviceId),
394
- 'id', toUrlHex(store.identityId),
395
- 'token', token
389
+ 'fdid', fdid,
390
+ 'expid', toBase64Url(store.deviceId),
391
+ 'id', toUrlHex(store.identityId),
392
+ 'token', token
396
393
  ], extraPairs);
397
394
  }
398
395
 
@@ -419,7 +416,9 @@ function httpPost(path, body, waVersion) {
419
416
 
420
417
  return new Promise((resolve, reject) => {
421
418
  const _httpDev = getDeviceConfig();
422
- const userAgent = `WhatsApp/${waVersion} iOS/${_httpDev.osVersion} Device/${_httpDev.model}`;
419
+ const userAgent = _httpDev.os === 'android'
420
+ ? `WhatsApp/${waVersion} A`
421
+ : `WhatsApp/${waVersion} iOS/${_httpDev.osVersion} Device/${_httpDev.model}`;
423
422
  const bodyBuf = Buffer.from(body, 'utf8');
424
423
  const opts = {
425
424
  hostname: 'v.whatsapp.net',
@@ -462,7 +461,7 @@ async function sendRequest(path, store, waVersion, useToken, extraPairs) {
462
461
  // ---------- Public API ----------
463
462
 
464
463
  async function checkIfRegistered(store) {
465
- const waVersion = await fetchWaVersion();
464
+ const waVersion = await fetchWaVersion(getDeviceConfig());
466
465
  return sendRequest('/exist', store, waVersion, false, null);
467
466
  }
468
467
 
@@ -491,9 +490,13 @@ async function checkNumberStatus(phoneNumber) {
491
490
 
492
491
  phoneNumber = String(phoneNumber).replace(/\D/g, '');
493
492
  const store = createNewStore(phoneNumber);
494
- const waVersion = await fetchWaVersion();
493
+ const waVersion = await fetchWaVersion(getDeviceConfig());
494
+ const { cc } = parsePhone(phoneNumber);
495
+ const meta = getCountryMeta(cc);
495
496
 
496
497
  const baseExtra = [
498
+ 'sim_mcc', meta.mcc,
499
+ 'sim_mnc', meta.mnc,
497
500
  'reason', '',
498
501
  'cellular_strength', '1'
499
502
  ];
@@ -589,7 +592,7 @@ async function assertRegistrationKeys(store, waVersion) {
589
592
  async function requestSmsCode(store, method) {
590
593
  method = method || 'sms';
591
594
  const _device = getDeviceConfig();
592
- const waVersion = await fetchWaVersion();
595
+ const waVersion = await fetchWaVersion(_device);
593
596
  store.version = waVersion;
594
597
  store.device = _device;
595
598
 
@@ -601,6 +604,8 @@ async function requestSmsCode(store, method) {
601
604
  async function _tryMethod(m) {
602
605
  const extra = [
603
606
  'method', m,
607
+ 'sim_mcc', '000',
608
+ 'sim_mnc', '000',
604
609
  'reason', '',
605
610
  'cellular_strength', '1'
606
611
  ];
@@ -676,7 +681,7 @@ async function requestSmsCode(store, method) {
676
681
 
677
682
  async function verifyCode(store, code) {
678
683
  const _device = getDeviceConfig();
679
- const waVersion = await fetchWaVersion();
684
+ const waVersion = await fetchWaVersion(_device);
680
685
  store.version = waVersion;
681
686
  store.device = _device;
682
687
  const normalized = code.replace(/[\s\-]/g, '').replace(/\D/g, '');
@@ -701,4 +706,4 @@ async function verifyCode(store, code) {
701
706
  throw new Error(`Verification failed: ${reason || JSON.stringify(result)}`);
702
707
  }
703
708
 
704
- module.exports = { checkIfRegistered, checkNumberStatus, requestSmsCode, verifyCode, fetchIosVersion, fetchWaVersion, parsePhone, getCountryMeta, assertRegistrationKeys };
709
+ module.exports = { checkIfRegistered, checkNumberStatus, requestSmsCode, verifyCode, fetchIosVersion, fetchAndroidVersion, fetchWaVersion, parsePhone, assertRegistrationKeys };
package/lib/Store.js CHANGED
@@ -5,7 +5,7 @@ const path = require('path');
5
5
  const crypto = require('crypto');
6
6
  const curveJs = require('curve25519-js');
7
7
  const { v4: uuidv4 } = require('uuid');
8
- const { IOS_DEVICE, IOS_VERSION_FALLBACK } = require('./constants');
8
+ const { IOS_DEVICE, IOS_VERSION_FALLBACK, ANDROID_VERSION_FALLBACK } = require('./constants');
9
9
  const { getDeviceConfig } = require('./DeviceConfig');
10
10
 
11
11
  // ─────────────────────────────────────────────────────────
@@ -60,7 +60,7 @@ function createNewStore(phoneNumber) {
60
60
  const identityId = crypto.randomBytes(16);
61
61
 
62
62
  const device = getDeviceConfig();
63
- const version = IOS_VERSION_FALLBACK;
63
+ const version = device.os === 'android' ? ANDROID_VERSION_FALLBACK : IOS_VERSION_FALLBACK;
64
64
 
65
65
  return {
66
66
  phoneNumber: String(phoneNumber).replace(/^\+/, ''),
package/lib/constants.js CHANGED
@@ -7,16 +7,18 @@ const REGISTRATION_PUBLIC_KEY = Buffer.from('8e8c0f74c3ebc5d7a6865c6c3c843856b06
7
7
 
8
8
  const MOBILE_PROLOGUE = Buffer.from([0x57, 0x41, 0x05, 0x03]);
9
9
 
10
- // iOS static tokens (MD5 approach): token = MD5( staticToken + MD5hex(waVersion) + nationalNumber )
10
+ // Static tokens used in WhatsApp registration token computation.
11
+ // token = MD5( staticToken + MD5hex(waVersion) + nationalNumber )
11
12
  const IOS_STATIC_TOKEN = '0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM';
12
13
  const IOS_BUSINESS_STATIC_TOKEN = 'USUDuDYDeQhY4RF2fCSp5m3F6kJ1M2J8wS7bbNA2';
14
+ const ANDROID_STATIC_TOKEN = 'Y29Cs6AVNR2bj5PBeKSYFd1nAKuvNQ3h';
13
15
 
14
- // WhatsApp version fallback — used when ALL live iTunes sources fail.
15
- // Updated: 2025-03. The library always tries the App Store first.
16
- const IOS_VERSION_FALLBACK = '2.26.10.74';
16
+ // WhatsApp version fallbacks — used when live fetch fails.
17
+ const IOS_VERSION_FALLBACK = '2.26.9.75';
18
+ const ANDROID_VERSION_FALLBACK = '2.24.13.80';
17
19
 
18
20
  // Safari UA for the iTunes lookup only.
19
- const IOS_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Mobile/15E148 Safari/604.1';
21
+ const IOS_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Mobile/15E148 Safari/604.1';
20
22
 
21
23
  // Default iOS device (iPhone 15 Pro, iOS 17.4.1).
22
24
  // platform 1 = iOS in WhatsApp's ClientPayload.UserAgent proto enum.
@@ -32,129 +34,139 @@ const IOS_DEVICE = {
32
34
  };
33
35
 
34
36
  // ─── iOS device profiles ───────────────────────────────────────────────────
35
- // Set WA_DEVICE=<key> in .env to select one.
36
- // When no profile is set, the library picks one at random for each new session.
37
- // platform 1 = IOS in WhatsApp's ClientPayload.UserAgent proto enum.
37
+ // Set WA_OS=ios WA_DEVICE=<key> in .env to select one.
38
38
  const IOS_DEVICE_PROFILES = {
39
- 'iphone16promax': {
40
- os: 'ios', platform: 1,
41
- model: 'iPhone 16 Pro Max', manufacturer: 'Apple',
42
- osVersion: '18.3.2', osBuildNumber: '22D82',
43
- modelId: 'iPhone17,2', deviceModelType: 2
44
- },
45
- 'iphone16pro': {
46
- os: 'ios', platform: 1,
47
- model: 'iPhone 16 Pro', manufacturer: 'Apple',
48
- osVersion: '18.3.2', osBuildNumber: '22D82',
49
- modelId: 'iPhone17,1', deviceModelType: 2
50
- },
51
- 'iphone16plus': {
52
- os: 'ios', platform: 1,
53
- model: 'iPhone 16 Plus', manufacturer: 'Apple',
54
- osVersion: '18.3.2', osBuildNumber: '22D82',
55
- modelId: 'iPhone17,4', deviceModelType: 2
56
- },
57
- 'iphone16': {
58
- os: 'ios', platform: 1,
59
- model: 'iPhone 16', manufacturer: 'Apple',
60
- osVersion: '18.3.2', osBuildNumber: '22D82',
61
- modelId: 'iPhone17,3', deviceModelType: 2
62
- },
63
- 'iphone15promax': {
64
- os: 'ios', platform: 1,
65
- model: 'iPhone 15 Pro Max', manufacturer: 'Apple',
66
- osVersion: '18.3.2', osBuildNumber: '22D82',
67
- modelId: 'iPhone16,2', deviceModelType: 2
68
- },
69
39
  'iphone15pro': {
70
40
  os: 'ios', platform: 1,
71
41
  model: 'iPhone 15 Pro', manufacturer: 'Apple',
72
- osVersion: '18.3.2', osBuildNumber: '22D82',
42
+ osVersion: '17.4.1', osBuildNumber: '21E236',
73
43
  modelId: 'iPhone16,1', deviceModelType: 2
74
44
  },
75
- 'iphone15plus': {
76
- os: 'ios', platform: 1,
77
- model: 'iPhone 15 Plus', manufacturer: 'Apple',
78
- osVersion: '18.3.2', osBuildNumber: '22D82',
79
- modelId: 'iPhone15,5', deviceModelType: 2
80
- },
81
45
  'iphone15': {
82
46
  os: 'ios', platform: 1,
83
47
  model: 'iPhone 15', manufacturer: 'Apple',
84
- osVersion: '18.3.2', osBuildNumber: '22D82',
48
+ osVersion: '17.4.1', osBuildNumber: '21E236',
85
49
  modelId: 'iPhone15,4', deviceModelType: 2
86
50
  },
87
- 'iphone14promax': {
51
+ 'iphone14': {
88
52
  os: 'ios', platform: 1,
89
- model: 'iPhone 14 Pro Max', manufacturer: 'Apple',
90
- osVersion: '18.3.2', osBuildNumber: '22D82',
91
- modelId: 'iPhone15,3', deviceModelType: 2
53
+ model: 'iPhone 14', manufacturer: 'Apple',
54
+ osVersion: '17.4.1', osBuildNumber: '21E236',
55
+ modelId: 'iPhone14,2', deviceModelType: 2
92
56
  },
93
57
  'iphone14pro': {
94
58
  os: 'ios', platform: 1,
95
59
  model: 'iPhone 14 Pro', manufacturer: 'Apple',
96
- osVersion: '18.3.2', osBuildNumber: '22D82',
60
+ osVersion: '17.4.1', osBuildNumber: '21E236',
97
61
  modelId: 'iPhone15,2', deviceModelType: 2
98
62
  },
99
- 'iphone14plus': {
100
- os: 'ios', platform: 1,
101
- model: 'iPhone 14 Plus', manufacturer: 'Apple',
102
- osVersion: '17.7.5', osBuildNumber: '21H516',
103
- modelId: 'iPhone14,8', deviceModelType: 2
104
- },
105
- 'iphone14': {
106
- os: 'ios', platform: 1,
107
- model: 'iPhone 14', manufacturer: 'Apple',
108
- osVersion: '17.7.5', osBuildNumber: '21H516',
109
- modelId: 'iPhone14,7', deviceModelType: 2
110
- },
111
- 'iphone13pro': {
112
- os: 'ios', platform: 1,
113
- model: 'iPhone 13 Pro', manufacturer: 'Apple',
114
- osVersion: '17.7.5', osBuildNumber: '21H516',
115
- modelId: 'iPhone14,2', deviceModelType: 2
116
- },
117
63
  'iphone13': {
118
64
  os: 'ios', platform: 1,
119
65
  model: 'iPhone 13', manufacturer: 'Apple',
120
- osVersion: '17.7.5', osBuildNumber: '21H516',
66
+ osVersion: '16.7.8', osBuildNumber: '20H343',
121
67
  modelId: 'iPhone14,5', deviceModelType: 2
122
68
  },
123
- 'iphone12pro': {
124
- os: 'ios', platform: 1,
125
- model: 'iPhone 12 Pro', manufacturer: 'Apple',
126
- osVersion: '17.7.5', osBuildNumber: '21H516',
127
- modelId: 'iPhone13,3', deviceModelType: 1
128
- },
129
69
  'iphone12': {
130
70
  os: 'ios', platform: 1,
131
71
  model: 'iPhone 12', manufacturer: 'Apple',
132
- osVersion: '17.7.5', osBuildNumber: '21H516',
72
+ osVersion: '15.8.3', osBuildNumber: '19H384',
133
73
  modelId: 'iPhone13,2', deviceModelType: 1
134
- },
135
- 'iphonese3': {
136
- os: 'ios', platform: 1,
137
- model: 'iPhone SE (3rd generation)', manufacturer: 'Apple',
138
- osVersion: '17.7.5', osBuildNumber: '21H516',
139
- modelId: 'iPhone14,6', deviceModelType: 1
140
- },
141
- 'iphone11pro': {
142
- os: 'ios', platform: 1,
143
- model: 'iPhone 11 Pro', manufacturer: 'Apple',
144
- osVersion: '17.7.5', osBuildNumber: '21H516',
145
- modelId: 'iPhone12,3', deviceModelType: 1
146
- },
147
- 'iphone11': {
148
- os: 'ios', platform: 1,
149
- model: 'iPhone 11', manufacturer: 'Apple',
150
- osVersion: '17.7.5', osBuildNumber: '21H516',
151
- modelId: 'iPhone12,1', deviceModelType: 1
152
- },
153
- 'iphonexs': {
154
- os: 'ios', platform: 1,
155
- model: 'iPhone Xs', manufacturer: 'Apple',
156
- osVersion: '16.7.11', osBuildNumber: '20H330',
157
- modelId: 'iPhone11,2', deviceModelType: 1
74
+ }
75
+ };
76
+
77
+ // ─── Android device profiles ───────────────────────────────────────────────
78
+ // Set WA_OS=android WA_DEVICE=<key> in .env to select one.
79
+ // platform 3 = ANDROID in WhatsApp's ClientPayload.UserAgent proto enum.
80
+ const ANDROID_DEVICE_PROFILES = {
81
+ 'samsung-s24-ultra': {
82
+ os: 'android', platform: 3,
83
+ model: 'Samsung Galaxy S24 Ultra', manufacturer: 'Samsung',
84
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
85
+ modelId: 'SM-S928B', deviceModelType: 2
86
+ },
87
+ 'samsung-s24': {
88
+ os: 'android', platform: 3,
89
+ model: 'Samsung Galaxy S24', manufacturer: 'Samsung',
90
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
91
+ modelId: 'SM-S921B', deviceModelType: 2
92
+ },
93
+ 'samsung-s23': {
94
+ os: 'android', platform: 3,
95
+ model: 'Samsung Galaxy S23', manufacturer: 'Samsung',
96
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
97
+ modelId: 'SM-S911B', deviceModelType: 2
98
+ },
99
+ 'samsung-s23-ultra': {
100
+ os: 'android', platform: 3,
101
+ model: 'Samsung Galaxy S23 Ultra', manufacturer: 'Samsung',
102
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
103
+ modelId: 'SM-S918B', deviceModelType: 2
104
+ },
105
+ 'samsung-a55': {
106
+ os: 'android', platform: 3,
107
+ model: 'Samsung Galaxy A55', manufacturer: 'Samsung',
108
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
109
+ modelId: 'SM-A556B', deviceModelType: 1
110
+ },
111
+ 'pixel8pro': {
112
+ os: 'android', platform: 3,
113
+ model: 'Pixel 8 Pro', manufacturer: 'Google',
114
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
115
+ modelId: 'Pixel 8 Pro', deviceModelType: 2
116
+ },
117
+ 'pixel8': {
118
+ os: 'android', platform: 3,
119
+ model: 'Pixel 8', manufacturer: 'Google',
120
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
121
+ modelId: 'Pixel 8', deviceModelType: 2
122
+ },
123
+ 'pixel7': {
124
+ os: 'android', platform: 3,
125
+ model: 'Pixel 7', manufacturer: 'Google',
126
+ osVersion: '14', osBuildNumber: 'TP1A.221005.002',
127
+ modelId: 'Pixel 7', deviceModelType: 2
128
+ },
129
+ 'pixel7a': {
130
+ os: 'android', platform: 3,
131
+ model: 'Pixel 7a', manufacturer: 'Google',
132
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
133
+ modelId: 'Pixel 7a', deviceModelType: 1
134
+ },
135
+ 'xiaomi14': {
136
+ os: 'android', platform: 3,
137
+ model: 'Xiaomi 14', manufacturer: 'Xiaomi',
138
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
139
+ modelId: '23127PN0CG', deviceModelType: 2
140
+ },
141
+ 'xiaomi13': {
142
+ os: 'android', platform: 3,
143
+ model: 'Xiaomi 13', manufacturer: 'Xiaomi',
144
+ osVersion: '13', osBuildNumber: 'TQ3A.230901.001',
145
+ modelId: '2211133G', deviceModelType: 2
146
+ },
147
+ 'oneplus12': {
148
+ os: 'android', platform: 3,
149
+ model: 'OnePlus 12', manufacturer: 'OnePlus',
150
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
151
+ modelId: 'CPH2573', deviceModelType: 2
152
+ },
153
+ 'oneplus11': {
154
+ os: 'android', platform: 3,
155
+ model: 'OnePlus 11', manufacturer: 'OnePlus',
156
+ osVersion: '13', osBuildNumber: 'TQ3A.230901.001',
157
+ modelId: 'CPH2449', deviceModelType: 2
158
+ },
159
+ 'oppo-find-x7': {
160
+ os: 'android', platform: 3,
161
+ model: 'OPPO Find X7', manufacturer: 'OPPO',
162
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
163
+ modelId: 'CPH2599', deviceModelType: 2
164
+ },
165
+ 'realme-gt5': {
166
+ os: 'android', platform: 3,
167
+ model: 'realme GT 5 Pro', manufacturer: 'realme',
168
+ osVersion: '14', osBuildNumber: 'UP1A.231005.007',
169
+ modelId: 'RMX3888', deviceModelType: 2
158
170
  }
159
171
  };
160
172
 
@@ -187,10 +199,13 @@ module.exports = {
187
199
  MOBILE_PROLOGUE,
188
200
  IOS_STATIC_TOKEN,
189
201
  IOS_BUSINESS_STATIC_TOKEN,
202
+ ANDROID_STATIC_TOKEN,
190
203
  IOS_VERSION_FALLBACK,
204
+ ANDROID_VERSION_FALLBACK,
191
205
  IOS_USER_AGENT,
192
206
  IOS_DEVICE,
193
207
  IOS_DEVICE_PROFILES,
208
+ ANDROID_DEVICE_PROFILES,
194
209
  SIGNAL_KEY_TYPE,
195
210
  RELEASE_CHANNEL,
196
211
  TAG