fca-zeid 0.0.1-security → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fca-zeid might be problematic. Click here for more details.

Files changed (111) hide show
  1. package/.gitattributes +2 -0
  2. package/Extra/Database/index.js +469 -0
  3. package/Extra/ExtraAddons.js +82 -0
  4. package/Extra/ExtraAutoGetAppState.js +20 -0
  5. package/Extra/ExtraFindUID.js +62 -0
  6. package/Extra/ExtraGetThread.js +340 -0
  7. package/Extra/ExtraScreenShot.js +430 -0
  8. package/Extra/ExtraUptimeRobot.js +38 -0
  9. package/Extra/Html/Classic/script.js +119 -0
  10. package/Extra/Html/Classic/style.css +8 -0
  11. package/Extra/Security/Index.js +173 -0
  12. package/Extra/Security/Step_1.js +6 -0
  13. package/Extra/Security/Step_2.js +22 -0
  14. package/Extra/Security/Step_3.js +22 -0
  15. package/Extra/Src/Change_Environment.js +24 -0
  16. package/Extra/Src/Check_Update.js +67 -0
  17. package/Extra/Src/History.js +115 -0
  18. package/Extra/Src/Instant_Update.js +65 -0
  19. package/Extra/Src/Last-Run.js +65 -0
  20. package/Extra/Src/Release_Memory.js +41 -0
  21. package/Extra/Src/Websocket.js +213 -0
  22. package/Extra/Src/image/checkmate.jpg +0 -0
  23. package/Extra/Src/uuid.js +137 -0
  24. package/Func/AcceptAgreement.js +31 -0
  25. package/Func/ClearCache.js +64 -0
  26. package/Func/ReportV1.js +54 -0
  27. package/Index.js +385 -0
  28. package/LICENSE +21 -0
  29. package/Language/index.json +223 -0
  30. package/Main.js +1193 -0
  31. package/README.md +144 -5
  32. package/broadcast.js +40 -0
  33. package/fca-horizon-rebuild.zip +0 -0
  34. package/logger.js +66 -0
  35. package/package.json +224 -3
  36. package/src/Dev_Horizon_Data.js +125 -0
  37. package/src/Premium.js +25 -0
  38. package/src/Screenshot.js +83 -0
  39. package/src/addExternalModule.js +16 -0
  40. package/src/addUserToGroup.js +79 -0
  41. package/src/changeAdminStatus.js +79 -0
  42. package/src/changeArchivedStatus.js +41 -0
  43. package/src/changeAvt.js +85 -0
  44. package/src/changeBio.js +65 -0
  45. package/src/changeBlockedStatus.js +36 -0
  46. package/src/changeGroupImage.js +106 -0
  47. package/src/changeNickname.js +45 -0
  48. package/src/changeThreadColor.js +62 -0
  49. package/src/changeThreadEmoji.js +42 -0
  50. package/src/createNewGroup.js +70 -0
  51. package/src/createPoll.js +60 -0
  52. package/src/deleteMessage.js +45 -0
  53. package/src/deleteThread.js +43 -0
  54. package/src/forwardAttachment.js +48 -0
  55. package/src/getAccessToken.js +28 -0
  56. package/src/getCurrentUserID.js +7 -0
  57. package/src/getEmojiUrl.js +27 -0
  58. package/src/getFriendsList.js +73 -0
  59. package/src/getMessage.js +80 -0
  60. package/src/getThreadHistory.js +537 -0
  61. package/src/getThreadInfo.js +425 -0
  62. package/src/getThreadList.js +213 -0
  63. package/src/getThreadMain.js +220 -0
  64. package/src/getThreadPictures.js +59 -0
  65. package/src/getUID.js +59 -0
  66. package/src/getUserID.js +62 -0
  67. package/src/getUserInfo.js +113 -0
  68. package/src/getUserInfoMain.js +65 -0
  69. package/src/getUserInfoV2.js +32 -0
  70. package/src/getUserInfoV3.js +63 -0
  71. package/src/getUserInfoV4.js +55 -0
  72. package/src/getUserInfoV5.js +61 -0
  73. package/src/handleFriendRequest.js +46 -0
  74. package/src/handleMessageRequest.js +49 -0
  75. package/src/httpGet.js +49 -0
  76. package/src/httpPost.js +48 -0
  77. package/src/httpPostFormData.js +41 -0
  78. package/src/listenMqtt.js +787 -0
  79. package/src/logout.js +68 -0
  80. package/src/markAsDelivered.js +48 -0
  81. package/src/markAsRead.js +70 -0
  82. package/src/markAsReadAll.js +43 -0
  83. package/src/markAsSeen.js +51 -0
  84. package/src/muteThread.js +47 -0
  85. package/src/removeUserFromGroup.js +49 -0
  86. package/src/resolvePhotoUrl.js +37 -0
  87. package/src/searchForThread.js +43 -0
  88. package/src/sendMessage.js +379 -0
  89. package/src/sendTypingIndicator.js +80 -0
  90. package/src/setMessageReaction.js +109 -0
  91. package/src/setPostReaction.js +102 -0
  92. package/src/setTitle.js +74 -0
  93. package/src/threadColors.js +39 -0
  94. package/src/unfriend.js +43 -0
  95. package/src/unsendMessage.js +40 -0
  96. package/test/Database_Test.js +4 -0
  97. package/test/Db2.js +530 -0
  98. package/test/Horizon_Database/A_README.md +1 -0
  99. package/test/Horizon_Database/Database.db +0 -0
  100. package/test/data/shareAttach.js +146 -0
  101. package/test/data/something.mov +0 -0
  102. package/test/data/test.png +0 -0
  103. package/test/data/test.txt +7 -0
  104. package/test/env/.env +0 -0
  105. package/test/example-config.json +18 -0
  106. package/test/example-db.db +0 -0
  107. package/test/memoryleak.js +18 -0
  108. package/test/test-page.js +140 -0
  109. package/test/test.js +385 -0
  110. package/test/testv2.js +18 -0
  111. package/utils.js +1684 -0
package/utils.js ADDED
@@ -0,0 +1,1684 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable no-undef */
3
+
4
+ /* eslint-disable no-prototype-builtins */
5
+
6
+ "use strict";
7
+ var url = require("url");
8
+ var log = require("npmlog");
9
+ const _ = require('lodash');
10
+ var stream = require("stream");
11
+ var bluebird = require("bluebird");
12
+ var querystring = require("querystring");
13
+ var request = bluebird.promisify(require("request").defaults({ jar: true }));
14
+
15
+ /**
16
+ * @param {any} url
17
+ */
18
+
19
+ function setProxy(url) {
20
+ if (typeof url == undefined) return request = bluebird.promisify(require("request").defaults({ jar: true }));
21
+ return request = bluebird.promisify(require("request").defaults({ jar: true, proxy: url }));
22
+ }
23
+
24
+ /**
25
+ * @param {string | URL} url
26
+ * @param {{ userAgent: any; }} options
27
+ * @param {{ region: any; }} [ctx]
28
+ * @param {undefined} [customHeader]
29
+ */
30
+
31
+ function getHeaders(url, options, ctx, customHeader) {
32
+ var headers = {
33
+ "Content-Type": "application/x-www-form-urlencoded",
34
+ Referer: "https://www.facebook.com/",
35
+ Host: url.replace("https://", "").split("/")[0],
36
+ Origin: "https://www.facebook.com",
37
+ "user-agent": (options.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36"),
38
+ Connection: "keep-alive",
39
+ "sec-fetch-site": 'same-origin',
40
+ "sec-fetch-mode": 'cors'
41
+ };
42
+ if (customHeader) Object.assign(headers, customHeader);
43
+ if (ctx && ctx.region) headers["X-MSGR-Region"] = ctx.region;
44
+
45
+ return headers;
46
+ }
47
+
48
+ /**
49
+ * @param {{ _read: any; _readableState: any; }} obj
50
+ */
51
+
52
+ function isReadableStream(obj) {
53
+ return (
54
+ obj instanceof stream.Stream &&
55
+ (getType(obj._read) === "Function" ||
56
+ getType(obj._read) === "AsyncFunction") &&
57
+ getType(obj._readableState) === "Object"
58
+ );
59
+ }
60
+
61
+ /**
62
+ * @param {any} url
63
+ * @param {any} jar
64
+ * @param {{ [x: string]: any; fb_dtsg?: any; jazoest?: any; hasOwnProperty?: any; }} qs
65
+ * @param {any} options
66
+ * @param {any} ctx
67
+ */
68
+
69
+ function get(url, jar, qs, options, ctx) {
70
+ // I'm still confused about this
71
+ if (getType(qs) === "Object")
72
+ for (var prop in qs)
73
+ if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") qs[prop] = JSON.stringify(qs[prop]);
74
+ var op = {
75
+ headers: getHeaders(url, options, ctx),
76
+ timeout: 60000,
77
+ qs: qs,
78
+ url: url,
79
+ method: "GET",
80
+ jar: jar,
81
+ gzip: true
82
+ };
83
+
84
+ return request(op).then(function(res) {
85
+ return res;
86
+ });
87
+ }
88
+
89
+ function post(url, jar, form, options, ctx, customHeader) {
90
+ var op = {
91
+ headers: getHeaders(url, options),
92
+ timeout: 60000,
93
+ url: url,
94
+ method: "POST",
95
+ form: form,
96
+ jar: jar,
97
+ gzip: true
98
+ };
99
+ return request(op).then(function(res) {
100
+ return res;
101
+ });
102
+ }
103
+
104
+ /**
105
+ * @param {any} url
106
+ * @param {any} jar
107
+ * @param {{ __user: any; __req: string; __rev: any; __a: number;
108
+ // __af: siteData.features,
109
+ fb_dtsg: any; jazoest: any; }} form
110
+ * @param {{ __user: any; __req: string; __rev: any; __a: number;
111
+ // __af: siteData.features,
112
+ fb_dtsg: any; jazoest: any; }} qs
113
+ * @param {any} options
114
+ * @param {any} ctx
115
+ */
116
+
117
+ function postFormData(url, jar, form, qs, options, ctx) {
118
+ var headers = getHeaders(url, options, ctx);
119
+ headers["Content-Type"] = "multipart/form-data";
120
+ var op = {
121
+ headers: headers,
122
+ timeout: 60000,
123
+ url: url,
124
+ method: "POST",
125
+ formData: form,
126
+ qs: qs,
127
+ jar: jar,
128
+ gzip: true
129
+ };
130
+
131
+ return request(op).then(function(res) {
132
+ return res;
133
+ });
134
+ }
135
+
136
+ /**
137
+ * @param {string | number | any[]} val
138
+ * @param {number} [len]
139
+ */
140
+
141
+ function padZeros(val, len) {
142
+ val = String(val);
143
+ len = len || 2;
144
+ while (val.length < len) val = "0" + val;
145
+ return val;
146
+ }
147
+
148
+ /**
149
+ * @param {any} clientID
150
+ */
151
+
152
+ function generateThreadingID(clientID) {
153
+ var k = Date.now();
154
+ var l = Math.floor(Math.random() * 4294967295);
155
+ var m = clientID;
156
+ return "<" + k + ":" + l + "-" + m + "@mail.projektitan.com>";
157
+ }
158
+
159
+ /**
160
+ * @param {string | any[]} data
161
+ */
162
+
163
+ function binaryToDecimal(data) {
164
+ var ret = "";
165
+ while (data !== "0") {
166
+ var end = 0;
167
+ var fullName = "";
168
+ var i = 0;
169
+ for (; i < data.length; i++) {
170
+ end = 2 * end + parseInt(data[i], 10);
171
+ if (end >= 10) {
172
+ fullName += "1";
173
+ end -= 10;
174
+ } else fullName += "0";
175
+ }
176
+ ret = end.toString() + ret;
177
+ data = fullName.slice(fullName.indexOf("1"));
178
+ }
179
+ return ret;
180
+ }
181
+
182
+ function generateOfflineThreadingID() {
183
+ var ret = Date.now();
184
+ var value = Math.floor(Math.random() * 4294967295);
185
+ var str = ("0000000000000000000000" + value.toString(2)).slice(-22);
186
+ var msgs = ret.toString(2) + str;
187
+ return binaryToDecimal(msgs);
188
+ }
189
+
190
+ var h;
191
+ var i = {};
192
+ var j = {
193
+ _: "%",
194
+ A: "%2",
195
+ B: "000",
196
+ C: "%7d",
197
+ D: "%7b%22",
198
+ E: "%2c%22",
199
+ F: "%22%3a",
200
+ G: "%2c%22ut%22%3a1",
201
+ H: "%2c%22bls%22%3a",
202
+ I: "%2c%22n%22%3a%22%",
203
+ J: "%22%3a%7b%22i%22%3a0%7d",
204
+ K: "%2c%22pt%22%3a0%2c%22vis%22%3a",
205
+ L: "%2c%22ch%22%3a%7b%22h%22%3a%22",
206
+ M: "%7b%22v%22%3a2%2c%22time%22%3a1",
207
+ N: ".channel%22%2c%22sub%22%3a%5b",
208
+ O: "%2c%22sb%22%3a1%2c%22t%22%3a%5b",
209
+ P: "%2c%22ud%22%3a100%2c%22lc%22%3a0",
210
+ Q: "%5d%2c%22f%22%3anull%2c%22uct%22%3a",
211
+ R: ".channel%22%2c%22sub%22%3a%5b1%5d",
212
+ S: "%22%2c%22m%22%3a0%7d%2c%7b%22i%22%3a",
213
+ T: "%2c%22blc%22%3a1%2c%22snd%22%3a1%2c%22ct%22%3a",
214
+ U: "%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
215
+ V: "%2c%22blc%22%3a0%2c%22snd%22%3a0%2c%22ct%22%3a",
216
+ W: "%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a",
217
+ X: "%2c%22ri%22%3a0%7d%2c%22state%22%3a%7b%22p%22%3a0%2c%22ut%22%3a1",
218
+ Y: "%2c%22pt%22%3a0%2c%22vis%22%3a1%2c%22bls%22%3a0%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
219
+ Z: "%2c%22sb%22%3a1%2c%22t%22%3a%5b%5d%2c%22f%22%3anull%2c%22uct%22%3a0%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a"
220
+ };
221
+ (function() {
222
+ var l = [];
223
+ for (var m in j) {
224
+ i[j[m]] = m;
225
+ l.push(j[m]);
226
+ }
227
+ l.reverse();
228
+ h = new RegExp(l.join("|"), "g");
229
+ })();
230
+
231
+ /**
232
+ * @param {string | number | boolean} str
233
+ */
234
+
235
+ function presenceEncode(str) {
236
+ return encodeURIComponent(str)
237
+ .replace(/([_A-Z])|%../g, function(m, n) {
238
+ return n ? "%" + n.charCodeAt(0).toString(16) : m;
239
+ })
240
+ .toLowerCase()
241
+ .replace(h, function(m) {
242
+ return i[m];
243
+ });
244
+ }
245
+
246
+ // eslint-disable-next-line no-unused-vars
247
+ /**
248
+ * @param {string} str
249
+ */
250
+
251
+ function presenceDecode(str) {
252
+ return decodeURIComponent(
253
+ str.replace(/[_A-Z]/g, function(/** @type {string | number} */m) {
254
+ return j[m];
255
+ })
256
+ );
257
+ }
258
+
259
+ /**
260
+ * @param {string} userID
261
+ */
262
+
263
+ function generatePresence(userID) {
264
+ var time = Date.now();
265
+ return (
266
+ "E" +
267
+ presenceEncode(
268
+ JSON.stringify({
269
+ v: 3,
270
+ time: parseInt(time / 1000, 10),
271
+ user: userID,
272
+ state: {
273
+ ut: 0,
274
+ t2: [],
275
+ lm2: null,
276
+ uct2: time,
277
+ tr: null,
278
+ tw: Math.floor(Math.random() * 4294967295) + 1,
279
+ at: time
280
+ },
281
+ ch: {
282
+ ["p_" + userID]: 0
283
+ }
284
+ })
285
+ )
286
+ );
287
+ }
288
+
289
+ function generateAccessiblityCookie() {
290
+ var time = Date.now();
291
+ return encodeURIComponent(
292
+ JSON.stringify({
293
+ sr: 0,
294
+ "sr-ts": time,
295
+ jk: 0,
296
+ "jk-ts": time,
297
+ kb: 0,
298
+ "kb-ts": time,
299
+ hcm: 0,
300
+ "hcm-ts": time
301
+ })
302
+ );
303
+ }
304
+
305
+ function getGUID() {
306
+ /** @type {number} */
307
+
308
+ var sectionLength = Date.now();
309
+ /** @type {string} */
310
+
311
+ var id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
312
+ /** @type {number} */
313
+
314
+ var r = Math.floor((sectionLength + Math.random() * 16) % 16);
315
+ /** @type {number} */
316
+
317
+ sectionLength = Math.floor(sectionLength / 16);
318
+ /** @type {string} */
319
+
320
+ var _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
321
+ return _guid;
322
+ });
323
+ return id;
324
+ }
325
+
326
+ /**
327
+ * @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
328
+ * @param {{ caption?: any; description?: any; id: any; is_malicious?: any; mime_type?: any; file_size?: any; filename?: any; image_data: any; href?: any; }} [attachment2]
329
+ */
330
+
331
+ function _formatAttachment(attachment1, attachment2) {
332
+ // TODO: THIS IS REALLY BAD
333
+ // This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
334
+ // two attachment objects, but sometimes only one. They each contain part of the
335
+ // data that you'd want so we merge them for convenience.
336
+ // Instead of having a bunch of if statements guarding every access to image_data,
337
+ // we set it to empty object and use the fact that it'll return undefined.
338
+
339
+ attachment2 = attachment2 || { id: "", image_data: {} };
340
+ attachment1 = attachment1.mercury ? attachment1.mercury : attachment1;
341
+ var blob = attachment1.blob_attachment;
342
+ var type =
343
+ blob && blob.__typename ? blob.__typename : attachment1.attach_type;
344
+ if (!type && attachment1.sticker_attachment) {
345
+ type = "StickerAttachment";
346
+ blob = attachment1.sticker_attachment;
347
+ } else if (!type && attachment1.extensible_attachment) {
348
+ if (
349
+ attachment1.extensible_attachment.story_attachment &&
350
+ attachment1.extensible_attachment.story_attachment.target &&
351
+ attachment1.extensible_attachment.story_attachment.target.__typename &&
352
+ attachment1.extensible_attachment.story_attachment.target.__typename === "MessageLocation"
353
+ ) type = "MessageLocation";
354
+ else type = "ExtensibleAttachment";
355
+
356
+ blob = attachment1.extensible_attachment;
357
+ }
358
+ // TODO: Determine whether "sticker", "photo", "file" etc are still used
359
+ // KEEP IN SYNC WITH getThreadHistory
360
+ switch (type) {
361
+ case "sticker":
362
+ return {
363
+ type: "sticker",
364
+ ID: attachment1.metadata.stickerID.toString(),
365
+ url: attachment1.url,
366
+
367
+ packID: attachment1.metadata.packID.toString(),
368
+ spriteUrl: attachment1.metadata.spriteURI,
369
+ spriteUrl2x: attachment1.metadata.spriteURI2x,
370
+ width: attachment1.metadata.width,
371
+ height: attachment1.metadata.height,
372
+
373
+ caption: attachment2.caption,
374
+ description: attachment2.description,
375
+
376
+ frameCount: attachment1.metadata.frameCount,
377
+ frameRate: attachment1.metadata.frameRate,
378
+ framesPerRow: attachment1.metadata.framesPerRow,
379
+ framesPerCol: attachment1.metadata.framesPerCol,
380
+
381
+ stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
382
+ spriteURI: attachment1.metadata.spriteURI, // @Legacy
383
+ spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
384
+ };
385
+ case "file":
386
+ return {
387
+ type: "file",
388
+ filename: attachment1.name,
389
+ ID: attachment2.id.toString(),
390
+ url: attachment1.url,
391
+
392
+ isMalicious: attachment2.is_malicious,
393
+ contentType: attachment2.mime_type,
394
+
395
+ name: attachment1.name, // @Legacy
396
+ mimeType: attachment2.mime_type, // @Legacy
397
+ fileSize: attachment2.file_size // @Legacy
398
+ };
399
+ case "photo":
400
+ return {
401
+ type: "photo",
402
+ ID: attachment1.metadata.fbid.toString(),
403
+ filename: attachment1.fileName,
404
+ thumbnailUrl: attachment1.thumbnail_url,
405
+
406
+ previewUrl: attachment1.preview_url,
407
+ previewWidth: attachment1.preview_width,
408
+ previewHeight: attachment1.preview_height,
409
+
410
+ largePreviewUrl: attachment1.large_preview_url,
411
+ largePreviewWidth: attachment1.large_preview_width,
412
+ largePreviewHeight: attachment1.large_preview_height,
413
+
414
+ url: attachment1.metadata.url, // @Legacy
415
+ width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
416
+ height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
417
+ name: attachment1.fileName // @Legacy
418
+ };
419
+ case "animated_image":
420
+ return {
421
+ type: "animated_image",
422
+ ID: attachment2.id.toString(),
423
+ filename: attachment2.filename,
424
+
425
+ previewUrl: attachment1.preview_url,
426
+ previewWidth: attachment1.preview_width,
427
+ previewHeight: attachment1.preview_height,
428
+
429
+ url: attachment2.image_data.url,
430
+ width: attachment2.image_data.width,
431
+ height: attachment2.image_data.height,
432
+
433
+ name: attachment1.name, // @Legacy
434
+ facebookUrl: attachment1.url, // @Legacy
435
+ thumbnailUrl: attachment1.thumbnail_url, // @Legacy
436
+ mimeType: attachment2.mime_type, // @Legacy
437
+ rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
438
+ rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
439
+ animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
440
+ animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
441
+ animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
442
+ animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
443
+ };
444
+ case "share":
445
+ return {
446
+ type: "share",
447
+ ID: attachment1.share.share_id.toString(),
448
+ url: attachment2.href,
449
+
450
+ title: attachment1.share.title,
451
+ description: attachment1.share.description,
452
+ source: attachment1.share.source,
453
+
454
+ image: attachment1.share.media.image,
455
+ width: attachment1.share.media.image_size.width,
456
+ height: attachment1.share.media.image_size.height,
457
+ playable: attachment1.share.media.playable,
458
+ duration: attachment1.share.media.duration,
459
+
460
+ subattachments: attachment1.share.subattachments,
461
+ properties: {},
462
+
463
+ animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
464
+ facebookUrl: attachment1.share.uri, // @Legacy
465
+ target: attachment1.share.target, // @Legacy
466
+ styleList: attachment1.share.style_list // @Legacy
467
+ };
468
+ case "video":
469
+ return {
470
+ type: "video",
471
+ ID: attachment1.metadata.fbid.toString(),
472
+ filename: attachment1.name,
473
+
474
+ previewUrl: attachment1.preview_url,
475
+ previewWidth: attachment1.preview_width,
476
+ previewHeight: attachment1.preview_height,
477
+
478
+ url: attachment1.url,
479
+ width: attachment1.metadata.dimensions.width,
480
+ height: attachment1.metadata.dimensions.height,
481
+
482
+ duration: attachment1.metadata.duration,
483
+ videoType: "unknown",
484
+
485
+ thumbnailUrl: attachment1.thumbnail_url // @Legacy
486
+ };
487
+ case "error":
488
+ return {
489
+ type: "error",
490
+
491
+ // Save error attachments because we're unsure of their format,
492
+ // and whether there are cases they contain something useful for debugging.
493
+ attachment1: attachment1,
494
+ attachment2: attachment2
495
+ };
496
+ case "MessageImage":
497
+ return {
498
+ type: "photo",
499
+ ID: blob.legacy_attachment_id,
500
+ filename: blob.filename,
501
+ thumbnailUrl: blob.thumbnail.uri,
502
+
503
+ previewUrl: blob.preview.uri,
504
+ previewWidth: blob.preview.width,
505
+ previewHeight: blob.preview.height,
506
+
507
+ largePreviewUrl: blob.large_preview.uri,
508
+ largePreviewWidth: blob.large_preview.width,
509
+ largePreviewHeight: blob.large_preview.height,
510
+
511
+ url: blob.large_preview.uri, // @Legacy
512
+ width: blob.original_dimensions.x, // @Legacy
513
+ height: blob.original_dimensions.y, // @Legacy
514
+ name: blob.filename // @Legacy
515
+ };
516
+ case "MessageAnimatedImage":
517
+ return {
518
+ type: "animated_image",
519
+ ID: blob.legacy_attachment_id,
520
+ filename: blob.filename,
521
+
522
+ previewUrl: blob.preview_image.uri,
523
+ previewWidth: blob.preview_image.width,
524
+ previewHeight: blob.preview_image.height,
525
+
526
+ url: blob.animated_image.uri,
527
+ width: blob.animated_image.width,
528
+ height: blob.animated_image.height,
529
+
530
+ thumbnailUrl: blob.preview_image.uri, // @Legacy
531
+ name: blob.filename, // @Legacy
532
+ facebookUrl: blob.animated_image.uri, // @Legacy
533
+ rawGifImage: blob.animated_image.uri, // @Legacy
534
+ animatedGifUrl: blob.animated_image.uri, // @Legacy
535
+ animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
536
+ animatedWebpUrl: blob.animated_image.uri, // @Legacy
537
+ animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
538
+ };
539
+ case "MessageVideo":
540
+ return {
541
+ type: "video",
542
+ filename: blob.filename,
543
+ ID: blob.legacy_attachment_id,
544
+
545
+ previewUrl: blob.large_image.uri,
546
+ previewWidth: blob.large_image.width,
547
+ previewHeight: blob.large_image.height,
548
+
549
+ url: blob.playable_url,
550
+ width: blob.original_dimensions.x,
551
+ height: blob.original_dimensions.y,
552
+
553
+ duration: blob.playable_duration_in_ms,
554
+ videoType: blob.video_type.toLowerCase(),
555
+
556
+ thumbnailUrl: blob.large_image.uri // @Legacy
557
+ };
558
+ case "MessageAudio":
559
+ return {
560
+ type: "audio",
561
+ filename: blob.filename,
562
+ ID: blob.url_shimhash,
563
+
564
+ audioType: blob.audio_type,
565
+ duration: blob.playable_duration_in_ms,
566
+ url: blob.playable_url,
567
+
568
+ isVoiceMail: blob.is_voicemail
569
+ };
570
+ case "StickerAttachment":
571
+ return {
572
+ type: "sticker",
573
+ ID: blob.id,
574
+ url: blob.url,
575
+
576
+ packID: blob.pack ? blob.pack.id : null,
577
+ spriteUrl: blob.sprite_image,
578
+ spriteUrl2x: blob.sprite_image_2x,
579
+ width: blob.width,
580
+ height: blob.height,
581
+
582
+ caption: blob.label,
583
+ description: blob.label,
584
+
585
+ frameCount: blob.frame_count,
586
+ frameRate: blob.frame_rate,
587
+ framesPerRow: blob.frames_per_row,
588
+ framesPerCol: blob.frames_per_column,
589
+
590
+ stickerID: blob.id, // @Legacy
591
+ spriteURI: blob.sprite_image, // @Legacy
592
+ spriteURI2x: blob.sprite_image_2x // @Legacy
593
+ };
594
+ case "MessageLocation":
595
+ var urlAttach = blob.story_attachment.url;
596
+ var mediaAttach = blob.story_attachment.media;
597
+
598
+ var u = querystring.parse(url.parse(urlAttach).query).u;
599
+ var where1 = querystring.parse(url.parse(u).query).where1;
600
+ var address = where1.split(", ");
601
+
602
+ var latitude;
603
+ var longitude;
604
+
605
+ try {
606
+ latitude = Number.parseFloat(address[0]);
607
+ longitude = Number.parseFloat(address[1]);
608
+ } catch (err) {
609
+ /* empty */
610
+
611
+ }
612
+
613
+ var imageUrl;
614
+ var width;
615
+ var height;
616
+
617
+ if (mediaAttach && mediaAttach.image) {
618
+ imageUrl = mediaAttach.image.uri;
619
+ width = mediaAttach.image.width;
620
+ height = mediaAttach.image.height;
621
+ }
622
+
623
+ return {
624
+ type: "location",
625
+ ID: blob.legacy_attachment_id,
626
+ latitude: latitude,
627
+ longitude: longitude,
628
+ image: imageUrl,
629
+ width: width,
630
+ height: height,
631
+ url: u || urlAttach,
632
+ address: where1,
633
+
634
+ facebookUrl: blob.story_attachment.url, // @Legacy
635
+ target: blob.story_attachment.target, // @Legacy
636
+ styleList: blob.story_attachment.style_list // @Legacy
637
+ };
638
+ case "ExtensibleAttachment":
639
+ return {
640
+ type: "share",
641
+ ID: blob.legacy_attachment_id,
642
+ url: blob.story_attachment.url,
643
+
644
+ title: blob.story_attachment.title_with_entities.text,
645
+ description: blob.story_attachment.description &&
646
+ blob.story_attachment.description.text,
647
+ source: blob.story_attachment.source ? blob.story_attachment.source.text : null,
648
+
649
+ image: blob.story_attachment.media &&
650
+ blob.story_attachment.media.image &&
651
+ blob.story_attachment.media.image.uri,
652
+ width: blob.story_attachment.media &&
653
+ blob.story_attachment.media.image &&
654
+ blob.story_attachment.media.image.width,
655
+ height: blob.story_attachment.media &&
656
+ blob.story_attachment.media.image &&
657
+ blob.story_attachment.media.image.height,
658
+ playable: blob.story_attachment.media &&
659
+ blob.story_attachment.media.is_playable,
660
+ duration: blob.story_attachment.media &&
661
+ blob.story_attachment.media.playable_duration_in_ms,
662
+ playableUrl: blob.story_attachment.media == null ? null : blob.story_attachment.media.playable_url,
663
+
664
+ subattachments: blob.story_attachment.subattachments,
665
+ properties: blob.story_attachment.properties.reduce(function(/** @type {{ [x: string]: any; }} */obj, /** @type {{ key: string | number; value: { text: any; }; }} */cur) {
666
+ obj[cur.key] = cur.value.text;
667
+ return obj;
668
+ }, {}),
669
+
670
+ facebookUrl: blob.story_attachment.url, // @Legacy
671
+ target: blob.story_attachment.target, // @Legacy
672
+ styleList: blob.story_attachment.style_list // @Legacy
673
+ };
674
+ case "MessageFile":
675
+ return {
676
+ type: "file",
677
+ filename: blob.filename,
678
+ ID: blob.message_file_fbid,
679
+
680
+ url: blob.url,
681
+ isMalicious: blob.is_malicious,
682
+ contentType: blob.content_type,
683
+
684
+ name: blob.filename,
685
+ mimeType: "",
686
+ fileSize: -1
687
+ };
688
+ default:
689
+ throw new Error(
690
+ "unrecognized attach_file of type " +
691
+ type +
692
+ "`" +
693
+ JSON.stringify(attachment1, null, 4) +
694
+ " attachment2: " +
695
+ JSON.stringify(attachment2, null, 4) +
696
+ "`"
697
+ );
698
+ }
699
+ }
700
+
701
+ /**
702
+ * @param {any[]} attachments
703
+ * @param {{ [x: string]: string | number; }} attachmentIds
704
+ * @param {{ [x: string]: any; }} attachmentMap
705
+ * @param {any} shareMap
706
+ */
707
+
708
+ function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
709
+ attachmentMap = shareMap || attachmentMap;
710
+ return attachments ?
711
+ attachments.map(function(/** @type {any} */val, /** @type {string | number} */i) {
712
+ if (!attachmentMap ||
713
+ !attachmentIds ||
714
+ !attachmentMap[attachmentIds[i]]
715
+ ) {
716
+ return _formatAttachment(val);
717
+ }
718
+ return _formatAttachment(val, attachmentMap[attachmentIds[i]]);
719
+ }) : [];
720
+ }
721
+
722
+ /**
723
+ * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
724
+ */
725
+
726
+ function formatDeltaMessage(m) {
727
+ var md = m.delta.messageMetadata;
728
+ var mdata =
729
+ m.delta.data === undefined ? [] :
730
+ m.delta.data.prng === undefined ? [] :
731
+ JSON.parse(m.delta.data.prng);
732
+ var m_id = mdata.map((/** @type {{ i: any; }} */u) => u.i);
733
+ var m_offset = mdata.map((/** @type {{ o: any; }} */u) => u.o);
734
+ var m_length = mdata.map((/** @type {{ l: any; }} */u) => u.l);
735
+ var mentions = {};
736
+ var body = m.delta.body || "";
737
+ var args = body == "" ? [] : body.trim().split(/\s+/);
738
+ 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]);
739
+
740
+ return {
741
+ type: "message",
742
+ senderID: formatID(md.actorFbId.toString()),
743
+ threadID: formatID((md.threadKey.threadFbId || md.threadKey.otherUserFbId).toString()),
744
+ messageID: md.messageId,
745
+ args: args,
746
+ body: body,
747
+ attachments: (m.delta.attachments || []).map((/** @type {any} */v) => _formatAttachment(v)),
748
+ mentions: mentions,
749
+ timestamp: md.timestamp,
750
+ isGroup: !!md.threadKey.threadFbId,
751
+ participantIDs: m.delta.participants || []
752
+ };
753
+ }
754
+
755
+ /**
756
+ * @param {string} id
757
+ */
758
+
759
+ function formatID(id) {
760
+ if (id != undefined && id != null) return id.replace(/(fb)?id[:.]/, "");
761
+ else return id;
762
+ }
763
+
764
+ /**
765
+ * @param {{ message: any; type: string; realtime_viewer_fbid: { toString: () => any; }; }} m
766
+ */
767
+
768
+ function formatMessage(m) {
769
+ var originalMessage = m.message ? m.message : m;
770
+ var obj = {
771
+ type: "message",
772
+ senderName: originalMessage.sender_name,
773
+ senderID: formatID(originalMessage.sender_fbid.toString()),
774
+ participantNames: originalMessage.group_thread_info ? originalMessage.group_thread_info.participant_names : [originalMessage.sender_name.split(" ")[0]],
775
+ participantIDs: originalMessage.group_thread_info ?
776
+ originalMessage.group_thread_info.participant_ids.map(function(/** @type {{ toString: () => any; }} */v) {
777
+ return formatID(v.toString());
778
+ }) : [formatID(originalMessage.sender_fbid)],
779
+ body: originalMessage.body || "",
780
+ threadID: formatID((originalMessage.thread_fbid || originalMessage.other_user_fbid).toString()),
781
+ threadName: originalMessage.group_thread_info ? originalMessage.group_thread_info.name : originalMessage.sender_name,
782
+ location: originalMessage.coordinates ? originalMessage.coordinates : null,
783
+ messageID: originalMessage.mid ? originalMessage.mid.toString() : originalMessage.message_id,
784
+ attachments: formatAttachment(
785
+ originalMessage.attachments,
786
+ originalMessage.attachmentIds,
787
+ originalMessage.attachment_map,
788
+ originalMessage.share_map
789
+ ),
790
+ timestamp: originalMessage.timestamp,
791
+ timestampAbsolute: originalMessage.timestamp_absolute,
792
+ timestampRelative: originalMessage.timestamp_relative,
793
+ timestampDatetime: originalMessage.timestamp_datetime,
794
+ tags: originalMessage.tags,
795
+ reactions: originalMessage.reactions ? originalMessage.reactions : [],
796
+ isUnread: originalMessage.is_unread
797
+ };
798
+
799
+ if (m.type === "pages_messaging") obj.pageID = m.realtime_viewer_fbid.toString();
800
+ obj.isGroup = obj.participantIDs.length > 2;
801
+
802
+ return obj;
803
+ }
804
+
805
+ /**
806
+ * @param {{ message: any; }} m
807
+ */
808
+
809
+ function formatEvent(m) {
810
+ var originalMessage = m.message ? m.message : m;
811
+ var logMessageType = originalMessage.log_message_type;
812
+ var logMessageData;
813
+ if (logMessageType === "log:generic-admin-text") {
814
+ logMessageData = originalMessage.log_message_data.untypedData;
815
+ logMessageType = getAdminTextMessageType(originalMessage.log_message_data.message_type);
816
+ } else logMessageData = originalMessage.log_message_data;
817
+
818
+ return Object.assign(formatMessage(originalMessage), {
819
+ type: "event",
820
+ logMessageType: logMessageType,
821
+ logMessageData: logMessageData,
822
+ logMessageBody: originalMessage.log_message_body
823
+ });
824
+ }
825
+
826
+ /**
827
+ * @param {{ action_type: any; }} m
828
+ */
829
+
830
+ function formatHistoryMessage(m) {
831
+ switch (m.action_type) {
832
+ case "ma-type:log-message":
833
+ return formatEvent(m);
834
+ default:
835
+ return formatMessage(m);
836
+ }
837
+ }
838
+
839
+ // Get a more readable message type for AdminTextMessages
840
+ /**
841
+ * @param {{ type: any; }} m
842
+ */
843
+
844
+ function getAdminTextMessageType(m) {
845
+ switch (m.type) {
846
+ case "joinable_group_link_mode_change":
847
+ return "log:link-status";
848
+ case "magic_words":
849
+ return "log:magic-words";
850
+ case "change_thread_theme":
851
+ return "log:thread-color";
852
+ case "change_thread_icon":
853
+ return "log:thread-icon";
854
+ case "change_thread_nickname":
855
+ return "log:user-nickname";
856
+ case "change_thread_admins":
857
+ return "log:thread-admins";
858
+ case "group_poll":
859
+ return "log:thread-poll";
860
+ case "change_thread_approval_mode":
861
+ return "log:thread-approval-mode";
862
+ case "messenger_call_log":
863
+ case "participant_joined_group_call":
864
+ return "log:thread-call";
865
+ case "pin_messages_v2":
866
+ return "log:thread-pinned";
867
+ }
868
+ }
869
+
870
+ /**
871
+ * @param {string} name
872
+ */
873
+
874
+ function getGenderByPhysicalMethod(name) {
875
+ var GirlName = ["LAN", "HÂN", "LINH", "MAI", "HOA", "THU", "BĂNG", "MỸ", "CHÂU", "THẢO", "THOA", "MẪN", "THÙY", "THỦY", "NGA", "NGÂN", "NGHI", "THƯ", "NGỌC", "BÍCH", "VÂN", "DIỆP", "CHI", "TIÊN", "XUÂN", "GIANG", "NHUNG", "DUNG", "NHƯ", "YẾN", "QUYÊN", "YẾN", "TƯỜNG", "VY", "PHƯƠNG", "LIÊN", "LAN", "HÀ", "MAI", "ĐAN", "HẠ", "QUYÊN", "LY", "HÒA", "OANH", "HƯƠNG", "HẰNG", "QUỲNH", "HẠNH", "NHIÊN", "NHẠN"];
876
+
877
+ var BoyName = ["HƯNG", "HUY", "KHẢI", "KHANG", "KHOA", "KHÔI", "KIÊN", "KIỆT", "LONG", "MINH", "ÂN", "BẢO", "BÌNH", "CƯỜNG", "ĐẠT", "ĐỨC", "DŨNG", "DUY", "HOÀNG", "HÙNG", "HƯNG", "NGHĨA", "NGUYÊN", "THẮNG", "THIỆN", "THỊNH", "TÒA", "TRIẾT", "TRUNG", "TRƯỜNG", "TUẤN", "NHÂN", "VŨ", "VINH", "PHONG", "PHÚC", "QUÂN", "QUANG", "SƠN", "TÀI", "THẮNG", "ĐĂNG", "VĂN", "VĨ", "QUANG", "MẠNH"];
878
+
879
+ var OtherName = ["ANH", "THANH", "TÂM", "DƯƠNG", "AN", "LÂM", "MIÊN", "TÚ", "LÂM", "BẰNG", "KHÁNH", "NHẬT", "VỸ", ".",",","/","%", "&","*","-","+"];
880
+
881
+ try {
882
+ var NameArray = name.split(" ");
883
+ name = NameArray[NameArray.length - 1];
884
+ var Name;
885
+ if (name == " " || name == null) return "UNKNOWN";
886
+ switch (GirlName.includes(name.toUpperCase())) {
887
+ case true: {
888
+ if (!OtherName.includes(name.toUpperCase()) && !BoyName.includes(name.toUpperCase())) Name = "FEMALE";
889
+ else Name = ['FEMALE','MALE'][Math.floor(Math.random() * 2)]; // just temp 🌚
890
+ }
891
+ break;
892
+ case false: {
893
+ if (!OtherName.includes(name.toUpperCase()) && !GirlName.includes(name.toUpperCase())) Name = "MALE";
894
+ else Name = ['FEMALE','MALE'][Math.floor(Math.random() * 2)]; // just temp 🌚
895
+ }
896
+ break;
897
+ }
898
+ }
899
+ catch (e) {
900
+ return "UNKNOWN";
901
+ }
902
+ return Name || "UNKNOWN";
903
+ }
904
+
905
+ /**
906
+ * @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
907
+ */
908
+
909
+ function formatDeltaEvent(m) {
910
+ var { updateData,getData,hasData } = require('./Extra/ExtraGetThread');
911
+ var logMessageType;
912
+ var logMessageData;
913
+
914
+ switch (m.class) {
915
+ case "AdminTextMessage":
916
+ logMessageType = getAdminTextMessageType(m);
917
+ logMessageData = m.untypedData;
918
+ break;
919
+ case "ThreadName":
920
+ logMessageType = "log:thread-name";
921
+ logMessageData = { name: m.name };
922
+ break;
923
+ case "ParticipantsAddedToGroupThread":
924
+ logMessageType = "log:subscribe";
925
+ logMessageData = { addedParticipants: m.addedParticipants };
926
+ break;
927
+ case "ParticipantLeftGroupThread":
928
+ logMessageType = "log:unsubscribe";
929
+ logMessageData = { leftParticipantFbId: m.leftParticipantFbId };
930
+ break;
931
+ case "UserLocation": {
932
+ logMessageType = "log:user-location";
933
+ logMessageData = {
934
+ Image: m.attachments[0].mercury.extensible_attachment.story_attachment.media.image,
935
+ Location: m.attachments[0].mercury.extensible_attachment.story_attachment.target.location_title,
936
+ coordinates: m.attachments[0].mercury.extensible_attachment.story_attachment.target.coordinate,
937
+ url: m.attachments[0].mercury.extensible_attachment.story_attachment.url
938
+ };
939
+ }
940
+ }
941
+ switch (hasData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()))) {
942
+ case true: {
943
+ switch (logMessageType) {
944
+ case "log:thread-color": {
945
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
946
+ x.emoji = (logMessageData.theme_emoji || x.emoji);
947
+ x.color = (logMessageData['theme_color'] || x.color);
948
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
949
+ }
950
+ break;
951
+ case "log:thread-icon": {
952
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
953
+ x.emoji = (logMessageData['thread_icon'] || x.emoji);
954
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
955
+ }
956
+ break;
957
+ case "log:user-nickname": {
958
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
959
+ x.nicknames[logMessageData.participant_id] = (logMessageData.nickname.length == 0 ? x.userInfo.find(i => i.id == String(logMessageData.participant_id)).name : logMessageData.nickname);
960
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
961
+ }
962
+ break;
963
+ case "log:thread-admins": {
964
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
965
+ switch (logMessageData.ADMIN_EVENT) {
966
+ case "add_admin": {
967
+ x.adminIDs.push({ id: logMessageData.TARGET_ID });
968
+ }
969
+ break;
970
+ case "remove_admin": {
971
+ x.adminIDs = x.adminIDs.filter(item => item.id != logMessageData.TARGET_ID);
972
+ }
973
+ break;
974
+ }
975
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
976
+ }
977
+ break;
978
+ case "log:thread-approval-mode": {
979
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
980
+ if (x.approvalMode == true) {
981
+ x.approvalMode = false;
982
+ }
983
+ else {
984
+ x.approvalMode = true;
985
+ }
986
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
987
+ }
988
+ break;
989
+ case "log:thread-name": {
990
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
991
+ x.threadName = (logMessageData.name || formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
992
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
993
+ }
994
+ break;
995
+ case "log:subscribe": {
996
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
997
+ for (let o of logMessageData.addedParticipants) {
998
+ if (x.userInfo.some(i => i.id == o.userFbId)) continue;
999
+ else {
1000
+ x.userInfo.push({
1001
+ id: o.userFbId,
1002
+ name: o.fullName,
1003
+ gender: getGenderByPhysicalMethod(o.fullName)
1004
+ });
1005
+ x.participantIDs.push(o.userFbId);
1006
+ }
1007
+ }
1008
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
1009
+ }
1010
+ break;
1011
+ case "log:unsubscribe": {
1012
+ let x = getData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()));
1013
+ x.participantIDs = x.participantIDs.filter(item => item != logMessageData.leftParticipantFbId);
1014
+ x.userInfo = x.userInfo.filter(item => item.id != logMessageData.leftParticipantFbId);
1015
+ if (x.adminIDs.some(i => i.id == logMessageData.leftParticipantFbId)) {
1016
+ x.adminIDs = x.adminIDs.filter(item => item.id != logMessageData.leftParticipantFbId);
1017
+ }
1018
+ updateData(formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),x);
1019
+ }
1020
+ break;
1021
+ }
1022
+ }
1023
+ }
1024
+
1025
+ return {
1026
+ type: "event",
1027
+ threadID: formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),
1028
+ logMessageType: logMessageType,
1029
+ logMessageData: logMessageData,
1030
+ logMessageBody: m.messageMetadata.adminText,
1031
+ author: m.messageMetadata.actorFbId,
1032
+ participantIDs: m.participants || []
1033
+ };
1034
+ }
1035
+
1036
+ /**
1037
+ * @param {{ st: any; from: { toString: () => any; }; to: any; thread_fbid: any; hasOwnProperty: (arg0: string) => any; from_mobile: any; realtime_viewer_fbid: any; }} event
1038
+ */
1039
+
1040
+ function formatTyp(event) {
1041
+ return {
1042
+ isTyping: !!event.st,
1043
+ from: event.from.toString(),
1044
+ threadID: formatID((event.to || event.thread_fbid || event.from).toString()),
1045
+ // When receiving typ indication from mobile, `from_mobile` isn't set.
1046
+ // If it is, we just use that value.
1047
+ fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
1048
+ userID: (event.realtime_viewer_fbid || event.from).toString(),
1049
+ type: "typ"
1050
+ };
1051
+ }
1052
+
1053
+ /**
1054
+ * @param {{ threadKey: { otherUserFbId: any; threadFbId: any; }; actorFbId: any; actionTimestampMs: any; }} delta
1055
+ */
1056
+
1057
+ function formatDeltaReadReceipt(delta) {
1058
+ // otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
1059
+ // In a group chat actorFbId is used for the reader and threadFbId for the thread.
1060
+ return {
1061
+ reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
1062
+ time: delta.actionTimestampMs,
1063
+ threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
1064
+ type: "read_receipt"
1065
+ };
1066
+ }
1067
+
1068
+ /**
1069
+ * @param {{ reader: { toString: () => any; }; time: any; thread_fbid: any; }} event
1070
+ */
1071
+
1072
+ function formatReadReceipt(event) {
1073
+ return {
1074
+ reader: event.reader.toString(),
1075
+ time: event.time,
1076
+ threadID: formatID((event.thread_fbid || event.reader).toString()),
1077
+ type: "read_receipt"
1078
+ };
1079
+ }
1080
+
1081
+ /**
1082
+ * @param {{ chat_ids: any[]; thread_fbids: any[]; timestamp: any; }} event
1083
+ */
1084
+
1085
+ function formatRead(event) {
1086
+ return {
1087
+ threadID: formatID(((event.chat_ids && event.chat_ids[0]) || (event.thread_fbids && event.thread_fbids[0])).toString()),
1088
+ time: event.timestamp,
1089
+ type: "read"
1090
+ };
1091
+ }
1092
+
1093
+ /**
1094
+ * @param {string} str
1095
+ * @param {string | any[]} startToken
1096
+ * @param {string} endToken
1097
+ */
1098
+
1099
+ function getFrom(str, startToken, endToken) {
1100
+ var start = str.indexOf(startToken) + startToken.length;
1101
+ if (start < startToken.length) return "";
1102
+
1103
+ var lastHalf = str.substring(start);
1104
+ var end = lastHalf.indexOf(endToken);
1105
+ if (end === -1) throw Error("Could not find endTime `" + endToken + "` in the given string.");
1106
+ return lastHalf.substring(0, end);
1107
+ }
1108
+
1109
+ /**
1110
+ * @param {string} html
1111
+ */
1112
+
1113
+ function makeParsable(html) {
1114
+ let withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/
1115
+ , "");
1116
+
1117
+ // (What the fuck FB, why windows style newlines?)
1118
+ // So sometimes FB will send us base multiple objects in the same response.
1119
+ // They're all valid JSON, one after the other, at the top level. We detect
1120
+ // that and make it parse-able by JSON.parse.
1121
+ // Ben - July 15th 2017
1122
+ //
1123
+ // It turns out that Facebook may insert random number of spaces before
1124
+ // next object begins (issue #616)
1125
+ // rav_kr - 2018-03-19
1126
+ let maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
1127
+ if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
1128
+
1129
+ return "[" + maybeMultipleObjects.join("},{") + "]";
1130
+ }
1131
+
1132
+ /**
1133
+ * @param {any} form
1134
+ */
1135
+
1136
+ function arrToForm(form) {
1137
+ return arrayToObject(form,
1138
+ function(/** @type {{ name: any; }} */v) {
1139
+ return v.name;
1140
+ },
1141
+ function(/** @type {{ val: any; }} */v) {
1142
+ return v.val;
1143
+ }
1144
+ );
1145
+ }
1146
+
1147
+ /**
1148
+ * @param {any[]} arr
1149
+ * @param {{ (v: any): any; (arg0: any): string | number; }} getKey
1150
+ * @param {{ (v: any): any; (arg0: any): any; }} getValue
1151
+ */
1152
+
1153
+ function arrayToObject(arr, getKey, getValue) {
1154
+ return arr.reduce(function(/** @type {{ [x: string]: any; }} */
1155
+ acc, /** @type {any} */val) {
1156
+ acc[getKey(val)] = getValue(val);
1157
+ return acc;
1158
+ }, {});
1159
+ }
1160
+
1161
+ function getSignatureID() {
1162
+ return Math.floor(Math.random() * 2147483648).toString(16);
1163
+ }
1164
+
1165
+ function generateTimestampRelative() {
1166
+ var d = new Date();
1167
+ return d.getHours() + ":" + padZeros(d.getMinutes());
1168
+ }
1169
+
1170
+ /**
1171
+ * @param {any} html
1172
+ * @param {any} userID
1173
+ * @param {{ fb_dtsg: any; ttstamp: any; globalOptions: any; }} ctx
1174
+ */
1175
+
1176
+ function makeDefaults(html, userID, ctx) {
1177
+ var reqCounter = 1;
1178
+ var fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
1179
+
1180
+ // @Hack Ok we've done hacky things, this is definitely on top 5.
1181
+ // We totally assume the object is flat and try parsing until a }.
1182
+ // If it works though it's cool because we get a bunch of extra data things.
1183
+ //
1184
+ // Update: we don't need this. Leaving it in in case we ever do.
1185
+ // Ben - July 15th 2017
1186
+
1187
+ // var siteData = getFrom(html, "[\"SiteData\",[],", "},");
1188
+ // try {
1189
+ // siteData = JSON.parse(siteData + "}");
1190
+ // } catch(e) {
1191
+ // log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
1192
+ // siteData = {};
1193
+ // }
1194
+
1195
+ var ttstamp = "2";
1196
+ for (var i = 0; i < fb_dtsg.length; i++) ttstamp += fb_dtsg.charCodeAt(i);
1197
+ var revision = getFrom(html, 'revision":', ",");
1198
+
1199
+ /**
1200
+ * @param {{ [x: string]: any; hasOwnProperty: (arg0: string) => any; }} obj
1201
+ */
1202
+
1203
+ function mergeWithDefaults(obj) {
1204
+ // @TODO This is missing a key called __dyn.
1205
+ // After some investigation it seems like __dyn is some sort of set that FB
1206
+ // calls BitMap. It seems like certain responses have a "define" key in the
1207
+ // res.jsmods arrays. I think the code iterates over those and calls `set`
1208
+ // on the bitmap for each of those keys. Then it calls
1209
+ // bitmap.toCompressedString() which returns what __dyn is.
1210
+ //
1211
+ // So far the API has been working without this.
1212
+ //
1213
+ // Ben - July 15th 2017
1214
+ var newObj = {
1215
+ __user: userID,
1216
+ __req: (reqCounter++).toString(36),
1217
+ __rev: revision,
1218
+ __a: 1,
1219
+ // __af: siteData.features,
1220
+ fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
1221
+ jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
1222
+ // __spin_r: siteData.__spin_r,
1223
+ // __spin_b: siteData.__spin_b,
1224
+ // __spin_t: siteData.__spin_t,
1225
+ };
1226
+
1227
+ // @TODO this is probably not needed.
1228
+ // Ben - July 15th 2017
1229
+ // if (siteData.be_key) {
1230
+ // newObj[siteData.be_key] = siteData.be_mode;
1231
+ // }
1232
+ // if (siteData.pkg_cohort_key) {
1233
+ // newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
1234
+ // }
1235
+
1236
+ if (!obj) return newObj;
1237
+ for (var prop in obj)
1238
+ if (obj.hasOwnProperty(prop))
1239
+ if (!newObj[prop]) newObj[prop] = obj[prop];
1240
+ return newObj;
1241
+ }
1242
+
1243
+ /**
1244
+ * @param {any} url
1245
+ * @param {any} jar
1246
+ * @param {any} form
1247
+ * @param {any} ctxx
1248
+ */
1249
+
1250
+ function postWithDefaults(url, jar, form, ctxx) {
1251
+ return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx);
1252
+ }
1253
+
1254
+ /**
1255
+ * @param {any} url
1256
+ * @param {any} jar
1257
+ * @param {any} qs
1258
+ * @param {any} ctxx
1259
+ */
1260
+
1261
+ function getWithDefaults(url, jar, qs, ctxx) {
1262
+ return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
1263
+ }
1264
+
1265
+ /**
1266
+ * @param {any} url
1267
+ * @param {any} jar
1268
+ * @param {any} form
1269
+ * @param {any} qs
1270
+ * @param {any} ctxx
1271
+ */
1272
+
1273
+ function postFormDataWithDefault(url, jar, form, qs, ctxx) {
1274
+ return postFormData(url, jar, mergeWithDefaults(form), mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
1275
+ }
1276
+
1277
+ return {
1278
+ get: getWithDefaults,
1279
+ post: postWithDefaults,
1280
+ postFormData: postFormDataWithDefault
1281
+ };
1282
+ }
1283
+
1284
+ /**
1285
+ * @param {{ jar: { setCookie: (arg0: string, arg1: string) => void; }; fb_dtsg: string; ttstamp: string; }} ctx
1286
+ * @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
1287
+ * @param {string | number} [retryCount]
1288
+ */
1289
+
1290
+ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
1291
+ if (retryCount == undefined) retryCount = 0;
1292
+ return function(/** @type {{ body: string; statusCode: string | number; request: { uri: { protocol: string; hostname: string; pathname: string; }; headers: { [x: string]: string; }; formData: any; method: string; }; }} */data) {
1293
+ return bluebird.try(function() {
1294
+ log.verbose("parseAndCheckLogin", data.body);
1295
+ if (data.statusCode >= 500 && data.statusCode < 600) {
1296
+ if (retryCount >= 5) {
1297
+ throw {
1298
+ error: "Request retry failed. Check the `res` and `statusCode` property on this error.",
1299
+ statusCode: data.statusCode,
1300
+ res: data.body
1301
+ };
1302
+ }
1303
+ retryCount++;
1304
+ var retryTime = Math.floor(Math.random() * 5000);
1305
+ log.warn("parseAndCheckLogin", "Got status code " + data.statusCode + " - " + retryCount + ". attempt to retry in " + retryTime + " milliseconds...");
1306
+ var url = data.request.uri.protocol + "//" + data.request.uri.hostname + data.request.uri.pathname;
1307
+ if (data.request.headers["Content-Type"].split(";")[0] === "multipart/form-data") {
1308
+ return bluebird.delay(retryTime).then(() => defaultFuncs.postFormData(url, ctx.jar, data.request.formData, {}))
1309
+ .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
1310
+ } else {
1311
+ return bluebird.delay(retryTime).then(() => defaultFuncs.post(url, ctx.jar, data.request.formData))
1312
+ .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
1313
+ }
1314
+ }
1315
+ if (data.statusCode !== 200) throw new Error("parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.");
1316
+
1317
+ var res = null;
1318
+ try {
1319
+ res = JSON.parse(makeParsable(data.body));
1320
+ } catch (e) {
1321
+ throw {
1322
+ error: "JSON.parse error. Check the `detail` property on this error.",
1323
+ detail: e,
1324
+ res: data.body
1325
+ };
1326
+ }
1327
+
1328
+ // In some cases the response contains only a redirect URL which should be followed
1329
+ if (res.redirect && data.request.method === "GET") return defaultFuncs.get(res.redirect, ctx.jar).then(parseAndCheckLogin(ctx, defaultFuncs));
1330
+
1331
+ // TODO: handle multiple cookies?
1332
+ if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
1333
+ res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace("_js_", "");
1334
+ var cookie = formatCookie(res.jsmods.require[0][3], "facebook");
1335
+ var cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
1336
+ ctx.jar.setCookie(cookie, "https://www.facebook.com");
1337
+ ctx.jar.setCookie(cookie2, "https://www.messenger.com");
1338
+ }
1339
+
1340
+ // On every request we check if we got a DTSG and we mutate the context so that we use the latest
1341
+ // one for the next requests.
1342
+ if (res.jsmods && Array.isArray(res.jsmods.require)) {
1343
+ var arr = res.jsmods.require;
1344
+ for (var i in arr) {
1345
+ if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
1346
+ ctx.fb_dtsg = arr[i][3][0];
1347
+
1348
+ // Update ttstamp since that depends on fb_dtsg
1349
+ ctx.ttstamp = "2";
1350
+ for (var j = 0; j < ctx.fb_dtsg.length; j++) ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
1351
+ }
1352
+ }
1353
+ }
1354
+
1355
+ if (res.error === 1357001) {
1356
+ if (global.Fca.Require.FastConfig.AutoLogin) {
1357
+ return global.Fca.Require.logger.Warning(global.Fca.Require.Language.Index.AutoLogin, function() {
1358
+ return global.Fca.Action('AutoLogin');
1359
+ });
1360
+ }
1361
+ else if (!global.Fca.Require.FastConfig.AutoLogin) {
1362
+ return global.Fca.Require.logger.Error(global.Fca.Require.Language.Index.ErrAppState);
1363
+ }
1364
+ return;
1365
+ }
1366
+ else return res;
1367
+ });
1368
+ };
1369
+ }
1370
+
1371
+ /**
1372
+ * @param {{ setCookie: (arg0: any, arg1: string) => void; }} jar
1373
+ */
1374
+
1375
+ function saveCookies(jar) {
1376
+ return function(/** @type {{ headers: { [x: string]: any[]; }; }} */res) {
1377
+ var cookies = res.headers["set-cookie"] || [];
1378
+ cookies.forEach(function(/** @type {string} */c) {
1379
+ if (c.indexOf(".facebook.com") > -1) { // yo wtf is this?
1380
+ jar.setCookie(c, "https://www.facebook.com");
1381
+ jar.setCookie(c.replace(/domain=\.facebook\.com/, "domain=.messenger.com"), "https://www.messenger.com");
1382
+ }
1383
+ });
1384
+ return res;
1385
+ };
1386
+ }
1387
+
1388
+ var NUM_TO_MONTH = [
1389
+ "Jan",
1390
+ "Feb",
1391
+ "Mar",
1392
+ "Apr",
1393
+ "May",
1394
+ "Jun",
1395
+ "Jul",
1396
+ "Aug",
1397
+ "Sep",
1398
+ "Oct",
1399
+ "Nov",
1400
+ "Dec"
1401
+ ];
1402
+ var NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1403
+
1404
+ /**
1405
+ * @param {{ getUTCDate: () => any; getUTCHours: () => any; getUTCMinutes: () => any; getUTCSeconds: () => any; getUTCDay: () => string | number; getUTCMonth: () => string | number; getUTCFullYear: () => string; }} date
1406
+ */
1407
+
1408
+ function formatDate(date) {
1409
+ var d = date.getUTCDate();
1410
+ d = d >= 10 ? d : "0" + d;
1411
+ var h = date.getUTCHours();
1412
+ h = h >= 10 ? h : "0" + h;
1413
+ var m = date.getUTCMinutes();
1414
+ m = m >= 10 ? m : "0" + m;
1415
+ var s = date.getUTCSeconds();
1416
+ s = s >= 10 ? s : "0" + s;
1417
+ return (NUM_TO_DAY[date.getUTCDay()] + ", " + d + " " + NUM_TO_MONTH[date.getUTCMonth()] + " " + date.getUTCFullYear() + " " + h + ":" + m + ":" + s + " GMT");
1418
+ }
1419
+
1420
+ /**
1421
+ * @param {string[]} arr
1422
+ * @param {string} url
1423
+ */
1424
+
1425
+ function formatCookie(arr, url) {
1426
+ return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com";
1427
+ }
1428
+
1429
+ /**
1430
+ * @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
1431
+ */
1432
+
1433
+ function formatThread(data) {
1434
+ return {
1435
+ threadID: formatID(data.thread_fbid.toString()),
1436
+ participants: data.participants.map(formatID),
1437
+ participantIDs: data.participants.map(formatID),
1438
+ name: data.name,
1439
+ nicknames: data.custom_nickname,
1440
+ snippet: data.snippet,
1441
+ snippetAttachments: data.snippet_attachments,
1442
+ snippetSender: formatID((data.snippet_sender || "").toString()),
1443
+ unreadCount: data.unread_count,
1444
+ messageCount: data.message_count,
1445
+ imageSrc: data.image_src,
1446
+ timestamp: data.timestamp,
1447
+ muteUntil: data.mute_until,
1448
+ isCanonicalUser: data.is_canonical_user,
1449
+ isCanonical: data.is_canonical,
1450
+ isSubscribed: data.is_subscribed,
1451
+ folder: data.folder,
1452
+ isArchived: data.is_archived,
1453
+ recipientsLoadable: data.recipients_loadable,
1454
+ hasEmailParticipant: data.has_email_participant,
1455
+ readOnly: data.read_only,
1456
+ canReply: data.can_reply,
1457
+ cannotReplyReason: data.cannot_reply_reason,
1458
+ lastMessageTimestamp: data.last_message_timestamp,
1459
+ lastReadTimestamp: data.last_read_timestamp,
1460
+ lastMessageType: data.last_message_type,
1461
+ emoji: data.custom_like_icon,
1462
+ color: data.custom_color,
1463
+ adminIDs: data.admin_ids,
1464
+ threadType: data.thread_type
1465
+ };
1466
+ }
1467
+
1468
+ /**
1469
+ * @param {any} obj
1470
+ */
1471
+
1472
+ function getType(obj) {
1473
+ return Object.prototype.toString.call(obj).slice(8, -1);
1474
+ }
1475
+
1476
+ /**
1477
+ * @param {{ lat: number; p: any; }} presence
1478
+ * @param {any} userID
1479
+ */
1480
+
1481
+ function formatProxyPresence(presence, userID) {
1482
+ if (presence.lat === undefined || presence.p === undefined) return null;
1483
+ return {
1484
+ type: "presence",
1485
+ timestamp: presence.lat * 1000,
1486
+ userID: userID || '',
1487
+ statuses: presence.p
1488
+ };
1489
+ }
1490
+
1491
+ /**
1492
+ * @param {{ la: number; a: any; }} presence
1493
+ * @param {any} userID
1494
+ */
1495
+
1496
+ function formatPresence(presence, userID) {
1497
+ return {
1498
+ type: "presence",
1499
+ timestamp: presence.la * 1000,
1500
+ userID: userID || '',
1501
+ statuses: presence.a
1502
+ };
1503
+ }
1504
+
1505
+ /**
1506
+ * @param {any} payload
1507
+ */
1508
+
1509
+ function decodeClientPayload(payload) {
1510
+ /*
1511
+ Special function which Client using to "encode" clients JSON payload
1512
+ */
1513
+
1514
+ /**
1515
+ * @param {string | any[]} array
1516
+ */
1517
+
1518
+ function Utf8ArrayToStr(array) {
1519
+ var out, i, len, c;
1520
+ var char2, char3;
1521
+ out = "";
1522
+ len = array.length;
1523
+ i = 0;
1524
+ while (i < len) {
1525
+ c = array[i++];
1526
+ switch (c >> 4) {
1527
+ case 0:
1528
+ case 1:
1529
+ case 2:
1530
+ case 3:
1531
+ case 4:
1532
+ case 5:
1533
+ case 6:
1534
+ case 7:
1535
+ out += String.fromCharCode(c);
1536
+ break;
1537
+ case 12:
1538
+ case 13:
1539
+ char2 = array[i++];
1540
+ out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
1541
+ break;
1542
+ case 14:
1543
+ char2 = array[i++];
1544
+ char3 = array[i++];
1545
+ out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
1546
+ break;
1547
+ }
1548
+ }
1549
+ return out;
1550
+ }
1551
+ return JSON.parse(Utf8ArrayToStr(payload));
1552
+ }
1553
+
1554
+ /**
1555
+ * @param {{ getCookies: (arg0: string) => string | any[]; }} jar
1556
+ */
1557
+
1558
+ function getAppState(jar, Encode) {
1559
+ var prettyMilliseconds = require('pretty-ms');
1560
+ var getText = globalThis.Fca.getText;
1561
+ var Security = require("./Extra/Security/Index");
1562
+ var appstate = jar.getCookies("https://www.facebook.com").concat(jar.getCookies("https://facebook.com")).concat(jar.getCookies("https://www.messenger.com"));
1563
+ var logger = require('./logger'),languageFile = require('./Language/index.json');
1564
+ var Language = languageFile.find(i => i.Language == globalThis.Fca.Require.FastConfig.Language).Folder.Index;
1565
+ var data;
1566
+ switch (require(process.cwd() + "/ConfigFca.json").EncryptFeature) {
1567
+ case true: {
1568
+ if (Encode == undefined) Encode = true;
1569
+ if (process.env['FBKEY'] != undefined && Encode) {
1570
+ logger.Normal(Language.EncryptSuccess);
1571
+ data = Security(JSON.stringify(appstate),process.env['FBKEY'],"Encrypt");
1572
+ }
1573
+ else return appstate;
1574
+ }
1575
+ break;
1576
+ case false: {
1577
+ data = appstate;
1578
+ }
1579
+ break;
1580
+ default: {
1581
+ logger.Normal(getText(Language.IsNotABoolean,require(process.cwd() + "/ConfigFca.json").EncryptFeature));
1582
+ data = appstate;
1583
+ }
1584
+ }
1585
+ if(!globalThis.Fca.Setting.get('getAppState')) {
1586
+ logger.Normal(getText(Language.ProcessDone,`${prettyMilliseconds(Date.now() - globalThis.Fca.startTime)}`),function() { globalThis.Fca.Setting.set('getAppState',true); });
1587
+ }
1588
+ return data;
1589
+ }
1590
+
1591
+ function getData_Path(Obj , Arr, Stt) {
1592
+ //default stt = 0
1593
+ if (Arr.length === 0 && Obj != undefined) {
1594
+ return Obj; //object
1595
+ }
1596
+ else if (Obj == undefined) {
1597
+ return Stt;
1598
+ }
1599
+ const head = Arr[0];
1600
+ if (head == undefined) {
1601
+ return Stt;
1602
+ }
1603
+ const tail = Arr.slice(1);
1604
+ return getData_Path(Obj[head], tail, Stt++);
1605
+ }
1606
+
1607
+
1608
+ function setData_Path(obj, path, value) {
1609
+ if (!path.length) {
1610
+ return obj;
1611
+ }
1612
+ const currentKey = path[0];
1613
+ let currentObj = obj[currentKey];
1614
+
1615
+ if (!currentObj) {
1616
+ obj[currentKey] = value;
1617
+ currentObj = obj[currentKey];
1618
+ }
1619
+ path.shift();
1620
+ if (!path.length) {
1621
+ currentObj = value;
1622
+ } else {
1623
+ currentObj = setData_Path(currentObj, path, value);
1624
+ }
1625
+
1626
+ return obj;
1627
+ }
1628
+
1629
+ function getPaths(obj, parentPath = []) {
1630
+ let paths = [];
1631
+ for (let prop in obj) {
1632
+ if (typeof obj[prop] === "object") {
1633
+ paths = paths.concat(getPaths(obj[prop], [...parentPath, prop]));
1634
+ } else {
1635
+ paths.push([...parentPath, prop]);
1636
+ }
1637
+ }
1638
+ return paths;
1639
+ }
1640
+
1641
+ module.exports = {
1642
+ isReadableStream:isReadableStream,
1643
+ get:get,
1644
+ post:post,
1645
+ postFormData:postFormData,
1646
+ generateThreadingID:generateThreadingID,
1647
+ generateOfflineThreadingID:generateOfflineThreadingID,
1648
+ getGUID:getGUID,
1649
+ getFrom:getFrom,
1650
+ makeParsable:makeParsable,
1651
+ arrToForm:arrToForm,
1652
+ getSignatureID:getSignatureID,
1653
+ getJar: request.jar,
1654
+ generateTimestampRelative:generateTimestampRelative,
1655
+ makeDefaults:makeDefaults,
1656
+ parseAndCheckLogin:parseAndCheckLogin,
1657
+ getGender: getGenderByPhysicalMethod,
1658
+ getData_Path,
1659
+ setData_Path,
1660
+ getPaths,
1661
+ saveCookies,
1662
+ getType,
1663
+ _formatAttachment,
1664
+ formatHistoryMessage,
1665
+ formatID,
1666
+ formatMessage,
1667
+ formatDeltaEvent,
1668
+ formatDeltaMessage,
1669
+ formatProxyPresence,
1670
+ formatPresence,
1671
+ formatTyp,
1672
+ formatDeltaReadReceipt,
1673
+ formatCookie,
1674
+ formatThread,
1675
+ formatReadReceipt,
1676
+ formatRead,
1677
+ generatePresence,
1678
+ generateAccessiblityCookie,
1679
+ formatDate,
1680
+ decodeClientPayload,
1681
+ getAppState,
1682
+ getAdminTextMessageType,
1683
+ setProxy
1684
+ };