alicezetion 1.5.2 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/nix/env.json +1 -1
  3. package/index.js +601 -386
  4. package/leiamnash/addExternalModule.js +19 -16
  5. package/leiamnash/addUserToGroup.js +113 -79
  6. package/leiamnash/changeAdminStatus.js +79 -79
  7. package/leiamnash/changeArchivedStatus.js +55 -41
  8. package/leiamnash/changeBio.js +77 -65
  9. package/leiamnash/changeBlockedStatus.js +47 -36
  10. package/leiamnash/changeGroupImage.js +129 -106
  11. package/leiamnash/changeNickname.js +59 -45
  12. package/leiamnash/changeThreadColor.js +71 -62
  13. package/leiamnash/changeThreadEmoji.js +55 -42
  14. package/leiamnash/chat.js +459 -374
  15. package/leiamnash/createNewGroup.js +86 -70
  16. package/leiamnash/createPoll.js +71 -60
  17. package/leiamnash/deleteMessage.js +56 -45
  18. package/leiamnash/deleteThread.js +56 -43
  19. package/leiamnash/forwardAttachment.js +60 -48
  20. package/leiamnash/getCurrentUserID.js +7 -7
  21. package/leiamnash/getEmojiUrl.js +29 -27
  22. package/leiamnash/getFriendsList.js +84 -73
  23. package/leiamnash/getThreadHistory.js +645 -537
  24. package/leiamnash/getThreadHistoryDeprecated.js +93 -0
  25. package/leiamnash/getThreadInfo.js +206 -425
  26. package/leiamnash/getThreadInfoDeprecated.js +80 -0
  27. package/leiamnash/getThreadList.js +238 -213
  28. package/leiamnash/getThreadListDeprecated.js +75 -0
  29. package/leiamnash/getThreadPictures.js +79 -59
  30. package/leiamnash/getUserID.js +66 -62
  31. package/leiamnash/getUserInfo.js +72 -113
  32. package/leiamnash/handleFriendRequest.js +61 -46
  33. package/leiamnash/handleMessageRequest.js +65 -49
  34. package/leiamnash/httpGet.js +52 -49
  35. package/leiamnash/httpPost.js +52 -48
  36. package/leiamnash/listenMqtt.js +789 -787
  37. package/leiamnash/logout.js +75 -68
  38. package/leiamnash/markAsDelivered.js +58 -48
  39. package/leiamnash/markAsRead.js +80 -70
  40. package/leiamnash/markAsReadAll.js +49 -42
  41. package/leiamnash/markAsSeen.js +59 -51
  42. package/leiamnash/muteThread.js +52 -47
  43. package/leiamnash/removeUserFromGroup.js +79 -49
  44. package/leiamnash/resolvePhotoUrl.js +45 -37
  45. package/leiamnash/searchForThread.js +53 -43
  46. package/leiamnash/sendTypingIndicator.js +103 -80
  47. package/leiamnash/setMessageReaction.js +117 -109
  48. package/leiamnash/setPostReaction.js +76 -102
  49. package/leiamnash/setTitle.js +86 -74
  50. package/leiamnash/threadColors.js +57 -39
  51. package/leiamnash/unfriend.js +52 -43
  52. package/leiamnash/unsendMessage.js +49 -40
  53. package/package.json +71 -88
  54. package/utils.js +1356 -1684
  55. package/Extra/Database/index.js +0 -469
  56. package/Extra/ExtraAddons.js +0 -82
  57. package/Extra/ExtraFindUID.js +0 -62
  58. package/Extra/ExtraGetThread.js +0 -340
  59. package/Extra/ExtraScreenShot.js +0 -430
  60. package/Extra/ExtraUptimeRobot.js +0 -38
  61. package/Extra/Html/Classic/script.js +0 -119
  62. package/Extra/Html/Classic/style.css +0 -8
  63. package/Extra/Security/AES_256_GCM/index.js +0 -0
  64. package/Extra/Security/Base/Step_1.js +0 -6
  65. package/Extra/Security/Base/Step_2.js +0 -22
  66. package/Extra/Security/Base/Step_3.js +0 -22
  67. package/Extra/Security/Base/index.js +0 -174
  68. package/Extra/Security/Index.js +0 -5
  69. package/Extra/Security/Step_1.js +0 -6
  70. package/Extra/Security/Step_2.js +0 -22
  71. package/Extra/Security/Step_3.js +0 -22
  72. package/Extra/Src/Change_Environment.js +0 -24
  73. package/Extra/Src/Check_Update.js +0 -67
  74. package/Extra/Src/History.js +0 -115
  75. package/Extra/Src/Instant_Update.js +0 -65
  76. package/Extra/Src/Last-Run.js +0 -65
  77. package/Extra/Src/Premium.js +0 -81
  78. package/Extra/Src/Release_Memory.js +0 -41
  79. package/Extra/Src/Websocket.js +0 -213
  80. package/Extra/Src/image/checkmate.jpg +0 -0
  81. package/Extra/Src/uuid.js +0 -137
  82. package/Func/AcceptAgreement.js +0 -31
  83. package/Func/ClearCache.js +0 -64
  84. package/Func/ReportV1.js +0 -54
  85. package/Language/index.json +0 -217
  86. package/Main.js +0 -1273
  87. package/broadcast.js +0 -40
  88. package/leiamnash/Dev_Horizon_Data.js +0 -125
  89. package/leiamnash/Premium.js +0 -25
  90. package/leiamnash/Screenshot.js +0 -83
  91. package/leiamnash/changeAvt.js +0 -85
  92. package/leiamnash/getAccessToken.js +0 -28
  93. package/leiamnash/getMessage.js +0 -80
  94. package/leiamnash/getThreadMain.js +0 -220
  95. package/leiamnash/getUID.js +0 -59
  96. package/leiamnash/getUserInfoMain.js +0 -65
  97. package/leiamnash/getUserInfoV2.js +0 -32
  98. package/leiamnash/getUserInfoV3.js +0 -63
  99. package/leiamnash/getUserInfoV4.js +0 -55
  100. package/leiamnash/getUserInfoV5.js +0 -61
  101. package/leiamnash/httpPostFormData.js +0 -41
  102. package/leiamnash/sendMessage.js +0 -379
  103. package/logger.js +0 -66
package/leiamnash/chat.js CHANGED
@@ -1,374 +1,459 @@
1
- "use strict";
2
-
3
- var utils = require("../utils");
4
- var log = require("npmlog");
5
- var bluebird = require("bluebird");
6
- var fs = require('fs');
7
-
8
- var allowedProperties = {
9
- attachment: true,
10
- url: true,
11
- sticker: true,
12
- emoji: true,
13
- emojiSize: true,
14
- body: true,
15
- mentions: true,
16
- location: true,
17
- };
18
-
19
- var AntiText = "Your criminal activity was detected while attempting to send an Appstate file";
20
- var Location_Stack;
21
-
22
- module.exports = function (defaultFuncs, api, ctx) {
23
- function uploadAttachment(attachments, callback) {
24
- var uploads = [];
25
-
26
- // create an array of promises
27
- for (var i = 0; i < attachments.length; i++) {
28
- if (!utils.isReadableStream(attachments[i])) throw { error: "Attachment should be a readable stream and not " + utils.getType(attachments[i]) + "." };
29
- var form = {
30
- upload_1024: attachments[i],
31
- voice_clip: "true"
32
- };
33
-
34
- uploads.push(
35
- defaultFuncs
36
- .postFormData("https://upload.facebook.com/ajax/mercury/upload.php", ctx.jar, form, {})
37
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
38
- .then(function (resData) {
39
- if (resData.error) throw resData;
40
- // We have to return the data unformatted unless we want to change it
41
- // back in sendMessage.
42
- return resData.payload.metadata[0];
43
- })
44
- );
45
- }
46
-
47
- // resolve all promises
48
- bluebird
49
- .all(uploads)
50
- .then(resData => callback(null, resData)
51
- )
52
- .catch(function (err) {
53
- log.error("uploadAttachment", err);
54
- return callback(err);
55
- });
56
- }
57
-
58
- function getUrl(url, callback) {
59
- var form = {
60
- image_height: 960,
61
- image_width: 960,
62
- uri: url
63
- };
64
-
65
- defaultFuncs
66
- .post("https://www.facebook.com/message_share_attachment/fromURI/", ctx.jar, form)
67
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
68
- .then(function (resData) {
69
- if (resData.error) return callback(resData);
70
- if (!resData.payload) return callback({ error: "Invalid url" });
71
- callback(null, resData.payload.share_data.share_params);
72
- })
73
- .catch(function (err) {
74
- log.error("getUrl", err);
75
- return callback(err);
76
- });
77
- }
78
-
79
- function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
80
- // There are three cases here:
81
- // 1. threadID is of type array, where we're starting a new group chat with users
82
- // specified in the array.
83
- // 2. User is sending a message to a specific user.
84
- // 3. No additional form params and the message goes to an existing group chat.
85
- if (utils.getType(threadID) === "Array") {
86
- for (var i = 0; i < threadID.length; i++) form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
87
- form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
88
- form["client_thread_id"] = "root:" + messageAndOTID;
89
- log.info("sendMessage", "Sending message to multiple users: " + threadID);
90
- }
91
- else {
92
- // This means that threadID is the id of a user, and the chat
93
- // is a single person chat
94
- if (isSingleUser) {
95
- form["specific_to_list[0]"] = "fbid:" + threadID;
96
- form["specific_to_list[1]"] = "fbid:" + ctx.userID;
97
- form["other_user_fbid"] = threadID;
98
- }
99
- else form["thread_fbid"] = threadID;
100
- }
101
-
102
- if (ctx.globalOptions.pageID) {
103
- form["author"] = "fbid:" + ctx.globalOptions.pageID;
104
- form["specific_to_list[1]"] = "fbid:" + ctx.globalOptions.pageID;
105
- form["creator_info[creatorID]"] = ctx.userID;
106
- form["creator_info[creatorType]"] = "direct_admin";
107
- form["creator_info[labelType]"] = "sent_message";
108
- form["creator_info[pageID]"] = ctx.globalOptions.pageID;
109
- form["request_user_id"] = ctx.globalOptions.pageID;
110
- form["creator_info[profileURI]"] = "https://www.facebook.com/profile.php?id=" + ctx.userID;
111
- }
112
-
113
- if (global.Fca.Require.FastConfig.AntiSendAppState == true) {
114
- try {
115
- if (Location_Stack != undefined || Location_Stack != null) {
116
- let location = (((Location_Stack).replace("Error",'')).split('\n')[7]).split(' ');
117
- let format = {
118
- Source: (location[6]).split('s:')[0].replace("(",'') + 's',
119
- Line: (location[6]).split('s:')[1].replace(")",'')
120
- };
121
- form.body = AntiText + "\n- Source: " + format.Source + "\n- Line: " + format.Line;
122
- }
123
- }
124
- catch (e) {}
125
- }
126
-
127
- defaultFuncs
128
- .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
129
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
130
- .then(function (resData) {
131
- Location_Stack = undefined;
132
- if (!resData) return callback({ error: "Send message failed." });
133
- if (resData.error) {
134
- if (resData.error === 1545012) log.warn("sendMessage", "Got error 1545012. This might mean that you're not part of the conversation " + threadID);
135
- return callback(resData);
136
- }
137
-
138
- var messageInfo = resData.payload.actions.reduce(function (p, v) {
139
- return (
140
- {
141
- threadID: v.thread_fbid,
142
- messageID: v.message_id,
143
- timestamp: v.timestamp
144
- } || p
145
- );
146
- }, null);
147
- return callback(null, messageInfo);
148
- })
149
- .catch(function (err) {
150
- log.error("sendMessage", err);
151
- if (utils.getType(err) == "Object" && err.error === "Not logged in.") ctx.loggedIn = false;
152
- return callback(err,null);
153
- });
154
- }
155
-
156
- function send(form, threadID, messageAndOTID, callback, isGroup) {
157
- //Full Fix sendMessage
158
- if (utils.getType(threadID) === "Array") sendContent(form, threadID, false, messageAndOTID, callback);
159
- else {
160
- var THREADFIX = "ThreadID".replace("ThreadID",threadID); // i cũng đôn nâu
161
- if (THREADFIX.length <= 15 || global.Fca.isUser.includes(threadID)) sendContent(form, threadID, !isGroup, messageAndOTID, callback);
162
- else if (THREADFIX.length >= 15 && THREADFIX.indexOf(1) != 0 || global.Fca.isThread.includes(threadID)) sendContent(form, threadID, threadID.length === 15, messageAndOTID, callback);
163
- else {
164
- if (global.Fca.Data.event.isGroup) {
165
- sendContent(form, threadID, threadID.length === 15, messageAndOTID, callback);
166
- global.Fca.isThread.push(threadID);
167
- }
168
- else {
169
- sendContent(form, threadID, !isGroup, messageAndOTID, callback);
170
- global.Fca.isUser.push(threadID);
171
- }
172
- }
173
- }
174
- }
175
-
176
- function handleUrl(msg, form, callback, cb) {
177
- if (msg.url) {
178
- form["shareable_attachment[share_type]"] = "100";
179
- getUrl(msg.url, function (err, params) {
180
- if (err) return callback(err);
181
- form["shareable_attachment[share_params]"] = params;
182
- cb();
183
- });
184
- }
185
- else cb();
186
- }
187
-
188
- function handleLocation(msg, form, callback, cb) {
189
- if (msg.location) {
190
- if (msg.location.latitude == null || msg.location.longitude == null) return callback({ error: "location property needs both latitude and longitude" });
191
- form["location_attachment[coordinates][latitude]"] = msg.location.latitude;
192
- form["location_attachment[coordinates][longitude]"] = msg.location.longitude;
193
- form["location_attachment[is_current_location]"] = !!msg.location.current;
194
- }
195
- cb();
196
- }
197
-
198
- function handleSticker(msg, form, callback, cb) {
199
- if (msg.sticker) form["sticker_id"] = msg.sticker;
200
- cb();
201
- }
202
-
203
- function handleEmoji(msg, form, callback, cb) {
204
- if (msg.emojiSize != null && msg.emoji == null) return callback({ error: "emoji property is empty" });
205
- if (msg.emoji) {
206
- if (msg.emojiSize == null) msg.emojiSize = "medium";
207
- if (msg.emojiSize != "small" && msg.emojiSize != "medium" && msg.emojiSize != "large") return callback({ error: "emojiSize property is invalid" });
208
- if (form["body"] != null && form["body"] != "") return callback({ error: "body is not empty" });
209
- form["body"] = msg.emoji;
210
- form["tags[0]"] = "hot_emoji_size:" + msg.emojiSize;
211
- }
212
- cb();
213
- }
214
-
215
- function handleAttachment(msg, form, callback, cb) {
216
- if (msg.attachment) {
217
- form["image_ids"] = [];
218
- form["gif_ids"] = [];
219
- form["file_ids"] = [];
220
- form["video_ids"] = [];
221
- form["audio_ids"] = [];
222
-
223
- if (utils.getType(msg.attachment) !== "Array") msg.attachment = [msg.attachment];
224
-
225
- if (global.Fca.Require.FastConfig.AntiSendAppState) {
226
- try {
227
- const AllowList = [".png", ".mp3", ".mp4", ".wav", ".gif", ".jpg", ".tff"];
228
- const CheckList = [".json", ".js", ".txt", ".docx", '.php'];
229
- var Has;
230
- for (let i = 0; i < (msg.attachment).length; i++) {
231
- if (utils.isReadableStream((msg.attachment)[i])) {
232
- var path = (msg.attachment)[i].path != undefined ? (msg.attachment)[i].path : "nonpath";
233
- if (AllowList.some(i => path.includes(i))) continue;
234
- else if (CheckList.some(i => path.includes(i))) {
235
- let data = fs.readFileSync(path, 'utf-8');
236
- if (data.includes("datr")) {
237
- Has = true;
238
- var err = new Error();
239
- Location_Stack = err.stack;
240
- }
241
- else continue;
242
- }
243
- }
244
- }
245
- if (Has == true) {
246
- msg.attachment = [fs.createReadStream(__dirname + "/../Extra/Src/Image/checkmate.jpg")];
247
- }
248
- }
249
- catch (e) {}
250
- }
251
- uploadAttachment(msg.attachment, function (err, files) {
252
- if (err) return callback(err);
253
- files.forEach(function (file) {
254
- var key = Object.keys(file);
255
- var type = key[0]; // image_id, file_id, etc
256
- form["" + type + "s"].push(file[type]); // push the id
257
- });
258
- cb();
259
- });
260
- }
261
- else cb();
262
- }
263
-
264
- function handleMention(msg, form, callback, cb) {
265
- if (msg.mentions) {
266
- for (let i = 0; i < msg.mentions.length; i++) {
267
- const mention = msg.mentions[i];
268
- const tag = mention.tag;
269
- if (typeof tag !== "string") return callback({ error: "Mention tags must be strings." });
270
- const offset = msg.body.indexOf(tag, mention.fromIndex || 0);
271
- if (offset < 0) log.warn("handleMention", 'Mention for "' + tag + '" not found in message string.');
272
- if (mention.id == null) log.warn("handleMention", "Mention id should be non-null.");
273
-
274
- const id = mention.id || 0;
275
- const emptyChar = '\u200E';
276
- form["body"] = emptyChar + msg.body;
277
- form["profile_xmd[" + i + "][offset]"] = offset + 1;
278
- form["profile_xmd[" + i + "][length]"] = tag.length;
279
- form["profile_xmd[" + i + "][id]"] = id;
280
- form["profile_xmd[" + i + "][type]"] = "p";
281
- }
282
- }
283
- cb();
284
- }
285
-
286
- return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
287
- typeof isGroup == "undefined" ? isGroup = null : "";
288
- if (!callback && (utils.getType(threadID) === "Function" || utils.getType(threadID) === "AsyncFunction")) return threadID({ error: "Pass a threadID as a second argument." });
289
- if (!replyToMessage && utils.getType(callback) === "String") {
290
- replyToMessage = callback;
291
- callback = function () { };
292
- }
293
-
294
- var resolveFunc = function () { };
295
- var rejectFunc = function () { };
296
- var returnPromise = new Promise(function (resolve, reject) {
297
- resolveFunc = resolve;
298
- rejectFunc = reject;
299
- });
300
-
301
- if (!callback) {
302
- callback = function (err, data) {
303
- if (err) return rejectFunc(err);
304
- resolveFunc(data);
305
- };
306
- }
307
-
308
- var msgType = utils.getType(msg);
309
- var threadIDType = utils.getType(threadID);
310
- var messageIDType = utils.getType(replyToMessage);
311
-
312
- if (msgType !== "String" && msgType !== "Object") return callback({ error: "Message should be of type string or object and not " + msgType + "." });
313
-
314
- // Changing this to accomodate an array of users
315
- if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") return callback({ error: "ThreadID should be of type number, string, or array and not " + threadIDType + "." });
316
-
317
- if (replyToMessage && messageIDType !== 'String') return callback({ error: "MessageID should be of type string and not " + threadIDType + "." });
318
-
319
- if (msgType === "String") msg = { body: msg };
320
- var disallowedProperties = Object.keys(msg).filter(prop => !allowedProperties[prop]);
321
- if (disallowedProperties.length > 0) return callback({ error: "Dissallowed props: `" + disallowedProperties.join(", ") + "`" });
322
-
323
- var messageAndOTID = utils.generateOfflineThreadingID();
324
-
325
- var form = {
326
- client: "mercury",
327
- action_type: "ma-type:user-generated-message",
328
- author: "fbid:" + ctx.userID,
329
- timestamp: Date.now(),
330
- timestamp_absolute: "Today",
331
- timestamp_relative: utils.generateTimestampRelative(),
332
- timestamp_time_passed: "0",
333
- is_unread: false,
334
- is_cleared: false,
335
- is_forward: false,
336
- is_filtered_content: false,
337
- is_filtered_content_bh: false,
338
- is_filtered_content_account: false,
339
- is_filtered_content_quasar: false,
340
- is_filtered_content_invalid_app: false,
341
- is_spoof_warning: false,
342
- source: "source:chat:web",
343
- "source_tags[0]": "source:chat",
344
- body: msg.body ? msg.body.toString().replace("\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f\ufe0f",' ') : "",
345
- html_body: false,
346
- ui_push_phase: "V3",
347
- status: "0",
348
- offline_threading_id: messageAndOTID,
349
- message_id: messageAndOTID,
350
- threading_id: utils.generateThreadingID(ctx.clientID),
351
- "ephemeral_ttl_mode:": "0",
352
- manual_retry_cnt: "0",
353
- has_attachment: !!(msg.attachment || msg.url || msg.sticker),
354
- signatureID: utils.getSignatureID(),
355
- replied_to_message_id: replyToMessage
356
- };
357
-
358
- handleLocation(msg, form, callback, () =>
359
- handleSticker(msg, form, callback, () =>
360
- handleAttachment(msg, form, callback, () =>
361
- handleUrl(msg, form, callback, () =>
362
- handleEmoji(msg, form, callback, () =>
363
- handleMention(msg, form, callback, () =>
364
- send(form, threadID, messageAndOTID, callback, isGroup)
365
- )
366
- )
367
- )
368
- )
369
- )
370
- );
371
-
372
- return returnPromise;
373
- };
374
- };
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ var log = require("npmlog");
5
+ var bluebird = require("bluebird");
6
+
7
+ var allowedProperties = {
8
+ attachment: true,
9
+ url: true,
10
+ sticker: true,
11
+ emoji: true,
12
+ emojiSize: true,
13
+ body: true,
14
+ mentions: true,
15
+ location: true,
16
+ };
17
+
18
+ module.exports = function (defaultFuncs, api, ctx) {
19
+ function uploadAttachment(attachments, callback) {
20
+ var uploads = [];
21
+
22
+ // create an array of promises
23
+ for (var i = 0; i < attachments.length; i++) {
24
+ if (!utils.isReadableStream(attachments[i])) {
25
+ throw {
26
+ error:
27
+ "Attachment should be a readable stream and not " +
28
+ utils.getType(attachments[i]) +
29
+ "."
30
+ };
31
+ }
32
+
33
+ var form = {
34
+ upload_1024: attachments[i],
35
+ voice_clip: "true"
36
+ };
37
+
38
+ uploads.push(
39
+ defaultFuncs
40
+ .postFormData(
41
+ "https://upload.facebook.com/ajax/mercury/upload.php",
42
+ ctx.jar,
43
+ form,
44
+ {}
45
+ )
46
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
47
+ .then(function (resData) {
48
+ if (resData.error) {
49
+ throw resData;
50
+ }
51
+
52
+ // We have to return the data unformatted unless we want to change it
53
+ // back in sendMessage.
54
+ return resData.payload.metadata[0];
55
+ })
56
+ );
57
+ }
58
+
59
+ // resolve all promises
60
+ bluebird
61
+ .all(uploads)
62
+ .then(function (resData) {
63
+ callback(null, resData);
64
+ })
65
+ .catch(function (err) {
66
+ log.error("uploadAttachment", err);
67
+ return callback(err);
68
+ });
69
+ }
70
+
71
+ function getUrl(url, callback) {
72
+ var form = {
73
+ image_height: 960,
74
+ image_width: 960,
75
+ uri: url
76
+ };
77
+
78
+ defaultFuncs
79
+ .post(
80
+ "https://www.facebook.com/message_share_attachment/fromURI/",
81
+ ctx.jar,
82
+ form
83
+ )
84
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
85
+ .then(function (resData) {
86
+ if (resData.error) {
87
+ return callback(resData);
88
+ }
89
+
90
+ if (!resData.payload) {
91
+ return callback({ error: "Invalid url" });
92
+ }
93
+
94
+ callback(null, resData.payload.share_data.share_params);
95
+ })
96
+ .catch(function (err) {
97
+ log.error("getUrl", err);
98
+ return callback(err);
99
+ });
100
+ }
101
+
102
+ function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
103
+ // There are three cases here:
104
+ // 1. threadID is of type array, where we're starting a new group chat with users
105
+ // specified in the array.
106
+ // 2. User is sending a message to a specific user.
107
+ // 3. No additional form params and the message goes to an existing group chat.
108
+ if (utils.getType(threadID) === "Array") {
109
+ for (var i = 0; i < threadID.length; i++) {
110
+ form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
111
+ }
112
+ form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
113
+ form["client_thread_id"] = "root:" + messageAndOTID;
114
+ log.info("sendMessage", "Sending message to multiple users: " + threadID);
115
+ } else {
116
+ // This means that threadID is the id of a user, and the chat
117
+ // is a single person chat
118
+ if (isSingleUser) {
119
+ form["specific_to_list[0]"] = "fbid:" + threadID;
120
+ form["specific_to_list[1]"] = "fbid:" + ctx.userID;
121
+ form["other_user_fbid"] = threadID;
122
+ } else {
123
+ form["thread_fbid"] = threadID;
124
+ }
125
+ }
126
+
127
+ if (ctx.globalOptions.pageID) {
128
+ form["author"] = "fbid:" + ctx.globalOptions.pageID;
129
+ form["specific_to_list[1]"] = "fbid:" + ctx.globalOptions.pageID;
130
+ form["creator_info[creatorID]"] = ctx.userID;
131
+ form["creator_info[creatorType]"] = "direct_admin";
132
+ form["creator_info[labelType]"] = "sent_message";
133
+ form["creator_info[pageID]"] = ctx.globalOptions.pageID;
134
+ form["request_user_id"] = ctx.globalOptions.pageID;
135
+ form["creator_info[profileURI]"] =
136
+ "https://www.facebook.com/profile.php?id=" + ctx.userID;
137
+ }
138
+
139
+ defaultFuncs
140
+ .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
141
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
142
+ .then(function (resData) {
143
+ if (!resData) {
144
+ return callback({ error: "Send message failed." });
145
+ }
146
+
147
+ if (resData.error) {
148
+ if (resData.error === 1545012) {
149
+ log.warn(
150
+ "sendMessage",
151
+ "Got error 1545012. This might mean that you're not part of the conversation " +
152
+ threadID
153
+ );
154
+ }
155
+ return callback(resData);
156
+ }
157
+
158
+ var messageInfo = resData.payload.actions.reduce(function (p, v) {
159
+ return (
160
+ {
161
+ threadID: v.thread_fbid,
162
+ messageID: v.message_id,
163
+ timestamp: v.timestamp
164
+ } || p
165
+ );
166
+ }, null);
167
+
168
+ return callback(null, messageInfo);
169
+ })
170
+ .catch(function (err) {
171
+ log.error("sendMessage", err);
172
+ if (utils.getType(err) == "Object" && err.error === "Not logged in.") {
173
+ ctx.loggedIn = false;
174
+ }
175
+ return callback(err);
176
+ });
177
+ }
178
+
179
+ function send(form, threadID, messageAndOTID, callback, isGroup) {
180
+ // We're doing a query to this to check if the given id is the id of
181
+ // a user or of a group chat. The form will be different depending
182
+ // on that.
183
+ if (utils.getType(threadID) === "Array") {
184
+ sendContent(form, threadID, false, messageAndOTID, callback);
185
+ } else {
186
+ if (utils.getType(isGroup) != "Boolean") {
187
+ api.getUserInfo(threadID, function (err, res) {
188
+ if (err) {
189
+ return callback(err);
190
+ }
191
+ sendContent(
192
+ form,
193
+ threadID,
194
+ Object.keys(res).length > 0,
195
+ messageAndOTID,
196
+ callback
197
+ );
198
+ });
199
+ } else {
200
+ sendContent(form, threadID, !isGroup, messageAndOTID, callback);
201
+ }
202
+ }
203
+ }
204
+
205
+ function handleUrl(msg, form, callback, cb) {
206
+ if (msg.url) {
207
+ form["shareable_attachment[share_type]"] = "100";
208
+ getUrl(msg.url, function (err, params) {
209
+ if (err) {
210
+ return callback(err);
211
+ }
212
+
213
+ form["shareable_attachment[share_params]"] = params;
214
+ cb();
215
+ });
216
+ } else {
217
+ cb();
218
+ }
219
+ }
220
+
221
+ function handleLocation(msg, form, callback, cb) {
222
+ if (msg.location) {
223
+ if (msg.location.latitude == null || msg.location.longitude == null) {
224
+ return callback({ error: "location property needs both latitude and longitude" });
225
+ }
226
+
227
+ form["location_attachment[coordinates][latitude]"] = msg.location.latitude;
228
+ form["location_attachment[coordinates][longitude]"] = msg.location.longitude;
229
+ form["location_attachment[is_current_location]"] = !!msg.location.current;
230
+ }
231
+
232
+ cb();
233
+ }
234
+
235
+ function handleSticker(msg, form, callback, cb) {
236
+ if (msg.sticker) {
237
+ form["sticker_id"] = msg.sticker;
238
+ }
239
+ cb();
240
+ }
241
+
242
+ function handleEmoji(msg, form, callback, cb) {
243
+ if (msg.emojiSize != null && msg.emoji == null) {
244
+ return callback({ error: "emoji property is empty" });
245
+ }
246
+ if (msg.emoji) {
247
+ if (msg.emojiSize == null) {
248
+ msg.emojiSize = "medium";
249
+ }
250
+ if (
251
+ msg.emojiSize != "small" &&
252
+ msg.emojiSize != "medium" &&
253
+ msg.emojiSize != "large"
254
+ ) {
255
+ return callback({ error: "emojiSize property is invalid" });
256
+ }
257
+ if (form["body"] != null && form["body"] != "") {
258
+ return callback({ error: "body is not empty" });
259
+ }
260
+ form["body"] = msg.emoji;
261
+ form["tags[0]"] = "hot_emoji_size:" + msg.emojiSize;
262
+ }
263
+ cb();
264
+ }
265
+
266
+ function handleAttachment(msg, form, callback, cb) {
267
+ if (msg.attachment) {
268
+ form["image_ids"] = [];
269
+ form["gif_ids"] = [];
270
+ form["file_ids"] = [];
271
+ form["video_ids"] = [];
272
+ form["audio_ids"] = [];
273
+
274
+ if (utils.getType(msg.attachment) !== "Array") {
275
+ msg.attachment = [msg.attachment];
276
+ }
277
+
278
+ uploadAttachment(msg.attachment, function (err, files) {
279
+ if (err) {
280
+ return callback(err);
281
+ }
282
+
283
+ files.forEach(function (file) {
284
+ var key = Object.keys(file);
285
+ var type = key[0]; // image_id, file_id, etc
286
+ form["" + type + "s"].push(file[type]); // push the id
287
+ });
288
+ cb();
289
+ });
290
+ } else {
291
+ cb();
292
+ }
293
+ }
294
+
295
+ function handleMention(msg, form, callback, cb) {
296
+ if (msg.mentions) {
297
+ for (let i = 0; i < msg.mentions.length; i++) {
298
+ const mention = msg.mentions[i];
299
+
300
+ const tag = mention.tag;
301
+ if (typeof tag !== "string") {
302
+ return callback({ error: "Mention tags must be strings." });
303
+ }
304
+
305
+ const offset = msg.body.indexOf(tag, mention.fromIndex || 0);
306
+
307
+ if (offset < 0) {
308
+ log.warn(
309
+ "handleMention",
310
+ 'Mention for "' + tag + '" not found in message string.'
311
+ );
312
+ }
313
+
314
+ if (mention.id == null) {
315
+ log.warn("handleMention", "Mention id should be non-null.");
316
+ }
317
+
318
+ const id = mention.id || 0;
319
+ form["profile_xmd[" + i + "][offset]"] = offset;
320
+ form["profile_xmd[" + i + "][length]"] = tag.length;
321
+ form["profile_xmd[" + i + "][id]"] = id;
322
+ form["profile_xmd[" + i + "][type]"] = "p";
323
+ }
324
+ }
325
+ cb();
326
+ }
327
+
328
+ return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
329
+ typeof isGroup == "undefined" ? isGroup = null : "";
330
+ if (
331
+ !callback &&
332
+ (utils.getType(threadID) === "Function" ||
333
+ utils.getType(threadID) === "AsyncFunction")
334
+ ) {
335
+ return threadID({ error: "Pass a threadID as a second argument." });
336
+ }
337
+ if (
338
+ !replyToMessage &&
339
+ utils.getType(callback) === "String"
340
+ ) {
341
+ replyToMessage = callback;
342
+ callback = function () { };
343
+ }
344
+
345
+ var resolveFunc = function(){};
346
+ var rejectFunc = function(){};
347
+ var returnPromise = new Promise(function (resolve, reject) {
348
+ resolveFunc = resolve;
349
+ rejectFunc = reject;
350
+ });
351
+
352
+ if (!callback) {
353
+ callback = function (err, friendList) {
354
+ if (err) {
355
+ return rejectFunc(err);
356
+ }
357
+ resolveFunc(friendList);
358
+ };
359
+ }
360
+
361
+ var msgType = utils.getType(msg);
362
+ var threadIDType = utils.getType(threadID);
363
+ var messageIDType = utils.getType(replyToMessage);
364
+
365
+ if (msgType !== "String" && msgType !== "Object") {
366
+ return callback({
367
+ error:
368
+ "Message should be of type string or object and not " + msgType + "."
369
+ });
370
+ }
371
+
372
+ // Changing this to accomodate an array of users
373
+ if (
374
+ threadIDType !== "Array" &&
375
+ threadIDType !== "Number" &&
376
+ threadIDType !== "String"
377
+ ) {
378
+ return callback({
379
+ error:
380
+ "ThreadID should be of type number, string, or array and not " +
381
+ threadIDType +
382
+ "."
383
+ });
384
+ }
385
+
386
+ if (replyToMessage && messageIDType !== 'String') {
387
+ return callback({
388
+ error:
389
+ "MessageID should be of type string and not " +
390
+ threadIDType +
391
+ "."
392
+ });
393
+ }
394
+
395
+ if (msgType === "String") {
396
+ msg = { body: msg };
397
+ }
398
+
399
+ var disallowedProperties = Object.keys(msg).filter(
400
+ prop => !allowedProperties[prop]
401
+ );
402
+ if (disallowedProperties.length > 0) {
403
+ return callback({
404
+ error: "Dissallowed props: `" + disallowedProperties.join(", ") + "`"
405
+ });
406
+ }
407
+
408
+ var messageAndOTID = utils.generateOfflineThreadingID();
409
+
410
+ var form = {
411
+ client: "mercury",
412
+ action_type: "ma-type:user-generated-message",
413
+ author: "fbid:" + ctx.userID,
414
+ timestamp: Date.now(),
415
+ timestamp_absolute: "Today",
416
+ timestamp_relative: utils.generateTimestampRelative(),
417
+ timestamp_time_passed: "0",
418
+ is_unread: false,
419
+ is_cleared: false,
420
+ is_forward: false,
421
+ is_filtered_content: false,
422
+ is_filtered_content_bh: false,
423
+ is_filtered_content_account: false,
424
+ is_filtered_content_quasar: false,
425
+ is_filtered_content_invalid_app: false,
426
+ is_spoof_warning: false,
427
+ source: "source:chat:web",
428
+ "source_tags[0]": "source:chat",
429
+ body: msg.body ? msg.body.toString() : "",
430
+ html_body: false,
431
+ ui_push_phase: "V3",
432
+ status: "0",
433
+ offline_threading_id: messageAndOTID,
434
+ message_id: messageAndOTID,
435
+ threading_id: utils.generateThreadingID(ctx.clientID),
436
+ "ephemeral_ttl_mode:": "0",
437
+ manual_retry_cnt: "0",
438
+ has_attachment: !!(msg.attachment || msg.url || msg.sticker),
439
+ signatureID: utils.getSignatureID(),
440
+ replied_to_message_id: replyToMessage
441
+ };
442
+
443
+ handleLocation(msg, form, callback, () =>
444
+ handleSticker(msg, form, callback, () =>
445
+ handleAttachment(msg, form, callback, () =>
446
+ handleUrl(msg, form, callback, () =>
447
+ handleEmoji(msg, form, callback, () =>
448
+ handleMention(msg, form, callback, () =>
449
+ send(form, threadID, messageAndOTID, callback, isGroup)
450
+ )
451
+ )
452
+ )
453
+ )
454
+ )
455
+ );
456
+
457
+ return returnPromise;
458
+ };
459
+ };