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