@ivncotacte/fca-ivan 1.5.2

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

Potentially problematic release.


This version of @ivncotacte/fca-ivan might be problematic. Click here for more details.

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