shadowx-fca 2.3.0 → 2.5.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.
package/checkUpdate.js CHANGED
@@ -15,7 +15,7 @@ async function checkForFCAUpdate() {
15
15
  const latestVersion = npmData.version;
16
16
 
17
17
  // Check current installed version in node_modules
18
- let currentVersion = '1.0.8';
18
+ let currentVersion = '2.4.0';
19
19
  const nodeModulesPackagePath = path.join(process.cwd(), 'node_modules', 'shadowx-fca', 'package.json');
20
20
  if (fs.existsSync(nodeModulesPackagePath)) {
21
21
  const installedPackage = JSON.parse(fs.readFileSync(nodeModulesPackagePath, 'utf-8'));
package/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  var utils = require("./utils");
4
4
  var cheerio = require("cheerio");
5
5
  var log = require("npmlog");
6
-
6
+ var crypto = require("crypto");
7
7
  log.maxRecordSize = 100;
8
8
  var checkVerified = null;
9
9
  const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
@@ -112,7 +112,7 @@ function buildAPI(globalOptions, html, jar) {
112
112
  }
113
113
  } catch { }
114
114
  if (fb_dtsg) {
115
- console.log("Found fb_dtsg!");
115
+ log.info("✅ | Found fb_Dtsg");
116
116
  }
117
117
  } catch (e) {
118
118
  console.log("Error finding fb_dtsg:", e);
@@ -124,33 +124,32 @@ function buildAPI(globalOptions, html, jar) {
124
124
  var userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
125
125
  var tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
126
126
  if (!userCookie && !tiktikCookie) {
127
- return log.error("Error! Your cookiestate is not valid!");
127
+ return log.error('login', "No cookie found for user, please check login information again");
128
128
  }
129
129
  if (html.includes("/checkpoint/block/?next")) {
130
- return log.error('error', "Appstate is dead rechange it!", 'error');
130
+ return log.error('login', "Appstate dead, please replace with a new one!", 'error');
131
131
  }
132
132
  userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
133
- //logger.log(`${cra(`[ CONNECT ]`)} Logged in as ${userID}`, "DATABASE");
133
+
134
134
  try { clearInterval(checkVerified); } catch (_) { }
135
135
  const clientID = (Math.random() * 2147483648 | 0).toString(16);
136
- let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb&sid=${userID}`;
137
- let region = "PNB";
136
+ let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=prn&sid=${userID}`;
137
+ let region = "PRN";
138
138
 
139
139
  try {
140
140
  const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
141
- if (endpointMatch.input.includes("601051028565049")) {
142
- console.log(`login error.`);
143
- ditconmemay = true;
141
+ if (endpointMatch && endpointMatch.input && endpointMatch.input.includes("601051028565049")) {
142
+ console.log(`login error due to automatic account`);
143
+ ditconmemay = true;
144
144
  }
145
145
  if (endpointMatch) {
146
146
  mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
147
147
  const url = new URL(mqttEndpoint);
148
- region = url.searchParams.get('region')?.toUpperCase() || "PNB";
148
+ region = url.searchParams.get('region')?.toUpperCase() || "PRN";
149
149
  }
150
150
  } catch (e) {
151
151
  console.log('Using default MQTT endpoint');
152
152
  }
153
- log.info('Logging in...');
154
153
  var ctx = {
155
154
  userID: userID,
156
155
  jar: jar,
@@ -170,8 +169,7 @@ function buildAPI(globalOptions, html, jar) {
170
169
  callback_Task: {},
171
170
  wsReqNumber: 0,
172
171
  wsTaskNumber: 0,
173
- reqCallbacks: {},
174
- threadTypes: {} // Store thread type (dm/group) for each thread
172
+ reqCallbacks: {}
175
173
  };
176
174
  var api = {
177
175
  setOptions: setOptions.bind(null, globalOptions),
@@ -217,28 +215,8 @@ function buildAPI(globalOptions, html, jar) {
217
215
  return null;
218
216
  }
219
217
  };
220
- //if (noMqttData) api.htmlData = noMqttData;
218
+
221
219
  require('fs').readdirSync(__dirname + '/src/').filter(v => v.endsWith('.js')).forEach(v => { api[v.replace('.js', '')] = require(`./src/${v}`)(utils.makeDefaults(html, userID, ctx), api, ctx); });
222
-
223
- // Store original sendMessage as the primary method
224
- const originalSendMessage = api.sendMessage;
225
-
226
- // Wrap sendMessage to use OldMessage as fallback on error
227
- api.sendMessage = async function(msg, threadID, callback, replyToMessage, isSingleUser) {
228
- try {
229
- return await originalSendMessage(msg, threadID, callback, replyToMessage, isSingleUser);
230
- } catch (error) {
231
- // If modern method fails, fallback to OldMessage
232
- console.log('sendMessage failed, using OldMessage fallback:', error.message);
233
- return api.OldMessage(msg, threadID, callback, replyToMessage, isSingleUser);
234
- }
235
- };
236
-
237
- // Provide explicit method for DM sending using OldMessage
238
- api.sendMessageDM = function(msg, threadID, callback, replyToMessage) {
239
- return api.OldMessage(msg, threadID, callback, replyToMessage, true);
240
- };
241
-
242
220
  api.listen = api.listenMqtt;
243
221
  return {
244
222
  ctx,
@@ -247,104 +225,345 @@ function buildAPI(globalOptions, html, jar) {
247
225
  };
248
226
  }
249
227
 
250
- function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
251
- return async function (res) {
228
+ // Session keeper to prevent logout
229
+ function startSessionKeeper(api, ctx) {
230
+ // Keep session alive with random activity
231
+ const keepAliveInterval = setInterval(async () => {
252
232
  try {
253
- const html = res.body;
254
- const $ = cheerio.load(html);
255
- let arr = [];
256
- $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
257
- arr = arr.filter(v => v.val && v.val.length);
258
- let form = utils.arrToForm(arr);
259
- form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
260
- form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
261
- form.email = email;
262
- form.pass = password;
263
- form.default_persistent = '0';
264
- form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
265
- form.locale = 'en_US';
266
- form.timezone = '240';
267
- form.lgnjs = Math.floor(Date.now() / 1000);
268
- const willBeCookies = html.split("\"_js_");
269
- willBeCookies.slice(1).forEach(val => {
270
- const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
271
- jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
272
- });
273
- log.info("Logging in...");
274
- const loginRes = await utils.post(
275
- "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
276
- jar,
277
- form,
278
- loginOptions
279
- );
280
- await utils.saveCookies(jar)(loginRes);
281
- const headers = loginRes.headers;
282
- if (!headers.location) throw new Error("Wrong username/password.");
283
- if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
284
- log.info("login", "You have login approvals turned on.");
285
- const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
286
- await utils.saveCookies(jar)(checkpointRes);
287
- const checkpointHtml = checkpointRes.body;
288
- const $ = cheerio.load(checkpointHtml);
233
+ const actions = [
234
+ async () => {
235
+ const res = await utils.get('https://www.facebook.com/', ctx.jar, null, ctx.globalOptions);
236
+ return res;
237
+ },
238
+ async () => {
239
+ const newDtsg = await api.getFreshDtsg();
240
+ if (newDtsg) ctx.fb_dtsg = newDtsg;
241
+ }
242
+ ];
243
+ const randomAction = actions[Math.floor(Math.random() * actions.length)];
244
+ await randomAction();
245
+ log.verbose("session", "Keep-alive ping sent");
246
+ } catch (e) {
247
+ log.verbose("session", "Keep-alive failed: " + e.message);
248
+ }
249
+ }, 240000 + Math.floor(Math.random() * 120000)); // 4-6 minutes
250
+
251
+ // Refresh DTSG periodically
252
+ const dtsgInterval = setInterval(async () => {
253
+ try {
254
+ const newDtsg = await api.getFreshDtsg();
255
+ if (newDtsg) {
256
+ ctx.fb_dtsg = newDtsg;
257
+ log.info("session", "DTSG refreshed");
258
+ }
259
+ } catch (e) {
260
+ log.verbose("session", "DTSG refresh failed");
261
+ }
262
+ }, 1800000); // 30 minutes
263
+
264
+ // Store intervals for cleanup
265
+ ctx._keepAliveInterval = keepAliveInterval;
266
+ ctx._dtsgInterval = dtsgInterval;
267
+ }
268
+
269
+ // Calculate jazoest for Facebook anti-bot
270
+ function calculateJazoest(token) {
271
+ let sum = 0;
272
+ for (let i = 0; i < token.length; i++) {
273
+ sum += token.charCodeAt(i);
274
+ }
275
+ return sum.toString();
276
+ }
277
+
278
+ // Modern authentication function
279
+ async function modernAuthenticate(email, password, jar, loginOptions) {
280
+ const API_KEYS = [
281
+ '350685531728|62f8ce9f74b12f84c123cc23437a4a32',
282
+ '256002347743983|374e60f8b9bb6b8cbb30f78030438895',
283
+ '882a8490361da98702bf97a021ddc14d|62f8ce9f74b12f84c123cc23437a4a32'
284
+ ];
285
+
286
+ const randomApiKey = API_KEYS[Math.floor(Math.random() * API_KEYS.length)];
287
+ const [appId, clientToken] = randomApiKey.includes('|') ? randomApiKey.split('|') : ['350685531728', randomApiKey];
288
+
289
+ const pax = Math.random() > 0.5 ? "PWD_BROWSER" : "PWD_FB4A";
290
+ const adid = [...Array(16)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
291
+ const device_id = crypto.randomUUID();
292
+ const family_device_id = crypto.randomUUID();
293
+ const machine_id = crypto.randomBytes(16).toString('hex');
294
+ const session_id = crypto.randomBytes(12).toString('hex');
295
+
296
+ const locales = {
297
+ "en_US": { code: "US", tz: "-240" },
298
+ "en_GB": { code: "GB", tz: "0" },
299
+ "fr_FR": { code: "FR", tz: "60" },
300
+ "de_DE": { code: "DE", tz: "60" },
301
+ "es_ES": { code: "ES", tz: "60" },
302
+ "it_IT": { code: "IT", tz: "60" },
303
+ "pt_BR": { code: "BR", tz: "-180" }
304
+ };
305
+
306
+ const localeKeys = Object.keys(locales);
307
+ const country_locale = localeKeys[Math.floor(Math.random() * localeKeys.length)];
308
+ const localeData = locales[country_locale];
309
+
310
+ const timestamp = Math.floor(Date.now() / 1000);
311
+ const connectionToken = `${appId}|${clientToken}`;
312
+ const jazoest = calculateJazoest(clientToken);
313
+
314
+ const data = {
315
+ adid: adid,
316
+ format: 'json',
317
+ device_id: device_id,
318
+ email: email,
319
+ enc_password: `#${pax}:0:${timestamp}:${password}`,
320
+ generate_analytics_claims: '1',
321
+ generate_session_cookies: '1',
322
+ generate_machine_id: '1',
323
+ machine_id: machine_id,
324
+ session_id: session_id,
325
+ credentials_type: 'password',
326
+ source: 'login',
327
+ error_detail_type: 'button_with_disabled',
328
+ enroll_misauth: 'false',
329
+ currently_logged_in_userid: '0',
330
+ locale: country_locale,
331
+ client_country_code: localeData.code,
332
+ timezone_offset: localeData.tz,
333
+ screen_resolution: '1920x1080',
334
+ available_screen_resolution: '1920x1040',
335
+ fb_api_req_friendly_name: 'authenticate',
336
+ api_key: clientToken,
337
+ access_token: connectionToken,
338
+ jazoest: jazoest,
339
+ meta_inf_fbmeta: '',
340
+ skip_api_login: 'false',
341
+ fb_api_caller_class: 'com.facebook.fblogin',
342
+ cpl: 'true',
343
+ try_num: '1',
344
+ family_device_id: family_device_id,
345
+ community_id: ''
346
+ };
347
+
348
+ const userAgents = [
349
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
350
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
351
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
352
+ ];
353
+
354
+ const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)];
355
+
356
+ const headers = {
357
+ 'User-Agent': userAgent,
358
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
359
+ 'Accept-Language': country_locale.replace('_', '-') + ',en-US;q=0.9',
360
+ 'Accept-Encoding': 'gzip, deflate, br',
361
+ 'Content-Type': 'application/x-www-form-urlencoded',
362
+ 'Host': 'graph.facebook.com',
363
+ 'Origin': 'https://www.facebook.com',
364
+ 'Referer': 'https://www.facebook.com/',
365
+ 'Connection': 'keep-alive',
366
+ 'Sec-Fetch-Dest': 'empty',
367
+ 'Sec-Fetch-Mode': 'cors',
368
+ 'Sec-Fetch-Site': 'same-site',
369
+ 'sec-ch-ua': '"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',
370
+ 'sec-ch-ua-mobile': '?0',
371
+ 'sec-ch-ua-platform': '"Windows"',
372
+ 'Cache-Control': 'no-cache',
373
+ 'Pragma': 'no-cache',
374
+ 'X-FB-Net-HNI': String(Math.floor(Math.random() * 90000) + 10000),
375
+ 'X-FB-SIM-HNI': String(Math.floor(Math.random() * 90000) + 10000),
376
+ 'Authorization': `OAuth ${connectionToken}`,
377
+ 'X-FB-Connection-Type': 'WIFI',
378
+ 'X-Tigon-Is-Retry': 'False',
379
+ 'x-fb-session-id': `nid=${session_id};pid=Main;tid=132;nc=1;fc=0;bc=0;cid=${clientToken}`,
380
+ 'x-fb-device-group': '5120',
381
+ 'X-FB-Friendly-Name': 'authenticate',
382
+ 'X-FB-Request-Analytics-Tags': 'graphservice',
383
+ 'X-FB-HTTP-Engine': 'Liger',
384
+ 'X-FB-Client-IP': 'True',
385
+ 'X-FB-Server-Cluster': 'True',
386
+ 'x-fb-connection-token': connectionToken
387
+ };
388
+
389
+ log.info("login", "Attempting modern authentication...");
390
+
391
+ const response = await utils.post(
392
+ "https://b-graph.facebook.com/auth/login",
393
+ jar,
394
+ data,
395
+ loginOptions,
396
+ null,
397
+ headers
398
+ );
399
+
400
+ return response;
401
+ }
402
+
403
+ // Handle 2FA checkpoint
404
+ async function handleCheckpoint(checkpointUrl, jar, loginOptions) {
405
+ log.info("login", "Login approvals are on. Expect an SMS shortly with a code to use for log in");
406
+
407
+ return new Promise((resolve, reject) => {
408
+ const submit2FA = async (code) => {
409
+ try {
410
+ const checkpointRes = await utils.get(checkpointUrl, jar, null, loginOptions);
411
+ const $ = cheerio.load(checkpointRes.body);
412
+
289
413
  let checkpointForm = [];
290
414
  $("form input").each((i, v) => checkpointForm.push({ val: $(v).val(), name: $(v).attr("name") }));
291
415
  checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
292
416
  const form = utils.arrToForm(checkpointForm);
293
- if (checkpointHtml.includes("checkpoint/?next")) {
294
- return new Promise((resolve, reject) => {
295
- const submit2FA = async (code) => {
296
- try {
297
- form.approvals_code = code;
298
- form['submit[Continue]'] = $("#checkpointSubmitButton").html();
299
- const approvalRes = await utils.post(
300
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
301
- jar,
302
- form,
303
- loginOptions
304
- );
305
- await utils.saveCookies(jar)(approvalRes);
306
- const approvalError = $("#approvals_code").parent().attr("data-xui-error");
307
- if (approvalError) throw new Error("Invalid 2FA code.");
308
- form.name_action_selected = 'dont_save';
309
- const finalRes = await utils.post(
310
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
311
- jar,
312
- form,
313
- loginOptions
314
- );
315
- await utils.saveCookies(jar)(finalRes);
316
- const appState = utils.getAppState(jar);
317
- resolve(await loginHelper(appState, email, password, loginOptions, callback));
318
- } catch (error) {
319
- reject(error);
320
- }
321
- };
322
- throw {
323
- error: 'login-approval',
324
- continue: submit2FA
325
- };
326
- });
417
+
418
+ form.approvals_code = code;
419
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html() || "Continue";
420
+
421
+ const approvalRes = await utils.post(
422
+ checkpointUrl,
423
+ jar,
424
+ form,
425
+ loginOptions
426
+ );
427
+
428
+ await utils.saveCookies(jar)(approvalRes);
429
+
430
+ const $approval = cheerio.load(approvalRes.body);
431
+ const approvalError = $approval("#approvals_code").parent().attr("data-xui-error");
432
+ if (approvalError) {
433
+ reject(new Error("Invalid 2FA code."));
434
+ return;
327
435
  }
328
- if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
329
- form['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
330
- await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
436
+
331
437
  form.name_action_selected = 'save_device';
332
- const reviewRes = await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
333
- const appState = utils.getAppState(jar);
334
- return await loginHelper(appState, email, password, loginOptions, callback);
438
+ const finalRes = await utils.post(
439
+ checkpointUrl,
440
+ jar,
441
+ form,
442
+ loginOptions
443
+ );
444
+
445
+ await utils.saveCookies(jar)(finalRes);
446
+ resolve(true);
447
+ } catch (error) {
448
+ reject(error);
335
449
  }
450
+ };
451
+
452
+ reject({
453
+ error: 'login-approval',
454
+ continue: submit2FA
455
+ });
456
+ });
457
+ }
458
+
459
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
460
+ return async function (res) {
461
+ try {
462
+ const html = res.body;
463
+
464
+ // Try modern authentication first
465
+ let loginSuccess = false;
466
+ let checkpointUrl = null;
467
+
468
+ try {
469
+ const modernRes = await modernAuthenticate(email, password, jar, loginOptions);
470
+ await utils.saveCookies(jar)(modernRes);
471
+
472
+ let responseBody;
473
+ try {
474
+ responseBody = JSON.parse(modernRes.body);
475
+ } catch (e) {
476
+ responseBody = { error: true };
477
+ }
478
+
479
+ if (responseBody.session_cookies) {
480
+ responseBody.session_cookies.forEach(cookie => {
481
+ jar.setCookie(
482
+ `${cookie.name}=${cookie.value}; Domain=.facebook.com; Path=/; Secure; HttpOnly`,
483
+ "https://www.facebook.com"
484
+ );
485
+ });
486
+ loginSuccess = true;
487
+ log.info("login", "Modern authentication successful");
488
+ } else if (responseBody.error && responseBody.error.code === 401) {
489
+ log.info("login", "Modern auth failed, falling back to traditional login");
490
+ } else if (responseBody.login_approval_url) {
491
+ checkpointUrl = responseBody.login_approval_url;
492
+ }
493
+ } catch (e) {
494
+ log.info("login", "Modern auth error, falling back to traditional: " + e.message);
495
+ }
496
+
497
+ // Handle checkpoint if needed
498
+ if (checkpointUrl) {
499
+ await handleCheckpoint(checkpointUrl, jar, loginOptions);
500
+ loginSuccess = true;
501
+ }
502
+
503
+ // Fallback to traditional login if modern fails
504
+ if (!loginSuccess) {
505
+ const $ = cheerio.load(html);
506
+ let arr = [];
507
+ $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
508
+ arr = arr.filter(v => v.val && v.val.length);
509
+ let form = utils.arrToForm(arr);
510
+ form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"");
511
+ form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
512
+ form.email = email;
513
+ form.pass = password;
514
+ form.default_persistent = '0';
515
+ form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
516
+ form.locale = 'en_US';
517
+ form.timezone = '240';
518
+ form.lgnjs = Math.floor(Date.now() / 1000);
519
+
520
+ const willBeCookies = html.split("\"_js_");
521
+ willBeCookies.slice(1).forEach(val => {
522
+ try {
523
+ const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
524
+ jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
525
+ } catch (e) {}
526
+ });
527
+
528
+ log.info("login", "Logging in via traditional method...");
529
+ const loginRes = await utils.post(
530
+ "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
531
+ jar,
532
+ form,
533
+ loginOptions
534
+ );
535
+ await utils.saveCookies(jar)(loginRes);
536
+
537
+ const headers = loginRes.headers;
538
+ if (!headers.location) throw new Error("Wrong username/password.");
539
+
540
+ if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
541
+ await handleCheckpoint(headers.location, jar, loginOptions);
542
+ }
543
+ }
544
+
545
+ // Final verification
336
546
  await utils.get('https://www.facebook.com/', jar, null, loginOptions);
547
+
548
+ // Add delay to avoid rate limiting
549
+ await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 3000));
550
+
337
551
  return await utils.saveCookies(jar);
552
+
338
553
  } catch (error) {
554
+ if (error.error === 'login-approval') {
555
+ callback(error);
556
+ return;
557
+ }
339
558
  callback(error);
340
559
  }
341
560
  };
342
561
  }
343
562
 
344
-
345
563
  function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
346
564
  let mainPromise = null;
347
565
  const jar = utils.getJar();
566
+
348
567
  if (appState) {
349
568
  try {
350
569
  appState = JSON.parse(appState);
@@ -390,7 +609,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
390
609
  .then(res => {
391
610
  const mobileAgentRegex = /MPageLoadClientMetrics/gs;
392
611
  if (!mobileAgentRegex.test(res.body)) {
393
- 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";
612
+ globalOptions.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
394
613
  return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
395
614
  }
396
615
  return res;
@@ -417,6 +636,10 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
417
636
  mainPromise
418
637
  .then(async () => {
419
638
  log.info('Login successful');
639
+
640
+ // Start session keeper to prevent logout
641
+ startSessionKeeper(api, ctx);
642
+
420
643
  callback(null, api);
421
644
  })
422
645
  .catch(e => {
@@ -424,7 +647,6 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
424
647
  });
425
648
  }
426
649
 
427
-
428
650
  function login(loginData, options, callback) {
429
651
  if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
430
652
  callback = options;
@@ -433,7 +655,7 @@ function login(loginData, options, callback) {
433
655
 
434
656
  var globalOptions = {
435
657
  selfListen: false,
436
- listenEvents: true,
658
+ listenEvents: false,
437
659
  listenTyping: false,
438
660
  updatePresence: false,
439
661
  forceLogin: false,
@@ -441,16 +663,18 @@ function login(loginData, options, callback) {
441
663
  autoMarkRead: false,
442
664
  autoReconnect: true,
443
665
  logRecordSize: 100,
444
- online: false,
666
+ online: true,
445
667
  emitReady: false,
446
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
668
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
447
669
  };
448
670
 
449
671
  var prCallback = null;
672
+ var returnPromise = null;
673
+
450
674
  if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
451
675
  var rejectFunc = null;
452
676
  var resolveFunc = null;
453
- var returnPromise = new Promise(function (resolve, reject) {
677
+ returnPromise = new Promise(function (resolve, reject) {
454
678
  resolveFunc = resolve;
455
679
  rejectFunc = reject;
456
680
  });
@@ -465,7 +689,7 @@ function login(loginData, options, callback) {
465
689
  setOptions(globalOptions, {
466
690
  logLevel: "silent",
467
691
  forceLogin: true,
468
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
692
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
469
693
  });
470
694
  loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
471
695
  } else if (loginData.appState) {
@@ -475,5 +699,4 @@ function login(loginData, options, callback) {
475
699
  return returnPromise;
476
700
  }
477
701
 
478
-
479
702
  module.exports = login;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadowx-fca",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "Unofficial Facebook Chat API for Node.js with Auto-Update System - modify by Mueid Mursalin Rifat",
5
5
  "main": "index.js",
6
6
  "files": [