@cexy/hoonfca 1.0.4 → 1.0.5

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