alicezetion 1.9.2 → 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. package/package.json +1 -1
  2. package/src/addExternalModule.js +19 -0
  3. package/src/addUserToGroup.js +113 -0
  4. package/src/changeAdminStatus.js +79 -0
  5. package/src/changeArchivedStatus.js +55 -0
  6. package/{leiamnash → src}/changeAvatar.js +2 -3
  7. package/src/changeBio.js +77 -0
  8. package/src/changeBlockedStatus.js +47 -0
  9. package/src/changeGroupImage.js +132 -0
  10. package/src/changeNickname.js +59 -0
  11. package/src/changeThreadColor.js +65 -0
  12. package/src/changeThreadEmoji.js +55 -0
  13. package/{leiamnash → src}/chat.js +29 -4
  14. package/src/createNewGroup.js +86 -0
  15. package/src/createPoll.js +71 -0
  16. package/src/deleteMessage.js +56 -0
  17. package/src/deleteThread.js +56 -0
  18. package/src/edit.js +66 -0
  19. package/src/forwardAttachment.js +60 -0
  20. package/src/getCurrentUserID.js +7 -0
  21. package/src/getEmojiUrl.js +29 -0
  22. package/src/getFriendsList.js +83 -0
  23. package/src/getThreadHistory.js +666 -0
  24. package/src/getThreadInfo.js +232 -0
  25. package/src/getThreadList.js +241 -0
  26. package/src/getThreadPictures.js +79 -0
  27. package/src/getUserID.js +66 -0
  28. package/src/getUserInfo.js +74 -0
  29. package/src/handleFriendRequest.js +61 -0
  30. package/src/handleMessageRequest.js +65 -0
  31. package/src/httpGet.js +57 -0
  32. package/src/httpPost.js +57 -0
  33. package/src/httpPostFormData.js +63 -0
  34. package/src/listenMqtt.js +853 -0
  35. package/src/logout.js +75 -0
  36. package/src/markAsDelivered.js +58 -0
  37. package/src/markAsRead.js +80 -0
  38. package/src/markAsReadAll.js +50 -0
  39. package/src/markAsSeen.js +59 -0
  40. package/src/muteThread.js +52 -0
  41. package/src/react.js +109 -0
  42. package/{leiamnash → src}/refreshFb_dtsg.js +1 -1
  43. package/src/removeUserFromGroup.js +79 -0
  44. package/src/resolvePhotoUrl.js +45 -0
  45. package/src/searchForThread.js +53 -0
  46. package/src/seen.js +50 -0
  47. package/src/sendMessage.js +477 -0
  48. package/src/sendTypingIndicator.js +103 -0
  49. package/src/setMessageReaction.js +121 -0
  50. package/src/setPostReaction.js +109 -0
  51. package/src/setTitle.js +86 -0
  52. package/src/threadColors.js +131 -0
  53. package/src/unfriend.js +52 -0
  54. package/src/unsendMessage.js +49 -0
  55. package/{leiamnash → src}/uploadAttachment.js +1 -2
  56. package/leiamnash/addExternalModule.js +0 -15
  57. package/leiamnash/addUserToGroup.js +0 -77
  58. package/leiamnash/changeAdminStatus.js +0 -47
  59. package/leiamnash/changeArchivedStatus.js +0 -41
  60. package/leiamnash/changeBio.js +0 -64
  61. package/leiamnash/changeBlockedStatus.js +0 -36
  62. package/leiamnash/changeGroupImage.js +0 -105
  63. package/leiamnash/changeNickname.js +0 -43
  64. package/leiamnash/changeThreadColor.js +0 -61
  65. package/leiamnash/changeThreadEmoji.js +0 -41
  66. package/leiamnash/createNewGroup.js +0 -70
  67. package/leiamnash/createPoll.js +0 -59
  68. package/leiamnash/deleteMessage.js +0 -44
  69. package/leiamnash/deleteThread.js +0 -42
  70. package/leiamnash/edit.js +0 -59
  71. package/leiamnash/forwardAttachment.js +0 -47
  72. package/leiamnash/forwardMessage.js +0 -0
  73. package/leiamnash/getCurrentUserID.js +0 -7
  74. package/leiamnash/getEmojiUrl.js +0 -27
  75. package/leiamnash/getFriendsList.js +0 -73
  76. package/leiamnash/getInfoVideo.js +0 -134
  77. package/leiamnash/getThreadHistory.js +0 -537
  78. package/leiamnash/getThreadHistoryDeprecated.js +0 -71
  79. package/leiamnash/getThreadInfo.js +0 -171
  80. package/leiamnash/getThreadInfoDeprecated.js +0 -56
  81. package/leiamnash/getThreadList.js +0 -213
  82. package/leiamnash/getThreadListDeprecated.js +0 -46
  83. package/leiamnash/getThreadPictures.js +0 -59
  84. package/leiamnash/getUserID.js +0 -61
  85. package/leiamnash/getUserInfo.js +0 -66
  86. package/leiamnash/handleFriendRequest.js +0 -46
  87. package/leiamnash/handleMessageRequest.js +0 -47
  88. package/leiamnash/httpGet.js +0 -47
  89. package/leiamnash/httpPost.js +0 -47
  90. package/leiamnash/httpPostFormData.js +0 -42
  91. package/leiamnash/listenMqtt.js +0 -853
  92. package/leiamnash/logout.js +0 -68
  93. package/leiamnash/markAsDelivered.js +0 -47
  94. package/leiamnash/markAsRead.js +0 -70
  95. package/leiamnash/markAsReadAll.js +0 -40
  96. package/leiamnash/markAsSeen.js +0 -48
  97. package/leiamnash/muteThread.js +0 -45
  98. package/leiamnash/react.js +0 -109
  99. package/leiamnash/removeUserFromGroup.js +0 -45
  100. package/leiamnash/resolvePhotoUrl.js +0 -36
  101. package/leiamnash/searchForThread.js +0 -42
  102. package/leiamnash/seen.js +0 -40
  103. package/leiamnash/sendMessage.js +0 -315
  104. package/leiamnash/sendTypingIndicator.js +0 -70
  105. package/leiamnash/setMessageReaction.js +0 -103
  106. package/leiamnash/setPostReaction.js +0 -63
  107. package/leiamnash/setTitle.js +0 -70
  108. package/leiamnash/threadColors.js +0 -41
  109. package/leiamnash/unfriend.js +0 -42
  110. package/leiamnash/unsendMessage.js +0 -39
  111. /package/{leiamnash → src}/getMessage.js +0 -0
@@ -1,853 +0,0 @@
1
- /* eslint-disable no-redeclare */
2
- "use strict";
3
- const utils = require("../utils");
4
- const log = require("npmlog");
5
- const mqtt = require('mqtt');
6
- const websocket = require('websocket-stream');
7
- const HttpsProxyAgent = require('https-proxy-agent');
8
- const EventEmitter = require('events');
9
-
10
- const identity = function () { };
11
-
12
- const 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
-
28
- "/legacy_web_mtouch"
29
- // "/inbox",
30
- // "/mercury",
31
- // "/messaging_events",
32
- // "/orca_message_notifications",
33
- // "/pp",
34
- // "/webrtc_response",
35
- ];
36
-
37
- function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
38
- //Don't really know what this does but I think it's for the active state?
39
- //TODO: Move to ctx when implemented
40
- const chatOn = ctx.globalOptions.online;
41
- const foreground = false;
42
-
43
- const sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
44
- const username = {
45
- u: ctx.i_userID || ctx.userID,
46
- s: sessionID,
47
- chat_on: chatOn,
48
- fg: foreground,
49
- d: utils.getGUID(),
50
- ct: "websocket",
51
- //App id from facebook
52
- aid: "219994525426954",
53
- mqtt_sid: "",
54
- cp: 3,
55
- ecp: 10,
56
- st: [],
57
- pm: [],
58
- dc: "",
59
- no_auto_fg: true,
60
- gas: null,
61
- pack: [],
62
- a: ctx.globalOptions.userAgent,
63
- aids: null
64
- };
65
- const cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
66
-
67
- let host;
68
- if (ctx.mqttEndpoint) {
69
- host = `${ctx.mqttEndpoint}&sid=${sessionID}`;
70
- } else if (ctx.region) {
71
- host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLocaleLowerCase()}&sid=${sessionID}`;
72
- } else {
73
- host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}`;
74
- }
75
-
76
- const options = {
77
- clientId: "mqttwsclient",
78
- protocolId: 'MQIsdp',
79
- protocolVersion: 3,
80
- username: JSON.stringify(username),
81
- clean: true,
82
- wsOptions: {
83
- headers: {
84
- 'Cookie': cookies,
85
- 'Origin': 'https://www.facebook.com',
86
- 'User-Agent': ctx.globalOptions.userAgent,
87
- 'Referer': 'https://www.facebook.com/',
88
- 'Host': new URL(host).hostname //'edge-chat.facebook.com'
89
- },
90
- origin: 'https://www.facebook.com',
91
- protocolVersion: 13
92
- },
93
- keepalive: 10,
94
- reschedulePings: false
95
- };
96
-
97
- if (typeof ctx.globalOptions.proxy != "undefined") {
98
- const agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
99
- options.wsOptions.agent = agent;
100
- }
101
-
102
- ctx.mqttClient = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
103
-
104
- const mqttClient = ctx.mqttClient;
105
-
106
- mqttClient.on('error', function (err) {
107
- log.error("listenMqtt", err);
108
- mqttClient.end();
109
- if (ctx.globalOptions.autoReconnect) {
110
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
111
- } else {
112
- utils.checkLiveCookie(ctx, defaultFuncs)
113
- .then(res => {
114
- globalCallback({
115
- type: "stop_listen",
116
- error: "Connection refused: Server unavailable"
117
- }, null);
118
- })
119
- .catch(err => {
120
- globalCallback({
121
- type: "account_inactive",
122
- error: "Maybe your account is blocked by facebook, please login and check at https://facebook.com"
123
- }, null);
124
- });
125
- }
126
- });
127
-
128
- mqttClient.on('close', function () {
129
-
130
- });
131
-
132
- mqttClient.on('connect', function () {
133
- topics.forEach(function (topicsub) {
134
- mqttClient.subscribe(topicsub);
135
- });
136
-
137
- let topic;
138
- const queue = {
139
- sync_api_version: 10,
140
- max_deltas_able_to_process: 1000,
141
- delta_batch_size: 500,
142
- encoding: "JSON",
143
- entity_fbid: ctx.i_userID || ctx.userID
144
- };
145
-
146
- if (ctx.syncToken) {
147
- topic = "/messenger_sync_get_diffs";
148
- queue.last_seq_id = ctx.lastSeqId;
149
- queue.sync_token = ctx.syncToken;
150
- } else {
151
- topic = "/messenger_sync_create_queue";
152
- queue.initial_titan_sequence_id = ctx.lastSeqId;
153
- queue.device_params = null;
154
- }
155
-
156
- mqttClient.publish(topic, JSON.stringify(queue), { qos: 1, retain: false });
157
- // set status online
158
- // fix by NTKhang
159
- mqttClient.publish("/foreground_state", JSON.stringify({ foreground: chatOn }), { qos: 1 });
160
- mqttClient.publish("/set_client_settings", JSON.stringify({ make_user_available_when_in_foreground: true }), { qos: 1 });
161
-
162
- const rTimeout = setTimeout(function () {
163
- mqttClient.end();
164
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
165
- }, 5000);
166
-
167
- ctx.tmsWait = function () {
168
- clearTimeout(rTimeout);
169
- ctx.globalOptions.emitReady ? globalCallback({
170
- type: "ready",
171
- error: null
172
- }) : "";
173
- delete ctx.tmsWait;
174
- };
175
-
176
- });
177
-
178
- mqttClient.on('message', function (topic, message, _packet) {
179
- let jsonMessage = Buffer.isBuffer(message) ? Buffer.from(message).toString() : message;
180
- try {
181
- jsonMessage = JSON.parse(jsonMessage);
182
- }
183
- catch (e) {
184
- jsonMessage = {};
185
- }
186
-
187
- if (jsonMessage.type === "jewel_requests_add") {
188
- globalCallback(null, {
189
- type: "friend_request_received",
190
- actorFbId: jsonMessage.from.toString(),
191
- timestamp: Date.now().toString()
192
- });
193
- }
194
- else if (jsonMessage.type === "jewel_requests_remove_old") {
195
- globalCallback(null, {
196
- type: "friend_request_cancel",
197
- actorFbId: jsonMessage.from.toString(),
198
- timestamp: Date.now().toString()
199
- });
200
- }
201
- else if (topic === "/t_ms") {
202
- if (ctx.tmsWait && typeof ctx.tmsWait == "function") {
203
- ctx.tmsWait();
204
- }
205
-
206
- if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
207
- ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
208
- ctx.syncToken = jsonMessage.syncToken;
209
- }
210
-
211
- if (jsonMessage.lastIssuedSeqId) {
212
- ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
213
- }
214
-
215
- //If it contains more than 1 delta
216
- for (const i in jsonMessage.deltas) {
217
- const delta = jsonMessage.deltas[i];
218
- parseDelta(defaultFuncs, api, ctx, globalCallback, { "delta": delta });
219
- }
220
- } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
221
- const typ = {
222
- type: "typ",
223
- isTyping: !!jsonMessage.state,
224
- from: jsonMessage.sender_fbid.toString(),
225
- threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
226
- };
227
- (function () { globalCallback(null, typ); })();
228
- } else if (topic === "/orca_presence") {
229
- if (!ctx.globalOptions.updatePresence) {
230
- for (const i in jsonMessage.list) {
231
- const data = jsonMessage.list[i];
232
- const userID = data["u"];
233
-
234
- const presence = {
235
- type: "presence",
236
- userID: userID.toString(),
237
- //Convert to ms
238
- timestamp: data["l"] * 1000,
239
- statuses: data["p"]
240
- };
241
- (function () { globalCallback(null, presence); })();
242
- }
243
- }
244
- }
245
-
246
- });
247
-
248
- }
249
-
250
- function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
251
- if (v.delta.class == "NewMessage") {
252
- //Not tested for pages
253
- if (ctx.globalOptions.pageID &&
254
- ctx.globalOptions.pageID != v.queue
255
- )
256
- return;
257
-
258
- (function resolveAttachmentUrl(i) {
259
- if (i == (v.delta.attachments || []).length) {
260
- let fmtMsg;
261
- try {
262
- fmtMsg = utils.formatDeltaMessage(v);
263
- } catch (err) {
264
- return globalCallback({
265
- error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
266
- detail: err,
267
- res: v,
268
- type: "parse_error"
269
- });
270
- }
271
- if (fmtMsg) {
272
- if (ctx.globalOptions.autoMarkDelivery) {
273
- markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
274
- }
275
- }
276
- return !ctx.globalOptions.selfListen &&
277
- (fmtMsg.senderID === ctx.i_userID || fmtMsg.senderID === ctx.userID) ?
278
- undefined :
279
- (function () { globalCallback(null, fmtMsg); })();
280
- } else {
281
- if (v.delta.attachments[i].mercury.attach_type == "photo") {
282
- api.resolvePhotoUrl(
283
- v.delta.attachments[i].fbid,
284
- (err, url) => {
285
- if (!err)
286
- v.delta.attachments[
287
- i
288
- ].mercury.metadata.url = url;
289
- return resolveAttachmentUrl(i + 1);
290
- }
291
- );
292
- } else {
293
- return resolveAttachmentUrl(i + 1);
294
- }
295
- }
296
- })(0);
297
- }
298
-
299
- if (v.delta.class == "ClientPayload") {
300
- const clientPayload = utils.decodeClientPayload(
301
- v.delta.payload
302
- );
303
-
304
- if (clientPayload && clientPayload.deltas) {
305
- for (const i in clientPayload.deltas) {
306
- const delta = clientPayload.deltas[i];
307
- if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
308
- (function () {
309
- globalCallback(null, {
310
- type: "message_reaction",
311
- threadID: (delta.deltaMessageReaction.threadKey
312
- .threadFbId ?
313
- delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey
314
- .otherUserFbId).toString(),
315
- messageID: delta.deltaMessageReaction.messageId,
316
- reaction: delta.deltaMessageReaction.reaction,
317
- senderID: delta.deltaMessageReaction.senderId == 0 ? delta.deltaMessageReaction.userId.toString() : delta.deltaMessageReaction.senderId.toString(),
318
- userID: (delta.deltaMessageReaction.userId || delta.deltaMessageReaction.senderId).toString()
319
- });
320
- })();
321
- } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
322
- (function () {
323
- globalCallback(null, {
324
- type: "message_unsend",
325
- threadID: (delta.deltaRecallMessageData.threadKey.threadFbId ?
326
- delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey
327
- .otherUserFbId).toString(),
328
- messageID: delta.deltaRecallMessageData.messageID,
329
- senderID: delta.deltaRecallMessageData.senderID.toString(),
330
- deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp,
331
- timestamp: delta.deltaRecallMessageData.timestamp
332
- });
333
- })();
334
- } else if (delta.deltaRemoveMessage && !!ctx.globalOptions.listenEvents) {
335
- (function () {
336
- globalCallback(null, {
337
- type: "message_self_delete",
338
- threadID: (delta.deltaRemoveMessage.threadKey.threadFbId ?
339
- delta.deltaRemoveMessage.threadKey.threadFbId : delta.deltaRemoveMessage.threadKey
340
- .otherUserFbId).toString(),
341
- messageID: delta.deltaRemoveMessage.messageIds.length == 1 ? delta.deltaRemoveMessage.messageIds[0] : delta.deltaRemoveMessage.messageIds,
342
- senderID: api.getCurrentUserID(),
343
- deletionTimestamp: delta.deltaRemoveMessage.deletionTimestamp,
344
- timestamp: delta.deltaRemoveMessage.timestamp
345
- });
346
- })();
347
- }
348
- else if (delta.deltaMessageReply) {
349
- //Mention block - #1
350
- let mdata =
351
- delta.deltaMessageReply.message === undefined ? [] :
352
- delta.deltaMessageReply.message.data === undefined ? [] :
353
- delta.deltaMessageReply.message.data.prng === undefined ? [] :
354
- JSON.parse(delta.deltaMessageReply.message.data.prng);
355
- let m_id = mdata.map(u => u.i);
356
- let m_offset = mdata.map(u => u.o);
357
- let m_length = mdata.map(u => u.l);
358
-
359
- const mentions = {};
360
-
361
- for (let i = 0; i < m_id.length; i++) {
362
- mentions[m_id[i]] = (delta.deltaMessageReply.message.body || "").substring(
363
- m_offset[i],
364
- m_offset[i] + m_length[i]
365
- );
366
- }
367
- //Mention block - 1#
368
- const callbackToReturn = {
369
- type: "message_reply",
370
- threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ?
371
- delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey
372
- .otherUserFbId).toString(),
373
- messageID: delta.deltaMessageReply.message.messageMetadata.messageId,
374
- senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
375
- attachments: (delta.deltaMessageReply.message.attachments || []).map(function (att) {
376
- const mercury = JSON.parse(att.mercuryJSON);
377
- Object.assign(att, mercury);
378
- return att;
379
- }).map(att => {
380
- let x;
381
- try {
382
- x = utils._formatAttachment(att);
383
- } catch (ex) {
384
- x = att;
385
- x.error = ex;
386
- x.type = "unknown";
387
- }
388
- return x;
389
- }),
390
- body: delta.deltaMessageReply.message.body || "",
391
- isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
392
- mentions: mentions,
393
- timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
394
- participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e => e.toString())
395
- };
396
-
397
- if (delta.deltaMessageReply.repliedToMessage) {
398
- //Mention block - #2
399
- mdata =
400
- delta.deltaMessageReply.repliedToMessage === undefined ? [] :
401
- delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
402
- delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
403
- JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
404
- m_id = mdata.map(u => u.i);
405
- m_offset = mdata.map(u => u.o);
406
- m_length = mdata.map(u => u.l);
407
-
408
- const rmentions = {};
409
-
410
- for (let i = 0; i < m_id.length; i++) {
411
- rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(
412
- m_offset[i],
413
- m_offset[i] + m_length[i]
414
- );
415
- }
416
- //Mention block - 2#
417
- callbackToReturn.messageReply = {
418
- threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ?
419
- delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey
420
- .otherUserFbId).toString(),
421
- messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
422
- senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId.toString(),
423
- attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) {
424
- const mercury = JSON.parse(att.mercuryJSON);
425
- Object.assign(att, mercury);
426
- return att;
427
- }).map(att => {
428
- let x;
429
- try {
430
- x = utils._formatAttachment(att);
431
- } catch (ex) {
432
- x = att;
433
- x.error = ex;
434
- x.type = "unknown";
435
- }
436
- return x;
437
- }),
438
- body: delta.deltaMessageReply.repliedToMessage.body || "",
439
- isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId,
440
- mentions: rmentions,
441
- timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp
442
- };
443
- } else if (delta.deltaMessageReply.replyToMessageId) {
444
- return defaultFuncs
445
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
446
- "av": ctx.globalOptions.pageID,
447
- "queries": JSON.stringify({
448
- "o0": {
449
- //Using the same doc_id as forcedFetch
450
- "doc_id": "2848441488556444",
451
- "query_params": {
452
- "thread_and_message_id": {
453
- "thread_id": callbackToReturn.threadID,
454
- "message_id": delta.deltaMessageReply.replyToMessageId.id
455
- }
456
- }
457
- }
458
- })
459
- })
460
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
461
- .then((resData) => {
462
- if (resData[resData.length - 1].error_results > 0) {
463
- throw resData[0].o0.errors;
464
- }
465
-
466
- if (resData[resData.length - 1].successful_results === 0) {
467
- throw { error: "forcedFetch: there was no successful_results", res: resData };
468
- }
469
-
470
- const fetchData = resData[0].o0.data.message;
471
-
472
- const mobj = {};
473
- for (const n in fetchData.message.ranges) {
474
- mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
475
- }
476
-
477
- callbackToReturn.messageReply = {
478
- threadID: callbackToReturn.threadID,
479
- messageID: fetchData.message_id,
480
- senderID: fetchData.message_sender.id.toString(),
481
- attachments: fetchData.message.blob_attachment.map(att => {
482
- let x;
483
- try {
484
- x = utils._formatAttachment({
485
- blob_attachment: att
486
- });
487
- } catch (ex) {
488
- x = att;
489
- x.error = ex;
490
- x.type = "unknown";
491
- }
492
- return x;
493
- }),
494
- body: fetchData.message.text || "",
495
- isGroup: callbackToReturn.isGroup,
496
- mentions: mobj,
497
- timestamp: parseInt(fetchData.timestamp_precise)
498
- };
499
- })
500
- .catch((err) => {
501
- log.error("forcedFetch", err);
502
- })
503
- .finally(function () {
504
- if (ctx.globalOptions.autoMarkDelivery) {
505
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
506
- }
507
- !ctx.globalOptions.selfListen &&
508
- (callbackToReturn.senderID === ctx.i_userID || callbackToReturn.senderID === ctx.userID) ?
509
- undefined :
510
- (function () { globalCallback(null, callbackToReturn); })();
511
- });
512
- } else {
513
- callbackToReturn.delta = delta;
514
- }
515
-
516
- if (ctx.globalOptions.autoMarkDelivery) {
517
- markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
518
- }
519
-
520
- return !ctx.globalOptions.selfListen &&
521
- (callbackToReturn.senderID === ctx.i_userID || callbackToReturn.senderID === ctx.userID) ?
522
- undefined :
523
- (function () { globalCallback(null, callbackToReturn); })();
524
- }
525
- }
526
- return;
527
- }
528
- }
529
-
530
- if (v.delta.class !== "NewMessage" &&
531
- !ctx.globalOptions.listenEvents
532
- )
533
- return;
534
-
535
- switch (v.delta.class) {
536
- case "ReadReceipt":
537
- var fmtMsg;
538
- try {
539
- fmtMsg = utils.formatDeltaReadReceipt(v.delta);
540
- }
541
- catch (err) {
542
- return globalCallback({
543
- error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
544
- detail: err,
545
- res: v.delta,
546
- type: "parse_error"
547
- });
548
- }
549
- return (function () { globalCallback(null, fmtMsg); })();
550
- case "AdminTextMessage":
551
- switch (v.delta.type) {
552
- case "change_thread_theme":
553
- case "change_thread_nickname":
554
- case "change_thread_icon":
555
- case "change_thread_quick_reaction":
556
- case "change_thread_admins":
557
- case "group_poll":
558
- case "joinable_group_link_mode_change":
559
- case "magic_words":
560
- case "change_thread_approval_mode":
561
- case "messenger_call_log":
562
- case "participant_joined_group_call":
563
- var fmtMsg;
564
- try {
565
- fmtMsg = utils.formatDeltaEvent(v.delta);
566
- }
567
- catch (err) {
568
- return globalCallback({
569
- error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
570
- detail: err,
571
- res: v.delta,
572
- type: "parse_error"
573
- });
574
- }
575
- return (function () { globalCallback(null, fmtMsg); })();
576
- default:
577
- return;
578
- }
579
- //For group images
580
- case "ForcedFetch":
581
- if (!v.delta.threadKey) return;
582
- var mid = v.delta.messageId;
583
- var tid = v.delta.threadKey.threadFbId;
584
- if (mid && tid) {
585
- const form = {
586
- "av": ctx.globalOptions.pageID,
587
- "queries": JSON.stringify({
588
- "o0": {
589
- //This doc_id is valid as of March 25, 2020
590
- "doc_id": "2848441488556444",
591
- "query_params": {
592
- "thread_and_message_id": {
593
- "thread_id": tid.toString(),
594
- "message_id": mid
595
- }
596
- }
597
- }
598
- })
599
- };
600
-
601
- defaultFuncs
602
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
603
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
604
- .then((resData) => {
605
- if (resData[resData.length - 1].error_results > 0) {
606
- throw resData[0].o0.errors;
607
- }
608
-
609
- if (resData[resData.length - 1].successful_results === 0) {
610
- throw { error: "forcedFetch: there was no successful_results", res: resData };
611
- }
612
-
613
- const fetchData = resData[0].o0.data.message;
614
-
615
- if (utils.getType(fetchData) == "Object") {
616
- log.info("forcedFetch", fetchData);
617
- switch (fetchData.__typename) {
618
- case "ThreadImageMessage":
619
- (!ctx.globalOptions.selfListenEvent && (fetchData.message_sender.id.toString() === ctx.i_userID || fetchData.message_sender.id.toString() === ctx.userID)) || !ctx.loggedIn ?
620
- undefined :
621
- (function () {
622
- globalCallback(null, {
623
- type: "event",
624
- threadID: utils.formatID(tid.toString()),
625
- messageID: fetchData.message_id,
626
- logMessageType: "log:thread-image",
627
- logMessageData: {
628
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
629
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
630
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
631
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
632
- },
633
- logMessageBody: fetchData.snippet,
634
- timestamp: fetchData.timestamp_precise,
635
- author: fetchData.message_sender.id
636
- });
637
- })();
638
- break;
639
- case "UserMessage":
640
- log.info("ff-Return", {
641
- type: "message",
642
- senderID: utils.formatID(fetchData.message_sender.id),
643
- body: fetchData.message.text || "",
644
- threadID: utils.formatID(tid.toString()),
645
- messageID: fetchData.message_id,
646
- attachments: [{
647
- type: "share",
648
- ID: fetchData.extensible_attachment.legacy_attachment_id,
649
- url: fetchData.extensible_attachment.story_attachment.url,
650
-
651
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
652
- description: fetchData.extensible_attachment.story_attachment.description.text,
653
- source: fetchData.extensible_attachment.story_attachment.source,
654
-
655
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
656
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
657
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
658
- playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
659
- duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
660
-
661
- subattachments: fetchData.extensible_attachment.subattachments,
662
- properties: fetchData.extensible_attachment.story_attachment.properties
663
- }],
664
- mentions: {},
665
- timestamp: parseInt(fetchData.timestamp_precise),
666
- participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
667
- isGroup: (fetchData.message_sender.id != tid.toString())
668
- });
669
- globalCallback(null, {
670
- type: "message",
671
- senderID: utils.formatID(fetchData.message_sender.id),
672
- body: fetchData.message.text || "",
673
- threadID: utils.formatID(tid.toString()),
674
- messageID: fetchData.message_id,
675
- attachments: [{
676
- type: "share",
677
- ID: fetchData.extensible_attachment.legacy_attachment_id,
678
- url: fetchData.extensible_attachment.story_attachment.url,
679
-
680
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
681
- description: fetchData.extensible_attachment.story_attachment.description.text,
682
- source: fetchData.extensible_attachment.story_attachment.source,
683
-
684
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
685
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
686
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
687
- playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
688
- duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
689
-
690
- subattachments: fetchData.extensible_attachment.subattachments,
691
- properties: fetchData.extensible_attachment.story_attachment.properties
692
- }],
693
- mentions: {},
694
- timestamp: parseInt(fetchData.timestamp_precise),
695
- participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
696
- isGroup: (fetchData.message_sender.id != tid.toString())
697
- });
698
- }
699
- } else {
700
- log.error("forcedFetch", fetchData);
701
- }
702
- })
703
- .catch((err) => {
704
- log.error("forcedFetch", err);
705
- });
706
- }
707
- break;
708
- case "ThreadName":
709
- case "ParticipantsAddedToGroupThread":
710
- case "ParticipantLeftGroupThread":
711
- case "ApprovalQueue":
712
- var formattedEvent;
713
- try {
714
- formattedEvent = utils.formatDeltaEvent(v.delta);
715
- } catch (err) {
716
- return globalCallback({
717
- error: "Problem parsing message object. Please open an issue at https://github.com/ntkhang03/fb-chat-api/issues.",
718
- detail: err,
719
- res: v.delta,
720
- type: "parse_error"
721
- });
722
- }
723
- return (!ctx.globalOptions.selfListenEvent && (formattedEvent.author.toString() === ctx.i_userID || formattedEvent.author.toString() === ctx.userID)) || !ctx.loggedIn ?
724
- undefined :
725
- (function () { globalCallback(null, formattedEvent); })();
726
- }
727
- }
728
-
729
- function markDelivery(ctx, api, threadID, messageID) {
730
- if (threadID && messageID) {
731
- api.markAsDelivered(threadID, messageID, (err) => {
732
- if (err) {
733
- log.error("markAsDelivered", err);
734
- } else {
735
- if (ctx.globalOptions.autoMarkRead) {
736
- api.markAsRead(threadID, (err) => {
737
- if (err) {
738
- log.error("markAsDelivered", err);
739
- }
740
- });
741
- }
742
- }
743
- });
744
- }
745
- }
746
-
747
- function getSeqId(defaultFuncs, api, ctx, globalCallback) {
748
- const jar = ctx.jar;
749
- utils
750
- .get('https://www.facebook.com/', jar, null, ctx.globalOptions, { noRef: true })
751
- .then(utils.saveCookies(jar))
752
- .then(function (resData) {
753
- const html = resData.body;
754
- const oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
755
- let mqttEndpoint = null;
756
- let region = null;
757
- let irisSeqID = null;
758
- let noMqttData = null;
759
-
760
- if (oldFBMQTTMatch) {
761
- irisSeqID = oldFBMQTTMatch[1];
762
- mqttEndpoint = oldFBMQTTMatch[2];
763
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
764
- log.info("login", `Got this account's message region: ${region}`);
765
- } else {
766
- const newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
767
- if (newFBMQTTMatch) {
768
- irisSeqID = newFBMQTTMatch[2];
769
- mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
770
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
771
- log.info("login", `Got this account's message region: ${region}`);
772
- } else {
773
- const legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
774
- if (legacyFBMQTTMatch) {
775
- mqttEndpoint = legacyFBMQTTMatch[4];
776
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
777
- log.warn("login", `Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...`);
778
- log.info("login", `Got this account's message region: ${region}`);
779
- log.info("login", `[Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`);
780
- } else {
781
- log.warn("login", "Cannot get MQTT region & sequence ID.");
782
- noMqttData = html;
783
- }
784
- }
785
- }
786
-
787
- ctx.lastSeqId = irisSeqID;
788
- ctx.mqttEndpoint = mqttEndpoint;
789
- ctx.region = region;
790
- if (noMqttData) {
791
- api["htmlData"] = noMqttData;
792
- }
793
-
794
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
795
- })
796
- .catch(function (err) {
797
- log.error("getSeqId", err);
798
- });
799
- }
800
-
801
- module.exports = function (defaultFuncs, api, ctx) {
802
- let globalCallback = identity;
803
-
804
- return function (callback) {
805
- class MessageEmitter extends EventEmitter {
806
- stopListening(callback) {
807
-
808
- callback = callback || (() => { });
809
- globalCallback = identity;
810
- if (ctx.mqttClient) {
811
- ctx.mqttClient.unsubscribe("/webrtc");
812
- ctx.mqttClient.unsubscribe("/rtc_multi");
813
- ctx.mqttClient.unsubscribe("/onevc");
814
- ctx.mqttClient.publish("/browser_close", "{}");
815
- ctx.mqttClient.end(false, function (...data) {
816
- callback(data);
817
- ctx.mqttClient = undefined;
818
- });
819
- }
820
- }
821
-
822
- async stopListeningAsync() {
823
- return new Promise((resolve) => {
824
- this.stopListening(resolve);
825
- });
826
- }
827
- }
828
-
829
- const msgEmitter = new MessageEmitter();
830
- globalCallback = (callback || function (error, message) {
831
- if (error) {
832
- return msgEmitter.emit("error", error);
833
- }
834
- msgEmitter.emit("message", message);
835
- });
836
-
837
- // Reset some stuff
838
- if (!ctx.firstListen)
839
- ctx.lastSeqId = null;
840
- ctx.syncToken = undefined;
841
- ctx.t_mqttCalled = false;
842
-
843
- if (!ctx.firstListen || !ctx.lastSeqId) {
844
- getSeqId(defaultFuncs, api, ctx, globalCallback);
845
- } else {
846
- listenMqtt(defaultFuncs, api, ctx, globalCallback);
847
- }
848
-
849
- api.stopListening = msgEmitter.stopListening;
850
- api.stopListeningAsync = msgEmitter.stopListeningAsync;
851
- return msgEmitter;
852
- };
853
- };