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.
- package/checkUpdate.js +112 -0
- package/index.js +106 -1
- package/package.json +2 -2
- 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;
|
|
102
|
-
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
|
|
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
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
583
|
-
|
|
584
|
-
|
|
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
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
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",
|
|
2547
|
-
"
|
|
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
|
|
2751
|
-
|
|
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
|
-
|
|
2931
|
+
getEventTime,
|
|
2860
2932
|
getSessionID,
|
|
2861
2933
|
getFormData,
|
|
2862
|
-
|
|
2863
|
-
presenceDecode,
|
|
2864
|
-
padZeros,
|
|
2865
|
-
binaryToDecimal,
|
|
2866
|
-
arrayToObject
|
|
2934
|
+
delay
|
|
2867
2935
|
};
|