@cexy/hoonfca 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +83 -0
  2. package/index.js +467 -0
  3. package/package.json +12 -0
  4. package/replit.nix +3 -0
  5. package/src/addExternalModule.js +25 -0
  6. package/src/addUserToGroup.js +98 -0
  7. package/src/changeAdminStatus.js +98 -0
  8. package/src/changeArchivedStatus.js +51 -0
  9. package/src/changeAvatar.js +89 -0
  10. package/src/changeBio.js +74 -0
  11. package/src/changeBlockedStatus.js +45 -0
  12. package/src/changeBlockedStatusMqtt.js +65 -0
  13. package/src/changeCover.js +92 -0
  14. package/src/changeGroupImage.js +110 -0
  15. package/src/changeName.js +106 -0
  16. package/src/changeNickname.js +58 -0
  17. package/src/changeThreadColor.js +62 -0
  18. package/src/changeThreadEmoji.js +54 -0
  19. package/src/changeUsername.js +80 -0
  20. package/src/createCommentPost.js +196 -0
  21. package/src/createNewGroup.js +81 -0
  22. package/src/createPoll.js +64 -0
  23. package/src/createPost.js +285 -0
  24. package/src/data/getThreadInfo.json +1 -0
  25. package/src/deleteMessage.js +55 -0
  26. package/src/deleteThread.js +55 -0
  27. package/src/editMessage.js +66 -0
  28. package/src/follow.js +71 -0
  29. package/src/forwardAttachment.js +57 -0
  30. package/src/getAccess.js +130 -0
  31. package/src/getAvatarUser.js +88 -0
  32. package/src/getBotInitialData.js +59 -0
  33. package/src/getCtx.js +5 -0
  34. package/src/getCurrentUserID.js +5 -0
  35. package/src/getEmojiUrl.js +18 -0
  36. package/src/getFriendsList.js +81 -0
  37. package/src/getMessage.js +827 -0
  38. package/src/getOptions.js +5 -0
  39. package/src/getRegion.js +7 -0
  40. package/src/getThreadHistory.js +496 -0
  41. package/src/getThreadHistoryDeprecated.js +95 -0
  42. package/src/getThreadInfo.js +194 -0
  43. package/src/getThreadInfoDeprecated.js +77 -0
  44. package/src/getThreadList.js +219 -0
  45. package/src/getThreadListDeprecated.js +86 -0
  46. package/src/getThreadPictures.js +85 -0
  47. package/src/getUserID.js +67 -0
  48. package/src/getUserInfo.js +89 -0
  49. package/src/handleFriendRequest.js +56 -0
  50. package/src/handleMessageRequest.js +65 -0
  51. package/src/httpGet.js +53 -0
  52. package/src/httpPost.js +53 -0
  53. package/src/httpPostFormData.js +58 -0
  54. package/src/listenMqtt.js +683 -0
  55. package/src/listenNotification.js +96 -0
  56. package/src/logout.js +77 -0
  57. package/src/markAsDelivered.js +53 -0
  58. package/src/markAsRead.js +74 -0
  59. package/src/markAsReadAll.js +46 -0
  60. package/src/markAsSeen.js +57 -0
  61. package/src/muteThread.js +49 -0
  62. package/src/pinMessage.js +60 -0
  63. package/src/refreshFb_dtsg.js +75 -0
  64. package/src/removeUserFromGroup.js +59 -0
  65. package/src/resolvePhotoUrl.js +47 -0
  66. package/src/searchForThread.js +55 -0
  67. package/src/searchStickers.js +59 -0
  68. package/src/sendMessage.js +444 -0
  69. package/src/sendMessageMqtt.js +326 -0
  70. package/src/sendTypingIndicator.js +54 -0
  71. package/src/setMessageReaction.js +126 -0
  72. package/src/setMessageReactionMqtt.js +74 -0
  73. package/src/setPostReaction.js +103 -0
  74. package/src/setProfileGuard.js +66 -0
  75. package/src/setStoryReaction.js +97 -0
  76. package/src/setTitle.js +100 -0
  77. package/src/shareContact.js +101 -0
  78. package/src/shareLink.js +105 -0
  79. package/src/stopListenMqtt.js +47 -0
  80. package/src/threadColors.js +119 -0
  81. package/src/unfriend.js +58 -0
  82. package/src/unsendMessage.js +51 -0
  83. package/src/uploadAttachment.js +98 -0
  84. package/utils.js +919 -0
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ @cexy/hoonfca
2
+
3
+ A modern, fast, and actively maintained Facebook Chat API for Node.js.
4
+ Built for Messenger bots with improved stability, performance, and compatibility.
5
+
6
+ ---
7
+
8
+ 📦 Installation
9
+
10
+ Install the package using npm:
11
+
12
+ npm install @cexy/rakibfca
13
+
14
+ ---
15
+
16
+ 🚀 Usage
17
+
18
+ const login = require("@cexy/rakibfca");
19
+
20
+ login(
21
+ {
22
+ appState: require("./appstate.json")
23
+ },
24
+ (err, api) => {
25
+ if (err) return console.error(err);
26
+
27
+ console.log("Logged in as:", api.getCurrentUserID());
28
+
29
+ api.listenMqtt((err, event) => {
30
+ if (err) return console.error(err);
31
+
32
+ console.log(event);
33
+ });
34
+ }
35
+ );
36
+
37
+ ---
38
+
39
+ ✨ Features
40
+
41
+ - ⚡ Fast and lightweight
42
+ - 🔒 AppState login support
43
+ - 💬 Messenger API support
44
+ - 📩 MQTT listener
45
+ - 🛠️ Regular bug fixes
46
+ - 🚀 Performance improvements
47
+ - 📦 Easy integration with Node.js projects
48
+
49
+ ---
50
+
51
+ 📋 Requirements
52
+
53
+ - Node.js 20+
54
+ - npm 10+
55
+
56
+ ---
57
+
58
+ 📖 Installation Example
59
+
60
+ mkdir my-bot
61
+ cd my-bot
62
+ npm init -y
63
+ npm install @cexy/rakibfca
64
+
65
+ ---
66
+
67
+ 🤝 Contributing
68
+
69
+ Contributions, bug reports, and feature requests are always welcome.
70
+
71
+ ---
72
+
73
+ 📄 License
74
+
75
+ MIT License
76
+
77
+ ---
78
+
79
+ 👨‍💻 Author
80
+
81
+ Rakib Hasan
82
+
83
+ NPM: @cexy/hoonfca
package/index.js ADDED
@@ -0,0 +1,467 @@
1
+ "use strict";
2
+
3
+ const utils = require("./utils");
4
+ const cheerio = require("cheerio");
5
+ const log = require("npmlog");
6
+
7
+ log.maxRecordSize = 100;
8
+ const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
9
+ global.ditconmemay = false;
10
+
11
+ function setOptions(globalOptions, options) {
12
+ Object.keys(options).forEach(function (key) {
13
+ switch (Boolean_Option.includes(key)) {
14
+ case true: {
15
+ globalOptions[key] = Boolean(options[key]);
16
+ break;
17
+ }
18
+ case false: {
19
+ switch (key) {
20
+ case 'pauseLog': {
21
+ if (options.pauseLog) log.pause();
22
+ else log.resume();
23
+ break;
24
+ }
25
+ case 'logLevel': {
26
+ log.level = options.logLevel;
27
+ globalOptions.logLevel = options.logLevel;
28
+ break;
29
+ }
30
+ case 'logRecordSize': {
31
+ log.maxRecordSize = options.logRecordSize;
32
+ globalOptions.logRecordSize = options.logRecordSize;
33
+ break;
34
+ }
35
+ case 'pageID': {
36
+ globalOptions.pageID = options.pageID.toString();
37
+ break;
38
+ }
39
+ case 'userAgent': {
40
+ globalOptions.userAgent = (options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36');
41
+ break;
42
+ }
43
+ case 'proxy': {
44
+ if (typeof options.proxy !== "string") {
45
+ delete globalOptions.proxy;
46
+ utils.setProxy();
47
+ } else {
48
+ globalOptions.proxy = options.proxy;
49
+ utils.setProxy(globalOptions.proxy);
50
+ }
51
+ break;
52
+ }
53
+ default: {
54
+ log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
55
+ break;
56
+ }
57
+ }
58
+ break;
59
+ }
60
+ }
61
+ });
62
+ }
63
+
64
+ function buildAPI(globalOptions, html, jar) {
65
+ let fb_dtsg = null;
66
+ let irisSeqID = null;
67
+
68
+ function extractFromHTML() {
69
+ try {
70
+ const $ = cheerio.load(html);
71
+ const patterns = [
72
+ /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
73
+ /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
74
+ /"token":"([^"]+)"/,
75
+ /{\\"token\\":\\"([^\\]+)\\"/,
76
+ /,\{"token":"([^"]+)"\},\d+\]/,
77
+ /"async_get_token":"([^"]+)"/,
78
+ /"dtsg":\{"token":"([^"]+)"/,
79
+ /DTSGInitialData[^>]+>([^<]+)/
80
+ ];
81
+
82
+ const scripts = $('script').get();
83
+ for (const script of scripts) {
84
+ const scriptText = $(script).html() || '';
85
+ for (const pattern of patterns) {
86
+ const match = scriptText.match(pattern);
87
+ if (match && match[1]) {
88
+ fb_dtsg = match[1].includes('\\"') ? match[1].replace(/\\"/g, '"') : match[1];
89
+ if (fb_dtsg.startsWith('{')) {
90
+ try { fb_dtsg = JSON.parse(fb_dtsg).token || fb_dtsg; } catch(e){}
91
+ }
92
+ break;
93
+ }
94
+ }
95
+ if (fb_dtsg) break;
96
+ }
97
+
98
+ if (!fb_dtsg) {
99
+ const dtsgInput = $('input[name="fb_dtsg"]').val();
100
+ if (dtsgInput) fb_dtsg = dtsgInput;
101
+ }
102
+
103
+ const seqMatches = html.match(/irisSeqID":"([^"]+)"/);
104
+ if (seqMatches && seqMatches[1]) {
105
+ irisSeqID = seqMatches[1];
106
+ }
107
+
108
+ if (!fb_dtsg) {
109
+ const jsonMatches = html.match(/\{"dtsg":({[^}]+})/);
110
+ if (jsonMatches && jsonMatches[1]) {
111
+ try {
112
+ const dtsgData = JSON.parse(jsonMatches[1]);
113
+ if (dtsgData.token) fb_dtsg = dtsgData.token;
114
+ } catch(e){}
115
+ }
116
+ }
117
+
118
+ if (fb_dtsg) {
119
+ console.log("Đã tìm thấy fb_dtsg");
120
+ }
121
+ } catch (e) {
122
+ console.log("Lỗi khi tìm fb_dtsg:", e);
123
+ }
124
+ }
125
+
126
+ extractFromHTML();
127
+ let userID;
128
+ const cookies = jar.getCookies("https://www.facebook.com");
129
+ const userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
130
+ const tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
131
+
132
+ if (!userCookie && !tiktikCookie) {
133
+ return log.error('login', "Không tìm thấy cookie cho người dùng, vui lòng kiểm tra lại thông tin đăng nhập");
134
+ }
135
+ if (html.includes("/checkpoint/block/?next")) {
136
+ return log.error('login', "Appstate die, vui lòng thay cái mới!", 'error');
137
+ }
138
+
139
+ userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
140
+ const clientID = (Math.random() * 2147483648 | 0).toString(16);
141
+ let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=prn&sid=${userID}`;
142
+ let region = "PRN";
143
+
144
+ try {
145
+ if (html.includes("601051028565049")) {
146
+ console.log(`lỗi login vì dính tài khoản tự động`);
147
+ global.ditconmemay = true;
148
+ }
149
+ const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
150
+ if (endpointMatch && endpointMatch[1]) {
151
+ mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
152
+ const url = new URL(mqttEndpoint);
153
+ region = url.searchParams.get('region')?.toUpperCase() || "PRN";
154
+ }
155
+ } catch (e) {
156
+ console.log('Using default MQTT endpoint');
157
+ }
158
+
159
+ log.info('login', 'Fix fca by DongDev x Satoru, published By Team Calyx');
160
+
161
+ const ctx = {
162
+ userID: userID,
163
+ jar: jar,
164
+ clientID: clientID,
165
+ globalOptions: globalOptions,
166
+ loggedIn: true,
167
+ access_token: 'NONE',
168
+ clientMutationId: 0,
169
+ mqttClient: undefined,
170
+ lastSeqId: irisSeqID,
171
+ syncToken: undefined,
172
+ mqttEndpoint: mqttEndpoint,
173
+ region: region,
174
+ firstListen: true,
175
+ fb_dtsg: fb_dtsg,
176
+ req_ID: 0,
177
+ callback_Task: {},
178
+ wsReqNumber: 0,
179
+ wsTaskNumber: 0,
180
+ reqCallbacks: {}
181
+ };
182
+
183
+ const defaultFuncs = utils.makeDefaults(html, userID, ctx);
184
+ const api = {
185
+ setOptions: setOptions.bind(null, globalOptions),
186
+ getAppState: () => utils.getAppState(jar),
187
+ postFormData: function (url, body) {
188
+ return defaultFuncs.postFormData(url, ctx.jar, body);
189
+ }
190
+ };
191
+
192
+ api.getFreshDtsg = async function () {
193
+ try {
194
+ const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
195
+ const $ = cheerio.load(res.body);
196
+ let newDtsg;
197
+ const patterns = [
198
+ /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
199
+ /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
200
+ /"token":"([^"]+)"/,
201
+ /name="fb_dtsg" value="([^"]+)"/
202
+ ];
203
+
204
+ const scripts = $('script').get();
205
+ for (const script of scripts) {
206
+ const scriptText = $(script).html() || '';
207
+ for (const pattern of patterns) {
208
+ const match = scriptText.match(pattern);
209
+ if (match && match[1]) {
210
+ newDtsg = match[1];
211
+ break;
212
+ }
213
+ }
214
+ if (newDtsg) break;
215
+ }
216
+
217
+ if (!newDtsg) {
218
+ newDtsg = $('input[name="fb_dtsg"]').val();
219
+ }
220
+
221
+ return newDtsg;
222
+ } catch (e) {
223
+ console.log("Error getting fresh dtsg:", e);
224
+ return null;
225
+ }
226
+ };
227
+
228
+ require('fs').readdirSync(__dirname + '/src/')
229
+ .filter(v => v.endsWith('.js'))
230
+ .forEach(v => {
231
+ api[v.replace('.js', '')] = require(`./src/${v}`)(defaultFuncs, api, ctx);
232
+ });
233
+
234
+ api.listen = api.listenMqtt;
235
+ return { ctx, defaultFuncs, api };
236
+ }
237
+
238
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
239
+ return async function (res) {
240
+ try {
241
+ const html = res.body;
242
+ const $ = cheerio.load(html);
243
+ let arr = [];
244
+ $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
245
+ arr = arr.filter(v => v.val && v.val.length);
246
+ const form = utils.arrToForm(arr);
247
+ form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
248
+ form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
249
+ form.email = email;
250
+ form.pass = password;
251
+ form.default_persistent = '0';
252
+ form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
253
+ form.locale = 'en_US';
254
+ form.timezone = '240';
255
+ form.lgnjs = Math.floor(Date.now() / 1000);
256
+
257
+ const willBeCookies = html.split("\"_js_");
258
+ willBeCookies.slice(1).forEach(val => {
259
+ try {
260
+ const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
261
+ jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
262
+ } catch(e){}
263
+ });
264
+
265
+ log.info("login", "Logging in...");
266
+ const loginRes = await utils.post(
267
+ "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
268
+ jar,
269
+ form,
270
+ loginOptions
271
+ );
272
+ await utils.saveCookies(jar)(loginRes);
273
+ const headers = loginRes.headers;
274
+ if (!headers.location) throw new Error("Wrong username/password.");
275
+
276
+ if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
277
+ log.info("login", "You have login approvals turned on.");
278
+ const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
279
+ await utils.saveCookies(jar)(checkpointRes);
280
+ const checkpointHtml = checkpointRes.body;
281
+ const $c = cheerio.load(checkpointHtml);
282
+ let checkpointForm = [];
283
+ $c("form input").each((i, v) => checkpointForm.push({ val: $c(v).val(), name: $c(v).attr("name") }));
284
+ checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
285
+ const form2fa = utils.arrToForm(checkpointForm);
286
+
287
+ if (checkpointHtml.includes("checkpoint/?next")) {
288
+ return new Promise((resolve, reject) => {
289
+ const submit2FA = async (code) => {
290
+ try {
291
+ form2fa.approvals_code = code;
292
+ form2fa['submit[Continue]'] = $c("#checkpointSubmitButton").html();
293
+ const approvalRes = await utils.post(
294
+ "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
295
+ jar,
296
+ form2fa,
297
+ loginOptions
298
+ );
299
+ await utils.saveCookies(jar)(approvalRes);
300
+ const $a = cheerio.load(approvalRes.body);
301
+ const approvalError = $a("#approvals_code").parent().attr("data-xui-error");
302
+ if (approvalError) throw new Error("Invalid 2FA code.");
303
+
304
+ form2fa.name_action_selected = 'dont_save';
305
+ const finalRes = await utils.post(
306
+ "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
307
+ jar,
308
+ form2fa,
309
+ loginOptions
310
+ );
311
+ await utils.saveCookies(jar)(finalRes);
312
+ const appState = utils.getAppState(jar);
313
+ resolve(await loginHelper(appState, email, password, loginOptions, callback, prCallback));
314
+ } catch (error) {
315
+ reject(error);
316
+ }
317
+ };
318
+ throw {
319
+ error: 'login-approval',
320
+ continue: submit2FA
321
+ };
322
+ });
323
+ }
324
+ if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
325
+ form2fa['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
326
+ await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form2fa, loginOptions);
327
+ form2fa.name_action_selected = 'save_device';
328
+ await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form2fa, loginOptions);
329
+ const appState = utils.getAppState(jar);
330
+ return await loginHelper(appState, email, password, loginOptions, callback, prCallback);
331
+ }
332
+ await utils.get('https://www.facebook.com/', jar, null, loginOptions);
333
+ return await utils.saveCookies(jar)(loginRes);
334
+ } catch (error) {
335
+ callback(error);
336
+ }
337
+ };
338
+ }
339
+
340
+ function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
341
+ let mainPromise = null;
342
+ const jar = utils.getJar();
343
+ if (appState) {
344
+ try {
345
+ if (typeof appState === 'string') {
346
+ appState = JSON.parse(appState);
347
+ }
348
+ } catch (e) {
349
+ return callback(new Error("Failed to parse appState"));
350
+ }
351
+
352
+ try {
353
+ appState.forEach(c => {
354
+ const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
355
+ jar.setCookie(str, "https://" + c.domain);
356
+ });
357
+ mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
358
+ .then(utils.saveCookies(jar));
359
+ } catch (e) {
360
+ return callback(new Error("Failed to load appState cookies: " + e.message));
361
+ }
362
+ } else {
363
+ mainPromise = utils
364
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
365
+ .then(utils.saveCookies(jar))
366
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
367
+ .then(() => utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar)));
368
+ }
369
+
370
+ function handleRedirect(res) {
371
+ const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
372
+ const redirect = reg.exec(res.body);
373
+ if (redirect && redirect[1]) {
374
+ return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
375
+ }
376
+ return res;
377
+ }
378
+
379
+ mainPromise = mainPromise
380
+ .then(handleRedirect)
381
+ .then(res => {
382
+ if (!/MPageLoadClientMetrics/gs.test(res.body)) {
383
+ globalOptions.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36";
384
+ return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
385
+ }
386
+ return res;
387
+ })
388
+ .then(handleRedirect)
389
+ .then(res => {
390
+ const Obj = buildAPI(globalOptions, res.body, jar);
391
+ return Obj ? Obj.api : null;
392
+ });
393
+
394
+ if (globalOptions.pageID) {
395
+ mainPromise = mainPromise
396
+ .then((api) => utils.get(`https://www.facebook.com/${globalOptions.pageID}/messages/?section=messages&subsection=inbox`, jar, null, globalOptions).then(resData => ({api, resData})))
397
+ .then(({api, resData}) => {
398
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
399
+ url = url.substring(0, url.length - 1);
400
+ return utils.get('https://www.facebook.com' + url, jar, null, globalOptions).then(() => api);
401
+ });
402
+ }
403
+
404
+ mainPromise
405
+ .then((api) => {
406
+ if(api) {
407
+ log.info('login', 'Đăng nhập thành công');
408
+ callback(null, api);
409
+ }
410
+ })
411
+ .catch(e => {
412
+ callback(e);
413
+ });
414
+ }
415
+
416
+ function login(loginData, options, callback) {
417
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
418
+ callback = options;
419
+ options = {};
420
+ }
421
+
422
+ const globalOptions = {
423
+ selfListen: false,
424
+ listenEvents: true,
425
+ listenTyping: false,
426
+ updatePresence: false,
427
+ forceLogin: false,
428
+ autoMarkDelivery: false,
429
+ autoMarkRead: false,
430
+ autoReconnect: true,
431
+ logRecordSize: 100,
432
+ online: false,
433
+ emitReady: false,
434
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
435
+ };
436
+
437
+ let prCallback = null;
438
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
439
+ let rejectFunc = null;
440
+ let resolveFunc = null;
441
+ const returnPromise = new Promise(function (resolve, reject) {
442
+ resolveFunc = resolve;
443
+ rejectFunc = reject;
444
+ });
445
+ prCallback = function (error, api) {
446
+ if (error) return rejectFunc(error);
447
+ return resolveFunc(api);
448
+ };
449
+ callback = prCallback;
450
+ }
451
+
452
+ if (loginData.email && loginData.password) {
453
+ setOptions(globalOptions, {
454
+ logLevel: "silent",
455
+ forceLogin: true,
456
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
457
+ });
458
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
459
+ } else if (loginData.appState) {
460
+ setOptions(globalOptions, options);
461
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
462
+ }
463
+
464
+ return prCallback ? returnPromise : null;
465
+ }
466
+
467
+ module.exports = login;
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@cexy/hoonfca",
3
+ "version": "1.0.0",
4
+ "description": "@cexy/hoonfca",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC"
12
+ }
package/replit.nix ADDED
@@ -0,0 +1,3 @@
1
+ {pkgs}: {
2
+ deps = [ ];
3
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+
5
+ module.exports = function (defaultFuncs, api, ctx) {
6
+ return function addExternalModule(moduleObj) {
7
+ const moduleType = utils.getType(moduleObj);
8
+
9
+ if (moduleType !== "Object") {
10
+ throw new Error(`moduleObj must be an object, not ${moduleType}!`);
11
+ }
12
+
13
+ Object.keys(moduleObj).forEach((apiName) => {
14
+ const functionType = utils.getType(moduleObj[apiName]);
15
+
16
+ if (functionType === "Function") {
17
+ api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx);
18
+ } else {
19
+ throw new Error(
20
+ `Item "${apiName}" in moduleObj must be a function, not ${functionType}!`
21
+ );
22
+ }
23
+ });
24
+ };
25
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+
5
+ module.exports = function (defaultFuncs, api, ctx) {
6
+ return function addUserToGroup(userID, threadID, callback) {
7
+ let resolveFunc = () => {};
8
+ let rejectFunc = () => {};
9
+ const returnPromise = new Promise((resolve, reject) => {
10
+ resolveFunc = resolve;
11
+ rejectFunc = reject;
12
+ });
13
+
14
+ const threadIDType = utils.getType(threadID);
15
+
16
+ if (!callback && (threadIDType === "Function" || threadIDType === "AsyncFunction")) {
17
+ throw new utils.CustomError({
18
+ error: "please pass a threadID as a second argument.",
19
+ });
20
+ }
21
+
22
+ if (!callback) {
23
+ callback = function (err) {
24
+ if (err) return rejectFunc(err);
25
+ resolveFunc();
26
+ };
27
+ }
28
+
29
+ if (threadIDType !== "Number" && threadIDType !== "String") {
30
+ throw new utils.CustomError({
31
+ error: `ThreadID should be of type Number or String and not ${threadIDType}.`,
32
+ });
33
+ }
34
+
35
+ // userID অ্যারে না হলে অ্যারেতে কনভার্ট করা হচ্ছে
36
+ if (utils.getType(userID) !== "Array") {
37
+ userID = [userID];
38
+ }
39
+
40
+ const messageAndOTID = utils.generateOfflineThreadingID();
41
+ const form = {
42
+ client: "mercury",
43
+ action_type: "ma-type:log-message",
44
+ author: "fbid:" + ctx.userID,
45
+ thread_id: "",
46
+ timestamp: Date.now(),
47
+ timestamp_absolute: "Today",
48
+ timestamp_relative: utils.generateTimestampRelative(),
49
+ timestamp_time_passed: "0",
50
+ is_unread: false,
51
+ is_cleared: false,
52
+ is_forward: false,
53
+ is_filtered_content: false,
54
+ is_filtered_content_bh: false,
55
+ is_filtered_content_account: false,
56
+ is_spoof_warning: false,
57
+ source: "source:chat:web",
58
+ "source_tags[0]": "source:chat",
59
+ log_message_type: "log:subscribe",
60
+ status: "0",
61
+ offline_threading_id: messageAndOTID,
62
+ message_id: messageAndOTID,
63
+ threading_id: utils.generateThreadingID(ctx.clientID),
64
+ manual_retry_cnt: "0",
65
+ thread_fbid: threadID,
66
+ };
67
+
68
+ // userID ভ্যালিডেশন এবং ফর্ম ডেটা বিল্ড
69
+ userID.forEach((id, index) => {
70
+ const idType = utils.getType(id);
71
+ if (idType !== "Number" && idType !== "String") {
72
+ throw new utils.CustomError({
73
+ error: `Elements of userID should be of type Number or String and not ${idType}.`,
74
+ });
75
+ }
76
+ form[`log_message_data[added_participants][${index}]`] = "fbid:" + id;
77
+ });
78
+
79
+ defaultFuncs
80
+ .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
81
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
82
+ .then(function (resData) {
83
+ if (!resData) {
84
+ throw new utils.CustomError({ error: "Add to group failed." });
85
+ }
86
+ if (resData.error) {
87
+ throw new utils.CustomError(resData);
88
+ }
89
+ return callback();
90
+ })
91
+ .catch(function (err) {
92
+ utils.error("addUserToGroup", err);
93
+ return callback(err);
94
+ });
95
+
96
+ return returnPromise;
97
+ };
98
+ };