maris 0.0.1-security → 1.9.0

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

Potentially problematic release.


This version of maris might be problematic. Click here for more details.

Files changed (113) hide show
  1. package/.editorconfig +12 -0
  2. package/.gitattributes +2 -0
  3. package/Extra/Database/index.js +469 -0
  4. package/Extra/ExtraAddons.js +82 -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/Premium.js +81 -0
  21. package/Extra/Src/Release_Memory.js +41 -0
  22. package/Extra/Src/Websocket.js +213 -0
  23. package/Extra/Src/image/checkmate.jpg +0 -0
  24. package/Extra/Src/uuid.js +137 -0
  25. package/FastConfigFca.json +39 -0
  26. package/Func/AcceptAgreement.js +31 -0
  27. package/Func/ClearCache.js +64 -0
  28. package/Func/ReportV1.js +54 -0
  29. package/LICENSE +21 -0
  30. package/Language/index.json +216 -0
  31. package/Main.js +1192 -0
  32. package/README.md +140 -5
  33. package/SECURITY.md +18 -0
  34. package/broadcast.js +40 -0
  35. package/index.js +383 -0
  36. package/logger.js +66 -0
  37. package/package.json +95 -3
  38. package/src/Dev_Horizon_Data.js +125 -0
  39. package/src/Premium.js +25 -0
  40. package/src/Screenshot.js +83 -0
  41. package/src/addExternalModule.js +16 -0
  42. package/src/addUserToGroup.js +79 -0
  43. package/src/changeAdminStatus.js +79 -0
  44. package/src/changeArchivedStatus.js +41 -0
  45. package/src/changeAvt.js +85 -0
  46. package/src/changeBio.js +65 -0
  47. package/src/changeBlockedStatus.js +36 -0
  48. package/src/changeGroupImage.js +106 -0
  49. package/src/changeNickname.js +45 -0
  50. package/src/changeThreadColor.js +62 -0
  51. package/src/changeThreadEmoji.js +42 -0
  52. package/src/createNewGroup.js +70 -0
  53. package/src/createPoll.js +60 -0
  54. package/src/deleteMessage.js +45 -0
  55. package/src/deleteThread.js +43 -0
  56. package/src/forwardAttachment.js +48 -0
  57. package/src/getAccessToken.js +28 -0
  58. package/src/getCurrentUserID.js +7 -0
  59. package/src/getEmojiUrl.js +27 -0
  60. package/src/getFriendsList.js +73 -0
  61. package/src/getMessage.js +80 -0
  62. package/src/getThreadHistory.js +537 -0
  63. package/src/getThreadInfo.js +425 -0
  64. package/src/getThreadList.js +213 -0
  65. package/src/getThreadMain.js +220 -0
  66. package/src/getThreadPictures.js +59 -0
  67. package/src/getUID.js +59 -0
  68. package/src/getUserID.js +62 -0
  69. package/src/getUserInfo.js +113 -0
  70. package/src/getUserInfoMain.js +65 -0
  71. package/src/getUserInfoV2.js +32 -0
  72. package/src/getUserInfoV3.js +63 -0
  73. package/src/getUserInfoV4.js +55 -0
  74. package/src/getUserInfoV5.js +61 -0
  75. package/src/handleFriendRequest.js +46 -0
  76. package/src/handleMessageRequest.js +49 -0
  77. package/src/httpGet.js +49 -0
  78. package/src/httpPost.js +48 -0
  79. package/src/httpPostFormData.js +41 -0
  80. package/src/listenMqtt.js +787 -0
  81. package/src/logout.js +68 -0
  82. package/src/markAsDelivered.js +48 -0
  83. package/src/markAsRead.js +70 -0
  84. package/src/markAsReadAll.js +43 -0
  85. package/src/markAsSeen.js +51 -0
  86. package/src/muteThread.js +47 -0
  87. package/src/removeUserFromGroup.js +49 -0
  88. package/src/resolvePhotoUrl.js +37 -0
  89. package/src/searchForThread.js +43 -0
  90. package/src/sendMessage.js +379 -0
  91. package/src/sendTypingIndicator.js +80 -0
  92. package/src/setMessageReaction.js +109 -0
  93. package/src/setPostReaction.js +102 -0
  94. package/src/setTitle.js +74 -0
  95. package/src/threadColors.js +39 -0
  96. package/src/unfriend.js +43 -0
  97. package/src/unsendMessage.js +40 -0
  98. package/test/Data_Vtuan/A_README.md +1 -0
  99. package/test/Data_Vtuan/Database.db +0 -0
  100. package/test/Database_Test.js +4 -0
  101. package/test/Db2.js +530 -0
  102. package/test/data/shareAttach.js +146 -0
  103. package/test/data/something.mov +0 -0
  104. package/test/data/test.png +0 -0
  105. package/test/data/test.txt +7 -0
  106. package/test/env/.env +0 -0
  107. package/test/example-config.json +18 -0
  108. package/test/example-db.db +0 -0
  109. package/test/memoryleak.js +18 -0
  110. package/test/test-page.js +140 -0
  111. package/test/test.js +385 -0
  112. package/test/testv2.js +18 -0
  113. 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() + "/FastConfigFca.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() + "/FastConfigFca.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
+ };