nodejs-insta-private-api-mqt 1.4.6 → 1.4.7
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.
|
@@ -13,7 +13,7 @@ const LOGIN_EXPERIMENTS = 'ig_android_fci_onboarding_friend_search,ig_android_de
|
|
|
13
13
|
const FACEBOOK_ANALYTICS_APPLICATION_ID = '567067343352427';
|
|
14
14
|
const FACEBOOK_OTA_FIELDS = 'update%7Bdownload_uri%2Cdownload_uri_delta_base%2Cversion_code_delta_base%2Cdownload_uri_delta%2Cfallback_to_full_update%2Cfile_size_delta%2Cversion_code%2Cpublished_date%2Cfile_size%2Cota_bundle_type%2Cresources_checksum%2Callowed_networks%2Crelease_id%7D';
|
|
15
15
|
const FACEBOOK_ORCA_APPLICATION_ID = '124024574287414';
|
|
16
|
-
const BLOKS_VERSION_ID = '
|
|
16
|
+
const BLOKS_VERSION_ID = '5e47baf35c5a270b44c8906c8b99063564b30ef69779f3dee0b828bee2e4ef5b';
|
|
17
17
|
const SUPPORTED_CAPABILITIES = [
|
|
18
18
|
{
|
|
19
19
|
value: '119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0',
|
|
@@ -345,6 +345,175 @@ class AccountRepository extends Repository {
|
|
|
345
345
|
return fallback;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Fetches the latest bloksVersionId from Instagram's launcher/sync endpoint.
|
|
350
|
+
* Saves result to bloks-version.json in the session folder (authinfo_instagram/<username>/).
|
|
351
|
+
* If fetch fails, keeps the existing bloksVersionId from state or falls back to hardcoded.
|
|
352
|
+
*/
|
|
353
|
+
async _fetchAndSaveBloksVersion(username) {
|
|
354
|
+
const fs = require('fs');
|
|
355
|
+
const path = require('path');
|
|
356
|
+
const FALLBACK_BLOKS = '5e47baf35c5a270b44c8906c8b99063564b30ef69779f3dee0b828bee2e4ef5b';
|
|
357
|
+
|
|
358
|
+
// Session folder: authinfo_instagram/<username>/
|
|
359
|
+
const sessionDir = path.join(
|
|
360
|
+
process.cwd(),
|
|
361
|
+
'authinfo_instagram',
|
|
362
|
+
username ? String(username) : 'default'
|
|
363
|
+
);
|
|
364
|
+
const bloksFile = path.join(sessionDir, 'bloks-version.json');
|
|
365
|
+
|
|
366
|
+
try { fs.mkdirSync(sessionDir, { recursive: true }); } catch (e) {}
|
|
367
|
+
|
|
368
|
+
const state = this.client.state || {};
|
|
369
|
+
const userAgent = this._resolveUserAgent();
|
|
370
|
+
const lang = state.language || 'ro_RO';
|
|
371
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
372
|
+
const androidDeviceId =
|
|
373
|
+
state.androidDeviceId || state.deviceId ||
|
|
374
|
+
`android-${crypto.randomBytes(8).toString('hex')}`;
|
|
375
|
+
const deviceUUID = state.uuid || state.deviceId ||
|
|
376
|
+
(crypto.randomUUID ? crypto.randomUUID() : require('uuid').v4());
|
|
377
|
+
const networkProps = buildNetworkProperties();
|
|
378
|
+
|
|
379
|
+
// Current bloksVersionId as starting point
|
|
380
|
+
const currentBloks = state.bloksVersionId || FALLBACK_BLOKS;
|
|
381
|
+
|
|
382
|
+
// Helper: extract 64-char hex bloksVersionId from any object/string
|
|
383
|
+
const extractBloks = (body) => {
|
|
384
|
+
if (!body) return null;
|
|
385
|
+
const bodyStr = typeof body === 'string' ? body : JSON.stringify(body);
|
|
386
|
+
// Direct fields
|
|
387
|
+
if (body.bloks_version_id && /^[a-f0-9]{64}$/.test(body.bloks_version_id)) return body.bloks_version_id;
|
|
388
|
+
if (body.bloksVersionId && /^[a-f0-9]{64}$/.test(body.bloksVersionId)) return body.bloksVersionId;
|
|
389
|
+
// Search in JSON string
|
|
390
|
+
const m = bodyStr.match(/"bloks_version_id"\s*:\s*"([a-f0-9]{64})"/) ||
|
|
391
|
+
bodyStr.match(/"bloksVersionId"\s*:\s*"([a-f0-9]{64})"/) ||
|
|
392
|
+
bodyStr.match(/"x-bloks-version-id"\s*:\s*"([a-f0-9]{64})"/) ||
|
|
393
|
+
bodyStr.match(/([a-f0-9]{64})/);
|
|
394
|
+
if (m && m[1] && /^[a-f0-9]{64}$/.test(m[1])) return m[1];
|
|
395
|
+
return null;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Helper: safe state setter for bloksVersionId
|
|
399
|
+
// state.bloksVersionId may be read-only (getter-only via Object.defineProperty)
|
|
400
|
+
// so we force-redefine it
|
|
401
|
+
const setBloksInState = (val) => {
|
|
402
|
+
try {
|
|
403
|
+
// Try direct set first
|
|
404
|
+
this.client.state.bloksVersionId = val;
|
|
405
|
+
return;
|
|
406
|
+
} catch (e) {}
|
|
407
|
+
try {
|
|
408
|
+
// Force redefine the property as writable
|
|
409
|
+
Object.defineProperty(this.client.state, 'bloksVersionId', {
|
|
410
|
+
value: val,
|
|
411
|
+
writable: true,
|
|
412
|
+
configurable: true,
|
|
413
|
+
enumerable: true,
|
|
414
|
+
});
|
|
415
|
+
return;
|
|
416
|
+
} catch (e) {}
|
|
417
|
+
try { this.client.state._bloksVersionId = val; } catch (e) {}
|
|
418
|
+
try {
|
|
419
|
+
// Last resort: patch constants object if that's where it comes from
|
|
420
|
+
if (this.client.state.constants) {
|
|
421
|
+
this.client.state.constants.BLOKS_VERSION_ID = val;
|
|
422
|
+
}
|
|
423
|
+
} catch (e) {}
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const commonHeaders = {
|
|
427
|
+
'accept-language': `${lang.replace('_', '-')}, en-US`,
|
|
428
|
+
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
|
429
|
+
'x-bloks-version-id': currentBloks,
|
|
430
|
+
'x-ig-android-id': androidDeviceId,
|
|
431
|
+
'x-ig-app-id': String(state.fbAnalyticsApplicationId || '567067343352427'),
|
|
432
|
+
'x-ig-app-locale': lang,
|
|
433
|
+
'x-ig-device-locale': lang,
|
|
434
|
+
'x-ig-mapped-locale': lang,
|
|
435
|
+
'x-ig-capabilities': '3brTv10=',
|
|
436
|
+
'x-ig-connection-type': 'MOBILE(UNKNOWN)',
|
|
437
|
+
'x-fb-connection-type': 'MOBILE.UNKNOWN',
|
|
438
|
+
'x-fb-client-ip': 'True',
|
|
439
|
+
'x-fb-server-cluster': 'True',
|
|
440
|
+
'x-fb-http-engine': 'MNS/TCP',
|
|
441
|
+
'x-fb-network-properties': networkProps,
|
|
442
|
+
'x-ig-timezone-offset': String(typeof state.timezoneOffset === 'number' ? state.timezoneOffset : 7200),
|
|
443
|
+
'x-mid': state.mid || `aZ${crypto.randomBytes(8).toString('hex')}`,
|
|
444
|
+
'x-pigeon-rawclienttime': `${nowSec}.${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`,
|
|
445
|
+
'x-pigeon-session-id': state.pigeonSessionId || `UFS-${crypto.randomBytes(16).toString('hex')}-0`,
|
|
446
|
+
'x-tigon-is-retry': 'False',
|
|
447
|
+
'x-ig-www-claim': state.igWWWClaim || '0',
|
|
448
|
+
'accept-encoding': 'gzip, deflate',
|
|
449
|
+
'user-agent': userAgent,
|
|
450
|
+
'x-fb-rmd': 'state=URL_ELIGIBLE',
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
let fetchedBloks = null;
|
|
454
|
+
let rawBody = null;
|
|
455
|
+
let endpointUsed = null;
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
// Endpoint 1: launcher/sync — sometimes returns bloks in config
|
|
459
|
+
const r1 = await this.client.request.send({
|
|
460
|
+
method: 'POST',
|
|
461
|
+
url: '/api/v1/launcher/sync/',
|
|
462
|
+
form: this.client.request.sign({ id: deviceUUID, server_config_retrieval: '1' }),
|
|
463
|
+
headers: { ...commonHeaders, 'x-fb-friendly-name': 'IgApi: launcher/sync/' },
|
|
464
|
+
});
|
|
465
|
+
rawBody = r1.body;
|
|
466
|
+
fetchedBloks = extractBloks(r1.body);
|
|
467
|
+
if (fetchedBloks) endpointUsed = 'launcher/sync';
|
|
468
|
+
} catch (e) {}
|
|
469
|
+
|
|
470
|
+
if (!fetchedBloks) {
|
|
471
|
+
try {
|
|
472
|
+
// Endpoint 2: qe/sync — often contains bloks version in headers/body
|
|
473
|
+
const r2 = await this.client.request.send({
|
|
474
|
+
method: 'POST',
|
|
475
|
+
url: '/api/v1/qe/sync/',
|
|
476
|
+
form: this.client.request.sign({ id: deviceUUID, server_config_retrieval: '1' }),
|
|
477
|
+
headers: { ...commonHeaders, 'x-fb-friendly-name': 'IgApi: qe/sync/' },
|
|
478
|
+
});
|
|
479
|
+
// Check response headers too
|
|
480
|
+
const hdrs = r2.headers || {};
|
|
481
|
+
const bloksHeader = hdrs['x-bloks-version-id'] || hdrs['bloks-version-id'];
|
|
482
|
+
if (bloksHeader && /^[a-f0-9]{64}$/.test(bloksHeader)) {
|
|
483
|
+
fetchedBloks = bloksHeader;
|
|
484
|
+
endpointUsed = 'qe/sync (header)';
|
|
485
|
+
} else {
|
|
486
|
+
fetchedBloks = extractBloks(r2.body);
|
|
487
|
+
if (fetchedBloks) endpointUsed = 'qe/sync (body)';
|
|
488
|
+
}
|
|
489
|
+
if (!rawBody) rawBody = r2.body;
|
|
490
|
+
} catch (e) {}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const gotNew = !!(fetchedBloks && fetchedBloks !== currentBloks);
|
|
494
|
+
const bloksToUse = fetchedBloks || currentBloks;
|
|
495
|
+
|
|
496
|
+
// Update state safely
|
|
497
|
+
setBloksInState(bloksToUse);
|
|
498
|
+
|
|
499
|
+
// Save to bloks-version.json in session folder
|
|
500
|
+
const saveData = {
|
|
501
|
+
username: username || 'unknown',
|
|
502
|
+
bloksVersionId: bloksToUse,
|
|
503
|
+
previousBloksVersionId: currentBloks,
|
|
504
|
+
updatedAt: new Date().toISOString(),
|
|
505
|
+
gotNewVersion: gotNew,
|
|
506
|
+
fetchSuccess: !!fetchedBloks,
|
|
507
|
+
endpointUsed: endpointUsed || 'none — kept existing',
|
|
508
|
+
rawResponse: rawBody || null,
|
|
509
|
+
};
|
|
510
|
+
try {
|
|
511
|
+
fs.writeFileSync(bloksFile, JSON.stringify(saveData, null, 2), 'utf8');
|
|
512
|
+
} catch (writeErr) {}
|
|
513
|
+
|
|
514
|
+
return bloksToUse;
|
|
515
|
+
}
|
|
516
|
+
|
|
348
517
|
async ensureCsrfToken() {
|
|
349
518
|
const cookieToken = this.client.state.cookieCsrfToken;
|
|
350
519
|
if (cookieToken && cookieToken !== 'missing' && cookieToken !== 'pending') {
|
|
@@ -883,6 +1052,9 @@ class AccountRepository extends Repository {
|
|
|
883
1052
|
|
|
884
1053
|
if (!username || !password) throw new Error('Username and password are required');
|
|
885
1054
|
|
|
1055
|
+
// Fetch latest bloksVersionId from Instagram and save to session folder
|
|
1056
|
+
try { await this._fetchAndSaveBloksVersion(username); } catch (e) {}
|
|
1057
|
+
|
|
886
1058
|
await this.ensureCsrfToken();
|
|
887
1059
|
|
|
888
1060
|
try { await this._launcherMobileConfig(true); } catch (e) {}
|