nodejs-insta-private-api-mqtt 1.1.6 → 1.1.8
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 +5 -14
- package/dist/core/client.js +249 -0
- package/dist/core/request.js +10 -15
- package/dist/core/state.js +4 -5
- package/dist/mqttot/mqttot.client.js +8 -37
- package/dist/mqttot/mqttot.connection.js +10 -5
- package/dist/realtime/realtime.client.js +6 -12
- package/dist/repositories/account.repository.js +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,15 +2,6 @@ Dear users,
|
|
|
2
2
|
First of all, when handling view-once images or videos, please make sure to save the received media in a folder such as /storage/emulated/0/Pictures/, or depending on your device's path. The photos and videos are saved correctly on your phone, but the library currently has some issues with uploading them back to Instagram. This will be resolved as soon as possible.
|
|
3
3
|
I post many versions of the project because Instagram changes the protocol almost daily, if you like this project leave a star on github https://github.com/Kunboruto20/nodejs-insta-private-api.git
|
|
4
4
|
|
|
5
|
-
⚠️ IMPORTANT NOTICE
|
|
6
|
-
This is an important announcement regarding the nodejs-insta-private-api library.
|
|
7
|
-
The old repository and NPM package were lost and are now associated with a different NPM account.
|
|
8
|
-
Starting from today, this NPM account will be the official and active source where this library will be published and maintained.
|
|
9
|
-
Please make sure you are using this package from this account only to receive future updates, fixes, and support.
|
|
10
|
-
|
|
11
|
-
You can subscribe to any Instagram topic in this library visit the bookstore code, it would help me a lot if you like this project and if it helps you!
|
|
12
|
-
|
|
13
|
-
If you see clones of nodejs-insta-private-api on npm don't download, it could be malicious code and you may have security issues on your Instagram accounts, always use this project or the nodejs-insta-private-api project but that's on the lost account, always use npm install nodejs-insta-private-api-mqtt in your projects
|
|
14
5
|
|
|
15
6
|
|
|
16
7
|
# nodejs-insta-private-api-mqtt
|
|
@@ -19,7 +10,7 @@ This project implements a complete and production-ready MQTT protocol client for
|
|
|
19
10
|
|
|
20
11
|
By leveraging MQTT instead of Instagram's REST API, this library achieves sub-500ms message latency, bidirectional real-time communication, and native support for notifications, presence tracking, and thread management. The implementation is reverse-engineered from Instagram's mobile app protocol and tested extensively for reliability and compatibility.
|
|
21
12
|
|
|
22
|
-
## Features ( - iOS + Android Full Support)
|
|
13
|
+
## Features (v5.61.11 - iOS + Android Full Support)
|
|
23
14
|
|
|
24
15
|
- **NEW: FULL iOS SUPPORT** - iPhone 16/15/14/13/12 + iPad Pro/Air device emulation
|
|
25
16
|
- **NEW: FULL ANDROID SUPPORT** - Samsung, Huawei, Google Pixel, OnePlus, Xiaomi, OPPO
|
|
@@ -75,7 +66,7 @@ Requires **Node.js 18 or higher**.
|
|
|
75
66
|
|
|
76
67
|
---
|
|
77
68
|
|
|
78
|
-
## NEW: Custom Device Emulation ()
|
|
69
|
+
## NEW: Custom Device Emulation (v5.60.7)
|
|
79
70
|
|
|
80
71
|
**Default Device:** Samsung Galaxy S25 Ultra (Android 15) - used automatically if you don't set a custom device.
|
|
81
72
|
|
|
@@ -93,7 +84,7 @@ This feature allows you to **choose which phone model Instagram sees** when your
|
|
|
93
84
|
The easiest way to set a custom device is using the built-in presets:
|
|
94
85
|
|
|
95
86
|
```javascript
|
|
96
|
-
const { IgApiClient } = require('nodejs-insta-private-api
|
|
87
|
+
const { IgApiClient } = require('nodejs-insta-private-api');
|
|
97
88
|
|
|
98
89
|
const ig = new IgApiClient();
|
|
99
90
|
|
|
@@ -911,7 +902,7 @@ const {
|
|
|
911
902
|
RealtimeClient,
|
|
912
903
|
downloadContentFromMessage,
|
|
913
904
|
isViewOnceMedia
|
|
914
|
-
} = require('nodejs-insta-private-api
|
|
905
|
+
} = require('nodejs-insta-private-api');
|
|
915
906
|
const fs = require('fs');
|
|
916
907
|
|
|
917
908
|
const ig = new IgApiClient();
|
|
@@ -964,7 +955,7 @@ const {
|
|
|
964
955
|
downloadMediaBuffer,
|
|
965
956
|
hasMedia,
|
|
966
957
|
getMediaType
|
|
967
|
-
} = require('nodejs-insta-private-api');
|
|
958
|
+
} = require('nodejs-insta-private-api-mqtt');
|
|
968
959
|
|
|
969
960
|
realtime.on('message', async (data) => {
|
|
970
961
|
const msg = data.message;
|
package/dist/core/client.js
CHANGED
|
@@ -72,10 +72,61 @@ class IgApiClient extends EventEmitter {
|
|
|
72
72
|
* NOTE: removed automatic realtime connection attempt.
|
|
73
73
|
*/
|
|
74
74
|
async login(credentials) {
|
|
75
|
+
// ANTI-BOT: Automatically simulate app launch if not already done recently
|
|
76
|
+
if (this.state.deviceId) {
|
|
77
|
+
try {
|
|
78
|
+
await this.simulateAppStart();
|
|
79
|
+
// Real behavior: fetch contact permissions, explore, etc.
|
|
80
|
+
await this.simulateAndroidBehavior();
|
|
81
|
+
} catch (e) {}
|
|
82
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
83
|
+
}
|
|
75
84
|
const result = await this.account.login(credentials);
|
|
76
85
|
return result;
|
|
77
86
|
}
|
|
78
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Additional Android-specific behavior simulation
|
|
90
|
+
*/
|
|
91
|
+
async simulateAndroidBehavior() {
|
|
92
|
+
if (this.state.verbose) console.log('[Anti-Bot] Simulating Android-specific background behaviors...');
|
|
93
|
+
|
|
94
|
+
// 0. Pre-login notification suppression / Trust signal
|
|
95
|
+
try {
|
|
96
|
+
await this.request.send({
|
|
97
|
+
url: '/api/v1/accounts/get_presence_disabled/',
|
|
98
|
+
method: 'GET',
|
|
99
|
+
});
|
|
100
|
+
} catch (e) {}
|
|
101
|
+
|
|
102
|
+
// 1. Fetch Contact Permission (often requested on start/login)
|
|
103
|
+
try {
|
|
104
|
+
await this.request.send({
|
|
105
|
+
url: '/api/v1/accounts/contact_point_pref/',
|
|
106
|
+
method: 'GET',
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {}
|
|
109
|
+
|
|
110
|
+
// 2. Fetch Zero Rating (Mobile data settings)
|
|
111
|
+
try {
|
|
112
|
+
await this.request.send({
|
|
113
|
+
url: '/api/v1/zero/get_headers/',
|
|
114
|
+
method: 'GET',
|
|
115
|
+
});
|
|
116
|
+
} catch (e) {}
|
|
117
|
+
|
|
118
|
+
// 3. Fetch Banyan (Explore/Search context)
|
|
119
|
+
try {
|
|
120
|
+
await this.request.send({
|
|
121
|
+
url: '/api/v1/banyan/banyan/',
|
|
122
|
+
method: 'GET',
|
|
123
|
+
qs: {
|
|
124
|
+
views: '["direct_user_search","direct_search_context","direct_share_sheet"]',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
} catch (e) {}
|
|
128
|
+
}
|
|
129
|
+
|
|
79
130
|
async logout() {
|
|
80
131
|
return await this.account.logout();
|
|
81
132
|
}
|
|
@@ -116,6 +167,88 @@ class IgApiClient extends EventEmitter {
|
|
|
116
167
|
// === UTILITY HELPER METHODS
|
|
117
168
|
// -------------------------------
|
|
118
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Simulates the exact sequence of requests an Android device makes when opening the Instagram app.
|
|
172
|
+
* This should be called BEFORE login to establish the device's presence as a legitimate app instance.
|
|
173
|
+
*/
|
|
174
|
+
async simulateAppStart() {
|
|
175
|
+
if (this.state.verbose) console.log('[Anti-Bot] Starting Android App Launch Simulation...');
|
|
176
|
+
|
|
177
|
+
// 1. Emulate Launcher Sync (Fetching app configuration)
|
|
178
|
+
// This tells Instagram "I am opening the app and checking for feature flags"
|
|
179
|
+
try {
|
|
180
|
+
await this.request.send({
|
|
181
|
+
url: '/api/v1/launcher/sync/',
|
|
182
|
+
method: 'POST',
|
|
183
|
+
form: {
|
|
184
|
+
configs: 'ig_android_launcher_sync_config',
|
|
185
|
+
id: this.state.uuid,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
if (this.state.verbose) console.log('[Anti-Bot] Launcher Sync: OK');
|
|
189
|
+
} catch (e) {
|
|
190
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Launcher Sync Failed (Non-fatal):', e.message);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 2. Emulate QE Sync (Quick Experiment Sync)
|
|
194
|
+
// Instagram apps check for A/B testing experiments on launch
|
|
195
|
+
try {
|
|
196
|
+
await this.request.send({
|
|
197
|
+
url: '/api/v1/qe/sync/',
|
|
198
|
+
method: 'POST',
|
|
199
|
+
form: {
|
|
200
|
+
experiments: 'ig_android_qe_sync_config',
|
|
201
|
+
id: this.state.uuid,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
if (this.state.verbose) console.log('[Anti-Bot] QE Sync: OK');
|
|
205
|
+
} catch (e) {
|
|
206
|
+
if (this.state.verbose) console.warn('[Anti-Bot] QE Sync Failed (Non-fatal):', e.message);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 3. Log Attribution (App Launch Event)
|
|
210
|
+
// This is crucial. Real apps report "I have launched".
|
|
211
|
+
try {
|
|
212
|
+
await this.request.send({
|
|
213
|
+
url: '/api/v1/attribution/log_attribution/',
|
|
214
|
+
method: 'POST',
|
|
215
|
+
form: {
|
|
216
|
+
adb_ifa: this.state.adsId, // Advertising ID
|
|
217
|
+
did: this.state.deviceId,
|
|
218
|
+
event_name: 'app_launch',
|
|
219
|
+
extra: JSON.stringify({
|
|
220
|
+
clock_skew: 0,
|
|
221
|
+
}),
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
if (this.state.verbose) console.log('[Anti-Bot] Attribution Logged: OK');
|
|
225
|
+
} catch (e) {
|
|
226
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Attribution Log Failed (Non-fatal):', e.message);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 4. Check App Updates (Optional but realistic)
|
|
230
|
+
// Simulates checking if a new version is available (often happens on launch)
|
|
231
|
+
if (this.state.verbose) console.log('[Anti-Bot] App Simulation Complete. Ready to Login.');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Login -> uses account.login. Returns whatever account.login returns.
|
|
236
|
+
* NOTE: removed automatic realtime connection attempt.
|
|
237
|
+
*/
|
|
238
|
+
async login(credentials) {
|
|
239
|
+
// ANTI-BOT: Automatically simulate app launch if not already done recently
|
|
240
|
+
// We check if we have a device ID, if so, we run simulation.
|
|
241
|
+
// Ideally we should track if simulated, but for now we run it on every login call to be safe.
|
|
242
|
+
if (this.state.deviceId) {
|
|
243
|
+
await this.simulateAppStart();
|
|
244
|
+
// Small delay to mimic human speed/app loading time
|
|
245
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const result = await this.account.login(credentials);
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
|
|
119
252
|
/**
|
|
120
253
|
* Generic retry helper for async functions.
|
|
121
254
|
*
|
|
@@ -227,6 +360,122 @@ class IgApiClient extends EventEmitter {
|
|
|
227
360
|
return this.state.verbose;
|
|
228
361
|
}
|
|
229
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Simulates the exact sequence of requests an Android device makes when opening the Instagram app.
|
|
365
|
+
*/
|
|
366
|
+
async simulateAppStart() {
|
|
367
|
+
if (this.state.verbose) console.log('[Anti-Bot] Starting Android App Launch Simulation...');
|
|
368
|
+
|
|
369
|
+
// 1. Emulate Launcher Sync
|
|
370
|
+
try {
|
|
371
|
+
await this.request.send({
|
|
372
|
+
url: '/api/v1/launcher/sync/',
|
|
373
|
+
method: 'POST',
|
|
374
|
+
form: {
|
|
375
|
+
configs: 'ig_android_launcher_sync_config',
|
|
376
|
+
id: this.state.uuid,
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
if (this.state.verbose) console.log('[Anti-Bot] Launcher Sync: OK');
|
|
380
|
+
} catch (e) {
|
|
381
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Launcher Sync Failed (Non-fatal):', e.message);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 2. Emulate QE Sync
|
|
385
|
+
try {
|
|
386
|
+
await this.request.send({
|
|
387
|
+
url: '/api/v1/qe/sync/',
|
|
388
|
+
method: 'POST',
|
|
389
|
+
form: {
|
|
390
|
+
experiments: 'ig_android_qe_sync_config',
|
|
391
|
+
id: this.state.uuid,
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
if (this.state.verbose) console.log('[Anti-Bot] QE Sync: OK');
|
|
395
|
+
} catch (e) {
|
|
396
|
+
if (this.state.verbose) console.warn('[Anti-Bot] QE Sync Failed (Non-fatal):', e.message);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 3. Log Attribution
|
|
400
|
+
try {
|
|
401
|
+
await this.request.send({
|
|
402
|
+
url: '/api/v1/attribution/log_attribution/',
|
|
403
|
+
method: 'POST',
|
|
404
|
+
form: {
|
|
405
|
+
adb_ifa: this.state.adsId,
|
|
406
|
+
did: this.state.deviceId,
|
|
407
|
+
event_name: 'app_launch',
|
|
408
|
+
extra: JSON.stringify({
|
|
409
|
+
clock_skew: 0,
|
|
410
|
+
}),
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
if (this.state.verbose) console.log('[Anti-Bot] Attribution Logged: OK');
|
|
414
|
+
} catch (e) {
|
|
415
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Attribution Log Failed (Non-fatal):', e.message);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (this.state.verbose) console.log('[Anti-Bot] App Simulation Complete. Ready to Login.');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Simulates the exact sequence of requests an Android device makes when opening the Instagram app.
|
|
423
|
+
*/
|
|
424
|
+
async simulateAppStart() {
|
|
425
|
+
if (this.state.verbose) console.log('[Anti-Bot] Starting Android App Launch Simulation...');
|
|
426
|
+
|
|
427
|
+
// 1. Emulate Launcher Sync
|
|
428
|
+
try {
|
|
429
|
+
await this.request.send({
|
|
430
|
+
url: '/api/v1/launcher/sync/',
|
|
431
|
+
method: 'POST',
|
|
432
|
+
form: {
|
|
433
|
+
configs: 'ig_android_launcher_sync_config',
|
|
434
|
+
id: this.state.uuid,
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
if (this.state.verbose) console.log('[Anti-Bot] Launcher Sync: OK');
|
|
438
|
+
} catch (e) {
|
|
439
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Launcher Sync Failed (Non-fatal):', e.message);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// 2. Emulate QE Sync
|
|
443
|
+
try {
|
|
444
|
+
await this.request.send({
|
|
445
|
+
url: '/api/v1/qe/sync/',
|
|
446
|
+
method: 'POST',
|
|
447
|
+
form: {
|
|
448
|
+
experiments: 'ig_android_qe_sync_config',
|
|
449
|
+
id: this.state.uuid,
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
if (this.state.verbose) console.log('[Anti-Bot] QE Sync: OK');
|
|
453
|
+
} catch (e) {
|
|
454
|
+
if (this.state.verbose) console.warn('[Anti-Bot] QE Sync Failed (Non-fatal):', e.message);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// 3. Log Attribution
|
|
458
|
+
try {
|
|
459
|
+
await this.request.send({
|
|
460
|
+
url: '/api/v1/attribution/log_attribution/',
|
|
461
|
+
method: 'POST',
|
|
462
|
+
form: {
|
|
463
|
+
adb_ifa: this.state.adsId,
|
|
464
|
+
did: this.state.deviceId,
|
|
465
|
+
event_name: 'app_launch',
|
|
466
|
+
extra: JSON.stringify({
|
|
467
|
+
clock_skew: 0,
|
|
468
|
+
}),
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
if (this.state.verbose) console.log('[Anti-Bot] Attribution Logged: OK');
|
|
472
|
+
} catch (e) {
|
|
473
|
+
if (this.state.verbose) console.warn('[Anti-Bot] Attribution Log Failed (Non-fatal):', e.message);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (this.state.verbose) console.log('[Anti-Bot] App Simulation Complete. Ready to Login.');
|
|
477
|
+
}
|
|
478
|
+
|
|
230
479
|
/**
|
|
231
480
|
* safeDestroy: a slightly more robust destroy which attempts to stop requests, etc.
|
|
232
481
|
*/
|
package/dist/core/request.js
CHANGED
|
@@ -13,11 +13,7 @@ class Request {
|
|
|
13
13
|
baseURL: 'https://i.instagram.com/',
|
|
14
14
|
timeout: 30000,
|
|
15
15
|
headers: {
|
|
16
|
-
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
|
17
|
-
'Accept-Encoding': 'gzip, deflate',
|
|
18
|
-
'Connection': 'keep-alive',
|
|
19
|
-
'Accept': '*/*',
|
|
20
|
-
'Accept-Language': 'en-US'
|
|
16
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
|
21
17
|
}
|
|
22
18
|
});
|
|
23
19
|
}
|
|
@@ -179,32 +175,31 @@ class Request {
|
|
|
179
175
|
error.response = response;
|
|
180
176
|
error.status = response.status;
|
|
181
177
|
error.data = data;
|
|
182
|
-
// Anti-bot: Randomize delay on error to mimic human reaction time
|
|
183
178
|
return error;
|
|
184
179
|
}
|
|
185
180
|
|
|
186
181
|
getDefaultHeaders() {
|
|
187
182
|
return {
|
|
188
183
|
'User-Agent': this.client.state.appUserAgent,
|
|
189
|
-
'X-Ads-Opt-Out': '
|
|
190
|
-
'X-IG-App-Locale':
|
|
191
|
-
'X-IG-Device-Locale':
|
|
184
|
+
'X-Ads-Opt-Out': this.client.state.adsOptOut ? '1' : '0',
|
|
185
|
+
'X-IG-App-Locale': this.client.state.language,
|
|
186
|
+
'X-IG-Device-Locale': this.client.state.language,
|
|
192
187
|
'X-Pigeon-Session-Id': this.client.state.pigeonSessionId,
|
|
193
188
|
'X-Pigeon-Rawclienttime': (Date.now() / 1000).toFixed(3),
|
|
194
|
-
'X-IG-Connection-Speed': `${random(
|
|
189
|
+
'X-IG-Connection-Speed': `${random(1000, 3700)}kbps`,
|
|
195
190
|
'X-IG-Bandwidth-Speed-KBPS': '-1.000',
|
|
196
191
|
'X-IG-Bandwidth-TotalBytes-B': '0',
|
|
197
192
|
'X-IG-Bandwidth-TotalTime-MS': '0',
|
|
198
193
|
'X-IG-Extended-CDN-Thumbnail-Cache-Busting-Value': this.client.state.thumbnailCacheBustingValue.toString(),
|
|
199
194
|
'X-Bloks-Version-Id': this.client.state.bloksVersionId,
|
|
200
195
|
'X-IG-WWW-Claim': this.client.state.igWWWClaim || '0',
|
|
201
|
-
'X-Bloks-Is-Layout-RTL':
|
|
202
|
-
'X-IG-Connection-Type':
|
|
203
|
-
'X-IG-Capabilities':
|
|
204
|
-
'X-IG-App-ID':
|
|
196
|
+
'X-Bloks-Is-Layout-RTL': this.client.state.isLayoutRTL.toString(),
|
|
197
|
+
'X-IG-Connection-Type': this.client.state.connectionTypeHeader,
|
|
198
|
+
'X-IG-Capabilities': this.client.state.capabilitiesHeader,
|
|
199
|
+
'X-IG-App-ID': this.client.state.fbAnalyticsApplicationId,
|
|
205
200
|
'X-IG-Device-ID': this.client.state.uuid,
|
|
206
201
|
'X-IG-Android-ID': this.client.state.deviceId,
|
|
207
|
-
'Accept-Language': '
|
|
202
|
+
'Accept-Language': this.client.state.language.replace('_', '-'),
|
|
208
203
|
'X-FB-HTTP-Engine': 'Liger',
|
|
209
204
|
'Authorization': this.client.state.authorization,
|
|
210
205
|
'Host': 'i.instagram.com',
|
package/dist/core/state.js
CHANGED
|
@@ -34,12 +34,12 @@ class State {
|
|
|
34
34
|
this.parsedAuthorization = undefined;
|
|
35
35
|
|
|
36
36
|
// ===== PLATFORM SUPPORT (iOS + Android) =====
|
|
37
|
-
this.platform = '
|
|
37
|
+
this.platform = 'android'; // 'android' or 'ios'
|
|
38
38
|
this.iosVersion = '18.1';
|
|
39
39
|
this.iosAppVersion = '347.0.0.36.89';
|
|
40
40
|
this.iosAppVersionCode = '618023787';
|
|
41
|
-
this.iosDeviceModel = '
|
|
42
|
-
this.iosDeviceName = 'iPhone
|
|
41
|
+
this.iosDeviceModel = 'iPhone16,2'; // iPhone 15 Pro Max
|
|
42
|
+
this.iosDeviceName = 'iPhone';
|
|
43
43
|
this.iosBundleId = 'com.burbn.instagram';
|
|
44
44
|
|
|
45
45
|
// cookie jar (tough-cookie)
|
|
@@ -101,8 +101,7 @@ class State {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
get iosUserAgent() {
|
|
104
|
-
|
|
105
|
-
return `Instagram 347.0.0.36.89 (iPhone17,1; iOS 18.1; en_US; en_US; scale=3.00; 1320x2868; 618023787) AppleWebKit/420+`;
|
|
104
|
+
return `Instagram ${this.iosAppVersion} (${this.iosDeviceModel}; iOS ${this.iosVersion}; ${this.language}; ${this.language}; scale=3.00; ${this.iosResolution}; ${this.iosAppVersionCode}) AppleWebKit/420+`;
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
get iosResolution() {
|
|
@@ -23,36 +23,12 @@ class MQTToTClient extends mqtts_1.MqttClient {
|
|
|
23
23
|
host: options.url,
|
|
24
24
|
port: 443,
|
|
25
25
|
proxyOptions: options.socksOptions,
|
|
26
|
-
additionalOptions:
|
|
27
|
-
...options.additionalOptions,
|
|
28
|
-
// Anti-Bot: Enforce TLS 1.3 with Unified Cipher Suites (iOS & Android 14/15)
|
|
29
|
-
minVersion: 'TLSv1.3',
|
|
30
|
-
maxVersion: 'TLSv1.3',
|
|
31
|
-
ciphers: [
|
|
32
|
-
'TLS_AES_128_GCM_SHA256',
|
|
33
|
-
'TLS_AES_256_GCM_SHA384',
|
|
34
|
-
'TLS_CHACHA20_POLY1305_SHA256'
|
|
35
|
-
].join(':'),
|
|
36
|
-
sigalgs: 'ecdsa_secp256r1_sha256:rsa_pss_rsae_sha256:rsa_pkcs1_sha256:ecdsa_secp384r1_sha384:rsa_pss_rsae_sha384:rsa_pkcs1_sha384:rsa_pss_rsae_sha512:rsa_pkcs1_sha512',
|
|
37
|
-
rejectUnauthorized: true,
|
|
38
|
-
},
|
|
26
|
+
additionalOptions: options.additionalOptions,
|
|
39
27
|
})
|
|
40
28
|
: new mqtts_1.TlsTransport({
|
|
41
29
|
host: options.url,
|
|
42
30
|
port: 443,
|
|
43
|
-
additionalOptions:
|
|
44
|
-
...options.additionalOptions,
|
|
45
|
-
// Anti-Bot: Enforce TLS 1.3 with Unified Cipher Suites (iOS & Android 14/15)
|
|
46
|
-
minVersion: 'TLSv1.3',
|
|
47
|
-
maxVersion: 'TLSv1.3',
|
|
48
|
-
ciphers: [
|
|
49
|
-
'TLS_AES_128_GCM_SHA256',
|
|
50
|
-
'TLS_AES_256_GCM_SHA384',
|
|
51
|
-
'TLS_CHACHA20_POLY1305_SHA256'
|
|
52
|
-
].join(':'),
|
|
53
|
-
sigalgs: 'ecdsa_secp256r1_sha256:rsa_pss_rsae_sha256:rsa_pkcs1_sha256:ecdsa_secp384r1_sha384:rsa_pss_rsae_sha384:rsa_pkcs1_sha384:rsa_pss_rsae_sha512:rsa_pkcs1_sha512',
|
|
54
|
-
rejectUnauthorized: true,
|
|
55
|
-
},
|
|
31
|
+
additionalOptions: options.additionalOptions,
|
|
56
32
|
}),
|
|
57
33
|
});
|
|
58
34
|
this.mqttotDebug = (msg, ...args) => (0, shared_1.debugChannel)('mqttot')(`${options.url}: ${msg}`, ...args);
|
|
@@ -89,17 +65,12 @@ class MQTToTClient extends mqtts_1.MqttClient {
|
|
|
89
65
|
* @param {MqttMessage} message
|
|
90
66
|
* @returns {Promise<MqttMessageOutgoing>}
|
|
91
67
|
*/
|
|
92
|
-
mqttotPublish(message) {
|
|
68
|
+
async mqttotPublish(message) {
|
|
93
69
|
this.mqttotDebug(`Publishing ${message.payload.byteLength}bytes to topic ${message.topic}`);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
topic: message.topic,
|
|
99
|
-
payload: await (0, shared_1.compressDeflate)(message.payload),
|
|
100
|
-
qosLevel: message.qosLevel,
|
|
101
|
-
}));
|
|
102
|
-
}, Math.random() * 50 + 10); // 10-60ms random jitter
|
|
70
|
+
return await this.publish({
|
|
71
|
+
topic: message.topic,
|
|
72
|
+
payload: await (0, shared_1.compressDeflate)(message.payload),
|
|
73
|
+
qosLevel: message.qosLevel,
|
|
103
74
|
});
|
|
104
75
|
}
|
|
105
76
|
/**
|
|
@@ -129,7 +100,7 @@ function mqttotConnectFlow(payload, requirePayload) {
|
|
|
129
100
|
type: mqtts_1.PacketType.Connect,
|
|
130
101
|
options: {
|
|
131
102
|
payload,
|
|
132
|
-
keepAlive:
|
|
103
|
+
keepAlive: 60,
|
|
133
104
|
},
|
|
134
105
|
}),
|
|
135
106
|
accept: mqtts_1.isConnAck,
|
|
@@ -7,6 +7,15 @@ class MQTToTConnection {
|
|
|
7
7
|
this.fbnsConnectionData = connectionData;
|
|
8
8
|
}
|
|
9
9
|
toThrift() {
|
|
10
|
+
// ANTI-BOT: Ensure User-Agent is explicitly set to the Android string in MQTT connection
|
|
11
|
+
if (this.fbnsConnectionData.clientInfo) {
|
|
12
|
+
this.fbnsConnectionData.clientInfo.clientType = Buffer.from('com.instagram.android');
|
|
13
|
+
// Ensure it uses the same UA as the REST API for consistency
|
|
14
|
+
if (this.fbnsConnectionData.clientInfo.userAgent) {
|
|
15
|
+
// Ensure we are using the correct buffer format for Thrift
|
|
16
|
+
this.fbnsConnectionData.clientInfo.userAgent = Buffer.from(this.fbnsConnectionData.clientInfo.userAgent);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
10
19
|
return (0, thrift_1.thriftWriteFromObject)(this.fbnsConnectionData, MQTToTConnection.thriftConfig);
|
|
11
20
|
}
|
|
12
21
|
toString() {
|
|
@@ -47,14 +56,10 @@ MQTToTConnection.thriftConfig = [
|
|
|
47
56
|
thrift_1.ThriftDescriptors.int64('anotherUnknown', 26),
|
|
48
57
|
]),
|
|
49
58
|
thrift_1.ThriftDescriptors.binary('password', 5),
|
|
50
|
-
// polyfill
|
|
59
|
+
// polyfill
|
|
51
60
|
thrift_1.ThriftDescriptors.int16('unknown', 5),
|
|
52
61
|
thrift_1.ThriftDescriptors.listOfBinary('getDiffsRequests', 6),
|
|
53
62
|
thrift_1.ThriftDescriptors.binary('zeroRatingTokenHash', 9),
|
|
54
63
|
thrift_1.ThriftDescriptors.mapBinaryBinary('appSpecificInfo', 10),
|
|
55
|
-
// Field 11 is "chat_on" state for presence - often missing in bots
|
|
56
|
-
thrift_1.ThriftDescriptors.boolean('chatOn', 11),
|
|
57
|
-
// Field 12 is "fg_keepalive" - foreground keepalive flag
|
|
58
|
-
thrift_1.ThriftDescriptors.boolean('fgKeepAlive', 12),
|
|
59
64
|
];
|
|
60
65
|
//# sourceMappingURL=mqttot.connection.js.map
|
|
@@ -230,37 +230,31 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
230
230
|
this.realtimeDebug(`SessionID generated (fallback): ${sessionid}`);
|
|
231
231
|
}
|
|
232
232
|
const password = `sessionid=${sessionid}`;
|
|
233
|
-
|
|
234
|
-
// MQTT Client Info - Unified Mobile Profile (iOS & Android)
|
|
235
233
|
this.connection = new mqttot_1.MQTToTConnection({
|
|
236
234
|
clientIdentifier: deviceId.substring(0, 20),
|
|
237
235
|
clientInfo: {
|
|
238
236
|
userId: BigInt(Number(this.ig.state.cookieUserId)),
|
|
239
237
|
userAgent,
|
|
240
|
-
clientCapabilities:
|
|
238
|
+
clientCapabilities: 183,
|
|
241
239
|
endpointCapabilities: 0,
|
|
242
240
|
publishFormat: 1,
|
|
243
241
|
noAutomaticForeground: false,
|
|
244
242
|
makeUserAvailableInForeground: true,
|
|
245
243
|
deviceId,
|
|
246
244
|
isInitiallyForeground: true,
|
|
247
|
-
networkType: 1,
|
|
245
|
+
networkType: 1,
|
|
248
246
|
networkSubtype: 0,
|
|
249
247
|
clientMqttSessionId: BigInt(Date.now()) & BigInt(0xffffffff),
|
|
250
|
-
subscribeTopics:
|
|
251
|
-
? [88, 135, 149, 150, 133, 146, 230, 231]
|
|
252
|
-
: [88, 135, 149, 150, 133, 146], // Android usually has fewer default subscriptions
|
|
248
|
+
subscribeTopics: [88, 135, 149, 150, 133, 146],
|
|
253
249
|
clientType: 'cookie_auth',
|
|
254
|
-
appId:
|
|
255
|
-
? BigInt(1217981644879628)
|
|
256
|
-
: BigInt(1217981644879628), // Same for both on mobile
|
|
250
|
+
appId: BigInt(567067343352427),
|
|
257
251
|
deviceSecret: '',
|
|
258
252
|
clientStack: 3,
|
|
259
253
|
...(this.initOptions?.connectOverrides || {}),
|
|
260
254
|
},
|
|
261
255
|
password,
|
|
262
256
|
appSpecificInfo: {
|
|
263
|
-
app_version: this.ig.state.
|
|
257
|
+
app_version: this.ig.state.appVersion,
|
|
264
258
|
'X-IG-Capabilities': this.ig.state.capabilitiesHeader,
|
|
265
259
|
everclear_subscriptions: JSON.stringify({
|
|
266
260
|
inapp_notification_subscribe_comment: '17899377895239777',
|
|
@@ -269,7 +263,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
269
263
|
presence_subscribe: '17846944882223835',
|
|
270
264
|
}),
|
|
271
265
|
'User-Agent': userAgent,
|
|
272
|
-
'Accept-Language': this.ig.state.language,
|
|
266
|
+
'Accept-Language': this.ig.state.language.replace('_', '-'),
|
|
273
267
|
},
|
|
274
268
|
});
|
|
275
269
|
}
|
|
@@ -88,6 +88,25 @@ class AccountRepository extends Repository {
|
|
|
88
88
|
|
|
89
89
|
// Handle common login errors
|
|
90
90
|
const body = response.body;
|
|
91
|
+
|
|
92
|
+
// ANTI-BOT: Handle choice/checkpoint automatically if requested
|
|
93
|
+
if (body.two_factor_required || body.step_name === 'select_verify_method') {
|
|
94
|
+
// Some versions of the API return checkpoint info here
|
|
95
|
+
if (this.client.state.verbose) console.log('[Anti-Bot] Checkpoint/2FA detected, attempting to bypass notification...');
|
|
96
|
+
try {
|
|
97
|
+
await this.client.request.send({
|
|
98
|
+
url: '/api/v1/accounts/login_confirm/',
|
|
99
|
+
method: 'POST',
|
|
100
|
+
form: this.client.request.sign({
|
|
101
|
+
_csrftoken: this.client.state.cookieCsrfToken,
|
|
102
|
+
guid: this.client.state.uuid,
|
|
103
|
+
device_id: this.client.state.deviceId,
|
|
104
|
+
is_relogin: true,
|
|
105
|
+
}),
|
|
106
|
+
});
|
|
107
|
+
} catch (e) {}
|
|
108
|
+
}
|
|
109
|
+
|
|
91
110
|
if (body.two_factor_required) {
|
|
92
111
|
const err = new Error('Two factor authentication required');
|
|
93
112
|
err.name = 'IgLoginTwoFactorRequiredError';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodejs-insta-private-api-mqtt",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "Complete Instagram MQTT protocol with FULL iOS + Android support. 33 device presets (21 iOS + 12 Android). iPhone 16/15/14/13/12, iPad Pro, Samsung, Pixel, Huawei. Real-time DM messaging, view-once media extraction, sub-500ms latency.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|