ws-rapido 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/index.js +477 -0
  2. package/package.json +46 -0
  3. package/src/addExternalModule.js +25 -0
  4. package/src/addUserToGroup.js +115 -0
  5. package/src/changeAdminStatus.js +103 -0
  6. package/src/changeArchivedStatus.js +55 -0
  7. package/src/changeAvatar.js +136 -0
  8. package/src/changeAvatarV2.js +86 -0
  9. package/src/changeBio.js +76 -0
  10. package/src/changeBlockedStatus.js +49 -0
  11. package/src/changeBlockedStatusMqtt.js +80 -0
  12. package/src/changeCover.js +72 -0
  13. package/src/changeGroupImage.js +135 -0
  14. package/src/changeName.js +78 -0
  15. package/src/changeNickname.js +59 -0
  16. package/src/changeThreadColor.js +65 -0
  17. package/src/changeThreadEmoji.js +55 -0
  18. package/src/changeUsername.js +58 -0
  19. package/src/createCommentPost.js +229 -0
  20. package/src/createNewGroup.js +88 -0
  21. package/src/createPoll.js +71 -0
  22. package/src/createPost.js +275 -0
  23. package/src/data/getThreadInfo.json +1 -0
  24. package/src/deleteMessage.js +56 -0
  25. package/src/deleteThread.js +56 -0
  26. package/src/editMessage.js +76 -0
  27. package/src/follow.js +74 -0
  28. package/src/forwardAttachment.js +60 -0
  29. package/src/getAccess.js +111 -0
  30. package/src/getAvatarUser.js +78 -0
  31. package/src/getBotInitialData.js +43 -0
  32. package/src/getCtx.js +5 -0
  33. package/src/getCurrentUserID.js +7 -0
  34. package/src/getEmojiUrl.js +29 -0
  35. package/src/getFriendsList.js +83 -0
  36. package/src/getMessage.js +835 -0
  37. package/src/getOptions.js +5 -0
  38. package/src/getRegion.js +7 -0
  39. package/src/getThreadHistory.js +680 -0
  40. package/src/getThreadHistoryDeprecated.js +93 -0
  41. package/src/getThreadInfo.js +227 -0
  42. package/src/getThreadInfoDeprecated.js +80 -0
  43. package/src/getThreadList.js +269 -0
  44. package/src/getThreadListDeprecated.js +75 -0
  45. package/src/getThreadPictures.js +79 -0
  46. package/src/getUID.js +122 -0
  47. package/src/getUserID.js +66 -0
  48. package/src/getUserInfo.js +82 -0
  49. package/src/handleFriendRequest.js +57 -0
  50. package/src/handleMessageRequest.js +65 -0
  51. package/src/httpGet.js +64 -0
  52. package/src/httpPost.js +64 -0
  53. package/src/httpPostFormData.js +70 -0
  54. package/src/listenMqtt.js +674 -0
  55. package/src/listenNotification.js +85 -0
  56. package/src/logout.js +75 -0
  57. package/src/markAsDelivered.js +55 -0
  58. package/src/markAsRead.js +85 -0
  59. package/src/markAsReadAll.js +50 -0
  60. package/src/markAsSeen.js +61 -0
  61. package/src/muteThread.js +52 -0
  62. package/src/pinMessage.js +59 -0
  63. package/src/refreshFb_dtsg.js +89 -0
  64. package/src/removeUserFromGroup.js +79 -0
  65. package/src/resolvePhotoUrl.js +45 -0
  66. package/src/searchForThread.js +53 -0
  67. package/src/searchStickers.js +53 -0
  68. package/src/sendMessage.js +442 -0
  69. package/src/sendMessageMqtt.js +316 -0
  70. package/src/sendTypingIndicator.js +28 -0
  71. package/src/setMessageReaction.js +122 -0
  72. package/src/setMessageReactionMqtt.js +62 -0
  73. package/src/setPostReaction.js +108 -0
  74. package/src/setProfileGuard.js +44 -0
  75. package/src/setStoryReaction.js +64 -0
  76. package/src/setTitle.js +90 -0
  77. package/src/shareContact.js +110 -0
  78. package/src/shareLink.js +59 -0
  79. package/src/stopListenMqtt.js +23 -0
  80. package/src/threadColors.js +131 -0
  81. package/src/unfriend.js +52 -0
  82. package/src/unsendMessage.js +45 -0
  83. package/src/uploadAttachment.js +94 -0
  84. package/utils.js +1441 -0
package/index.js ADDED
@@ -0,0 +1,477 @@
1
+ "use strict";
2
+ const utils = require("./utils");
3
+ const fs = require("fs");
4
+ const cron = require("node-cron");
5
+ let globalOptions = {};
6
+ let ctx = null;
7
+ let _defaultFuncs = null;
8
+ let api = null;
9
+ let region;
10
+ const errorRetrieving = "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.";
11
+ async function setOptions(globalOptions_from, options = {}) {
12
+ Object.keys(options).map((key) => {
13
+ switch (key) {
14
+ case 'online':
15
+ globalOptions_from.online = Boolean(options.online);
16
+ break;
17
+ case 'selfListen':
18
+ globalOptions_from.selfListen = Boolean(options.selfListen);
19
+ break;
20
+ case 'selfListenEvent':
21
+ globalOptions_from.selfListenEvent = options.selfListenEvent;
22
+ break;
23
+ case 'listenEvents':
24
+ globalOptions_from.listenEvents = Boolean(options.listenEvents);
25
+ break;
26
+ case 'pageID':
27
+ globalOptions_from.pageID = options.pageID.toString();
28
+ break;
29
+ case 'updatePresence':
30
+ globalOptions_from.updatePresence = Boolean(options.updatePresence);
31
+ break;
32
+ case 'forceLogin':
33
+ globalOptions_from.forceLogin = Boolean(options.forceLogin);
34
+ break;
35
+ case 'userAgent':
36
+ globalOptions_from.userAgent = options.userAgent;
37
+ break;
38
+ case 'autoMarkDelivery':
39
+ globalOptions_from.autoMarkDelivery = Boolean(options.autoMarkDelivery);
40
+ break;
41
+ case 'autoMarkRead':
42
+ globalOptions_from.autoMarkRead = Boolean(options.autoMarkRead);
43
+ break;
44
+ case 'listenTyping':
45
+ globalOptions_from.listenTyping = Boolean(options.listenTyping);
46
+ break;
47
+ case 'proxy':
48
+ if (typeof options.proxy != "string") {
49
+ delete globalOptions_from.proxy;
50
+ utils.setProxy();
51
+ } else {
52
+ globalOptions_from.proxy = options.proxy;
53
+ utils.setProxy(globalOptions_from.proxy);
54
+ }
55
+ break;
56
+ case 'autoReconnect':
57
+ globalOptions_from.autoReconnect = Boolean(options.autoReconnect);
58
+ break;
59
+ case 'emitReady':
60
+ globalOptions_from.emitReady = Boolean(options.emitReady);
61
+ break;
62
+ case 'randomUserAgent':
63
+ globalOptions_from.randomUserAgent = Boolean(options.randomUserAgent);
64
+ if (globalOptions_from.randomUserAgent) {
65
+ globalOptions_from.userAgent = utils.randomUserAgent();
66
+ utils.warn("Random user agent enabled. This is an EXPERIMENTAL feature and I think this won't on some accounts. turn it on at your own risk. Contact the owner for more information about experimental features.");
67
+ utils.warn("randomUserAgent", "UA selected:", globalOptions_from.userAgent);
68
+ }
69
+ break;
70
+ case 'bypassRegion':
71
+ globalOptions_from.bypassRegion = options.bypassRegion;
72
+ break;
73
+ default:
74
+ break;
75
+ }
76
+ });
77
+ globalOptions = globalOptions_from;
78
+ }
79
+
80
+ async function updateDTSG(res, appstate, userId) {
81
+ try {
82
+ const appstateCUser = (appstate.find(i => i.key == 'i_user') || appstate.find(i => i.key == 'c_user'))
83
+ const UID = userId || appstateCUser.value;
84
+ if (!res || !res.body) {
85
+ throw new Error("Invalid response: Response body is missing.");
86
+ }
87
+ const fb_dtsg = utils.getFrom(res.body, '["DTSGInitData",[],{"token":"', '","');
88
+ const jazoest = utils.getFrom(res.body, 'jazoest=', '",');
89
+ if (fb_dtsg && jazoest) {
90
+ const filePath = 'fb_dtsg_data.json';
91
+ let existingData = {};
92
+ if (fs.existsSync(filePath)) {
93
+ const fileContent = fs.readFileSync(filePath, 'utf8');
94
+ existingData = JSON.parse(fileContent);
95
+ }
96
+ existingData[UID] = {
97
+ fb_dtsg,
98
+ jazoest
99
+ };
100
+ fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2), 'utf8');
101
+ }
102
+ return res;
103
+ } catch (error) {
104
+ utils.error(`Error updating DTSG for user ${userId}: ${error.message}`);
105
+ return;
106
+ }
107
+ }
108
+
109
+
110
+ let isBehavior = false;
111
+ async function bypassAutoBehavior(resp, jar, appstate, ID) {
112
+ try {
113
+ const appstateCUser = (appstate.find(i => i.key == 'c_user') || appstate.find(i => i.key == 'i_user'))
114
+ const UID = ID || appstateCUser.value;
115
+ const FormBypass = {
116
+ av: UID,
117
+ fb_api_caller_class: "RelayModern",
118
+ fb_api_req_friendly_name: "FBScrapingWarningMutation",
119
+ variables: JSON.stringify({}),
120
+ server_timestamps: true,
121
+ doc_id: 6339492849481770
122
+ }
123
+ const kupal = () => {
124
+ utils.warn(`We suspect automated behavior on account ${UID}. Some accounts might experience auto logout, and you need to resubmit your appstate again every automated behavior detection.`);
125
+ if (!isBehavior) isBehavior = true;
126
+ };
127
+ if (resp) {
128
+ if (resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
129
+ if (resp.request.uri.href.includes('601051028565049')) {
130
+ const fb_dtsg = utils.getFrom(resp.body, '["DTSGInitData",[],{"token":"', '","');
131
+ const jazoest = utils.getFrom(resp.body, 'jazoest=', '",');
132
+ const lsd = utils.getFrom(resp.body, "[\"LSD\",[],{\"token\":\"", "\"}");
133
+ return utils.post("https://www.facebook.com/api/graphql/", jar, {
134
+ ...FormBypass,
135
+ fb_dtsg,
136
+ jazoest,
137
+ lsd
138
+ }, globalOptions).then(utils.saveCookies(jar)).then(res => {
139
+ kupal();
140
+ return res;
141
+ });
142
+ } else return resp;
143
+ } else return resp;
144
+ }
145
+ } catch (e) {
146
+ utils.error(e);
147
+ }
148
+ }
149
+
150
+ async function checkIfSuspended(resp, appstate) {
151
+ try {
152
+ const appstateCUser = (appstate.find(i => i.key == 'c_user') || appstate.find(i => i.key == 'i_user'))
153
+ const UID = appstateCUser?.value;
154
+ const suspendReasons = {};
155
+ if (resp) {
156
+ if (resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
157
+ if (resp.request.uri.href.includes('1501092823525282')) {
158
+ const daystoDisable = resp.body?.match(/"log_out_uri":"(.*?)","title":"(.*?)"/);
159
+ if (daystoDisable && daystoDisable[2]) {
160
+ suspendReasons.durationInfo = daystoDisable[2];
161
+ utils.error(`Suspension time remaining:`, suspendReasons.durationInfo);
162
+ }
163
+ const reasonDescription = resp.body?.match(/"reason_section_body":"(.*?)"/);
164
+ if (reasonDescription && reasonDescription[1]) {
165
+ suspendReasons.longReason = reasonDescription?.[1];
166
+ const reasonReplace = suspendReasons?.longReason?.toLowerCase()?.replace("your account, or activity on it, doesn't follow our community standards on ", "");
167
+ suspendReasons.shortReason = reasonReplace?.substring(0, 1).toUpperCase() + reasonReplace?.substring(1);
168
+ utils.error(`Alert on ${UID}:`, `Account has been suspended!`);
169
+ utils.error(`Why suspended:`, suspendReasons.longReason)
170
+ utils.error(`Reason on suspension:`, suspendReasons.shortReason);
171
+ }
172
+ ctx = null;
173
+ return {
174
+ suspended: true,
175
+ suspendReasons
176
+ }
177
+ }
178
+ } else return;
179
+ }
180
+ } catch (error) {
181
+ return;
182
+ }
183
+ }
184
+
185
+ async function checkIfLocked(resp, appstate) {
186
+ try {
187
+ const appstateCUser = (appstate.find(i => i.key == 'c_user') || appstate.find(i => i.key == 'i_user'))
188
+ const UID = appstateCUser?.value;
189
+ const lockedReasons = {};
190
+ if (resp) {
191
+ if (resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
192
+ if (resp.request.uri.href.includes('828281030927956')) {
193
+ const lockDesc = resp.body.match(/"is_unvetted_flow":true,"title":"(.*?)"/);
194
+ if (lockDesc && lockDesc[1]) {
195
+ lockedReasons.reason = lockDesc[1];
196
+ utils.error(`Alert on ${UID}:`, lockedReasons.reason);
197
+ }
198
+ ctx = null;
199
+ return {
200
+ locked: true,
201
+ lockedReasons
202
+ }
203
+ }
204
+ } else return;
205
+ }
206
+ } catch (e) {
207
+ utils.error("error", e);
208
+ }
209
+ }
210
+
211
+ function buildAPI(html, jar) {
212
+ let fb_dtsg;
213
+ let userID;
214
+ const tokenMatch = html.match(/DTSGInitialData.*?token":"(.*?)"/);
215
+ if (tokenMatch) {
216
+ fb_dtsg = tokenMatch[1];
217
+ }
218
+ //hajime pogi
219
+ //@Kenneth Panio: i fixed the cookie do not change or remove this line what it does? we know that facebook account allow multiple profile in single account so it allow us to login which specific profile we use
220
+ let cookie = jar.getCookies("https://www.facebook.com");
221
+ let primary_profile = cookie.filter(function(val) {
222
+ return val.cookieString().split("=")[0] === "c_user";
223
+ });
224
+ let secondary_profile = cookie.filter(function(val) {
225
+ return val.cookieString().split("=")[0] === "i_user";
226
+ });
227
+ if (primary_profile.length === 0 && secondary_profile.length === 0) {
228
+ throw {
229
+ error: errorRetrieving,
230
+ };
231
+ } else {
232
+ if (html.indexOf("/checkpoint/block/?next") > -1) {
233
+ return utils.warn(
234
+ "login",
235
+ "Checkpoint detected. Please log in with a browser to verify."
236
+ );
237
+ }
238
+ if (secondary_profile[0] && secondary_profile[0].cookieString().includes('i_user')) {
239
+ userID = secondary_profile[0].cookieString().split("=")[1].toString();
240
+ } else {
241
+ userID = primary_profile[0].cookieString().split("=")[1].toString();
242
+ }
243
+ }
244
+ utils.log("Logged in!");
245
+ const clientID = (Math.random() * 2147483648 | 0).toString(16);
246
+ const CHECK_MQTT = {
247
+ oldFBMQTTMatch: html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/),
248
+ newFBMQTTMatch: html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/),
249
+ legacyFBMQTTMatch: html.match(/\["MqttWebConfig",\[\],{"fbid":"(.*?)","appID":219994525426954,"endpoint":"(.*?)","pollingEndpoint":"(.*?)"/)
250
+ }
251
+ let Slot = Object.keys(CHECK_MQTT);
252
+ let mqttEndpoint, irisSeqID;
253
+ Object.keys(CHECK_MQTT).map((MQTT) => {
254
+ if (globalOptions.bypassRegion) return;
255
+ if (CHECK_MQTT[MQTT] && !region) {
256
+ switch (Slot.indexOf(MQTT)) {
257
+ case 0: {
258
+ irisSeqID = CHECK_MQTT[MQTT][1];
259
+ mqttEndpoint = CHECK_MQTT[MQTT][2].replace(/\\\//g, "/");
260
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
261
+ break;
262
+ }
263
+ case 1: {
264
+ irisSeqID = CHECK_MQTT[MQTT][2];
265
+ mqttEndpoint = CHECK_MQTT[MQTT][1].replace(/\\\//g, "/");
266
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
267
+ break;
268
+ }
269
+ case 2: {
270
+ mqttEndpoint = CHECK_MQTT[MQTT][2].replace(/\\\//g, "/"); //this really important.
271
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
272
+ break;
273
+ }
274
+ }
275
+ return;
276
+ }
277
+ });
278
+ if (globalOptions.bypassRegion)
279
+ region = globalOptions.bypassRegion.toUpperCase();
280
+ else if (!region)
281
+ region = ["prn", "pnb", "vll", "hkg", "sin", "ftw", "ash"][Math.random() * 5 | 0].toUpperCase();
282
+ if (globalOptions.bypassRegion || !mqttEndpoint)
283
+ mqttEndpoint = "wss://edge-chat.facebook.com/chat?region=" + region;
284
+ let ctx = {
285
+ userID,
286
+ jar,
287
+ clientID,
288
+ globalOptions,
289
+ loggedIn: true,
290
+ access_token: 'NONE',
291
+ clientMutationId: 0,
292
+ mqttClient: undefined,
293
+ lastSeqId: irisSeqID,
294
+ syncToken: undefined,
295
+ mqttEndpoint,
296
+ wsReqNumber: 0,
297
+ wsTaskNumber: 0,
298
+ reqCallbacks: {},
299
+ region,
300
+ firstListen: true,
301
+ fb_dtsg
302
+ };
303
+ cron.schedule('0 0 * * *', () => {
304
+ const fbDtsgData = JSON.parse(fs.readFileSync('fb_dtsg_data.json', 'utf8'));
305
+ if (fbDtsgData && fbDtsgData[userID]) {
306
+ const userFbDtsg = fbDtsgData[userID];
307
+ api.refreshFb_dtsg(userFbDtsg)
308
+ .then(() => utils.log(`Fb_dtsg refreshed successfully for user ${userID}.`))
309
+ .catch((err) => utils.error(`Error during Fb_dtsg refresh for user ${userID}:`, err));
310
+ } else {
311
+ utils.error(`No fb_dtsg data found for user ${userID}.`);
312
+ }
313
+ }, {
314
+ timezone: 'Asia/Manila'
315
+ });
316
+ let defaultFuncs = utils.makeDefaults(html, userID, ctx);
317
+ return [ctx, defaultFuncs];
318
+ }
319
+
320
+ async function loginHelper(appState, email, password, apiCustomized = {}, callback) {
321
+ let mainPromise = null;
322
+ const jar = utils.getJar();
323
+ utils.log('Logging in...');
324
+ if (appState) {
325
+ if (utils.getType(appState) === 'Array' && appState.some(c => c.name)) {
326
+ appState = appState.map(c => {
327
+ c.key = c.name;
328
+ delete c.name;
329
+ return c;
330
+ });
331
+ }
332
+ else if (utils.getType(appState) === 'String') {
333
+ const arrayAppState = [];
334
+ appState.split(';').forEach(c => {
335
+ const [key, value] = c.split('=');
336
+ arrayAppState.push({
337
+ key: (key || "").trim(),
338
+ value: (value || "").trim(),
339
+ domain: ".facebook.com",
340
+ path: "/",
341
+ expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365
342
+ });
343
+ });
344
+ appState = arrayAppState;
345
+ }
346
+
347
+ appState.map(c => {
348
+ const str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
349
+ jar.setCookie(str, "http://" + c.domain);
350
+ });
351
+
352
+ mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
353
+ .then(utils.saveCookies(jar));
354
+ } else if (email && password) {
355
+ throw { error: "Credentials method is not implemented to ws3-fca yet. " };
356
+ } else {
357
+ throw { error: "Please provide either appState or credentials." };
358
+ }
359
+
360
+ api = {
361
+ setOptions: setOptions.bind(null, globalOptions),
362
+ getAppState() {
363
+ const appState = utils.getAppState(jar);
364
+ if (!Array.isArray(appState)) return [];
365
+ const uniqueAppState = appState.filter((item, index, self) => {
366
+ return self.findIndex((t) => t.key === item.key) === index;
367
+ });
368
+ return uniqueAppState.length > 0 ? uniqueAppState : appState;
369
+ }
370
+ };
371
+ mainPromise = mainPromise
372
+ .then(res => bypassAutoBehavior(res, jar, appState))
373
+ .then(res => updateDTSG(res, appState))
374
+ .then(async (res) => {
375
+ const resp = await utils.get(`https://www.facebook.com/home.php`, jar, null, globalOptions);
376
+ const html = resp?.body;
377
+ const stuff = await buildAPI(html, jar);
378
+ ctx = stuff[0];
379
+ _defaultFuncs = stuff[1];
380
+ api.addFunctions = (directory) => {
381
+ const folder = directory.endsWith("/") ? directory : (directory + "/");
382
+ fs.readdirSync(folder)
383
+ .filter(v => v.endsWith('.js'))
384
+ .map(v => {
385
+ api[v.replace('.js', '')] = require(folder + v)(_defaultFuncs, api, ctx);
386
+ });
387
+ }
388
+ api.addFunctions(__dirname + '/src');
389
+ api.listen = api.listenMqtt;
390
+ api.ws3 = {
391
+ ...apiCustomized
392
+ };
393
+ const bi = await api.getBotInitialData();
394
+ if (!bi.error) {
395
+ utils.log("Hello,", bi.name);
396
+ utils.log("My User ID:", bi.uid);
397
+ ctx.userName = bi.name;
398
+ } else {
399
+ utils.warn(bi.error);
400
+ utils.warn(`WARNING: Failed to fetch account info. Proceeding to log in for user ${ctx.userID}`);
401
+ }
402
+ utils.log("Connected to server region:", region || "UNKNOWN");
403
+ return res;
404
+ });
405
+ if (globalOptions.pageID) {
406
+ mainPromise = mainPromise
407
+ .then(function() {
408
+ return utils
409
+ .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
410
+ })
411
+ .then(function(resData) {
412
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
413
+ url = url.substring(0, url.length - 1);
414
+ return utils
415
+ .get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
416
+ });
417
+ }
418
+
419
+ mainPromise
420
+ .then(async (res) => {
421
+ const detectLocked = await checkIfLocked(res, appState);
422
+ if (detectLocked) throw detectLocked;
423
+ const detectSuspension = await checkIfSuspended(res, appState);
424
+ if (detectSuspension) throw detectSuspension;
425
+ utils.log("Successfully logged in.");
426
+ utils.log("To check updates: you may check on https://github.com/NethWs3Dev/ws3-fca");
427
+
428
+ return callback(null, api);
429
+ }).catch(e => callback(e));
430
+ }
431
+
432
+ async function login(loginData, options, callback) {
433
+ if (utils.getType(options) === 'Function' ||
434
+ utils.getType(options) === 'AsyncFunction') {
435
+ callback = options;
436
+ options = {};
437
+ }
438
+ const globalOptions = {
439
+ selfListen: false,
440
+ selfListenEvent: false,
441
+ listenEvents: true,
442
+ listenTyping: false,
443
+ updatePresence: false,
444
+ forceLogin: false,
445
+ autoMarkDelivery: false,
446
+ autoMarkRead: true,
447
+ autoReconnect: true,
448
+ online: true,
449
+ emitReady: false,
450
+ userAgent: utils.defaultUserAgent,
451
+ randomUserAgent: false
452
+ };
453
+ if (options) Object.assign(globalOptions, options);
454
+ const loginws3 = () => {
455
+ loginHelper(loginData?.appState, loginData?.email, loginData?.password, {
456
+ relogin() {
457
+ loginws3();
458
+ }
459
+ },
460
+ (loginError, loginApi) => {
461
+ if (loginError) {
462
+ if (isBehavior) {
463
+ utils.warn("Failed after dismiss behavior, will relogin automatically...");
464
+ isBehavior = false;
465
+ loginws3();
466
+ }
467
+ utils.error("login", loginError);
468
+ return callback(loginError);
469
+ }
470
+ callback(null, loginApi);
471
+ });
472
+ }
473
+ setOptions(globalOptions, options).then(_ => loginws3());
474
+ return;
475
+ }
476
+
477
+ module.exports = login;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "ws-rapido",
3
+ "version": "1.0.0",
4
+ "description": "A unofficial Facebook Chat API from NethWs3 (Ws3-fca)",
5
+ "keywords": [
6
+ "facebook",
7
+ "chat",
8
+ "api",
9
+ "fca"
10
+ ],
11
+ "homepage": "https://github.com/daikirapido/ws-rapido#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/daikirapido/ws-rapido/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/daikirapido/ws-rapido.git"
18
+ },
19
+ "license": "ISC",
20
+ "author": "NETHWS3 × RAPIDO",
21
+ "type": "commonjs",
22
+ "main": "index.js",
23
+ "scripts": {
24
+ "start": "node index.js"
25
+ },
26
+ "dependencies": {
27
+ "axios": "^1.6.5",
28
+ "chalk": "^3.0.0",
29
+ "cheerio": "^0.22.0",
30
+ "gradient-string": "^1.1.0",
31
+ "https-proxy-agent": "^4.0.0",
32
+ "mqtt": "^3.0.0",
33
+ "node-cron": "^3.0.3",
34
+ "patch-package": "^8.0.0",
35
+ "request": "^2.88.2",
36
+ "websocket-stream": "^5.5.0"
37
+ },
38
+ "devDependencies": {
39
+ "eslint": "^7.5.0",
40
+ "mocha": "^7.0.1",
41
+ "prettier": "^1.11.1"
42
+ },
43
+ "engines": {
44
+ "node": ">=10.x"
45
+ }
46
+ }
@@ -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
+ 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(
13
+ `Item "${apiName}" in moduleObj must be a function, not ${utils.getType(
14
+ moduleObj[apiName],
15
+ )}!`,
16
+ );
17
+ }
18
+ }
19
+ } else {
20
+ throw new Error(
21
+ `moduleObj must be an object, not ${utils.getType(moduleObj)}!`,
22
+ );
23
+ }
24
+ };
25
+ };
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+ // @NethWs3Dev
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({
21
+ error: "please pass a threadID as a second argument.",
22
+ });
23
+ }
24
+
25
+ if (!callback) {
26
+ callback = function (err) {
27
+ if (err) {
28
+ return rejectFunc(err);
29
+ }
30
+ resolveFunc();
31
+ };
32
+ }
33
+
34
+ if (
35
+ utils.getType(threadID) !== "Number" &&
36
+ utils.getType(threadID) !== "String"
37
+ ) {
38
+ throw new utils.CustomError({
39
+ error:
40
+ "ThreadID should be of type Number or String and not " +
41
+ utils.getType(threadID) +
42
+ ".",
43
+ });
44
+ }
45
+
46
+ if (utils.getType(userID) !== "Array") {
47
+ userID = [userID];
48
+ }
49
+
50
+ const messageAndOTID = utils.generateOfflineThreadingID();
51
+ const form = {
52
+ client: "mercury",
53
+ action_type: "ma-type:log-message",
54
+ author: "fbid:" + (ctx.userID),
55
+ thread_id: "",
56
+ timestamp: Date.now(),
57
+ timestamp_absolute: "Today",
58
+ timestamp_relative: utils.generateTimestampRelative(),
59
+ timestamp_time_passed: "0",
60
+ is_unread: false,
61
+ is_cleared: false,
62
+ is_forward: false,
63
+ is_filtered_content: false,
64
+ is_filtered_content_bh: false,
65
+ is_filtered_content_account: false,
66
+ is_spoof_warning: false,
67
+ source: "source:chat:web",
68
+ "source_tags[0]": "source:chat",
69
+ log_message_type: "log:subscribe",
70
+ status: "0",
71
+ offline_threading_id: messageAndOTID,
72
+ message_id: messageAndOTID,
73
+ threading_id: utils.generateThreadingID(ctx.clientID),
74
+ manual_retry_cnt: "0",
75
+ thread_fbid: threadID,
76
+ };
77
+
78
+ for (let i = 0; i < userID.length; i++) {
79
+ if (
80
+ utils.getType(userID[i]) !== "Number" &&
81
+ utils.getType(userID[i]) !== "String"
82
+ ) {
83
+ throw new utils.CustomError({
84
+ error:
85
+ "Elements of userID should be of type Number or String and not " +
86
+ utils.getType(userID[i]) +
87
+ ".",
88
+ });
89
+ }
90
+
91
+ form["log_message_data[added_participants][" + i + "]"] =
92
+ "fbid:" + userID[i];
93
+ }
94
+
95
+ defaultFuncs
96
+ .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
97
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
98
+ .then(function (resData) {
99
+ if (!resData) {
100
+ throw new utils.CustomError({ error: "Add to group failed." });
101
+ }
102
+ if (resData.error) {
103
+ throw new utils.CustomError(resData);
104
+ }
105
+
106
+ return callback();
107
+ })
108
+ .catch(function (err) {
109
+ utils.error("addUserToGroup", err);
110
+ return callback(err);
111
+ });
112
+
113
+ return returnPromise;
114
+ };
115
+ };