ws-rapido 1.0.0

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