nodejs-insta-private-api-mqt 1.3.74 → 1.3.76

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.
@@ -264,7 +264,7 @@ class Request {
264
264
  if (!url) return;
265
265
  const path = url.toLowerCase();
266
266
 
267
- if (path.includes('/accounts/login/') || path.includes('/launcher/sync/')) {
267
+ if (path.includes('/accounts/login/') || path.includes('/launcher/sync/') || path.includes('/bloks/async_action/com.bloks.www.bloks.caa.login')) {
268
268
  this.navChain.simulateAppOpen();
269
269
  return;
270
270
  }
@@ -188,11 +188,19 @@ class State {
188
188
  } catch {
189
189
  // fallback to parsed authorization if available
190
190
  this.updateAuthorization();
191
- if (!this.parsedAuthorization) throw new Error('Could not find ds_user_id');
192
- return this.parsedAuthorization.ds_user_id;
191
+ if (this.parsedAuthorization && this.parsedAuthorization.ds_user_id) {
192
+ return this.parsedAuthorization.ds_user_id;
193
+ }
194
+ // fallback: check if userId was set directly on state
195
+ if (this._userId) return this._userId;
196
+ return null;
193
197
  }
194
198
  }
195
199
 
200
+ set cookieUserId(val) {
201
+ this._userId = val;
202
+ }
203
+
196
204
  get cookieUsername() {
197
205
  try {
198
206
  return this.extractCookieValue('ds_user');
@@ -45,22 +45,84 @@ class AccountRepository extends Repository {
45
45
  const { encrypted, time } = this.encryptPassword(password);
46
46
 
47
47
  return this.requestWithRetry(async () => {
48
- const countryCode = this.client.state.countryCode || 1;
48
+ const aacInitTimestamp = Math.floor(Date.now() / 1000) - Math.floor(Math.random() * 50);
49
+ const aacjid = crypto.randomUUID ? crypto.randomUUID() : require('uuid').v4();
50
+ const aaccs = crypto.randomBytes(32).toString('base64url');
51
+
52
+ const clientInputParams = {
53
+ aac: JSON.stringify({
54
+ aac_init_timestamp: aacInitTimestamp,
55
+ aacjid: aacjid,
56
+ aaccs: aaccs,
57
+ }),
58
+ sim_phones: [],
59
+ aymh_accounts: [],
60
+ network_bssid: null,
61
+ secure_family_device_id: '',
62
+ has_granted_read_contacts_permissions: 0,
63
+ auth_secure_device_id: '',
64
+ has_whatsapp_installed: 1,
65
+ password: `#PWD_INSTAGRAM:4:${time}:${encrypted}`,
66
+ sso_token_map_json_string: '{}',
67
+ block_store_machine_id: '',
68
+ ig_vetted_device_nonces: '{}',
69
+ contact_point: username,
70
+ machine_id: this.client.state.mid || '',
71
+ login_attempt_count: '0',
72
+ reg_flow_taken: 'phone',
73
+ device_id: this.client.state.uuid,
74
+ phone_id: this.client.state.phoneId,
75
+ family_device_id: this.client.state.phoneId,
76
+ encryption_enabled: '1',
77
+ has_dbl_tap_login: 0,
78
+ jazoest: AccountRepository.createJazoest(this.client.state.phoneId),
79
+ openid_tokens: '{}',
80
+ };
81
+
82
+ const serverParams = {
83
+ credential_type: 'password',
84
+ device_id: this.client.state.uuid,
85
+ };
86
+
87
+ const paramsJson = JSON.stringify({
88
+ client_input_params: clientInputParams,
89
+ server_params: serverParams,
90
+ });
91
+
92
+ const attestParams = AccountRepository.generateAttestParams(this.client.state);
93
+
94
+ const bloksHeaders = {
95
+ 'X-Bloks-Prism-Ax-Base-Colors-Enabled': 'false',
96
+ 'X-Bloks-Prism-Button-Version': 'CONTROL',
97
+ 'X-Bloks-Prism-Colors-Enabled': 'true',
98
+ 'X-Bloks-Prism-Font-Enabled': 'false',
99
+ 'X-Bloks-Prism-Indigo-Link-Version': '0',
100
+ 'X-FB-Friendly-Name': 'IgApi: bloks/async_action/com.bloks.www.bloks.caa.login.async.send_login_request/',
101
+ 'X-FB-Request-Analytics-Tags': JSON.stringify({
102
+ network_tags: {
103
+ product: this.client.state.fbAnalyticsApplicationId,
104
+ purpose: 'fetch',
105
+ surface: 'undefined',
106
+ request_category: 'api',
107
+ retry_attempt: '0',
108
+ },
109
+ }),
110
+ 'X-IG-Client-Endpoint': 'com.bloks.www.caa.login.aymh_single_profile_screen_entry',
111
+ 'X-Tigon-Is-Retry': 'False',
112
+ 'X-FB-RMD': 'state=URL_ELIGIBLE',
113
+ 'X-IG-Attest-Params': JSON.stringify(attestParams),
114
+ 'X-FB-Connection-Type': 'MOBILE.LTE',
115
+ 'X-FB-Network-Properties': 'VPN;Metered;Validated;LocalAddrs=/10.0.0.2,;',
116
+ 'X-FB-Conn-UUID-Client': crypto.randomBytes(16).toString('hex'),
117
+ 'Accept-Encoding': 'zstd',
118
+ 'X-FB-HTTP-Engine': 'MNS/TCP',
119
+ };
120
+
49
121
  const response = await this.client.request.send({
50
122
  method: 'POST',
51
- url: '/api/v1/accounts/login/',
52
- form: this.client.request.sign({
53
- jazoest: AccountRepository.createJazoest(this.client.state.phoneId),
54
- country_codes: JSON.stringify([{ country_code: String(countryCode), source: ['default'] }]),
55
- phone_id: this.client.state.phoneId,
56
- enc_password: `#PWD_INSTAGRAM:4:${time}:${encrypted}`,
57
- username,
58
- adid: this.client.state.adid,
59
- guid: this.client.state.uuid,
60
- device_id: this.client.state.deviceId,
61
- google_tokens: '[]',
62
- login_attempt_count: '0',
63
- }),
123
+ url: '/api/v1/bloks/async_action/com.bloks.www.bloks.caa.login.async.send_login_request/',
124
+ form: { params: paramsJson },
125
+ headers: bloksHeaders,
64
126
  });
65
127
 
66
128
  const body = response.body;
@@ -88,7 +150,51 @@ class AccountRepository extends Repository {
88
150
  throw err;
89
151
  }
90
152
 
91
- return body.logged_in_user;
153
+ if (body.layout) {
154
+ const layoutStr = typeof body.layout === 'string' ? body.layout : JSON.stringify(body.layout);
155
+
156
+ if (layoutStr.includes('two_factor_required') || layoutStr.includes('"two_factor_info"')) {
157
+ let twoFactorInfo = null;
158
+ try {
159
+ const match = layoutStr.match(/"two_factor_info"\s*:\s*(\{[^}]+\})/);
160
+ if (match) twoFactorInfo = JSON.parse(match[1]);
161
+ } catch (e) {}
162
+ const err = new Error('Two factor authentication required');
163
+ err.name = 'IgLoginTwoFactorRequiredError';
164
+ err.twoFactorInfo = twoFactorInfo;
165
+ throw err;
166
+ }
167
+
168
+ if (layoutStr.includes('bad_password') || layoutStr.includes('incorrect_password')) {
169
+ const err = new Error('Bad password');
170
+ err.name = 'IgLoginBadPasswordError';
171
+ throw err;
172
+ }
173
+
174
+ if (layoutStr.includes('invalid_user') || layoutStr.includes('user_not_found')) {
175
+ const err = new Error('Invalid user');
176
+ err.name = 'IgLoginInvalidUserError';
177
+ throw err;
178
+ }
179
+
180
+ if (layoutStr.includes('challenge_required')) {
181
+ const err = new Error('Challenge required');
182
+ err.name = 'IgCheckpointError';
183
+ err.challengeInfo = body.challenge || null;
184
+ throw err;
185
+ }
186
+ }
187
+
188
+ if (body.logged_in_user) {
189
+ return body.logged_in_user;
190
+ }
191
+
192
+ try {
193
+ const userInfo = await this.currentUser();
194
+ return userInfo.user || userInfo;
195
+ } catch (e) {
196
+ return body;
197
+ }
92
198
  });
93
199
  }
94
200
 
@@ -459,6 +565,96 @@ class AccountRepository extends Repository {
459
565
  });
460
566
  }
461
567
 
568
+ static generateAttestParams(state) {
569
+ const challengeNonce = crypto.randomBytes(24).toString('base64url');
570
+
571
+ const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
572
+ namedCurve: 'prime256v1',
573
+ });
574
+
575
+ const signedData = crypto.sign(null, Buffer.from(challengeNonce), privateKey);
576
+ const signedNonce = signedData.toString('base64');
577
+
578
+ const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
579
+ const keyHash = crypto.createHash('sha256').update(publicKeyDer).digest('hex');
580
+
581
+ const leafCertPem = AccountRepository._generateSelfSignedCert(privateKey, publicKey, 'Android Keystore Key');
582
+ const intermediateCertPem = AccountRepository._generateSelfSignedCert(privateKey, publicKey, 'TEE');
583
+
584
+ const certificateChain = leafCertPem + '\n' + intermediateCertPem;
585
+
586
+ return {
587
+ attestation: [{
588
+ version: 2,
589
+ type: 'keystore',
590
+ errors: [0],
591
+ challenge_nonce: challengeNonce,
592
+ signed_nonce: signedNonce,
593
+ key_hash: keyHash,
594
+ certificate_chain: certificateChain,
595
+ }],
596
+ };
597
+ }
598
+
599
+ static _generateSelfSignedCert(privateKey, publicKey, cn) {
600
+ const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
601
+ const serialNumber = crypto.randomBytes(8);
602
+ const now = new Date();
603
+ const notBefore = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);
604
+ const notAfter = new Date(now.getTime() + 10 * 365 * 24 * 60 * 60 * 1000);
605
+
606
+ const cnBytes = Buffer.from(cn, 'utf8');
607
+ const cnSeq = Buffer.concat([
608
+ Buffer.from([0x30, cnBytes.length + 13]),
609
+ Buffer.from([0x31, cnBytes.length + 11]),
610
+ Buffer.from([0x30, cnBytes.length + 9]),
611
+ Buffer.from([0x06, 0x03, 0x55, 0x04, 0x03]),
612
+ Buffer.from([0x0c, cnBytes.length]),
613
+ cnBytes,
614
+ ]);
615
+
616
+ function encodeTime(date) {
617
+ const str = date.toISOString().replace(/[-:T]/g, '').slice(2, 14) + 'Z';
618
+ return Buffer.concat([Buffer.from([0x17, str.length]), Buffer.from(str)]);
619
+ }
620
+
621
+ const validityBuf = Buffer.concat([
622
+ encodeTime(notBefore),
623
+ encodeTime(notAfter),
624
+ ]);
625
+ const validity = Buffer.concat([Buffer.from([0x30, validityBuf.length]), validityBuf]);
626
+
627
+ const tbs = Buffer.concat([
628
+ Buffer.from([0xa0, 0x03, 0x02, 0x01, 0x02]),
629
+ Buffer.from([0x02, serialNumber.length]), serialNumber,
630
+ Buffer.from([0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]),
631
+ cnSeq,
632
+ validity,
633
+ cnSeq,
634
+ publicKeyDer,
635
+ ]);
636
+
637
+ const tbsSeq = Buffer.concat([Buffer.from([0x30, 0x82]), Buffer.alloc(2), tbs]);
638
+ tbsSeq.writeUInt16BE(tbs.length, 2);
639
+
640
+ const signature = crypto.sign(null, tbsSeq, privateKey);
641
+
642
+ const sigBitString = Buffer.concat([
643
+ Buffer.from([0x03, signature.length + 1, 0x00]),
644
+ signature,
645
+ ]);
646
+
647
+ const algId = Buffer.from([0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]);
648
+
649
+ const certBody = Buffer.concat([tbsSeq, algId, sigBitString]);
650
+ const cert = Buffer.concat([Buffer.from([0x30, 0x82]), Buffer.alloc(2), certBody]);
651
+ cert.writeUInt16BE(certBody.length, 2);
652
+
653
+ const b64 = cert.toString('base64');
654
+ const lines = b64.match(/.{1,76}/g) || [b64];
655
+ return '-----BEGIN CERTIFICATE-----\n' + lines.join('\n') + '\n-----END CERTIFICATE-----';
656
+ }
657
+
462
658
  static createJazoest(input) {
463
659
  const buf = Buffer.from(input, 'ascii');
464
660
  let sum = 0;
@@ -1228,7 +1228,13 @@ async function extractStateData(igState) {
1228
1228
  const cookieFields = await extractCookieFields(igState);
1229
1229
 
1230
1230
  // Primary identifiers
1231
- const userIdFromState = igState.cookieUserId || igState.userId || igState.user_id || null;
1231
+ let userIdFromState = null;
1232
+ try {
1233
+ userIdFromState = igState.cookieUserId || null;
1234
+ } catch (e) {}
1235
+ if (!userIdFromState) {
1236
+ userIdFromState = igState.userId || igState.user_id || null;
1237
+ }
1232
1238
  const dsUserIdFromCookies = cookieFields.dsUserIdCookie || igState.dsUserId || igState.ds_user_id || null;
1233
1239
  const sessionIdFromCookies = cookieFields.sessionIdCookie || null;
1234
1240
  const csrfFromCookies = cookieFields.csrfTokenCookie || null;
@@ -1297,7 +1303,9 @@ async function applyStateData(igState, authState) {
1297
1303
 
1298
1304
  // apply new creds-derived fields if state supports them (non-intrusive)
1299
1305
  try {
1300
- if (creds.userId && !igState.cookieUserId) igState.cookieUserId = creds.userId;
1306
+ let _hasCookieUserId = false;
1307
+ try { _hasCookieUserId = !!igState.cookieUserId; } catch (e) {}
1308
+ if (creds.userId && !_hasCookieUserId) igState.cookieUserId = creds.userId;
1301
1309
  if (creds.username && !igState.username) igState.username = creds.username;
1302
1310
  if (creds.rankToken && !igState.rankToken) igState.rankToken = creds.rankToken;
1303
1311
  if (creds.sessionId && !igState.sessionId) igState.sessionId = creds.sessionId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-insta-private-api-mqt",
3
- "version": "1.3.74",
3
+ "version": "1.3.76",
4
4
  "description": "Complete Instagram MQTT protocol with FULL Featured REALTIME And api Rest All in one project .",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {