fca-rqzax-remake 0.0.1-security → 2.4.1

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.

Potentially problematic release.


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

Files changed (69) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -0
  2. package/.cache/replit/modules.stamp +0 -0
  3. package/.cache/replit/nix/env.json +1 -0
  4. package/.gitattributes +2 -0
  5. package/.travis.yml +6 -0
  6. package/CHANGELOG.md +2 -0
  7. package/DOCS.md +1738 -0
  8. package/LICENSE-MIT +21 -0
  9. package/README.md +213 -3
  10. package/index.js +542 -0
  11. package/package.json +65 -3
  12. package/replit.nix +9 -0
  13. package/src/addExternalModule.js +16 -0
  14. package/src/addUserToGroup.js +78 -0
  15. package/src/changeAdminStatus.js +79 -0
  16. package/src/changeArchivedStatus.js +41 -0
  17. package/src/changeBio.js +65 -0
  18. package/src/changeBlockedStatus.js +36 -0
  19. package/src/changeGroupImage.js +106 -0
  20. package/src/changeNickname.js +45 -0
  21. package/src/changeThreadColor.js +62 -0
  22. package/src/changeThreadEmoji.js +42 -0
  23. package/src/createNewGroup.js +70 -0
  24. package/src/createPoll.js +60 -0
  25. package/src/deleteMessage.js +45 -0
  26. package/src/deleteThread.js +43 -0
  27. package/src/forwardAttachment.js +48 -0
  28. package/src/getCurrentUserID.js +7 -0
  29. package/src/getEmojiUrl.js +27 -0
  30. package/src/getFriendsList.js +73 -0
  31. package/src/getThreadHistory.js +537 -0
  32. package/src/getThreadHistoryDeprecated.js +71 -0
  33. package/src/getThreadInfo.js +171 -0
  34. package/src/getThreadInfoDeprecated.js +56 -0
  35. package/src/getThreadList.js +213 -0
  36. package/src/getThreadListDeprecated.js +46 -0
  37. package/src/getThreadPictures.js +59 -0
  38. package/src/getUserID.js +62 -0
  39. package/src/getUserInfo.js +66 -0
  40. package/src/handleFriendRequest.js +46 -0
  41. package/src/handleMessageRequest.js +49 -0
  42. package/src/httpGet.js +49 -0
  43. package/src/httpPost.js +48 -0
  44. package/src/listenMqtt.js +654 -0
  45. package/src/logout.js +68 -0
  46. package/src/markAsDelivered.js +48 -0
  47. package/src/markAsRead.js +70 -0
  48. package/src/markAsReadAll.js +43 -0
  49. package/src/markAsSeen.js +51 -0
  50. package/src/muteThread.js +47 -0
  51. package/src/removeUserFromGroup.js +49 -0
  52. package/src/resolvePhotoUrl.js +37 -0
  53. package/src/searchForThread.js +43 -0
  54. package/src/sendMessage.js +321 -0
  55. package/src/sendTypingIndicator.js +80 -0
  56. package/src/setMessageReaction.js +109 -0
  57. package/src/setPostReaction.js +64 -0
  58. package/src/setTitle.js +74 -0
  59. package/src/threadColors.js +41 -0
  60. package/src/unfriend.js +43 -0
  61. package/src/unsendMessage.js +40 -0
  62. package/test/data/shareAttach.js +146 -0
  63. package/test/data/something.mov +0 -0
  64. package/test/data/test.png +0 -0
  65. package/test/data/test.txt +7 -0
  66. package/test/example-config.json +18 -0
  67. package/test/test-page.js +140 -0
  68. package/test/test.js +385 -0
  69. package/utils.js +1234 -0
@@ -0,0 +1,654 @@
1
+ /* eslint-disable no-redeclare */
2
+ "use strict";
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+ var mqtt = require('mqtt');
6
+ var websocket = require('websocket-stream');
7
+ var HttpsProxyAgent = require('https-proxy-agent');
8
+ const EventEmitter = require('events');
9
+
10
+
11
+ var identity = function () { };
12
+ var form = {};
13
+ var getSeqID = function () { };
14
+
15
+ var topics = ["/legacy_web","/webrtc","/rtc_multi","/onevc","/br_sr","/sr_res","/t_ms","/thread_typing","/orca_typing_notifications","/notify_disconnect","/orca_presence","/inbox","/mercury", "/messaging_events", "/orca_message_notifications", "/pp","/webrtc_response"];
16
+
17
+ /* [ Noti ? ]
18
+ ! "/br_sr", //Notification
19
+ * => Need to publish /br_sr right after this
20
+
21
+ ! "/notify_disconnect",
22
+ * => Need to publish /messenger_sync_create_queue right after this
23
+
24
+ ! "/orca_presence",
25
+ * => Will receive /sr_res right here.
26
+ */
27
+
28
+ async function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
29
+ //Don't really know what this does but I think it's for the active state?
30
+ //TODO: Move to ctx when implemented
31
+ var chatOn = ctx.globalOptions.online;
32
+ var foreground = false;
33
+
34
+ var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
35
+ var username = {u: ctx.userID,s: sessionID,chat_on: chatOn,fg: foreground,d: utils.getGUID(),ct: "websocket",aid: "219994525426954", mqtt_sid: "",cp: 3,ecp: 10,st: [],pm: [],dc: "",no_auto_fg: true,gas: null,pack: []};
36
+ var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
37
+
38
+ var host;
39
+ if (ctx.mqttEndpoint) host = `${ctx.mqttEndpoint}&sid=${sessionID}`;
40
+ else if (ctx.region) host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLocaleLowerCase()}&sid=${sessionID}`;
41
+ else host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}`;
42
+
43
+ var options = {
44
+ clientId: "mqttwsclient",
45
+ protocolId: 'MQIsdp',
46
+ protocolVersion: 3,
47
+ username: JSON.stringify(username),
48
+ clean: true,
49
+ wsOptions: {
50
+ headers: {
51
+ 'Cookie': cookies,
52
+ 'Origin': 'https://www.facebook.com',
53
+ 'User-Agent': ctx.globalOptions.userAgent,
54
+ 'Referer': 'https://www.facebook.com/',
55
+ 'Host': new URL(host).hostname //'edge-chat.facebook.com'
56
+ },
57
+ origin: 'https://www.facebook.com',
58
+ protocolVersion: 13
59
+ },
60
+ keepalive: 13,
61
+ reschedulePings: true
62
+ };
63
+
64
+ if (typeof ctx.globalOptions.proxy != "undefined") {
65
+ var agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
66
+ options.wsOptions.agent = agent;
67
+ }
68
+
69
+ ctx.mqttClient = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
70
+
71
+ var mqttClient = ctx.mqttClient;
72
+
73
+ mqttClient.on('error', function (err) {
74
+ log.error("listenMqtt", err);
75
+ mqttClient.end();
76
+ if (ctx.globalOptions.autoReconnect) getSeqID();
77
+ else globalCallback({ type: "stop_listen", error: "Connection refused: Server unavailable" }, null);
78
+ });
79
+
80
+ mqttClient.on('connect', function () {
81
+
82
+ const http = require("http");
83
+ const dashboard = http.createServer(function (request, res) {
84
+ res.writeHead(200, "OK", { "Content-Type": "text/plain" });
85
+ res.write("Vô Nghĩa");
86
+ res.end();
87
+ });
88
+ /*
89
+ ! Chỉ Dành Cho Mấy Pro Chạy Laptop Hoặc PC Thôi =))
90
+ */
91
+ dashboard.listen(1000);
92
+
93
+ topics.forEach(topicsub => mqttClient.subscribe(topicsub));
94
+
95
+ var topic;
96
+ var queue = {
97
+ sync_api_version: 11,
98
+ max_deltas_able_to_process: 100,
99
+ delta_batch_size: 500,
100
+ encoding: "JSON",
101
+ entity_fbid: ctx.userID,
102
+ };
103
+
104
+ if (ctx.syncToken) {
105
+ topic = "/messenger_sync_get_diffs";
106
+ queue.last_seq_id = ctx.lastSeqId;
107
+ queue.sync_token = ctx.syncToken;
108
+ } else {
109
+ topic = "/messenger_sync_create_queue";
110
+ queue.initial_titan_sequence_id = ctx.lastSeqId;
111
+ queue.device_params = null;
112
+ }
113
+
114
+ mqttClient.publish(topic, JSON.stringify(queue), { qos: 1, retain: false });
115
+
116
+ var rTimeout = setTimeout(function () {
117
+ mqttClient.end();
118
+ getSeqID();
119
+ }, 3000);
120
+
121
+ ctx.tmsWait = function () {
122
+ clearTimeout(rTimeout);
123
+ ctx.globalOptions.emitReady ? globalCallback({type: "ready",error: null}) : '';
124
+ delete ctx.tmsWait;
125
+ };
126
+ });
127
+
128
+ mqttClient.on('message', function (topic, message, _packet) {
129
+ let jsonMessage = Buffer.from(message).toString('utf-8');
130
+ try { jsonMessage = JSON.parse(jsonMessage); }
131
+ catch (e) { jsonMessage = {}; }
132
+ if (topic === "/t_ms") {
133
+ if (ctx.tmsWait && typeof ctx.tmsWait == "function") ctx.tmsWait();
134
+
135
+ if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
136
+ ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
137
+ ctx.syncToken = jsonMessage.syncToken;
138
+ }
139
+
140
+ if (jsonMessage.lastIssuedSeqId) ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
141
+
142
+ //If it contains more than 1 delta
143
+ for (var i in jsonMessage.deltas) {
144
+ var delta = jsonMessage.deltas[i];
145
+ parseDelta(defaultFuncs, api, ctx, globalCallback, { "delta": delta });
146
+ }
147
+ } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
148
+ var typ = {
149
+ type: "typ",
150
+ isTyping: !!jsonMessage.state,
151
+ from: jsonMessage.sender_fbid.toString(),
152
+ threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
153
+ };
154
+ (function () { globalCallback(null, typ); })();
155
+ } else if (topic === "/orca_presence") {
156
+ if (!ctx.globalOptions.updatePresence) {
157
+ for (var i in jsonMessage.list) {
158
+ var data = jsonMessage.list[i];
159
+ var userID = data["u"];
160
+
161
+ var presence = {
162
+ type: "presence",
163
+ userID: userID.toString(),
164
+ //Convert to ms
165
+ timestamp: data["l"] * 1000,
166
+ statuses: data["p"]
167
+ };
168
+ (function () { globalCallback(null, presence); })();
169
+ }
170
+ }
171
+ }
172
+
173
+ });
174
+
175
+ mqttClient.on('close', function () {
176
+ //(function () { globalCallback("Connection closed."); })();
177
+ });
178
+ }
179
+
180
+ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
181
+ if (v.delta.class == "NewMessage") {
182
+ //Not tested for pages
183
+ if (ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue) return;
184
+
185
+ (function resolveAttachmentUrl(i) {
186
+ if (v.delta.attachments && (i == v.delta.attachments.length)) {
187
+ var fmtMsg;
188
+ try {
189
+ fmtMsg = utils.formatDeltaMessage(v);
190
+ } catch (err) {
191
+ return globalCallback({
192
+ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
193
+ detail: err,
194
+ res: v,
195
+ type: "parse_error"
196
+ });
197
+ }
198
+ if (fmtMsg)
199
+ if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
200
+
201
+ return !ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID ? undefined : (function () { globalCallback(null, fmtMsg); })();
202
+ } else {
203
+ if (v.delta.attachments && (v.delta.attachments[i].mercury.attach_type == "photo")) {
204
+ api.resolvePhotoUrl(v.delta.attachments[i].fbid, (err, url) => {
205
+ if (!err) v.delta.attachments[i].mercury.metadata.url = url;
206
+ return resolveAttachmentUrl(i + 1);
207
+ });
208
+ } else return resolveAttachmentUrl(i + 1);
209
+ }
210
+ })(0);
211
+ }
212
+
213
+ if (v.delta.class == "ClientPayload") {
214
+ var clientPayload = utils.decodeClientPayload(v.delta.payload);
215
+ if (clientPayload && clientPayload.deltas) {
216
+ for (var i in clientPayload.deltas) {
217
+ var delta = clientPayload.deltas[i];
218
+ if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
219
+ (function () {
220
+ globalCallback(null, {
221
+ type: "message_reaction",
222
+ threadID: (delta.deltaMessageReaction.threadKey.threadFbId ? delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey.otherUserFbId).toString(),
223
+ messageID: delta.deltaMessageReaction.messageId,
224
+ reaction: delta.deltaMessageReaction.reaction,
225
+ senderID: delta.deltaMessageReaction.senderId.toString(),
226
+ userID: delta.deltaMessageReaction.userId.toString()
227
+ });
228
+ })();
229
+ } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
230
+ (function () {
231
+ globalCallback(null, {
232
+ type: "message_unsend",
233
+ threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ? delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
234
+ messageID: delta.deltaRecallMessageData.messageID,
235
+ senderID: delta.deltaRecallMessageData.senderID.toString(),
236
+ deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
237
+ timestamp: delta.deltaRecallMessageData.timestamp
238
+ });
239
+ })();
240
+ } else if (delta.deltaMessageReply) {
241
+ //Mention block - #1
242
+ var mdata =
243
+ delta.deltaMessageReply.message === undefined ? [] :
244
+ delta.deltaMessageReply.message.data === undefined ? [] :
245
+ delta.deltaMessageReply.message.data.prng === undefined ? [] :
246
+ JSON.parse(delta.deltaMessageReply.message.data.prng);
247
+ var m_id = mdata.map(u => u.i);
248
+ var m_offset = mdata.map(u => u.o);
249
+ var m_length = mdata.map(u => u.l);
250
+
251
+ var mentions = {};
252
+
253
+ for (var i = 0; i < m_id.length; i++) mentions[m_id[i]] = (delta.deltaMessageReply.message.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
254
+ //Mention block - 1#
255
+ var callbackToReturn = {
256
+ type: "message_reply",
257
+ threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey.otherUserFbId).toString(),
258
+ messageID: delta.deltaMessageReply.message.messageMetadata.messageId,
259
+ senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
260
+ attachments: delta.deltaMessageReply.message.attachments.map(function (att) {
261
+ var mercury = JSON.parse(att.mercuryJSON);
262
+ Object.assign(att, mercury);
263
+ return att;
264
+ }).map(att => {
265
+ var x;
266
+ try {
267
+ x = utils._formatAttachment(att);
268
+ } catch (ex) {
269
+ x = att;
270
+ x.error = ex;
271
+ x.type = "unknown";
272
+ }
273
+ return x;
274
+ }),
275
+ args: (delta.deltaMessageReply.message.body || "").trim().split(/\s+/),
276
+ body: (delta.deltaMessageReply.message.body || ""),
277
+ isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
278
+ mentions: mentions,
279
+ timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
280
+ participantIDs: (delta.deltaMessageReply.message.participants || []).map(e => e.toString())
281
+ };
282
+
283
+ if (delta.deltaMessageReply.repliedToMessage) {
284
+ //Mention block - #2
285
+ mdata =
286
+ delta.deltaMessageReply.repliedToMessage === undefined ? [] :
287
+ delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
288
+ delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
289
+ JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
290
+ m_id = mdata.map(u => u.i);
291
+ m_offset = mdata.map(u => u.o);
292
+ m_length = mdata.map(u => u.l);
293
+
294
+ var rmentions = {};
295
+
296
+ for (var i = 0; i < m_id.length; i++) rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
297
+ //Mention block - 2#
298
+ callbackToReturn.messageReply = {
299
+ threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.otherUserFbId).toString(),
300
+ messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
301
+ senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
302
+ attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) {
303
+ var mercury = JSON.parse(att.mercuryJSON);
304
+ Object.assign(att, mercury);
305
+ return att;
306
+ }).map(att => {
307
+ var x;
308
+ try {
309
+ x = utils._formatAttachment(att);
310
+ } catch (ex) {
311
+ x = att;
312
+ x.error = ex;
313
+ x.type = "unknown";
314
+ }
315
+ return x;
316
+ }),
317
+ args: (delta.deltaMessageReply.repliedToMessage.body || "").trim().split(/\s+/),
318
+ body: delta.deltaMessageReply.repliedToMessage.body || "",
319
+ isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId,
320
+ mentions: rmentions,
321
+ timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp,
322
+ participantIDs: (delta.deltaMessageReply.repliedToMessage.participants || []).map(e => e.toString())
323
+ };
324
+ } else if (delta.deltaMessageReply.replyToMessageId) {
325
+ return defaultFuncs
326
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
327
+ "av": ctx.globalOptions.pageID,
328
+ "queries": JSON.stringify({
329
+ "o0": {
330
+ //Using the same doc_id as forcedFetch
331
+ "doc_id": "2848441488556444",
332
+ "query_params": {
333
+ "thread_and_message_id": {
334
+ "thread_id": callbackToReturn.threadID,
335
+ "message_id": delta.deltaMessageReply.replyToMessageId.id,
336
+ }
337
+ }
338
+ }
339
+ })
340
+ })
341
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
342
+ .then((resData) => {
343
+ if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
344
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
345
+ var fetchData = resData[0].o0.data.message;
346
+ var mobj = {};
347
+ for (var n in fetchData.message.ranges) mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
348
+
349
+ callbackToReturn.messageReply = {
350
+ threadID: callbackToReturn.threadID,
351
+ messageID: fetchData.message_id,
352
+ senderID: fetchData.message_sender.id.toString(),
353
+ attachments: fetchData.message.blob_attachment.map(att => {
354
+ var x;
355
+ try {
356
+ x = utils._formatAttachment({ blob_attachment: att });
357
+ } catch (ex) {
358
+ x = att;
359
+ x.error = ex;
360
+ x.type = "unknown";
361
+ }
362
+ return x;
363
+ }),
364
+ args: (fetchData.message.text || "").trim().split(/\s+/) || [],
365
+ body: fetchData.message.text || "",
366
+ isGroup: callbackToReturn.isGroup,
367
+ mentions: mobj,
368
+ timestamp: parseInt(fetchData.timestamp_precise)
369
+ };
370
+ })
371
+ .catch(err => log.error("forcedFetch", err))
372
+ .finally(function () {
373
+ if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
374
+ !ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
375
+ });
376
+ } else callbackToReturn.delta = delta;
377
+
378
+ if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
379
+
380
+ return !ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
381
+ }
382
+ }
383
+ return;
384
+ }
385
+ }
386
+
387
+ if (v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents) return;
388
+ switch (v.delta.class) {
389
+ case "ReadReceipt":
390
+ var fmtMsg;
391
+ try {
392
+ fmtMsg = utils.formatDeltaReadReceipt(v.delta);
393
+ } catch (err) {
394
+ return globalCallback({
395
+ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
396
+ detail: err,
397
+ res: v.delta,
398
+ type: "parse_error"
399
+ });
400
+ }
401
+ return (function () { globalCallback(null, fmtMsg); })();
402
+ case "AdminTextMessage":
403
+ switch (v.delta.type) {
404
+ case "change_thread_theme":
405
+ case "change_thread_icon":
406
+ case "change_thread_nickname":
407
+ case "change_thread_admins":
408
+ case "change_thread_approval_mode":
409
+ case "group_poll":
410
+ case "messenger_call_log":
411
+ case "participant_joined_group_call":
412
+ var fmtMsg;
413
+ try {
414
+ fmtMsg = utils.formatDeltaEvent(v.delta);
415
+ } catch (err) {
416
+ return globalCallback({
417
+ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
418
+ detail: err,
419
+ res: v.delta,
420
+ type: "parse_error"
421
+ });
422
+ }
423
+ return (function () { globalCallback(null, fmtMsg); })();
424
+ default:
425
+ return;
426
+ }
427
+ break;
428
+ //For group images
429
+ case "ForcedFetch":
430
+ if (!v.delta.threadKey) return;
431
+ var mid = v.delta.messageId;
432
+ var tid = v.delta.threadKey.threadFbId;
433
+ if (mid && tid) {
434
+ const form = {
435
+ "av": ctx.globalOptions.pageID,
436
+ "queries": JSON.stringify({
437
+ "o0": {
438
+ //This doc_id is valid as of March 25, 2020
439
+ "doc_id": "2848441488556444",
440
+ "query_params": {
441
+ "thread_and_message_id": {
442
+ "thread_id": tid.toString(),
443
+ "message_id": mid,
444
+ }
445
+ }
446
+ }
447
+ })
448
+ };
449
+
450
+ defaultFuncs
451
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
452
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
453
+ .then((resData) => {
454
+ if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
455
+
456
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
457
+
458
+ var fetchData = resData[0].o0.data.message;
459
+
460
+ if (utils.getType(fetchData) == "Object") {
461
+ log.info("forcedFetch", fetchData);
462
+ switch (fetchData.__typename) {
463
+ case "ThreadImageMessage":
464
+ (!ctx.globalOptions.selfListen &&
465
+ fetchData.message_sender.id.toString() === ctx.userID) ||
466
+ !ctx.loggedIn ?
467
+ undefined :
468
+ (function () {
469
+ globalCallback(null, {
470
+ type: "change_thread_image",
471
+ threadID: utils.formatID(tid.toString()),
472
+ snippet: fetchData.snippet,
473
+ timestamp: fetchData.timestamp_precise,
474
+ author: fetchData.message_sender.id,
475
+ image: {
476
+ attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
477
+ width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
478
+ height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
479
+ url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
480
+ }
481
+ });
482
+ })();
483
+ break;
484
+ case "UserMessage":
485
+ log.info("ff-Return", {
486
+ type: "message",
487
+ senderID: utils.formatID(fetchData.message_sender.id),
488
+ body: fetchData.message.text || "",
489
+ threadID: utils.formatID(tid.toString()),
490
+ messageID: fetchData.message_id,
491
+ attachments: [{
492
+ type: "share",
493
+ ID: fetchData.extensible_attachment.legacy_attachment_id,
494
+ url: fetchData.extensible_attachment.story_attachment.url,
495
+
496
+ title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
497
+ description: fetchData.extensible_attachment.story_attachment.description.text,
498
+ source: fetchData.extensible_attachment.story_attachment.source,
499
+
500
+ image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
501
+ width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
502
+ height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
503
+ playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
504
+ duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
505
+
506
+ subattachments: fetchData.extensible_attachment.subattachments,
507
+ properties: fetchData.extensible_attachment.story_attachment.properties,
508
+ }],
509
+ mentions: {},
510
+ timestamp: parseInt(fetchData.timestamp_precise),
511
+ isGroup: (fetchData.message_sender.id != tid.toString())
512
+ });
513
+ globalCallback(null, {
514
+ type: "message",
515
+ senderID: utils.formatID(fetchData.message_sender.id),
516
+ body: fetchData.message.text || "",
517
+ threadID: utils.formatID(tid.toString()),
518
+ messageID: fetchData.message_id,
519
+ attachments: [{
520
+ type: "share",
521
+ ID: fetchData.extensible_attachment.legacy_attachment_id,
522
+ url: fetchData.extensible_attachment.story_attachment.url,
523
+
524
+ title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
525
+ description: fetchData.extensible_attachment.story_attachment.description.text,
526
+ source: fetchData.extensible_attachment.story_attachment.source,
527
+
528
+ image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
529
+ width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
530
+ height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
531
+ playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
532
+ duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
533
+
534
+ subattachments: fetchData.extensible_attachment.subattachments,
535
+ properties: fetchData.extensible_attachment.story_attachment.properties,
536
+ }],
537
+ mentions: {},
538
+ timestamp: parseInt(fetchData.timestamp_precise),
539
+ isGroup: (fetchData.message_sender.id != tid.toString())
540
+ });
541
+ }
542
+ } else log.error("forcedFetch", fetchData);
543
+ })
544
+ .catch((err) => log.error("forcedFetch", err));
545
+ }
546
+ break;
547
+ case "ThreadName":
548
+ case "ParticipantsAddedToGroupThread":
549
+ case "ParticipantLeftGroupThread":
550
+ var formattedEvent;
551
+ try {
552
+ formattedEvent = utils.formatDeltaEvent(v.delta);
553
+ } catch (err) {
554
+ return globalCallback({
555
+ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
556
+ detail: err,
557
+ res: v.delta,
558
+ type: "parse_error"
559
+ });
560
+ }
561
+ return (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) || !ctx.loggedIn ? undefined : (function () { globalCallback(null, formattedEvent); })();
562
+ }
563
+ }
564
+
565
+ function markDelivery(ctx, api, threadID, messageID) {
566
+ if (threadID && messageID) {
567
+ api.markAsDelivered(threadID, messageID, (err) => {
568
+ if (err) log.error("markAsDelivered", err);
569
+ else {
570
+ if (ctx.globalOptions.autoMarkRead) {
571
+ api.markAsRead(threadID, (err) => {
572
+ if (err) log.error("markAsDelivered", err);
573
+ });
574
+ }
575
+ }
576
+ });
577
+ }
578
+ }
579
+
580
+ module.exports = function (defaultFuncs, api, ctx) {
581
+ var globalCallback = identity;
582
+ getSeqID = function getSeqID() {
583
+ ctx.t_mqttCalled = false;
584
+ defaultFuncs
585
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
586
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
587
+ .then((resData) => {
588
+ if (utils.getType(resData) != "Array") throw { error: "Chưa Đăng Nhập Được - Appstate Đã Bị Lỗi", res: resData };
589
+ if (resData && resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
590
+ if (resData[resData.length - 1].successful_results === 0) throw { error: "getSeqId: there was no successful_results", res: resData };
591
+ if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) {
592
+ ctx.lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id;
593
+ listenMqtt(defaultFuncs, api, ctx, globalCallback);
594
+ } else throw { error: "getSeqId: no sync_sequence_id found.", res: resData };
595
+ })
596
+ .catch((err) => {
597
+ log.error("getSeqId", err);
598
+ if (utils.getType(err) == "Object" && err.error === "Chưa Đăng Nhập Được - Appstate Đã Bị Lỗi") ctx.loggedIn = false;
599
+ return globalCallback(err);
600
+ });
601
+ };
602
+
603
+ return async function (callback) {
604
+ class MessageEmitter extends EventEmitter {
605
+ stopListening(callback) {
606
+ callback = callback || (() => { });
607
+ globalCallback = identity;
608
+ if (ctx.mqttClient) {
609
+ ctx.mqttClient.unsubscribe("/webrtc");
610
+ ctx.mqttClient.unsubscribe("/rtc_multi");
611
+ ctx.mqttClient.unsubscribe("/onevc");
612
+ ctx.mqttClient.publish("/browser_close", "{}");
613
+ ctx.mqttClient.end(false, function (...data) {
614
+ callback(data);
615
+ ctx.mqttClient = undefined;
616
+ });
617
+ }
618
+ }
619
+ }
620
+
621
+ var msgEmitter = new MessageEmitter();
622
+ globalCallback = (callback || function (error, message) {
623
+ if (error) return msgEmitter.emit("error", error);
624
+ msgEmitter.emit("message", message);
625
+ });
626
+
627
+ //Reset some stuff
628
+ if (!ctx.firstListen) ctx.lastSeqId = null;
629
+ ctx.syncToken = undefined;
630
+ ctx.t_mqttCalled = false;
631
+
632
+ //Same request as getThreadList
633
+ form = {
634
+ "av": ctx.globalOptions.pageID,
635
+ "queries": JSON.stringify({
636
+ "o0": {
637
+ "doc_id": "3336396659757871",
638
+ "query_params": {
639
+ "limit": 1,
640
+ "before": null,
641
+ "tags": ["INBOX"],
642
+ "includeDeliveryReceipts": false,
643
+ "includeSeqID": true
644
+ }
645
+ }
646
+ })
647
+ };
648
+
649
+ if (!ctx.firstListen || !ctx.lastSeqId) getSeqID();
650
+ else listenMqtt(defaultFuncs, api, ctx, globalCallback);
651
+ ctx.firstListen = false;
652
+ return msgEmitter;
653
+ };
654
+ };