nodejs-insta-private-api-mqt 1.3.78 → 1.3.79
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/dist/repositories/account.repository.js +799 -831
- package/package.json +9 -2
|
@@ -1,838 +1,806 @@
|
|
|
1
|
-
// AccountRepository.js
|
|
2
|
-
// Complete file with improved certificate generation using node-forge
|
|
3
|
-
// Ready to copy and use. Requires: npm install node-forge uuid
|
|
4
|
-
|
|
5
1
|
const Repository = require('../core/repository');
|
|
6
2
|
const crypto = require('crypto');
|
|
7
|
-
const forge = require('node-forge');
|
|
8
|
-
const { v4: uuidv4 } = require('uuid');
|
|
9
3
|
|
|
10
4
|
class AccountRepository extends Repository {
|
|
11
|
-
constructor(client) {
|
|
12
|
-
super(client);
|
|
13
|
-
this.maxRetries = 3;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async requestWithRetry(requestFn, retries = 0) {
|
|
17
|
-
try {
|
|
18
|
-
const result = await requestFn();
|
|
19
|
-
return result;
|
|
20
|
-
} catch (error) {
|
|
21
|
-
const shouldRetry =
|
|
22
|
-
(error.data?.error_type === 'server_error' ||
|
|
23
|
-
error.data?.error_type === 'rate_limited') &&
|
|
24
|
-
retries < this.maxRetries;
|
|
25
|
-
if (shouldRetry) {
|
|
26
|
-
const delay = 1000 * (retries + 1);
|
|
27
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
28
|
-
return this.requestWithRetry(requestFn, retries + 1);
|
|
29
|
-
}
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async login(credentialsOrUsername, passwordArg) {
|
|
35
|
-
let username, password;
|
|
36
|
-
if (typeof credentialsOrUsername === 'object' && credentialsOrUsername !== null) {
|
|
37
|
-
username = credentialsOrUsername.username;
|
|
38
|
-
password = credentialsOrUsername.password;
|
|
39
|
-
} else {
|
|
40
|
-
username = credentialsOrUsername;
|
|
41
|
-
password = passwordArg;
|
|
42
|
-
}
|
|
43
|
-
if (!username || !password) {
|
|
44
|
-
throw new Error('Username and password are required');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!this.client.state.passwordEncryptionPubKey) {
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const { encrypted, time } = this.encryptPassword(password);
|
|
52
|
-
|
|
53
|
-
return this.requestWithRetry(async () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
async
|
|
324
|
-
return this.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
return
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
return
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
return {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
};
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
async
|
|
770
|
-
const response = await this.client.request.send({
|
|
771
|
-
method: 'GET',
|
|
772
|
-
url: '/api/v1/
|
|
773
|
-
});
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
_uuid: this.client.state.uuid,
|
|
811
|
-
config_value: String(configValue),
|
|
812
|
-
}),
|
|
813
|
-
});
|
|
814
|
-
return response.body;
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
async pushPreferences(preferences = 'default') {
|
|
819
|
-
return this.requestWithRetry(async () => {
|
|
820
|
-
const response = await this.client.request.send({
|
|
821
|
-
method: 'POST',
|
|
822
|
-
url: '/api/v1/push/register/',
|
|
823
|
-
form: this.client.request.sign({
|
|
824
|
-
_uuid: this.client.state.uuid,
|
|
825
|
-
device_type: 'android_mqtt',
|
|
826
|
-
is_main_push_channel: 'true',
|
|
827
|
-
phone_id: this.client.state.phoneId,
|
|
828
|
-
device_token: '',
|
|
829
|
-
guid: this.client.state.uuid,
|
|
830
|
-
users: preferences,
|
|
831
|
-
}),
|
|
832
|
-
});
|
|
833
|
-
return response.body;
|
|
834
|
-
});
|
|
835
|
-
}
|
|
5
|
+
constructor(client) {
|
|
6
|
+
super(client);
|
|
7
|
+
this.maxRetries = 3;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async requestWithRetry(requestFn, retries = 0) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await requestFn();
|
|
13
|
+
return result;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
const shouldRetry =
|
|
16
|
+
(error.data?.error_type === 'server_error' ||
|
|
17
|
+
error.data?.error_type === 'rate_limited') &&
|
|
18
|
+
retries < this.maxRetries;
|
|
19
|
+
if (shouldRetry) {
|
|
20
|
+
const delay = 1000 * (retries + 1);
|
|
21
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
22
|
+
return this.requestWithRetry(requestFn, retries + 1);
|
|
23
|
+
}
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async login(credentialsOrUsername, passwordArg) {
|
|
29
|
+
let username, password;
|
|
30
|
+
if (typeof credentialsOrUsername === 'object' && credentialsOrUsername !== null) {
|
|
31
|
+
username = credentialsOrUsername.username;
|
|
32
|
+
password = credentialsOrUsername.password;
|
|
33
|
+
} else {
|
|
34
|
+
username = credentialsOrUsername;
|
|
35
|
+
password = passwordArg;
|
|
36
|
+
}
|
|
37
|
+
if (!username || !password) {
|
|
38
|
+
throw new Error('Username and password are required');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!this.client.state.passwordEncryptionPubKey) {
|
|
42
|
+
await this.syncLoginExperiments();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { encrypted, time } = this.encryptPassword(password);
|
|
46
|
+
|
|
47
|
+
return this.requestWithRetry(async () => {
|
|
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': 'gzip, deflate',
|
|
118
|
+
'X-FB-HTTP-Engine': 'Liger',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const response = await this.client.request.send({
|
|
122
|
+
method: 'POST',
|
|
123
|
+
url: '/api/v1/bloks/async_action/com.bloks.www.bloks.caa.login.async.send_login_request/',
|
|
124
|
+
form: { params: paramsJson },
|
|
125
|
+
headers: bloksHeaders,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const body = response.body;
|
|
129
|
+
|
|
130
|
+
if (body.two_factor_required) {
|
|
131
|
+
const err = new Error('Two factor authentication required');
|
|
132
|
+
err.name = 'IgLoginTwoFactorRequiredError';
|
|
133
|
+
err.twoFactorInfo = body.two_factor_info;
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
if (body.error_type === 'bad_password') {
|
|
137
|
+
const err = new Error('Bad password');
|
|
138
|
+
err.name = 'IgLoginBadPasswordError';
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
if (body.error_type === 'invalid_user') {
|
|
142
|
+
const err = new Error('Invalid user');
|
|
143
|
+
err.name = 'IgLoginInvalidUserError';
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
if (body.message === 'challenge_required') {
|
|
147
|
+
const err = new Error('Challenge required');
|
|
148
|
+
err.name = 'IgCheckpointError';
|
|
149
|
+
err.challengeInfo = body.challenge;
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
|
|
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
|
+
const bearerMatch = layoutStr.match(/Bearer IGT:2:[A-Za-z0-9+\/=]+/);
|
|
188
|
+
if (bearerMatch) {
|
|
189
|
+
this.client.state.authorization = bearerMatch[0];
|
|
190
|
+
this.client.state.updateAuthorization();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const pkMatch = layoutStr.match(/\\"pk\\":(\d+)/);
|
|
194
|
+
if (pkMatch) {
|
|
195
|
+
this.client.state.cookieUserId = pkMatch[1];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const wwwClaimMatch = layoutStr.match(/IG-Set-WWW-Claim[\\"\s:]+([a-f0-9]+)/i);
|
|
199
|
+
if (wwwClaimMatch) {
|
|
200
|
+
this.client.state.igWWWClaim = wwwClaimMatch[1];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const encKeyIdMatch = layoutStr.match(/IG-Set-Password-Encryption-Key-Id[\\"\s:]+(\d+)/i);
|
|
204
|
+
if (encKeyIdMatch) {
|
|
205
|
+
this.client.state.passwordEncryptionKeyId = parseInt(encKeyIdMatch[1]);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const encPubKeyMatch = layoutStr.match(/IG-Set-Password-Encryption-Pub-Key[\\"\s:]+([A-Za-z0-9+\/=]+)/i);
|
|
209
|
+
if (encPubKeyMatch) {
|
|
210
|
+
this.client.state.passwordEncryptionPubKey = encPubKeyMatch[1];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const loginResponseMatch = layoutStr.match(/\\"logged_in_user\\":\{[^}]*\\"pk\\":(\d+)[^}]*\\"username\\":\\"([^"\\]+)\\"/);
|
|
214
|
+
if (loginResponseMatch) {
|
|
215
|
+
return {
|
|
216
|
+
pk: parseInt(loginResponseMatch[1]),
|
|
217
|
+
pk_id: loginResponseMatch[1],
|
|
218
|
+
username: loginResponseMatch[2],
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (body.logged_in_user) {
|
|
224
|
+
return body.logged_in_user;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const userInfo = await this.currentUser();
|
|
229
|
+
return userInfo.user || userInfo;
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return body;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async twoFactorLogin(username, verificationCode, twoFactorIdentifier, verificationMethod = '1') {
|
|
237
|
+
return this.requestWithRetry(async () => {
|
|
238
|
+
const response = await this.client.request.send({
|
|
239
|
+
method: 'POST',
|
|
240
|
+
url: '/api/v1/accounts/two_factor_login/',
|
|
241
|
+
form: this.client.request.sign({
|
|
242
|
+
username,
|
|
243
|
+
verification_code: verificationCode,
|
|
244
|
+
two_factor_identifier: twoFactorIdentifier,
|
|
245
|
+
verification_method: verificationMethod,
|
|
246
|
+
trust_this_device: '1',
|
|
247
|
+
guid: this.client.state.uuid,
|
|
248
|
+
device_id: this.client.state.deviceId,
|
|
249
|
+
phone_id: this.client.state.phoneId,
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
return response.body;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async logout() {
|
|
257
|
+
return this.requestWithRetry(async () => {
|
|
258
|
+
const response = await this.client.request.send({
|
|
259
|
+
method: 'POST',
|
|
260
|
+
url: '/api/v1/accounts/logout/',
|
|
261
|
+
form: this.client.request.sign({
|
|
262
|
+
_uuid: this.client.state.uuid,
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
return response.body;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async currentUser() {
|
|
270
|
+
return this.requestWithRetry(async () => {
|
|
271
|
+
const response = await this.client.request.send({
|
|
272
|
+
method: 'GET',
|
|
273
|
+
url: '/api/v1/accounts/current_user/',
|
|
274
|
+
qs: { edit: true },
|
|
275
|
+
});
|
|
276
|
+
return response.body;
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async accountInfo() {
|
|
281
|
+
return this.currentUser();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async editProfile({ externalUrl, phoneNumber, username, fullName, biography, email } = {}) {
|
|
285
|
+
return this.requestWithRetry(async () => {
|
|
286
|
+
const current = await this.currentUser();
|
|
287
|
+
const user = current.user || current;
|
|
288
|
+
const response = await this.client.request.send({
|
|
289
|
+
method: 'POST',
|
|
290
|
+
url: '/api/v1/accounts/edit_profile/',
|
|
291
|
+
form: this.client.request.sign({
|
|
292
|
+
_uuid: this.client.state.uuid,
|
|
293
|
+
external_url: externalUrl !== undefined ? externalUrl : (user.external_url || ''),
|
|
294
|
+
phone_number: phoneNumber !== undefined ? phoneNumber : (user.phone_number || ''),
|
|
295
|
+
username: username !== undefined ? username : user.username,
|
|
296
|
+
full_name: fullName !== undefined ? fullName : (user.full_name || ''),
|
|
297
|
+
biography: biography !== undefined ? biography : (user.biography || ''),
|
|
298
|
+
email: email !== undefined ? email : (user.email || ''),
|
|
299
|
+
}),
|
|
300
|
+
});
|
|
301
|
+
return response.body;
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async setBiography(biography) {
|
|
306
|
+
return this.editProfile({ biography });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async setExternalUrl(url) {
|
|
310
|
+
return this.editProfile({ externalUrl: url });
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async removeBioLinks() {
|
|
314
|
+
return this.editProfile({ externalUrl: '' });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async setGender(gender) {
|
|
318
|
+
return this.requestWithRetry(async () => {
|
|
319
|
+
const response = await this.client.request.send({
|
|
320
|
+
method: 'POST',
|
|
321
|
+
url: '/api/v1/accounts/set_gender/',
|
|
322
|
+
form: this.client.request.sign({
|
|
323
|
+
_uuid: this.client.state.uuid,
|
|
324
|
+
gender,
|
|
325
|
+
}),
|
|
326
|
+
});
|
|
327
|
+
return response.body;
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async setPrivate() {
|
|
332
|
+
return this.requestWithRetry(async () => {
|
|
333
|
+
const response = await this.client.request.send({
|
|
334
|
+
method: 'POST',
|
|
335
|
+
url: '/api/v1/accounts/set_private/',
|
|
336
|
+
form: this.client.request.sign({
|
|
337
|
+
_uuid: this.client.state.uuid,
|
|
338
|
+
}),
|
|
339
|
+
});
|
|
340
|
+
return response.body;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async setPublic() {
|
|
345
|
+
return this.requestWithRetry(async () => {
|
|
346
|
+
const response = await this.client.request.send({
|
|
347
|
+
method: 'POST',
|
|
348
|
+
url: '/api/v1/accounts/set_public/',
|
|
349
|
+
form: this.client.request.sign({
|
|
350
|
+
_uuid: this.client.state.uuid,
|
|
351
|
+
}),
|
|
352
|
+
});
|
|
353
|
+
return response.body;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
async changePassword(oldPassword, newPassword) {
|
|
358
|
+
const oldEnc = this.encryptPassword(oldPassword);
|
|
359
|
+
const newEnc = this.encryptPassword(newPassword);
|
|
360
|
+
return this.requestWithRetry(async () => {
|
|
361
|
+
const response = await this.client.request.send({
|
|
362
|
+
method: 'POST',
|
|
363
|
+
url: '/api/v1/accounts/change_password/',
|
|
364
|
+
form: this.client.request.sign({
|
|
365
|
+
_uuid: this.client.state.uuid,
|
|
366
|
+
enc_old_password: `#PWD_INSTAGRAM:4:${oldEnc.time}:${oldEnc.encrypted}`,
|
|
367
|
+
enc_new_password1: `#PWD_INSTAGRAM:4:${newEnc.time}:${newEnc.encrypted}`,
|
|
368
|
+
enc_new_password2: `#PWD_INSTAGRAM:4:${newEnc.time}:${newEnc.encrypted}`,
|
|
369
|
+
}),
|
|
370
|
+
});
|
|
371
|
+
return response.body;
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async sendConfirmEmail() {
|
|
376
|
+
return this.requestWithRetry(async () => {
|
|
377
|
+
const response = await this.client.request.send({
|
|
378
|
+
method: 'POST',
|
|
379
|
+
url: '/api/v1/accounts/send_confirm_email/',
|
|
380
|
+
form: this.client.request.sign({
|
|
381
|
+
_uuid: this.client.state.uuid,
|
|
382
|
+
send_source: 'edit_profile',
|
|
383
|
+
}),
|
|
384
|
+
});
|
|
385
|
+
return response.body;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async sendConfirmPhoneNumber(phoneNumber) {
|
|
390
|
+
return this.requestWithRetry(async () => {
|
|
391
|
+
const response = await this.client.request.send({
|
|
392
|
+
method: 'POST',
|
|
393
|
+
url: '/api/v1/accounts/send_confirm_phone_number/',
|
|
394
|
+
form: this.client.request.sign({
|
|
395
|
+
_uuid: this.client.state.uuid,
|
|
396
|
+
phone_number: phoneNumber,
|
|
397
|
+
}),
|
|
398
|
+
});
|
|
399
|
+
return response.body;
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async profilePictureChange(uploadId) {
|
|
404
|
+
return this.requestWithRetry(async () => {
|
|
405
|
+
const response = await this.client.request.send({
|
|
406
|
+
method: 'POST',
|
|
407
|
+
url: '/api/v1/accounts/change_profile_picture/',
|
|
408
|
+
form: this.client.request.sign({
|
|
409
|
+
_uuid: this.client.state.uuid,
|
|
410
|
+
use_fbuploader: 'true',
|
|
411
|
+
upload_id: uploadId,
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
414
|
+
return response.body;
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async profilePictureRemove() {
|
|
419
|
+
return this.requestWithRetry(async () => {
|
|
420
|
+
const response = await this.client.request.send({
|
|
421
|
+
method: 'POST',
|
|
422
|
+
url: '/api/v1/accounts/remove_profile_picture/',
|
|
423
|
+
form: this.client.request.sign({
|
|
424
|
+
_uuid: this.client.state.uuid,
|
|
425
|
+
}),
|
|
426
|
+
});
|
|
427
|
+
return response.body;
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async newsInbox() {
|
|
432
|
+
return this.requestWithRetry(async () => {
|
|
433
|
+
const response = await this.client.request.send({
|
|
434
|
+
method: 'GET',
|
|
435
|
+
url: '/api/v1/news/inbox/',
|
|
436
|
+
});
|
|
437
|
+
return response.body;
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async syncLoginExperiments() {
|
|
442
|
+
return this.requestWithRetry(async () => {
|
|
443
|
+
const response = await this.client.request.send({
|
|
444
|
+
method: 'POST',
|
|
445
|
+
url: '/api/v1/qe/sync/',
|
|
446
|
+
form: this.client.request.sign({
|
|
447
|
+
id: this.client.state.uuid,
|
|
448
|
+
server_config_retrieval: '1',
|
|
449
|
+
experiments: this.client.state.constants.LOGIN_EXPERIMENTS,
|
|
450
|
+
}),
|
|
451
|
+
});
|
|
452
|
+
return response.body;
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async syncPostLoginExperiments() {
|
|
457
|
+
let userId;
|
|
458
|
+
try { userId = this.client.state.cookieUserId; } catch { userId = '0'; }
|
|
459
|
+
return this.requestWithRetry(async () => {
|
|
460
|
+
const response = await this.client.request.send({
|
|
461
|
+
method: 'POST',
|
|
462
|
+
url: '/api/v1/qe/sync/',
|
|
463
|
+
form: this.client.request.sign({
|
|
464
|
+
id: userId,
|
|
465
|
+
_uid: userId,
|
|
466
|
+
_uuid: this.client.state.uuid,
|
|
467
|
+
server_config_retrieval: '1',
|
|
468
|
+
experiments: this.client.state.constants.EXPERIMENTS,
|
|
469
|
+
}),
|
|
470
|
+
});
|
|
471
|
+
return response.body;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
async syncLauncher(preLogin = true) {
|
|
476
|
+
const data = {
|
|
477
|
+
id: this.client.state.uuid,
|
|
478
|
+
server_config_retrieval: '1',
|
|
479
|
+
};
|
|
480
|
+
if (!preLogin) {
|
|
481
|
+
try {
|
|
482
|
+
data._uid = this.client.state.cookieUserId;
|
|
483
|
+
data._uuid = this.client.state.uuid;
|
|
484
|
+
} catch {}
|
|
485
|
+
}
|
|
486
|
+
return this.requestWithRetry(async () => {
|
|
487
|
+
const response = await this.client.request.send({
|
|
488
|
+
method: 'POST',
|
|
489
|
+
url: '/api/v1/launcher/sync/',
|
|
490
|
+
form: this.client.request.sign(data),
|
|
491
|
+
});
|
|
492
|
+
return response.body;
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async syncDeviceFeatures() {
|
|
497
|
+
return this.requestWithRetry(async () => {
|
|
498
|
+
const response = await this.client.request.send({
|
|
499
|
+
method: 'POST',
|
|
500
|
+
url: '/api/v1/devices/sync/',
|
|
501
|
+
form: this.client.request.sign({
|
|
502
|
+
id: this.client.state.uuid,
|
|
503
|
+
server_config_retrieval: '1',
|
|
504
|
+
}),
|
|
505
|
+
});
|
|
506
|
+
return response.body;
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
async getPrefillCandidates() {
|
|
511
|
+
return this.requestWithRetry(async () => {
|
|
512
|
+
const response = await this.client.request.send({
|
|
513
|
+
method: 'POST',
|
|
514
|
+
url: '/api/v1/accounts/get_prefill_candidates/',
|
|
515
|
+
form: this.client.request.sign({
|
|
516
|
+
android_device_id: this.client.state.deviceId,
|
|
517
|
+
phone_id: this.client.state.phoneId,
|
|
518
|
+
usages: '["account_recovery_omnibox"]',
|
|
519
|
+
device_id: this.client.state.uuid,
|
|
520
|
+
}),
|
|
521
|
+
});
|
|
522
|
+
return response.body;
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async contactPointPrefill(usage = 'prefill') {
|
|
527
|
+
return this.requestWithRetry(async () => {
|
|
528
|
+
const response = await this.client.request.send({
|
|
529
|
+
method: 'POST',
|
|
530
|
+
url: '/api/v1/accounts/contact_point_prefill/',
|
|
531
|
+
form: this.client.request.sign({
|
|
532
|
+
phone_id: this.client.state.phoneId,
|
|
533
|
+
usage,
|
|
534
|
+
}),
|
|
535
|
+
});
|
|
536
|
+
return response.body;
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async getZrToken(params = {}) {
|
|
541
|
+
return this.requestWithRetry(async () => {
|
|
542
|
+
const response = await this.client.request.send({
|
|
543
|
+
method: 'GET',
|
|
544
|
+
url: '/api/v1/zr/token/result/',
|
|
545
|
+
qs: {
|
|
546
|
+
device_id: this.client.state.deviceId,
|
|
547
|
+
custom_device_id: this.client.state.uuid,
|
|
548
|
+
fetch_reason: 'token_expired',
|
|
549
|
+
token_hash: '',
|
|
550
|
+
...params,
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
return response.body;
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async getConsentSignupConfig() {
|
|
558
|
+
return this.requestWithRetry(async () => {
|
|
559
|
+
const response = await this.client.request.send({
|
|
560
|
+
method: 'GET',
|
|
561
|
+
url: '/api/v1/consent/get_signup_config/',
|
|
562
|
+
qs: {
|
|
563
|
+
guid: this.client.state.uuid,
|
|
564
|
+
main_account_selected: false,
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
return response.body;
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
async sendRecoveryFlowEmail(query) {
|
|
572
|
+
return this.requestWithRetry(async () => {
|
|
573
|
+
const response = await this.client.request.send({
|
|
574
|
+
url: '/api/v1/accounts/send_recovery_flow_email/',
|
|
575
|
+
method: 'POST',
|
|
576
|
+
form: this.client.request.sign({
|
|
577
|
+
adid: '',
|
|
578
|
+
guid: this.client.state.uuid,
|
|
579
|
+
device_id: this.client.state.deviceId,
|
|
580
|
+
query,
|
|
581
|
+
}),
|
|
582
|
+
});
|
|
583
|
+
return response.body;
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
async sendRecoveryFlowSms(query) {
|
|
588
|
+
return this.requestWithRetry(async () => {
|
|
589
|
+
const response = await this.client.request.send({
|
|
590
|
+
url: '/api/v1/accounts/send_recovery_flow_sms/',
|
|
591
|
+
method: 'POST',
|
|
592
|
+
form: this.client.request.sign({
|
|
593
|
+
adid: '',
|
|
594
|
+
guid: this.client.state.uuid,
|
|
595
|
+
device_id: this.client.state.deviceId,
|
|
596
|
+
query,
|
|
597
|
+
}),
|
|
598
|
+
});
|
|
599
|
+
return response.body;
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
static generateAttestParams(state) {
|
|
604
|
+
const challengeNonce = crypto.randomBytes(24).toString('base64url');
|
|
605
|
+
|
|
606
|
+
const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
|
|
607
|
+
namedCurve: 'prime256v1',
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
const signedData = crypto.sign(null, Buffer.from(challengeNonce), privateKey);
|
|
611
|
+
const signedNonce = signedData.toString('base64');
|
|
612
|
+
|
|
613
|
+
const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
|
|
614
|
+
const keyHash = crypto.createHash('sha256').update(publicKeyDer).digest('hex');
|
|
615
|
+
|
|
616
|
+
const leafCertPem = AccountRepository._generateSelfSignedCert(privateKey, publicKey, 'Android Keystore Key');
|
|
617
|
+
const intermediateCertPem = AccountRepository._generateSelfSignedCert(privateKey, publicKey, 'TEE');
|
|
618
|
+
|
|
619
|
+
const certificateChain = leafCertPem + '\n' + intermediateCertPem;
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
attestation: [{
|
|
623
|
+
version: 2,
|
|
624
|
+
type: 'keystore',
|
|
625
|
+
errors: [0],
|
|
626
|
+
challenge_nonce: challengeNonce,
|
|
627
|
+
signed_nonce: signedNonce,
|
|
628
|
+
key_hash: keyHash,
|
|
629
|
+
certificate_chain: certificateChain,
|
|
630
|
+
}],
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
static _generateSelfSignedCert(privateKey, publicKey, cn) {
|
|
635
|
+
const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
|
|
636
|
+
const serialNumber = crypto.randomBytes(8);
|
|
637
|
+
const now = new Date();
|
|
638
|
+
const notBefore = new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);
|
|
639
|
+
const notAfter = new Date(now.getTime() + 10 * 365 * 24 * 60 * 60 * 1000);
|
|
640
|
+
|
|
641
|
+
const cnBytes = Buffer.from(cn, 'utf8');
|
|
642
|
+
const cnSeq = Buffer.concat([
|
|
643
|
+
Buffer.from([0x30, cnBytes.length + 13]),
|
|
644
|
+
Buffer.from([0x31, cnBytes.length + 11]),
|
|
645
|
+
Buffer.from([0x30, cnBytes.length + 9]),
|
|
646
|
+
Buffer.from([0x06, 0x03, 0x55, 0x04, 0x03]),
|
|
647
|
+
Buffer.from([0x0c, cnBytes.length]),
|
|
648
|
+
cnBytes,
|
|
649
|
+
]);
|
|
650
|
+
|
|
651
|
+
function encodeTime(date) {
|
|
652
|
+
const str = date.toISOString().replace(/[-:T]/g, '').slice(2, 14) + 'Z';
|
|
653
|
+
return Buffer.concat([Buffer.from([0x17, str.length]), Buffer.from(str)]);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const validityBuf = Buffer.concat([
|
|
657
|
+
encodeTime(notBefore),
|
|
658
|
+
encodeTime(notAfter),
|
|
659
|
+
]);
|
|
660
|
+
const validity = Buffer.concat([Buffer.from([0x30, validityBuf.length]), validityBuf]);
|
|
661
|
+
|
|
662
|
+
const tbs = Buffer.concat([
|
|
663
|
+
Buffer.from([0xa0, 0x03, 0x02, 0x01, 0x02]),
|
|
664
|
+
Buffer.from([0x02, serialNumber.length]), serialNumber,
|
|
665
|
+
Buffer.from([0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]),
|
|
666
|
+
cnSeq,
|
|
667
|
+
validity,
|
|
668
|
+
cnSeq,
|
|
669
|
+
publicKeyDer,
|
|
670
|
+
]);
|
|
671
|
+
|
|
672
|
+
const tbsSeq = Buffer.concat([Buffer.from([0x30, 0x82]), Buffer.alloc(2), tbs]);
|
|
673
|
+
tbsSeq.writeUInt16BE(tbs.length, 2);
|
|
674
|
+
|
|
675
|
+
const signature = crypto.sign(null, tbsSeq, privateKey);
|
|
676
|
+
|
|
677
|
+
const sigBitString = Buffer.concat([
|
|
678
|
+
Buffer.from([0x03, signature.length + 1, 0x00]),
|
|
679
|
+
signature,
|
|
680
|
+
]);
|
|
681
|
+
|
|
682
|
+
const algId = Buffer.from([0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]);
|
|
683
|
+
|
|
684
|
+
const certBody = Buffer.concat([tbsSeq, algId, sigBitString]);
|
|
685
|
+
const cert = Buffer.concat([Buffer.from([0x30, 0x82]), Buffer.alloc(2), certBody]);
|
|
686
|
+
cert.writeUInt16BE(certBody.length, 2);
|
|
687
|
+
|
|
688
|
+
const b64 = cert.toString('base64');
|
|
689
|
+
const lines = b64.match(/.{1,76}/g) || [b64];
|
|
690
|
+
return '-----BEGIN CERTIFICATE-----\n' + lines.join('\n') + '\n-----END CERTIFICATE-----';
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
static createJazoest(input) {
|
|
694
|
+
const buf = Buffer.from(input, 'ascii');
|
|
695
|
+
let sum = 0;
|
|
696
|
+
for (let i = 0; i < buf.byteLength; i++) {
|
|
697
|
+
sum += buf.readUInt8(i);
|
|
698
|
+
}
|
|
699
|
+
return `2${sum}`;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
encryptPassword(password) {
|
|
703
|
+
if (!this.client.state.passwordEncryptionPubKey) {
|
|
704
|
+
return { time: Math.floor(Date.now() / 1000).toString(), encrypted: password };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const randKey = crypto.randomBytes(32);
|
|
708
|
+
const iv = crypto.randomBytes(12);
|
|
709
|
+
|
|
710
|
+
const rsaEncrypted = crypto.publicEncrypt({
|
|
711
|
+
key: Buffer.from(this.client.state.passwordEncryptionPubKey, 'base64').toString(),
|
|
712
|
+
padding: crypto.constants.RSA_PKCS1_PADDING,
|
|
713
|
+
}, randKey);
|
|
714
|
+
|
|
715
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', randKey, iv);
|
|
716
|
+
const time = Math.floor(Date.now() / 1000).toString();
|
|
717
|
+
cipher.setAAD(Buffer.from(time));
|
|
718
|
+
|
|
719
|
+
const aesEncrypted = Buffer.concat([cipher.update(password, 'utf8'), cipher.final()]);
|
|
720
|
+
const sizeBuffer = Buffer.alloc(2, 0);
|
|
721
|
+
sizeBuffer.writeInt16LE(rsaEncrypted.byteLength, 0);
|
|
722
|
+
const authTag = cipher.getAuthTag();
|
|
723
|
+
|
|
724
|
+
return {
|
|
725
|
+
time,
|
|
726
|
+
encrypted: Buffer.concat([
|
|
727
|
+
Buffer.from([1, this.client.state.passwordEncryptionKeyId || 0]),
|
|
728
|
+
iv,
|
|
729
|
+
sizeBuffer,
|
|
730
|
+
rsaEncrypted,
|
|
731
|
+
authTag,
|
|
732
|
+
aesEncrypted
|
|
733
|
+
]).toString('base64')
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
async passwordPublicKeys() {
|
|
738
|
+
const response = await this.client.request.send({
|
|
739
|
+
method: 'GET',
|
|
740
|
+
url: '/api/v1/qe/sync/',
|
|
741
|
+
});
|
|
742
|
+
const headers = response.headers || {};
|
|
743
|
+
const keyId = parseInt(headers['ig-set-password-encryption-key-id'] || '0');
|
|
744
|
+
const pubKey = headers['ig-set-password-encryption-pub-key'] || '';
|
|
745
|
+
return { keyId, pubKey };
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
async setPresenceDisabled(disabled = true) {
|
|
749
|
+
return this.requestWithRetry(async () => {
|
|
750
|
+
const response = await this.client.request.send({
|
|
751
|
+
method: 'POST',
|
|
752
|
+
url: '/api/v1/accounts/set_presence_disabled/',
|
|
753
|
+
form: this.client.request.sign({
|
|
754
|
+
_uuid: this.client.state.uuid,
|
|
755
|
+
disabled: disabled ? '1' : '0',
|
|
756
|
+
}),
|
|
757
|
+
});
|
|
758
|
+
return response.body;
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
async getCommentFilter() {
|
|
763
|
+
return this.requestWithRetry(async () => {
|
|
764
|
+
const response = await this.client.request.send({
|
|
765
|
+
method: 'GET',
|
|
766
|
+
url: '/api/v1/accounts/get_comment_filter/',
|
|
767
|
+
});
|
|
768
|
+
return response.body;
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async setCommentFilter(configValue = 0) {
|
|
773
|
+
return this.requestWithRetry(async () => {
|
|
774
|
+
const response = await this.client.request.send({
|
|
775
|
+
method: 'POST',
|
|
776
|
+
url: '/api/v1/accounts/set_comment_filter/',
|
|
777
|
+
form: this.client.request.sign({
|
|
778
|
+
_uuid: this.client.state.uuid,
|
|
779
|
+
config_value: String(configValue),
|
|
780
|
+
}),
|
|
781
|
+
});
|
|
782
|
+
return response.body;
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
async pushPreferences(preferences = 'default') {
|
|
787
|
+
return this.requestWithRetry(async () => {
|
|
788
|
+
const response = await this.client.request.send({
|
|
789
|
+
method: 'POST',
|
|
790
|
+
url: '/api/v1/push/register/',
|
|
791
|
+
form: this.client.request.sign({
|
|
792
|
+
_uuid: this.client.state.uuid,
|
|
793
|
+
device_type: 'android_mqtt',
|
|
794
|
+
is_main_push_channel: 'true',
|
|
795
|
+
phone_id: this.client.state.phoneId,
|
|
796
|
+
device_token: '',
|
|
797
|
+
guid: this.client.state.uuid,
|
|
798
|
+
users: preferences,
|
|
799
|
+
}),
|
|
800
|
+
});
|
|
801
|
+
return response.body;
|
|
802
|
+
});
|
|
803
|
+
}
|
|
836
804
|
}
|
|
837
805
|
|
|
838
806
|
module.exports = AccountRepository;
|