fca-orion-api 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/config.js +5 -0
  2. package/data/fcaVersion.json +0 -0
  3. package/index.js +417 -0
  4. package/instantUpdate.js +40 -0
  5. package/package.json +30 -0
  6. package/src/addExternalModule.js +19 -0
  7. package/src/addUserToGroup.js +113 -0
  8. package/src/changeAdminStatus.js +79 -0
  9. package/src/changeArchivedStatus.js +55 -0
  10. package/src/changeAvatar.js +126 -0
  11. package/src/changeBio.js +77 -0
  12. package/src/changeBlockedStatus.js +47 -0
  13. package/src/changeGroupImage.js +132 -0
  14. package/src/changeNickname.js +59 -0
  15. package/src/changeThreadColor.js +65 -0
  16. package/src/changeThreadEmoji.js +55 -0
  17. package/src/createNewGroup.js +86 -0
  18. package/src/createPoll.js +71 -0
  19. package/src/deleteMessage.js +56 -0
  20. package/src/deleteThread.js +56 -0
  21. package/src/forwardAttachment.js +60 -0
  22. package/src/getCurrentUserID.js +7 -0
  23. package/src/getEmojiUrl.js +29 -0
  24. package/src/getFriendsList.js +83 -0
  25. package/src/getMessage.js +796 -0
  26. package/src/getThreadHistory.js +666 -0
  27. package/src/getThreadInfo.js +232 -0
  28. package/src/getThreadList.js +241 -0
  29. package/src/getThreadPictures.js +79 -0
  30. package/src/getUserID.js +66 -0
  31. package/src/getUserInfo.js +74 -0
  32. package/src/handleFriendRequest.js +61 -0
  33. package/src/handleMessageRequest.js +65 -0
  34. package/src/httpGet.js +57 -0
  35. package/src/httpPost.js +57 -0
  36. package/src/httpPostFormData.js +63 -0
  37. package/src/listenMqtt.js +853 -0
  38. package/src/logout.js +75 -0
  39. package/src/markAsDelivered.js +58 -0
  40. package/src/markAsRead.js +80 -0
  41. package/src/markAsReadAll.js +50 -0
  42. package/src/markAsSeen.js +59 -0
  43. package/src/muteThread.js +52 -0
  44. package/src/refreshFb_dtsg.js +81 -0
  45. package/src/removeUserFromGroup.js +79 -0
  46. package/src/resolvePhotoUrl.js +45 -0
  47. package/src/searchForThread.js +53 -0
  48. package/src/sendMessage.js +477 -0
  49. package/src/sendTypingIndicator.js +103 -0
  50. package/src/setMessageReaction.js +121 -0
  51. package/src/setPostReaction.js +109 -0
  52. package/src/setTitle.js +86 -0
  53. package/src/threadColors.js +131 -0
  54. package/src/unfriend.js +52 -0
  55. package/src/unsendMessage.js +49 -0
  56. package/src/uploadAttachment.js +95 -0
  57. package/utils.js +1545 -0
package/config.js ADDED
@@ -0,0 +1,5 @@
1
+
2
+ module.exports = {
3
+ MainName: "[ test ]",
4
+ AutoUpdate: true
5
+ };
File without changes
package/index.js ADDED
@@ -0,0 +1,417 @@
1
+ "use strict";
2
+
3
+ const utils = require("./utils");
4
+ const log = require("npmlog");
5
+ const fs = require('fs');
6
+ const gradient = require("gradient-string");
7
+
8
+ const checkVerified = null;
9
+
10
+ const defaultLogRecordSize = 100;
11
+ log.maxRecordSize = defaultLogRecordSize;
12
+
13
+ const chalk = require('chalk');
14
+
15
+ const error = chalk.bold.red;
16
+ const warning = chalk.hex('#FFA500');
17
+ const success = chalk.greenBright;
18
+
19
+ const configContent = `
20
+ module.exports = {
21
+ MainName: "[ test ]",
22
+ AutoUpdate: true
23
+ };
24
+ `;
25
+
26
+ const configPath = 'config.js';
27
+
28
+ if (!fs.existsSync(configPath)) {
29
+ fs.writeFileSync(configPath, configContent);
30
+ }
31
+
32
+ const { MainName } = configPath;
33
+ const InstantUpdate = require('./instantUpdate.js');
34
+
35
+ function setOptions(globalOptions, options) {
36
+ Object.keys(options).map(function (key) {
37
+ switch (key) {
38
+ case 'online':
39
+ globalOptions.online = Boolean(options.online);
40
+ break;
41
+ case 'logLevel':
42
+ log.level = options.logLevel;
43
+ globalOptions.logLevel = options.logLevel;
44
+ break;
45
+ case 'logRecordSize':
46
+ log.maxRecordSize = options.logRecordSize;
47
+ globalOptions.logRecordSize = options.logRecordSize;
48
+ break;
49
+ case 'selfListen':
50
+ globalOptions.selfListen = Boolean(options.selfListen);
51
+ break;
52
+ case 'selfListenEvent':
53
+ globalOptions.selfListenEvent = options.selfListenEvent;
54
+ break;
55
+ case 'listenEvents':
56
+ globalOptions.listenEvents = Boolean(options.listenEvents);
57
+ break;
58
+ case 'pageID':
59
+ globalOptions.pageID = options.pageID.toString();
60
+ break;
61
+ case 'updatePresence':
62
+ globalOptions.updatePresence = Boolean(options.updatePresence);
63
+ break;
64
+ case 'forceLogin':
65
+ globalOptions.forceLogin = Boolean(options.forceLogin);
66
+ break;
67
+ case 'userAgent':
68
+ globalOptions.userAgent = options.userAgent;
69
+ break;
70
+ case 'autoMarkDelivery':
71
+ globalOptions.autoMarkDelivery = Boolean(options.autoMarkDelivery);
72
+ break;
73
+ case 'autoMarkRead':
74
+ globalOptions.autoMarkRead = Boolean(options.autoMarkRead);
75
+ break;
76
+ case 'listenTyping':
77
+ globalOptions.listenTyping = Boolean(options.listenTyping);
78
+ break;
79
+ case 'proxy':
80
+ if (typeof options.proxy != "string") {
81
+ delete globalOptions.proxy;
82
+ utils.setProxy();
83
+ } else {
84
+ globalOptions.proxy = options.proxy;
85
+ utils.setProxy(globalOptions.proxy);
86
+ }
87
+ break;
88
+ case 'autoReconnect':
89
+ globalOptions.autoReconnect = Boolean(options.autoReconnect);
90
+ break;
91
+ case 'emitReady':
92
+ globalOptions.emitReady = Boolean(options.emitReady);
93
+ break;
94
+ default:
95
+ console.log(gradient('orange', 'yellow')('setOptions') + chalk.warning("Unrecognized option given to setOptions: " + key));
96
+ break;
97
+ }
98
+ });
99
+ }
100
+
101
+ function buildAPI(globalOptions, html, jar) {
102
+ const maybeCookie = jar.getCookies("https://www.facebook.com").filter(function (val) {
103
+ return val.cookieString().split("=")[0] === "c_user";
104
+ });
105
+
106
+ const objCookie = jar.getCookies("https://www.facebook.com").reduce(function (obj, val) {
107
+ obj[val.cookieString().split("=")[0]] = val.cookieString().split("=")[1];
108
+ return obj;
109
+ }, {});
110
+
111
+ if (maybeCookie.length === 0) {
112
+ throw { error: "Error retrieving userID. This can be caused by a lot of things, including getting blocked by Facebook for logging in from an unknown location. Try logging in with a browser to verify." };
113
+ }
114
+
115
+ if (html.indexOf("/checkpoint/block/?next") > -1) {
116
+ console.log(warning("Checkpoint detected. Please log in with a browser to verify."));
117
+ }
118
+
119
+ console.log(gradient('orange', 'yellow').multiline(["▒█▀▄▒█▀▄░▄▀▄░░▒█▒██▀░▄▀▀░▀█▀░░░▄▀▄▒█▀▄░█░▄▀▄░█▄░█", "░█▀▒░█▀▄░▀▄▀░▀▄█░█▄▄░▀▄▄░▒█▒▒░░▀▄▀░█▀▄░█░▀▄▀░█▒▀█",].join('\n')));
120
+ console.log('');
121
+
122
+ const userID = maybeCookie[0].cookieString().split("=")[1].toString();
123
+ const i_userID = objCookie.i_user || null;
124
+ const localVersion = require('../package.json').version;
125
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` Logged in as ${userID}`));
126
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` The version of FCA-ORION you currently have is`) + chalk.greenBright(` ${localVersion}`));
127
+
128
+ try {
129
+ clearInterval(checkVerified);
130
+ } catch (_) { }
131
+
132
+ const clientID = (Math.random() * 2147483648 | 0).toString(16);
133
+
134
+
135
+ const oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
136
+ let mqttEndpoint = null;
137
+ let region = null;
138
+ let irisSeqID = null;
139
+ let noMqttData = null;
140
+
141
+ if (oldFBMQTTMatch) {
142
+ irisSeqID = oldFBMQTTMatch[1];
143
+ mqttEndpoint = oldFBMQTTMatch[2];
144
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
145
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` Got this account's message region: ${region}`));
146
+ } else {
147
+ const newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
148
+ if (newFBMQTTMatch) {
149
+ irisSeqID = newFBMQTTMatch[2];
150
+ mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
151
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
152
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` Got this account's message region: ${region}`));
153
+ } else {
154
+ const legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
155
+ if (legacyFBMQTTMatch) {
156
+ mqttEndpoint = legacyFBMQTTMatch[4];
157
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
158
+ console.log(warning('Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...'));
159
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` Got this account's message region: ${region}`));
160
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` [Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`));
161
+ } else {
162
+ console.log(warning('Cannot get MQTT region & sequence ID.'));
163
+ noMqttData = html;
164
+ }
165
+ }
166
+ }
167
+
168
+ // All data available to api functions
169
+ const ctx = {
170
+ userID: userID,
171
+ i_userID: i_userID,
172
+ jar: jar,
173
+ clientID: clientID,
174
+ globalOptions: globalOptions,
175
+ loggedIn: true,
176
+ access_token: 'NONE',
177
+ clientMutationId: 0,
178
+ mqttClient: undefined,
179
+ lastSeqId: irisSeqID,
180
+ syncToken: undefined,
181
+ mqttEndpoint,
182
+ region,
183
+ firstListen: true
184
+ };
185
+
186
+ const api = {
187
+ setOptions: setOptions.bind(null, globalOptions),
188
+ getAppState: function getAppState() {
189
+ const appState = utils.getAppState(jar);
190
+ // filter duplicate
191
+ return appState.filter((item, index, self) => self.findIndex((t) => { return t.key === item.key; }) === index);
192
+ }
193
+ };
194
+
195
+ if (noMqttData) {
196
+ api["htmlData"] = noMqttData;
197
+ }
198
+
199
+ const apiFuncNames = [
200
+ 'addExternalModule',
201
+ 'addUserToGroup',
202
+ 'changeAdminStatus',
203
+ 'changeArchivedStatus',
204
+ 'changeAvatar',
205
+ 'changeBio',
206
+ 'changeBlockedStatus',
207
+ 'changeGroupImage',
208
+ 'changeNickname',
209
+ 'changeThreadColor',
210
+ 'changeThreadEmoji',
211
+ 'createNewGroup',
212
+ 'createPoll',
213
+ 'deleteMessage',
214
+ 'deleteThread',
215
+ 'forwardAttachment',
216
+ 'getCurrentUserID',
217
+ 'getEmojiUrl',
218
+ 'getFriendsList',
219
+ 'getMessage',
220
+ 'getThreadHistory',
221
+ 'getThreadInfo',
222
+ 'getThreadList',
223
+ 'getThreadPictures',
224
+ 'getUserID',
225
+ 'getUserInfo',
226
+ 'handleMessageRequest',
227
+ 'listenMqtt',
228
+ 'logout',
229
+ 'markAsDelivered',
230
+ 'markAsRead',
231
+ 'markAsReadAll',
232
+ 'markAsSeen',
233
+ 'muteThread',
234
+ 'refreshFb_dtsg',
235
+ 'removeUserFromGroup',
236
+ 'resolvePhotoUrl',
237
+ 'searchForThread',
238
+ 'sendMessage',
239
+ 'sendTypingIndicator',
240
+ 'setMessageReaction',
241
+ 'setPostReaction',
242
+ 'setTitle',
243
+ 'threadColors',
244
+ 'unsendMessage',
245
+ 'unfriend',
246
+
247
+ // HTTP
248
+ 'httpGet',
249
+ 'httpPost',
250
+ 'httpPostFormData',
251
+
252
+ 'uploadAttachment'
253
+ ];
254
+
255
+ const defaultFuncs = utils.makeDefaults(html, i_userID || userID, ctx);
256
+
257
+ // Load all api functions in a loop
258
+ apiFuncNames.map(function (v) {
259
+ api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
260
+ });
261
+
262
+ //Removing original `listen` that uses pull.
263
+ //Map it to listenMqtt instead for backward compatibly.
264
+ api.listen = api.listenMqtt;
265
+
266
+ return [ctx, defaultFuncs, api];
267
+ }
268
+
269
+ // Helps the login
270
+ function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
271
+ let mainPromise = null;
272
+ const jar = utils.getJar();
273
+
274
+ // If we're given an appState we loop through it and save each cookie
275
+ // back into the jar.
276
+ if (appState) {
277
+ // check and convert cookie to appState
278
+ if (utils.getType(appState) === 'Array' && appState.some(c => c.name)) {
279
+ appState = appState.map(c => {
280
+ c.key = c.name;
281
+ delete c.name;
282
+ return c;
283
+ });
284
+ }
285
+ else if (utils.getType(appState) === 'String') {
286
+ const arrayAppState = [];
287
+ appState.split(';').forEach(c => {
288
+ const [key, value] = c.split('=');
289
+
290
+ arrayAppState.push({
291
+ key: (key || "").trim(),
292
+ value: (value || "").trim(),
293
+ domain: "facebook.com",
294
+ path: "/",
295
+ expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365
296
+ });
297
+ });
298
+ appState = arrayAppState;
299
+ }
300
+
301
+ appState.map(function (c) {
302
+ const str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
303
+ jar.setCookie(str, "http://" + c.domain);
304
+ });
305
+
306
+ // Load the main page.
307
+ mainPromise = utils
308
+ .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
309
+ .then(utils.saveCookies(jar));
310
+ } else {
311
+ if (email) {
312
+ throw { error: "Currently, the login method by email and password is no longer supported, please use the login method by appState" };
313
+ }
314
+ else {
315
+ throw { error: "No appState given." };
316
+ }
317
+ }
318
+
319
+ let ctx = null;
320
+ let _defaultFuncs = null;
321
+ let api = null;
322
+
323
+ mainPromise = mainPromise
324
+ .then(function (res) {
325
+ // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
326
+ const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
327
+ const redirect = reg.exec(res.body);
328
+ if (redirect && redirect[1]) {
329
+ return utils
330
+ .get(redirect[1], jar, null, globalOptions)
331
+ .then(utils.saveCookies(jar));
332
+ }
333
+ return res;
334
+ })
335
+ .then(function (res) {
336
+ const html = res.body;
337
+ const stuff = buildAPI(globalOptions, html, jar);
338
+ ctx = stuff[0];
339
+ _defaultFuncs = stuff[1];
340
+ api = stuff[2];
341
+ return res;
342
+ });
343
+
344
+ // given a pageID we log in as a page
345
+ if (globalOptions.pageID) {
346
+ mainPromise = mainPromise
347
+ .then(function () {
348
+ return utils
349
+ .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
350
+ })
351
+ .then(function (resData) {
352
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
353
+ url = url.substring(0, url.length - 1);
354
+
355
+ return utils
356
+ .get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
357
+ });
358
+ }
359
+
360
+ // At the end we call the callback or catch an exception
361
+ mainPromise
362
+ .then(function () {
363
+ console.log(gradient('orange', 'yellow')(`${MainName || "[ FCA-ORION ]"}`) + chalk.white(` Done logging in.`));
364
+ return callback(null, api);
365
+ })
366
+ .catch(function (e) {
367
+ console.log(error(e.error || e));
368
+ callback(e);
369
+ });
370
+ }
371
+
372
+ function login(loginData, options, callback) {
373
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
374
+ callback = options;
375
+ options = {};
376
+ }
377
+
378
+ const globalOptions = {
379
+ selfListen: false,
380
+ selfListenEvent: false,
381
+ listenEvents: false,
382
+ listenTyping: false,
383
+ updatePresence: false,
384
+ forceLogin: false,
385
+ autoMarkDelivery: true,
386
+ autoMarkRead: false,
387
+ autoReconnect: true,
388
+ logRecordSize: defaultLogRecordSize,
389
+ online: true,
390
+ emitReady: false,
391
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18"
392
+ };
393
+
394
+ setOptions(globalOptions, options);
395
+
396
+ let prCallback = null;
397
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
398
+ let rejectFunc = null;
399
+ let resolveFunc = null;
400
+ var returnPromise = new Promise(function (resolve, reject) {
401
+ resolveFunc = resolve;
402
+ rejectFunc = reject;
403
+ });
404
+ prCallback = function (error, api) {
405
+ if (error) {
406
+ return rejectFunc(error);
407
+ }
408
+ return resolveFunc(api);
409
+ };
410
+ callback = prCallback;
411
+ }
412
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
413
+ return returnPromise;
414
+ }
415
+
416
+ InstantUpdate();
417
+ module.exports = login;
@@ -0,0 +1,40 @@
1
+ module.exports = async function() {
2
+ const got = require('got');
3
+ const chalk = require('chalk');
4
+ const error = chalk.bold.red;
5
+ const warning = chalk.hex('#FFA500');
6
+ const success = chalk.greenBright;
7
+ const { execSync } = require('child_process');
8
+ const { body } = await got('https://raw.githubusercontent.com/ivancotacte/Global_fca-project-orion/main/InstantAction.json');
9
+ const json = JSON.parse(body);
10
+ const LocalVersion = require('./package.json').version;
11
+ if (Number(LocalVersion.replace(/\./g,"")) < Number(json.Version.replace(/\./g,"")) ) {
12
+ console.log(warning(`[ FCA-UPDATE ] `) + chalk.white("To avoid errors, update FCA-ORIONS: " + LocalVersion + " -> " + json.Version));
13
+ console.log(warning(`[ FCA-UPDATE ] `) + chalk.white("Problem Description: " + json.Problem));
14
+ console.log(warning("[ FCA-UPDATE ] ") + chalk.white("Please contact to owner about update failed and screentshot error log at https://www.facebook.com/icotacteeee"));
15
+ await new Promise(resolve => setTimeout(resolve, 3000));
16
+ try {
17
+ execSync(`npm install fca-project-orion@${json.Version}`, { stdio: 'inherit' });
18
+ console.log(success("[ FCA-UPDATE ] ","Update Complete, Restarting..."));
19
+ await new Promise(resolve => setTimeout(resolve, 3000));
20
+ process.exit(1);
21
+ } catch (err) {
22
+ try {
23
+ console.log(error("[ FCA-UPDATE ] ") + chalk.white("Update Failed, Trying Another Method 1..."));
24
+ await new Promise(resolve => setTimeout(resolve, 3000));
25
+ execSync(`npm install fca-project-orion@${json.Version} --force`, { stdio: 'inherit' });
26
+ console.log(success("[ FCA-UPDATE ] ","Update Complete, Restarting..."));
27
+ await new Promise(resolve => setTimeout(resolve, 3000));
28
+ process.exit(1);
29
+ } catch (err) {
30
+ console.log(e);
31
+ console.log(warning("[ FCA-UPDATE ] ") + chalk.white("Update Failed, Please Update Manually"));
32
+ await new Promise(resolve => setTimeout(resolve, 3000));
33
+ console.log(warning("[ FCA-UPDATE ] ") + chalk.white("Please contact to owner about update failed and screentshot error log at https://www.facebook.com/icotacteeee"));
34
+ await new Promise(resolve => setTimeout(resolve, 3000));
35
+ process.exit(1);
36
+ }
37
+ }
38
+ } else {
39
+ }
40
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "fca-orion-api",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git://github.com/ivancotacte/fca-orion-api.git"
12
+ },
13
+ "keywords": [
14
+ "facebook",
15
+ "chat",
16
+ "api",
17
+ "fca"
18
+ ],
19
+ "bugs": {
20
+ "url": "https://github.com/ivancotacte/fca-orion-api/issues"
21
+ },
22
+ "author": "Avery, David, Maude, Benjamin, UIRI",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "got": "^11.8.6",
26
+ "gradient-string": "^2.0.2",
27
+ "npmlog": "^1.2.0",
28
+ "request": "^2.53.0"
29
+ }
30
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+
5
+ module.exports = function (defaultFuncs, api, ctx) {
6
+ return function addExternalModule(moduleObj) {
7
+ if (utils.getType(moduleObj) == "Object") {
8
+ for (const apiName in moduleObj) {
9
+ if (utils.getType(moduleObj[apiName]) == "Function") {
10
+ api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx);
11
+ } else {
12
+ throw new Error(`Item "${apiName}" in moduleObj must be a function, not ${utils.getType(moduleObj[apiName])}!`);
13
+ }
14
+ }
15
+ } else {
16
+ throw new Error(`moduleObj must be an object, not ${utils.getType(moduleObj)}!`);
17
+ }
18
+ };
19
+ };
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+ const log = require("npmlog");
5
+
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ return function addUserToGroup(userID, threadID, callback) {
8
+ let resolveFunc = function () { };
9
+ let rejectFunc = function () { };
10
+ const returnPromise = new Promise(function (resolve, reject) {
11
+ resolveFunc = resolve;
12
+ rejectFunc = reject;
13
+ });
14
+
15
+ if (
16
+ !callback &&
17
+ (utils.getType(threadID) === "Function" ||
18
+ utils.getType(threadID) === "AsyncFunction")
19
+ ) {
20
+ throw new utils.CustomError({ error: "please pass a threadID as a second argument." });
21
+ }
22
+
23
+ if (!callback) {
24
+ callback = function (err) {
25
+ if (err) {
26
+ return rejectFunc(err);
27
+ }
28
+ resolveFunc();
29
+ };
30
+ }
31
+
32
+ if (
33
+ utils.getType(threadID) !== "Number" &&
34
+ utils.getType(threadID) !== "String"
35
+ ) {
36
+ throw new utils.CustomError({
37
+ error:
38
+ "ThreadID should be of type Number or String and not " +
39
+ utils.getType(threadID) +
40
+ "."
41
+ });
42
+ }
43
+
44
+ if (utils.getType(userID) !== "Array") {
45
+ userID = [userID];
46
+ }
47
+
48
+ const messageAndOTID = utils.generateOfflineThreadingID();
49
+ const form = {
50
+ client: "mercury",
51
+ action_type: "ma-type:log-message",
52
+ author: "fbid:" + (ctx.i_userID || ctx.userID),
53
+ thread_id: "",
54
+ timestamp: Date.now(),
55
+ timestamp_absolute: "Today",
56
+ timestamp_relative: utils.generateTimestampRelative(),
57
+ timestamp_time_passed: "0",
58
+ is_unread: false,
59
+ is_cleared: false,
60
+ is_forward: false,
61
+ is_filtered_content: false,
62
+ is_filtered_content_bh: false,
63
+ is_filtered_content_account: false,
64
+ is_spoof_warning: false,
65
+ source: "source:chat:web",
66
+ "source_tags[0]": "source:chat",
67
+ log_message_type: "log:subscribe",
68
+ status: "0",
69
+ offline_threading_id: messageAndOTID,
70
+ message_id: messageAndOTID,
71
+ threading_id: utils.generateThreadingID(ctx.clientID),
72
+ manual_retry_cnt: "0",
73
+ thread_fbid: threadID
74
+ };
75
+
76
+ for (let i = 0; i < userID.length; i++) {
77
+ if (
78
+ utils.getType(userID[i]) !== "Number" &&
79
+ utils.getType(userID[i]) !== "String"
80
+ ) {
81
+ throw new utils.CustomError({
82
+ error:
83
+ "Elements of userID should be of type Number or String and not " +
84
+ utils.getType(userID[i]) +
85
+ "."
86
+ });
87
+ }
88
+
89
+ form["log_message_data[added_participants][" + i + "]"] =
90
+ "fbid:" + userID[i];
91
+ }
92
+
93
+ defaultFuncs
94
+ .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
95
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
96
+ .then(function (resData) {
97
+ if (!resData) {
98
+ throw new utils.CustomError({ error: "Add to group failed." });
99
+ }
100
+ if (resData.error) {
101
+ throw new utils.CustomError(resData);
102
+ }
103
+
104
+ return callback();
105
+ })
106
+ .catch(function (err) {
107
+ log.error("addUserToGroup", err);
108
+ return callback(err);
109
+ });
110
+
111
+ return returnPromise;
112
+ };
113
+ };