shadowx-fca 1.2.0 → 2.0.0

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.
Files changed (4) hide show
  1. package/checkUpdate.js +112 -0
  2. package/index.js +106 -1
  3. package/package.json +2 -2
  4. package/utils.js +298 -230
package/utils.js CHANGED
@@ -1,6 +1,6 @@
1
-
2
1
  // @ts-nocheck
3
2
  /* eslint-disable no-undef */
3
+
4
4
  /* eslint-disable no-prototype-builtins */
5
5
 
6
6
  "use strict";
@@ -14,6 +14,7 @@ var request = bluebird.promisify(require("request").defaults({ jar: true }));
14
14
  /**
15
15
  * @param {any} url
16
16
  */
17
+
17
18
  function setProxy(url) {
18
19
  if (typeof url == "undefined") return request = bluebird.promisify(require("request").defaults({ jar: true }));
19
20
  return request = bluebird.promisify(require("request").defaults({ jar: true, proxy: url }));
@@ -25,6 +26,7 @@ function setProxy(url) {
25
26
  * @param {{ region: any; }} [ctx]
26
27
  * @param {undefined} [customHeader]
27
28
  */
29
+
28
30
  function getHeaders(url, options, ctx, customHeader) {
29
31
  var headers = {
30
32
  "Content-Type": "application/x-www-form-urlencoded",
@@ -45,6 +47,7 @@ function getHeaders(url, options, ctx, customHeader) {
45
47
  /**
46
48
  * @param {{ _read: any; _readableState: any; }} obj
47
49
  */
50
+
48
51
  function isReadableStream(obj) {
49
52
  return (
50
53
  obj instanceof stream.Stream &&
@@ -61,7 +64,9 @@ function isReadableStream(obj) {
61
64
  * @param {any} options
62
65
  * @param {any} ctx
63
66
  */
67
+
64
68
  function get(url, jar, qs, options, ctx) {
69
+ // I'm still confused about this
65
70
  if (getType(qs) === "Object")
66
71
  for (var prop in qs)
67
72
  if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") qs[prop] = JSON.stringify(qs[prop]);
@@ -98,11 +103,16 @@ function post(url, jar, form, options, ctx, customHeader) {
98
103
  /**
99
104
  * @param {any} url
100
105
  * @param {any} jar
101
- * @param {{ __user: any; __req: string; __rev: any; __a: number; fb_dtsg: any; jazoest: any; }} form
102
- * @param {{ __user: any; __req: string; __rev: any; __a: number; fb_dtsg: any; jazoest: any; }} qs
106
+ * @param {{ __user: any; __req: string; __rev: any; __a: number;
107
+ // __af: siteData.features,
108
+ fb_dtsg: any; jazoest: any; }} form
109
+ * @param {{ __user: any; __req: string; __rev: any; __a: number;
110
+ // __af: siteData.features,
111
+ fb_dtsg: any; jazoest: any; }} qs
103
112
  * @param {any} options
104
113
  * @param {any} ctx
105
114
  */
115
+
106
116
  function postFormData(url, jar, form, qs, options, ctx) {
107
117
  var headers = getHeaders(url, options, ctx);
108
118
  headers["Content-Type"] = "multipart/form-data";
@@ -126,6 +136,7 @@ function postFormData(url, jar, form, qs, options, ctx) {
126
136
  * @param {string | number | any[]} val
127
137
  * @param {number} [len]
128
138
  */
139
+
129
140
  function padZeros(val, len) {
130
141
  val = String(val);
131
142
  len = len || 2;
@@ -136,6 +147,7 @@ function padZeros(val, len) {
136
147
  /**
137
148
  * @param {any} clientID
138
149
  */
150
+
139
151
  function generateThreadingID(clientID) {
140
152
  var k = Date.now();
141
153
  var l = Math.floor(Math.random() * 4294967295);
@@ -146,6 +158,7 @@ function generateThreadingID(clientID) {
146
158
  /**
147
159
  * @param {string | any[]} data
148
160
  */
161
+
149
162
  function binaryToDecimal(data) {
150
163
  var ret = "";
151
164
  while (data !== "0") {
@@ -217,6 +230,7 @@ var j = {
217
230
  /**
218
231
  * @param {string | number | boolean} str
219
232
  */
233
+
220
234
  function presenceEncode(str) {
221
235
  return encodeURIComponent(str)
222
236
  .replace(/([_A-Z])|%../g, function (m, n) {
@@ -228,9 +242,11 @@ function presenceEncode(str) {
228
242
  });
229
243
  }
230
244
 
245
+ // eslint-disable-next-line no-unused-vars
231
246
  /**
232
247
  * @param {string} str
233
248
  */
249
+
234
250
  function presenceDecode(str) {
235
251
  return decodeURIComponent(
236
252
  str.replace(/[_A-Z]/g, function (/** @type {string | number} */m) {
@@ -242,6 +258,7 @@ function presenceDecode(str) {
242
258
  /**
243
259
  * @param {string} userID
244
260
  */
261
+
245
262
  function generatePresence(userID) {
246
263
  var time = Date.now();
247
264
  return (
@@ -285,10 +302,20 @@ function generateAccessiblityCookie() {
285
302
  }
286
303
 
287
304
  function getGUID() {
305
+ /** @type {number} */
306
+
288
307
  var sectionLength = Date.now();
308
+ /** @type {string} */
309
+
289
310
  var id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
311
+ /** @type {number} */
312
+
290
313
  var r = Math.floor((sectionLength + Math.random() * 16) % 16);
314
+ /** @type {number} */
315
+
291
316
  sectionLength = Math.floor(sectionLength / 16);
317
+ /** @type {string} */
318
+
292
319
  var _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
293
320
  return _guid;
294
321
  });
@@ -299,7 +326,15 @@ function getGUID() {
299
326
  * @param {{ mercury: any; blob_attachment: any; attach_type: any; sticker_attachment: any; extensible_attachment: { story_attachment: { target: { __typename: string; }; }; }; metadata: { stickerID: { toString: () => any; }; packID: { toString: () => any; }; spriteURI: any; spriteURI2x: any; width: any; height: any; frameCount: any; frameRate: any; framesPerRow: any; framesPerCol: any; fbid: { toString: () => any; }; url: any; dimensions: { split: (arg0: string) => any[]; width: any; height: any; }; duration: any; }; url: any; name: any; fileName: any; thumbnail_url: any; preview_url: any; preview_width: any; preview_height: any; large_preview_url: any; large_preview_width: any; large_preview_height: any; share: { share_id: { toString: () => any; }; title: any; description: any; source: any; media: { image: any; image_size: { width: any; height: any; }; playable: any; duration: any; animated_image_size: any; }; subattachments: any; uri: any; target: any; style_list: any; }; }} attachment1
300
327
  * @param {{ caption?: any; description?: any; id: any; is_malicious?: any; mime_type?: any; file_size?: any; filename?: any; image_data: any; href?: any; }} [attachment2]
301
328
  */
329
+
302
330
  function _formatAttachment(attachment1, attachment2) {
331
+ // TODO: THIS IS REALLY BAD
332
+ // This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
333
+ // two attachment objects, but sometimes only one. They each contain part of the
334
+ // data that you'd want so we merge them for convenience.
335
+ // Instead of having a bunch of if statements guarding every access to image_data,
336
+ // we set it to empty object and use the fact that it'll return undefined.
337
+
303
338
  attachment2 = attachment2 || { id: "", image_data: {} };
304
339
  attachment1 = attachment1.mercury ? attachment1.mercury : attachment1;
305
340
  var blob = attachment1.blob_attachment;
@@ -319,27 +354,32 @@ function _formatAttachment(attachment1, attachment2) {
319
354
 
320
355
  blob = attachment1.extensible_attachment;
321
356
  }
322
-
357
+ // TODO: Determine whether "sticker", "photo", "file" etc are still used
358
+ // KEEP IN SYNC WITH getThreadHistory
323
359
  switch (type) {
324
360
  case "sticker":
325
361
  return {
326
362
  type: "sticker",
327
363
  ID: attachment1.metadata.stickerID.toString(),
328
364
  url: attachment1.url,
365
+
329
366
  packID: attachment1.metadata.packID.toString(),
330
367
  spriteUrl: attachment1.metadata.spriteURI,
331
368
  spriteUrl2x: attachment1.metadata.spriteURI2x,
332
369
  width: attachment1.metadata.width,
333
370
  height: attachment1.metadata.height,
371
+
334
372
  caption: attachment2.caption,
335
373
  description: attachment2.description,
374
+
336
375
  frameCount: attachment1.metadata.frameCount,
337
376
  frameRate: attachment1.metadata.frameRate,
338
377
  framesPerRow: attachment1.metadata.framesPerRow,
339
378
  framesPerCol: attachment1.metadata.framesPerCol,
340
- stickerID: attachment1.metadata.stickerID.toString(),
341
- spriteURI: attachment1.metadata.spriteURI,
342
- spriteURI2x: attachment1.metadata.spriteURI2x
379
+
380
+ stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
381
+ spriteURI: attachment1.metadata.spriteURI, // @Legacy
382
+ spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
343
383
  };
344
384
  case "file":
345
385
  return {
@@ -347,11 +387,13 @@ function _formatAttachment(attachment1, attachment2) {
347
387
  filename: attachment1.name,
348
388
  ID: attachment2.id.toString(),
349
389
  url: attachment1.url,
390
+
350
391
  isMalicious: attachment2.is_malicious,
351
392
  contentType: attachment2.mime_type,
352
- name: attachment1.name,
353
- mimeType: attachment2.mime_type,
354
- fileSize: attachment2.file_size
393
+
394
+ name: attachment1.name, // @Legacy
395
+ mimeType: attachment2.mime_type, // @Legacy
396
+ fileSize: attachment2.file_size // @Legacy
355
397
  };
356
398
  case "photo":
357
399
  return {
@@ -359,77 +401,94 @@ function _formatAttachment(attachment1, attachment2) {
359
401
  ID: attachment1.metadata.fbid.toString(),
360
402
  filename: attachment1.fileName,
361
403
  thumbnailUrl: attachment1.thumbnail_url,
404
+
362
405
  previewUrl: attachment1.preview_url,
363
406
  previewWidth: attachment1.preview_width,
364
407
  previewHeight: attachment1.preview_height,
408
+
365
409
  largePreviewUrl: attachment1.large_preview_url,
366
410
  largePreviewWidth: attachment1.large_preview_width,
367
411
  largePreviewHeight: attachment1.large_preview_height,
368
- url: attachment1.metadata.url,
369
- width: attachment1.metadata.dimensions.split(",")[0],
370
- height: attachment1.metadata.dimensions.split(",")[1],
371
- name: attachment1.fileName
412
+
413
+ url: attachment1.metadata.url, // @Legacy
414
+ width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
415
+ height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
416
+ name: attachment1.fileName // @Legacy
372
417
  };
373
418
  case "animated_image":
374
419
  return {
375
420
  type: "animated_image",
376
421
  ID: attachment2.id.toString(),
377
422
  filename: attachment2.filename,
423
+
378
424
  previewUrl: attachment1.preview_url,
379
425
  previewWidth: attachment1.preview_width,
380
426
  previewHeight: attachment1.preview_height,
427
+
381
428
  url: attachment2.image_data.url,
382
429
  width: attachment2.image_data.width,
383
430
  height: attachment2.image_data.height,
384
- name: attachment1.name,
385
- facebookUrl: attachment1.url,
386
- thumbnailUrl: attachment1.thumbnail_url,
387
- mimeType: attachment2.mime_type,
388
- rawGifImage: attachment2.image_data.raw_gif_image,
389
- rawWebpImage: attachment2.image_data.raw_webp_image,
390
- animatedGifUrl: attachment2.image_data.animated_gif_url,
391
- animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url,
392
- animatedWebpUrl: attachment2.image_data.animated_webp_url,
393
- animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url
431
+
432
+ name: attachment1.name, // @Legacy
433
+ facebookUrl: attachment1.url, // @Legacy
434
+ thumbnailUrl: attachment1.thumbnail_url, // @Legacy
435
+ mimeType: attachment2.mime_type, // @Legacy
436
+ rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
437
+ rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
438
+ animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
439
+ animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
440
+ animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
441
+ animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
394
442
  };
395
443
  case "share":
396
444
  return {
397
445
  type: "share",
398
446
  ID: attachment1.share.share_id.toString(),
399
447
  url: attachment2.href,
448
+
400
449
  title: attachment1.share.title,
401
450
  description: attachment1.share.description,
402
451
  source: attachment1.share.source,
452
+
403
453
  image: attachment1.share.media.image,
404
454
  width: attachment1.share.media.image_size.width,
405
455
  height: attachment1.share.media.image_size.height,
406
456
  playable: attachment1.share.media.playable,
407
457
  duration: attachment1.share.media.duration,
458
+
408
459
  subattachments: attachment1.share.subattachments,
409
460
  properties: {},
410
- animatedImageSize: attachment1.share.media.animated_image_size,
411
- facebookUrl: attachment1.share.uri,
412
- target: attachment1.share.target,
413
- styleList: attachment1.share.style_list
461
+
462
+ animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
463
+ facebookUrl: attachment1.share.uri, // @Legacy
464
+ target: attachment1.share.target, // @Legacy
465
+ styleList: attachment1.share.style_list // @Legacy
414
466
  };
415
467
  case "video":
416
468
  return {
417
469
  type: "video",
418
470
  ID: attachment1.metadata.fbid.toString(),
419
471
  filename: attachment1.name,
472
+
420
473
  previewUrl: attachment1.preview_url,
421
474
  previewWidth: attachment1.preview_width,
422
475
  previewHeight: attachment1.preview_height,
476
+
423
477
  url: attachment1.url,
424
478
  width: attachment1.metadata.dimensions.width,
425
479
  height: attachment1.metadata.dimensions.height,
480
+
426
481
  duration: attachment1.metadata.duration,
427
482
  videoType: "unknown",
428
- thumbnailUrl: attachment1.thumbnail_url
483
+
484
+ thumbnailUrl: attachment1.thumbnail_url // @Legacy
429
485
  };
430
486
  case "error":
431
487
  return {
432
488
  type: "error",
489
+
490
+ // Save error attachments because we're unsure of their format,
491
+ // and whether there are cases they contain something useful for debugging.
433
492
  attachment1: attachment1,
434
493
  attachment2: attachment2
435
494
  };
@@ -439,60 +498,72 @@ function _formatAttachment(attachment1, attachment2) {
439
498
  ID: blob.legacy_attachment_id,
440
499
  filename: blob.filename,
441
500
  thumbnailUrl: blob.thumbnail.uri,
501
+
442
502
  previewUrl: blob.preview.uri,
443
503
  previewWidth: blob.preview.width,
444
504
  previewHeight: blob.preview.height,
505
+
445
506
  largePreviewUrl: blob.large_preview.uri,
446
507
  largePreviewWidth: blob.large_preview.width,
447
508
  largePreviewHeight: blob.large_preview.height,
448
- url: blob.large_preview.uri,
449
- width: blob.original_dimensions.x,
450
- height: blob.original_dimensions.y,
451
- name: blob.filename
509
+
510
+ url: blob.large_preview.uri, // @Legacy
511
+ width: blob.original_dimensions.x, // @Legacy
512
+ height: blob.original_dimensions.y, // @Legacy
513
+ name: blob.filename // @Legacy
452
514
  };
453
515
  case "MessageAnimatedImage":
454
516
  return {
455
517
  type: "animated_image",
456
518
  ID: blob.legacy_attachment_id,
457
519
  filename: blob.filename,
520
+
458
521
  previewUrl: blob.preview_image.uri,
459
522
  previewWidth: blob.preview_image.width,
460
523
  previewHeight: blob.preview_image.height,
524
+
461
525
  url: blob.animated_image.uri,
462
526
  width: blob.animated_image.width,
463
527
  height: blob.animated_image.height,
464
- thumbnailUrl: blob.preview_image.uri,
465
- name: blob.filename,
466
- facebookUrl: blob.animated_image.uri,
467
- rawGifImage: blob.animated_image.uri,
468
- animatedGifUrl: blob.animated_image.uri,
469
- animatedGifPreviewUrl: blob.preview_image.uri,
470
- animatedWebpUrl: blob.animated_image.uri,
471
- animatedWebpPreviewUrl: blob.preview_image.uri
528
+
529
+ thumbnailUrl: blob.preview_image.uri, // @Legacy
530
+ name: blob.filename, // @Legacy
531
+ facebookUrl: blob.animated_image.uri, // @Legacy
532
+ rawGifImage: blob.animated_image.uri, // @Legacy
533
+ animatedGifUrl: blob.animated_image.uri, // @Legacy
534
+ animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
535
+ animatedWebpUrl: blob.animated_image.uri, // @Legacy
536
+ animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
472
537
  };
473
538
  case "MessageVideo":
474
539
  return {
475
540
  type: "video",
476
541
  filename: blob.filename,
477
542
  ID: blob.legacy_attachment_id,
543
+
478
544
  previewUrl: blob.large_image.uri,
479
545
  previewWidth: blob.large_image.width,
480
546
  previewHeight: blob.large_image.height,
547
+
481
548
  url: blob.playable_url,
482
549
  width: blob.original_dimensions.x,
483
550
  height: blob.original_dimensions.y,
551
+
484
552
  duration: blob.playable_duration_in_ms,
485
553
  videoType: blob.video_type.toLowerCase(),
486
- thumbnailUrl: blob.large_image.uri
554
+
555
+ thumbnailUrl: blob.large_image.uri // @Legacy
487
556
  };
488
557
  case "MessageAudio":
489
558
  return {
490
559
  type: "audio",
491
560
  filename: blob.filename,
492
561
  ID: blob.url_shimhash,
562
+
493
563
  audioType: blob.audio_type,
494
564
  duration: blob.playable_duration_in_ms,
495
565
  url: blob.playable_url,
566
+
496
567
  isVoiceMail: blob.is_voicemail
497
568
  };
498
569
  case "StickerAttachment":
@@ -500,43 +571,54 @@ function _formatAttachment(attachment1, attachment2) {
500
571
  type: "sticker",
501
572
  ID: blob.id,
502
573
  url: blob.url,
574
+
503
575
  packID: blob.pack ? blob.pack.id : null,
504
576
  spriteUrl: blob.sprite_image,
505
577
  spriteUrl2x: blob.sprite_image_2x,
506
578
  width: blob.width,
507
579
  height: blob.height,
580
+
508
581
  caption: blob.label,
509
582
  description: blob.label,
583
+
510
584
  frameCount: blob.frame_count,
511
585
  frameRate: blob.frame_rate,
512
586
  framesPerRow: blob.frames_per_row,
513
587
  framesPerCol: blob.frames_per_column,
514
- stickerID: blob.id,
515
- spriteURI: blob.sprite_image,
516
- spriteURI2x: blob.sprite_image_2x
588
+
589
+ stickerID: blob.id, // @Legacy
590
+ spriteURI: blob.sprite_image, // @Legacy
591
+ spriteURI2x: blob.sprite_image_2x // @Legacy
517
592
  };
518
593
  case "MessageLocation":
519
594
  var urlAttach = blob.story_attachment.url;
520
595
  var mediaAttach = blob.story_attachment.media;
596
+
521
597
  var u = querystring.parse(url.parse(urlAttach).query).u;
522
598
  var where1 = querystring.parse(url.parse(u).query).where1;
523
599
  var address = where1.split(", ");
600
+
524
601
  var latitude;
525
602
  var longitude;
603
+
526
604
  try {
527
605
  latitude = Number.parseFloat(address[0]);
528
606
  longitude = Number.parseFloat(address[1]);
529
607
  } catch (err) {
530
608
  /* empty */
609
+
531
610
  }
611
+
532
612
  var imageUrl;
533
613
  var width;
534
614
  var height;
615
+
535
616
  if (mediaAttach && mediaAttach.image) {
536
617
  imageUrl = mediaAttach.image.uri;
537
618
  width = mediaAttach.image.width;
538
619
  height = mediaAttach.image.height;
539
620
  }
621
+
540
622
  return {
541
623
  type: "location",
542
624
  ID: blob.legacy_attachment_id,
@@ -547,19 +629,22 @@ function _formatAttachment(attachment1, attachment2) {
547
629
  height: height,
548
630
  url: u || urlAttach,
549
631
  address: where1,
550
- facebookUrl: blob.story_attachment.url,
551
- target: blob.story_attachment.target,
552
- styleList: blob.story_attachment.style_list
632
+
633
+ facebookUrl: blob.story_attachment.url, // @Legacy
634
+ target: blob.story_attachment.target, // @Legacy
635
+ styleList: blob.story_attachment.style_list // @Legacy
553
636
  };
554
637
  case "ExtensibleAttachment":
555
638
  return {
556
639
  type: "share",
557
640
  ID: blob.legacy_attachment_id,
558
641
  url: blob.story_attachment.url,
642
+
559
643
  title: blob.story_attachment.title_with_entities.text,
560
644
  description: blob.story_attachment.description &&
561
645
  blob.story_attachment.description.text,
562
646
  source: blob.story_attachment.source ? blob.story_attachment.source.text : null,
647
+
563
648
  image: blob.story_attachment.media &&
564
649
  blob.story_attachment.media.image &&
565
650
  blob.story_attachment.media.image.uri,
@@ -574,23 +659,27 @@ function _formatAttachment(attachment1, attachment2) {
574
659
  duration: blob.story_attachment.media &&
575
660
  blob.story_attachment.media.playable_duration_in_ms,
576
661
  playableUrl: blob.story_attachment.media == null ? null : blob.story_attachment.media.playable_url,
662
+
577
663
  subattachments: blob.story_attachment.subattachments,
578
664
  properties: blob.story_attachment.properties.reduce(function (/** @type {{ [x: string]: any; }} */obj, /** @type {{ key: string | number; value: { text: any; }; }} */cur) {
579
665
  obj[cur.key] = cur.value.text;
580
666
  return obj;
581
667
  }, {}),
582
- facebookUrl: blob.story_attachment.url,
583
- target: blob.story_attachment.target,
584
- styleList: blob.story_attachment.style_list
668
+
669
+ facebookUrl: blob.story_attachment.url, // @Legacy
670
+ target: blob.story_attachment.target, // @Legacy
671
+ styleList: blob.story_attachment.style_list // @Legacy
585
672
  };
586
673
  case "MessageFile":
587
674
  return {
588
675
  type: "file",
589
676
  filename: blob.filename,
590
677
  ID: blob.message_file_fbid,
678
+
591
679
  url: blob.url,
592
680
  isMalicious: blob.is_malicious,
593
681
  contentType: blob.content_type,
682
+
594
683
  name: blob.filename,
595
684
  mimeType: "",
596
685
  fileSize: -1
@@ -614,6 +703,7 @@ function _formatAttachment(attachment1, attachment2) {
614
703
  * @param {{ [x: string]: any; }} attachmentMap
615
704
  * @param {any} shareMap
616
705
  */
706
+
617
707
  function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
618
708
  attachmentMap = shareMap || attachmentMap;
619
709
  return attachments ?
@@ -628,61 +718,20 @@ function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
628
718
  }) : [];
629
719
  }
630
720
 
631
- /**
632
- * Extract mentions from message - supports legacy (data.prng) and new format (messageMetadata.data.data.Gb.asMap.data).
633
- * @param {Object} m - Raw message object (NewMessage delta)
634
- * @returns {Object} mentions - Map of userID -> mention text
635
- */
636
- function getMentionsFromDeltaMessage(m) {
637
- var body = m.body || "";
638
- var mentions = {};
639
- var mdata = [];
640
- if (m.data && m.data.prng) {
641
- try {
642
- mdata = JSON.parse(m.data.prng);
643
- } catch (e) {
644
- mdata = [];
645
- }
646
- }
647
- if (mdata.length > 0) {
648
- for (var i = 0; i < mdata.length; i++) {
649
- var id = mdata[i].i;
650
- var o = parseInt(mdata[i].o, 10) || 0;
651
- var l = parseInt(mdata[i].l, 10) || 0;
652
- mentions[String(id)] = body.substring(o, o + l);
653
- }
654
- return mentions;
655
- }
656
- var md = m.messageMetadata;
657
- if (md && md.data && md.data.data && md.data.data.Gb && md.data.data.Gb.asMap && md.data.data.Gb.asMap.data) {
658
- var gbData = md.data.data.Gb.asMap.data;
659
- for (var key in gbData) {
660
- if (!Object.prototype.hasOwnProperty.call(gbData, key)) continue;
661
- var entry = gbData[key];
662
- if (entry && entry.asMap && entry.asMap.data) {
663
- var d = entry.asMap.data;
664
- var id = d.id && d.id.asLong ? String(d.id.asLong) : null;
665
- var offset = parseInt((d.offset && d.offset.asLong) ? d.offset.asLong : 0, 10);
666
- var len = parseInt((d.length && d.length.asLong) ? d.length.asLong : 0, 10);
667
- if (id != null) {
668
- mentions[id] = body.substring(offset, offset + len);
669
- }
670
- }
671
- }
672
- }
673
- return mentions;
674
- }
675
-
676
721
  /**
677
722
  * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
678
723
  */
724
+
679
725
  function formatDeltaMessage(m) {
680
726
  var md = m.delta.messageMetadata;
727
+ var mdata = m.delta.data === undefined ? [] : m.delta.data.prng === undefined ? [] : JSON.parse(m.delta.data.prng);
728
+ var m_id = mdata.map(u => u.i);
729
+ var m_offset = mdata.map(u => u.o);
730
+ var m_length = mdata.map(u => u.l);
731
+ var mentions = {};
681
732
  var body = m.delta.body || "";
682
-
683
- // Use the new improved mention extraction function
684
- var mentions = getMentionsFromDeltaMessage(m.delta);
685
733
  var args = body == "" ? [] : body.trim().split(/\s+/);
734
+ for (var i = 0; i < m_id.length; i++) mentions[m_id[i]] = m.delta.body.substring(m_offset[i], m_offset[i] + m_length[i]);
686
735
 
687
736
  // Determine if this is a DM or group
688
737
  const otherUserFbId = md.threadKey.otherUserFbId;
@@ -701,8 +750,7 @@ function formatDeltaMessage(m) {
701
750
  timestamp: md.timestamp,
702
751
  isGroup: !!threadFbId,
703
752
  isSingleUser: isSingleUser,
704
- participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || [],
705
- isUnread: md.isUnread !== undefined ? md.isUnread : false
753
+ participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || []
706
754
  };
707
755
  }
708
756
 
@@ -712,6 +760,7 @@ function formatID(id) {
712
760
  }
713
761
 
714
762
  function isDMThread(threadID) {
763
+ // DM threads don't have 't_' prefix and are typically numeric user IDs
715
764
  return typeof threadID === 'string' && !threadID.includes('t_');
716
765
  }
717
766
 
@@ -779,6 +828,7 @@ function formatHistoryMessage(m) {
779
828
  /**
780
829
  * @param {{ type: any; }} m
781
830
  */
831
+
782
832
  function getAdminTextMessageType(m) {
783
833
  switch (m.type) {
784
834
  case "joinable_group_link_mode_change":
@@ -788,7 +838,6 @@ function getAdminTextMessageType(m) {
788
838
  case "change_thread_theme":
789
839
  return "log:thread-color";
790
840
  case "change_thread_icon":
791
- case "change_thread_quick_reaction":
792
841
  return "log:thread-icon";
793
842
  case "change_thread_nickname":
794
843
  return "log:user-nickname";
@@ -803,16 +852,13 @@ function getAdminTextMessageType(m) {
803
852
  return "log:thread-call";
804
853
  case "pin_messages_v2":
805
854
  return "log:thread-pinned";
806
- case "unpin_messages_v2":
807
- return "log:unpin-message";
808
- default:
809
- return m.type;
810
855
  }
811
856
  }
812
857
 
813
858
  /**
814
859
  * @param {string} name
815
860
  */
861
+
816
862
  function getGenderByPhysicalMethod(name) {
817
863
  const female_name = [
818
864
  "Phương Chi",
@@ -2151,64 +2197,21 @@ function getGenderByPhysicalMethod(name) {
2151
2197
  return Name || "UNKNOWN";
2152
2198
  }
2153
2199
 
2154
- /**
2155
- * Extract mentions from message - supports legacy (data.prng) and new format (messageMetadata.data.data.Gb.asMap.data).
2156
- * @param {Object} m - Raw message object (NewMessage delta)
2157
- * @returns {Object} mentions - Map of userID -> mention text
2158
- */
2159
- function getMentionsFromDeltaMessage(m) {
2160
- var body = m.body || "";
2161
- var mentions = {};
2162
- var mdata = [];
2163
-
2164
- // Try legacy format (data.prng)
2165
- if (m.data && m.data.prng) {
2166
- try {
2167
- mdata = JSON.parse(m.data.prng);
2168
- } catch (e) {
2169
- mdata = [];
2170
- }
2171
- }
2172
-
2173
- if (mdata.length > 0) {
2174
- for (var i = 0; i < mdata.length; i++) {
2175
- var id = mdata[i].i;
2176
- var o = parseInt(mdata[i].o, 10) || 0;
2177
- var l = parseInt(mdata[i].l, 10) || 0;
2178
- mentions[String(id)] = body.substring(o, o + l);
2179
- }
2180
- return mentions;
2181
- }
2182
-
2183
- // Try new format (messageMetadata.data.data.Gb.asMap.data)
2184
- var md = m.messageMetadata;
2185
- if (md && md.data && md.data.data && md.data.data.Gb &&
2186
- md.data.data.Gb.asMap && md.data.data.Gb.asMap.data) {
2187
- var gbData = md.data.data.Gb.asMap.data;
2188
- for (var key in gbData) {
2189
- if (!Object.prototype.hasOwnProperty.call(gbData, key)) continue;
2190
- var entry = gbData[key];
2191
- if (entry && entry.asMap && entry.asMap.data) {
2192
- var d = entry.asMap.data;
2193
- var id = d.id && d.id.asLong ? String(d.id.asLong) : null;
2194
- var offset = parseInt((d.offset && d.offset.asLong) ? d.offset.asLong : 0, 10);
2195
- var len = parseInt((d.length && d.length.asLong) ? d.length.asLong : 0, 10);
2196
- if (id != null) {
2197
- mentions[id] = body.substring(offset, offset + len);
2198
- }
2199
- }
2200
- }
2201
- }
2202
- return mentions;
2203
- }
2204
-
2205
2200
  /**
2206
2201
  * @param {{ [x: string]: { [x: string]: { [x: string]: any; }; }; class: any; untypedData: any; name: any; addedParticipants: any; leftParticipantFbId: any; messageMetadata: { threadKey: { threadFbId: any; otherUserFbId: any; }; adminText: any; actorFbId: any; }; participants: any; }} m
2207
2202
  */
2203
+
2208
2204
  function formatDeltaEvent(m) {
2209
2205
  var logMessageType;
2210
2206
  var logMessageData;
2211
2207
 
2208
+ // log:thread-color => {theme_color}
2209
+ // log:user-nickname => {participant_id, nickname}
2210
+ // log:thread-icon => {thread_icon}
2211
+ // log:thread-name => {name}
2212
+ // log:subscribe => {addedParticipants - [Array]}
2213
+ // log:unsubscribe => {leftParticipantFbId}
2214
+ // console.log(m)
2212
2215
  switch (m.class) {
2213
2216
  case "JoinableMode":
2214
2217
  if (m.mode) return;
@@ -2244,47 +2247,17 @@ function formatDeltaEvent(m) {
2244
2247
  };
2245
2248
  }
2246
2249
 
2247
- /**
2248
- * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
2249
- */
2250
- function formatDeltaMessage(m) {
2251
- var md = m.delta.messageMetadata;
2252
- var body = m.delta.body || "";
2253
-
2254
- // Use the new mention extraction function
2255
- var mentions = getMentionsFromDeltaMessage(m.delta);
2256
- var args = body == "" ? [] : body.trim().split(/\s+/);
2257
-
2258
- // Determine if this is a DM or group
2259
- const otherUserFbId = md.threadKey.otherUserFbId;
2260
- const threadFbId = md.threadKey.threadFbId;
2261
- const isSingleUser = !!otherUserFbId && !threadFbId;
2262
-
2263
- return {
2264
- type: "message",
2265
- senderID: formatID(md.actorFbId.toString()),
2266
- threadID: formatID((threadFbId || otherUserFbId).toString()),
2267
- messageID: md.messageId,
2268
- args: args,
2269
- body: body,
2270
- attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
2271
- mentions: mentions,
2272
- timestamp: md.timestamp,
2273
- isGroup: !!threadFbId,
2274
- isSingleUser: isSingleUser,
2275
- participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || [],
2276
- isUnread: md.isUnread !== undefined ? md.isUnread : false
2277
- };
2278
- }
2279
-
2280
2250
  /**
2281
2251
  * @param {{ st: any; from: { toString: () => any; }; to: any; thread_fbid: any; hasOwnProperty: (arg0: string) => any; from_mobile: any; realtime_viewer_fbid: any; }} event
2282
2252
  */
2253
+
2283
2254
  function formatTyp(event) {
2284
2255
  return {
2285
2256
  isTyping: !!event.st,
2286
2257
  from: event.from.toString(),
2287
2258
  threadID: formatID((event.to || event.thread_fbid || event.from).toString()),
2259
+ // When receiving typ indication from mobile, `from_mobile` isn't set.
2260
+ // If it is, we just use that value.
2288
2261
  fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
2289
2262
  userID: (event.realtime_viewer_fbid || event.from).toString(),
2290
2263
  type: "typ"
@@ -2294,18 +2267,22 @@ function formatTyp(event) {
2294
2267
  /**
2295
2268
  * @param {{ threadKey: { otherUserFbId: any; threadFbId: any; }; actorFbId: any; actionTimestampMs: any; }} delta
2296
2269
  */
2297
- function formatDeltaReadReceipt(delta) {
2298
- return {
2299
- reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
2300
- time: delta.actionTimestampMs,
2301
- threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
2302
- type: "read_receipt"
2303
- };
2304
- }
2270
+
2271
+ // function formatDeltaReadReceipt(delta) {
2272
+ // // otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
2273
+ // // In a group chat actorFbId is used for the reader and threadFbId for the thread.
2274
+ // return {
2275
+ // reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
2276
+ // time: delta.actionTimestampMs,
2277
+ // threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
2278
+ // type: "read_receipt"
2279
+ // };
2280
+ // }
2305
2281
 
2306
2282
  /**
2307
2283
  * @param {{ reader: { toString: () => any; }; time: any; thread_fbid: any; }} event
2308
2284
  */
2285
+
2309
2286
  function formatReadReceipt(event) {
2310
2287
  return {
2311
2288
  reader: event.reader.toString(),
@@ -2318,6 +2295,7 @@ function formatReadReceipt(event) {
2318
2295
  /**
2319
2296
  * @param {{ chat_ids: any[]; thread_fbids: any[]; timestamp: any; }} event
2320
2297
  */
2298
+
2321
2299
  function formatRead(event) {
2322
2300
  return {
2323
2301
  threadID: formatID(((event.chat_ids && event.chat_ids[0]) || (event.thread_fbids && event.thread_fbids[0])).toString()),
@@ -2331,6 +2309,7 @@ function formatRead(event) {
2331
2309
  * @param {string | any[]} startToken
2332
2310
  * @param {string} endToken
2333
2311
  */
2312
+
2334
2313
  function getFrom(str, startToken, endToken) {
2335
2314
  var start = str.indexOf(startToken) + startToken.length;
2336
2315
  if (start < startToken.length) return "";
@@ -2344,9 +2323,20 @@ function getFrom(str, startToken, endToken) {
2344
2323
  /**
2345
2324
  * @param {string} html
2346
2325
  */
2347
- function makeParsable(html) {
2348
- let withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/ , "");
2349
2326
 
2327
+ function makeParsable(html) {
2328
+ let withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/
2329
+ , "");
2330
+
2331
+ // (What the fuck FB, why windows style newlines?)
2332
+ // So sometimes FB will send us base multiple objects in the same response.
2333
+ // They're all valid JSON, one after the other, at the top level. We detect
2334
+ // that and make it parse-able by JSON.parse.
2335
+ // Ben - July 15th 2017
2336
+ //
2337
+ // It turns out that Facebook may insert random number of spaces before
2338
+ // next object begins (issue #616)
2339
+ // rav_kr - 2018-03-19
2350
2340
  let maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
2351
2341
  if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
2352
2342
 
@@ -2356,6 +2346,7 @@ function makeParsable(html) {
2356
2346
  /**
2357
2347
  * @param {any} form
2358
2348
  */
2349
+
2359
2350
  function arrToForm(form) {
2360
2351
  return arrayToObject(form,
2361
2352
  function (/** @type {{ name: any; }} */v) {
@@ -2372,6 +2363,7 @@ function arrToForm(form) {
2372
2363
  * @param {{ (v: any): any; (arg0: any): string | number; }} getKey
2373
2364
  * @param {{ (v: any): any; (arg0: any): any; }} getValue
2374
2365
  */
2366
+
2375
2367
  function arrayToObject(arr, getKey, getValue) {
2376
2368
  return arr.reduce(function (/** @type {{ [x: string]: any; }} */
2377
2369
  acc, /** @type {any} */val) {
@@ -2394,10 +2386,26 @@ function generateTimestampRelative() {
2394
2386
  * @param {any} userID
2395
2387
  * @param {{ fb_dtsg: any; ttstamp: any; globalOptions: any; }} ctx
2396
2388
  */
2389
+
2397
2390
  function makeDefaults(html, userID, ctx) {
2398
2391
  var reqCounter = 1;
2399
2392
  var fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
2400
2393
 
2394
+ // @Hack Ok we've done hacky things, this is definitely on top 5.
2395
+ // We totally assume the object is flat and try parsing until a }.
2396
+ // If it works though it's cool because we get a bunch of extra data things.
2397
+ //
2398
+ // Update: we don't need this. Leaving it in in case we ever do.
2399
+ // Ben - July 15th 2017
2400
+
2401
+ // var siteData = getFrom(html, "[\"SiteData\",[],", "},");
2402
+ // try {
2403
+ // siteData = JSON.parse(siteData + "}");
2404
+ // } catch(e) {
2405
+ // log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
2406
+ // siteData = {};
2407
+ // }
2408
+
2401
2409
  var ttstamp = "2";
2402
2410
  for (var i = 0; i < fb_dtsg.length; i++) ttstamp += fb_dtsg.charCodeAt(i);
2403
2411
  var revision = getFrom(html, 'revision":', ",");
@@ -2405,16 +2413,40 @@ function makeDefaults(html, userID, ctx) {
2405
2413
  /**
2406
2414
  * @param {{ [x: string]: any; hasOwnProperty: (arg0: string) => any; }} obj
2407
2415
  */
2416
+
2408
2417
  function mergeWithDefaults(obj) {
2418
+ // @TODO This is missing a key called __dyn.
2419
+ // After some investigation it seems like __dyn is some sort of set that FB
2420
+ // calls BitMap. It seems like certain responses have a "define" key in the
2421
+ // res.jsmods arrays. I think the code iterates over those and calls `set`
2422
+ // on the bitmap for each of those keys. Then it calls
2423
+ // bitmap.toCompressedString() which returns what __dyn is.
2424
+ //
2425
+ // So far the API has been working without this.
2426
+ //
2427
+ // Ben - July 15th 2017
2409
2428
  var newObj = {
2410
2429
  __user: userID,
2411
2430
  __req: (reqCounter++).toString(36),
2412
2431
  __rev: revision,
2413
2432
  __a: 1,
2433
+ // __af: siteData.features,
2414
2434
  fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
2415
2435
  jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
2436
+ // __spin_r: siteData.__spin_r,
2437
+ // __spin_b: siteData.__spin_b,
2438
+ // __spin_t: siteData.__spin_t,
2416
2439
  };
2417
2440
 
2441
+ // @TODO this is probably not needed.
2442
+ // Ben - July 15th 2017
2443
+ // if (siteData.be_key) {
2444
+ // newObj[siteData.be_key] = siteData.be_mode;
2445
+ // }
2446
+ // if (siteData.pkg_cohort_key) {
2447
+ // newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
2448
+ // }
2449
+
2418
2450
  if (!obj) return newObj;
2419
2451
  for (var prop in obj)
2420
2452
  if (obj.hasOwnProperty(prop))
@@ -2428,6 +2460,7 @@ function makeDefaults(html, userID, ctx) {
2428
2460
  * @param {any} form
2429
2461
  * @param {any} ctxx
2430
2462
  */
2463
+
2431
2464
  function postWithDefaults(url, jar, form, ctxx) {
2432
2465
  return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx);
2433
2466
  }
@@ -2438,6 +2471,7 @@ function makeDefaults(html, userID, ctx) {
2438
2471
  * @param {any} qs
2439
2472
  * @param {any} ctxx
2440
2473
  */
2474
+
2441
2475
  function getWithDefaults(url, jar, qs, ctxx) {
2442
2476
  return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
2443
2477
  }
@@ -2449,6 +2483,7 @@ function makeDefaults(html, userID, ctx) {
2449
2483
  * @param {any} qs
2450
2484
  * @param {any} ctxx
2451
2485
  */
2486
+
2452
2487
  function postFormDataWithDefault(url, jar, form, qs, ctxx) {
2453
2488
  return postFormData(url, jar, mergeWithDefaults(form), mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
2454
2489
  }
@@ -2465,6 +2500,7 @@ function makeDefaults(html, userID, ctx) {
2465
2500
  * @param {{ postFormData: (arg0: string, arg1: any, arg2: any, arg3: {}) => any; post: (arg0: string, arg1: any, arg2: any) => any; get: (arg0: any, arg1: any) => Promise<any>; }} defaultFuncs
2466
2501
  * @param {string | number} [retryCount]
2467
2502
  */
2503
+
2468
2504
  function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2469
2505
  if (retryCount == undefined) retryCount = 0;
2470
2506
  return function (data) {
@@ -2499,8 +2535,10 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2499
2535
  };
2500
2536
  }
2501
2537
 
2538
+ // In some cases the response contains only a redirect URL which should be followed
2502
2539
  if (res.redirect && data.request.method === "GET") return defaultFuncs.get(res.redirect, ctx.jar).then(parseAndCheckLogin(ctx, defaultFuncs));
2503
2540
 
2541
+ // TODO: handle multiple cookies?
2504
2542
  if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
2505
2543
  res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace("_js_", "");
2506
2544
  var cookie = formatCookie(res.jsmods.require[0][3], "facebook");
@@ -2509,11 +2547,15 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2509
2547
  ctx.jar.setCookie(cookie2, "https://www.messenger.com");
2510
2548
  }
2511
2549
 
2550
+ // On every request we check if we got a DTSG and we mutate the context so that we use the latest
2551
+ // one for the next requests.
2512
2552
  if (res.jsmods && Array.isArray(res.jsmods.require)) {
2513
2553
  var arr = res.jsmods.require;
2514
2554
  for (var i in arr) {
2515
2555
  if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
2516
2556
  ctx.fb_dtsg = arr[i][3][0];
2557
+
2558
+ // Update ttstamp since that depends on fb_dtsg
2517
2559
  ctx.ttstamp = "2";
2518
2560
  for (var j = 0; j < ctx.fb_dtsg.length; j++) ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
2519
2561
  }
@@ -2529,11 +2571,12 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2529
2571
  /**
2530
2572
  * @param {{ setCookie: (arg0: any, arg1: string) => void; }} jar
2531
2573
  */
2574
+
2532
2575
  function saveCookies(jar) {
2533
2576
  return function (/** @type {{ headers: { [x: string]: any[]; }; }} */res) {
2534
2577
  var cookies = res.headers["set-cookie"] || [];
2535
2578
  cookies.forEach(function (/** @type {string} */c) {
2536
- if (c.indexOf(".facebook.com") > -1) {
2579
+ if (c.indexOf(".facebook.com") > -1) { // yo wtf is this?
2537
2580
  jar.setCookie(c, "https://www.facebook.com");
2538
2581
  jar.setCookie(c.replace(/domain=\.facebook\.com/, "domain=.messenger.com"), "https://www.messenger.com");
2539
2582
  }
@@ -2543,14 +2586,25 @@ function saveCookies(jar) {
2543
2586
  }
2544
2587
 
2545
2588
  var NUM_TO_MONTH = [
2546
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2547
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2589
+ "Jan",
2590
+ "Feb",
2591
+ "Mar",
2592
+ "Apr",
2593
+ "May",
2594
+ "Jun",
2595
+ "Jul",
2596
+ "Aug",
2597
+ "Sep",
2598
+ "Oct",
2599
+ "Nov",
2600
+ "Dec"
2548
2601
  ];
2549
2602
  var NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2550
2603
 
2551
2604
  /**
2552
2605
  * @param {{ getUTCDate: () => any; getUTCHours: () => any; getUTCMinutes: () => any; getUTCSeconds: () => any; getUTCDay: () => string | number; getUTCMonth: () => string | number; getUTCFullYear: () => string; }} date
2553
2606
  */
2607
+
2554
2608
  function formatDate(date) {
2555
2609
  var d = date.getUTCDate();
2556
2610
  d = d >= 10 ? d : "0" + d;
@@ -2567,6 +2621,7 @@ function formatDate(date) {
2567
2621
  * @param {string[]} arr
2568
2622
  * @param {string} url
2569
2623
  */
2624
+
2570
2625
  function formatCookie(arr, url) {
2571
2626
  return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com";
2572
2627
  }
@@ -2574,6 +2629,7 @@ function formatCookie(arr, url) {
2574
2629
  /**
2575
2630
  * @param {{ thread_fbid: { toString: () => any; }; participants: any[]; name: any; custom_nickname: any; snippet: any; snippet_attachments: any; snippet_sender: any; unread_count: any; message_count: any; image_src: any; timestamp: any; mute_until: any; is_canonical_user: any; is_canonical: any; is_subscribed: any; folder: any; is_archived: any; recipients_loadable: any; has_email_participant: any; read_only: any; can_reply: any; cannot_reply_reason: any; last_message_timestamp: any; last_read_timestamp: any; last_message_type: any; custom_like_icon: any; custom_color: any; admin_ids: any; thread_type: any; }} data
2576
2631
  */
2632
+
2577
2633
  function formatThread(data) {
2578
2634
  return {
2579
2635
  threadID: formatID(data.thread_fbid.toString()),
@@ -2612,6 +2668,7 @@ function formatThread(data) {
2612
2668
  /**
2613
2669
  * @param {any} obj
2614
2670
  */
2671
+
2615
2672
  function getType(obj) {
2616
2673
  return Object.prototype.toString.call(obj).slice(8, -1);
2617
2674
  }
@@ -2620,6 +2677,7 @@ function getType(obj) {
2620
2677
  * @param {{ lat: number; p: any; }} presence
2621
2678
  * @param {any} userID
2622
2679
  */
2680
+
2623
2681
  function formatProxyPresence(presence, userID) {
2624
2682
  if (presence.lat === undefined || presence.p === undefined) return null;
2625
2683
  return {
@@ -2634,6 +2692,7 @@ function formatProxyPresence(presence, userID) {
2634
2692
  * @param {{ la: number; a: any; }} presence
2635
2693
  * @param {any} userID
2636
2694
  */
2695
+
2637
2696
  function formatPresence(presence, userID) {
2638
2697
  return {
2639
2698
  type: "presence",
@@ -2646,7 +2705,16 @@ function formatPresence(presence, userID) {
2646
2705
  /**
2647
2706
  * @param {any} payload
2648
2707
  */
2708
+
2649
2709
  function decodeClientPayload(payload) {
2710
+ /*
2711
+ Special function which Client using to "encode" clients JSON payload
2712
+ */
2713
+
2714
+ /**
2715
+ * @param {string | any[]} array
2716
+ */
2717
+
2650
2718
  function Utf8ArrayToStr(array) {
2651
2719
  var out, i, len, c;
2652
2720
  var char2, char3;
@@ -2686,13 +2754,15 @@ function decodeClientPayload(payload) {
2686
2754
  /**
2687
2755
  * @param {{ getCookies: (arg0: string) => string | any[]; }} jar
2688
2756
  */
2757
+
2689
2758
  function getAppState(jar) {
2690
2759
  return jar.getCookies("https://www.facebook.com").concat(jar.getCookies("https://facebook.com")).concat(jar.getCookies("https://www.messenger.com"));
2691
2760
  }
2692
2761
 
2693
2762
  function getData_Path(Obj, Arr, Stt) {
2763
+ //default stt = 0
2694
2764
  if (Arr.length === 0 && Obj != undefined) {
2695
- return Obj;
2765
+ return Obj; //object
2696
2766
  }
2697
2767
  else if (Obj == undefined) {
2698
2768
  return Stt;
@@ -2705,6 +2775,7 @@ function getData_Path(Obj, Arr, Stt) {
2705
2775
  return getData_Path(Obj[head], tail, Stt++);
2706
2776
  }
2707
2777
 
2778
+
2708
2779
  function setData_Path(obj, path, value) {
2709
2780
  if (!path.length) {
2710
2781
  return obj;
@@ -2747,10 +2818,8 @@ function getJazoest() {
2747
2818
  return result;
2748
2819
  }
2749
2820
 
2750
- function getCurrentTimestamp() {
2751
- const date = new Date();
2752
- const unixTime = date.getTime();
2753
- return unixTime;
2821
+ function getEventTime() {
2822
+ return Date.now();
2754
2823
  }
2755
2824
 
2756
2825
  function getSessionID() {
@@ -2809,23 +2878,27 @@ function cleanHTML(text) {
2809
2878
  return text;
2810
2879
  }
2811
2880
 
2881
+ function delay(ms) {
2882
+ return new Promise(resolve => setTimeout(resolve, ms));
2883
+ }
2884
+
2812
2885
  module.exports = {
2813
2886
  cleanHTML,
2814
- isReadableStream,
2815
- get,
2816
- post,
2817
- postFormData,
2818
- generateThreadingID,
2819
- generateOfflineThreadingID,
2820
- getGUID,
2821
- getFrom,
2822
- makeParsable,
2823
- arrToForm,
2824
- getSignatureID,
2887
+ isReadableStream: isReadableStream,
2888
+ get: get,
2889
+ post: post,
2890
+ postFormData: postFormData,
2891
+ generateThreadingID: generateThreadingID,
2892
+ generateOfflineThreadingID: generateOfflineThreadingID,
2893
+ getGUID: getGUID,
2894
+ getFrom: getFrom,
2895
+ makeParsable: makeParsable,
2896
+ arrToForm: arrToForm,
2897
+ getSignatureID: getSignatureID,
2825
2898
  getJar: request.jar,
2826
- generateTimestampRelative,
2827
- makeDefaults,
2828
- parseAndCheckLogin,
2899
+ generateTimestampRelative: generateTimestampRelative,
2900
+ makeDefaults: makeDefaults,
2901
+ parseAndCheckLogin: parseAndCheckLogin,
2829
2902
  getGender: getGenderByPhysicalMethod,
2830
2903
  getData_Path,
2831
2904
  setData_Path,
@@ -2838,11 +2911,10 @@ module.exports = {
2838
2911
  formatMessage,
2839
2912
  formatDeltaEvent,
2840
2913
  formatDeltaMessage,
2841
- getMentionsFromDeltaMessage,
2842
- formatDeltaReadReceipt,
2843
2914
  formatProxyPresence,
2844
2915
  formatPresence,
2845
2916
  formatTyp,
2917
+ // formatDeltaReadReceipt,
2846
2918
  formatCookie,
2847
2919
  formatThread,
2848
2920
  formatReadReceipt,
@@ -2856,12 +2928,8 @@ module.exports = {
2856
2928
  setProxy,
2857
2929
  isDMThread,
2858
2930
  getJazoest,
2859
- getCurrentTimestamp,
2931
+ getEventTime,
2860
2932
  getSessionID,
2861
2933
  getFormData,
2862
- presenceEncode,
2863
- presenceDecode,
2864
- padZeros,
2865
- binaryToDecimal,
2866
- arrayToObject
2934
+ delay
2867
2935
  };