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