shadowx-fca 2.6.0 → 2.7.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/index.js +197 -346
- package/package.json +1 -1
- package/src/listenMqtt.js +2 -2
- package/utils.js +1305 -7
- package/src/shareContact.js.bak +0 -110
package/index.js
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
var utils = require("./utils");
|
|
4
4
|
var cheerio = require("cheerio");
|
|
5
5
|
var log = require("npmlog");
|
|
6
|
-
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
/*var { getThemeColors } = require("../../func/utils/log.js");
|
|
9
|
+
var logger = require("../../func/utils/log.js");
|
|
10
|
+
var { cra, cv, cb, co } = getThemeColors();*/
|
|
7
11
|
log.maxRecordSize = 100;
|
|
8
12
|
var checkVerified = null;
|
|
9
13
|
const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
|
|
@@ -112,7 +116,7 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
112
116
|
}
|
|
113
117
|
} catch { }
|
|
114
118
|
if (fb_dtsg) {
|
|
115
|
-
log
|
|
119
|
+
// console.log("Found fb_dtsg!");
|
|
116
120
|
}
|
|
117
121
|
} catch (e) {
|
|
118
122
|
console.log("Error finding fb_dtsg:", e);
|
|
@@ -124,32 +128,33 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
124
128
|
var userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
|
|
125
129
|
var tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
|
|
126
130
|
if (!userCookie && !tiktikCookie) {
|
|
127
|
-
return log.error(
|
|
131
|
+
return log.error("Error! Your cookiestate is not valid!");
|
|
128
132
|
}
|
|
129
133
|
if (html.includes("/checkpoint/block/?next")) {
|
|
130
|
-
return log.error('
|
|
134
|
+
return log.error('error', "Appstate is dead rechange it!", 'error');
|
|
131
135
|
}
|
|
132
136
|
userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
|
|
133
|
-
|
|
137
|
+
|
|
134
138
|
try { clearInterval(checkVerified); } catch (_) { }
|
|
135
139
|
const clientID = (Math.random() * 2147483648 | 0).toString(16);
|
|
136
|
-
let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=
|
|
137
|
-
let region = "
|
|
140
|
+
let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=pnb&sid=${userID}`;
|
|
141
|
+
let region = "PNB";
|
|
138
142
|
|
|
139
143
|
try {
|
|
140
144
|
const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
|
|
141
|
-
if (endpointMatch
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
if (endpointMatch.input.includes("601051028565049")) {
|
|
146
|
+
console.log(`login error.`);
|
|
147
|
+
ditconmemay = true;
|
|
144
148
|
}
|
|
145
149
|
if (endpointMatch) {
|
|
146
150
|
mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
|
|
147
151
|
const url = new URL(mqttEndpoint);
|
|
148
|
-
region = url.searchParams.get('region')?.toUpperCase() || "
|
|
152
|
+
region = url.searchParams.get('region')?.toUpperCase() || "PNB";
|
|
149
153
|
}
|
|
150
154
|
} catch (e) {
|
|
151
155
|
console.log('Using default MQTT endpoint');
|
|
152
156
|
}
|
|
157
|
+
console.log('SAHU-FCA: Logging in...');
|
|
153
158
|
var ctx = {
|
|
154
159
|
userID: userID,
|
|
155
160
|
jar: jar,
|
|
@@ -169,8 +174,83 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
169
174
|
callback_Task: {},
|
|
170
175
|
wsReqNumber: 0,
|
|
171
176
|
wsTaskNumber: 0,
|
|
172
|
-
reqCallbacks: {}
|
|
177
|
+
reqCallbacks: {},
|
|
178
|
+
threadTypes: {}
|
|
173
179
|
};
|
|
180
|
+
let config = { enableTypingIndicator: false, typingDuration: 4000 };
|
|
181
|
+
try {
|
|
182
|
+
const rootConfigPath = path.join(process.cwd(), 'config.json');
|
|
183
|
+
if (fs.existsSync(rootConfigPath)) {
|
|
184
|
+
const rootConfig = JSON.parse(fs.readFileSync(rootConfigPath, 'utf8'));
|
|
185
|
+
if (rootConfig && typeof rootConfig === 'object') {
|
|
186
|
+
if (typeof rootConfig.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = rootConfig.enableTypingIndicator;
|
|
187
|
+
if (typeof rootConfig.typingDuration !== 'undefined') config.typingDuration = rootConfig.typingDuration;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const fcaConfigPath = path.join(__dirname, 'config.json');
|
|
192
|
+
if (fs.existsSync(fcaConfigPath)) {
|
|
193
|
+
const fcaConfig = JSON.parse(fs.readFileSync(fcaConfigPath, 'utf8'));
|
|
194
|
+
if (fcaConfig && typeof fcaConfig === 'object') {
|
|
195
|
+
if (typeof fcaConfig.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = fcaConfig.enableTypingIndicator;
|
|
196
|
+
if (typeof fcaConfig.typingDuration !== 'undefined') config.typingDuration = fcaConfig.typingDuration;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (global.GoatBot && global.GoatBot.config) {
|
|
201
|
+
if (typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') config.enableTypingIndicator = global.GoatBot.config.enableTypingIndicator;
|
|
202
|
+
if (typeof global.GoatBot.config.typingDuration !== 'undefined') config.typingDuration = global.GoatBot.config.typingDuration;
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
console.log('Error loading config.json:', e);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const refreshFcaConfig = () => {
|
|
209
|
+
try {
|
|
210
|
+
const updatedConfig = { enableTypingIndicator: false, typingDuration: 4000 };
|
|
211
|
+
|
|
212
|
+
if (fs.existsSync(path.join(process.cwd(), 'config.json'))) {
|
|
213
|
+
const rootConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'config.json'), 'utf8'));
|
|
214
|
+
if (rootConfig && typeof rootConfig === 'object') {
|
|
215
|
+
if (typeof rootConfig.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = rootConfig.enableTypingIndicator;
|
|
216
|
+
if (typeof rootConfig.typingDuration !== 'undefined') updatedConfig.typingDuration = rootConfig.typingDuration;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (fs.existsSync(path.join(__dirname, 'config.json'))) {
|
|
221
|
+
const fcaConfig = JSON.parse(fs.readFileSync(path.join(__dirname, 'config.json'), 'utf8'));
|
|
222
|
+
if (fcaConfig && typeof fcaConfig === 'object') {
|
|
223
|
+
if (typeof fcaConfig.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = fcaConfig.enableTypingIndicator;
|
|
224
|
+
if (typeof fcaConfig.typingDuration !== 'undefined') updatedConfig.typingDuration = fcaConfig.typingDuration;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (global.GoatBot && global.GoatBot.config) {
|
|
229
|
+
if (typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') updatedConfig.enableTypingIndicator = global.GoatBot.config.enableTypingIndicator;
|
|
230
|
+
if (typeof global.GoatBot.config.typingDuration !== 'undefined') updatedConfig.typingDuration = global.GoatBot.config.typingDuration;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
ctx.config = updatedConfig;
|
|
234
|
+
config = updatedConfig;
|
|
235
|
+
if (global.GoatBot) global.GoatBot.config = global.GoatBot.config || {};
|
|
236
|
+
if (global.GoatBot && typeof global.GoatBot.config.enableTypingIndicator !== 'undefined') {
|
|
237
|
+
global.GoatBot.config.enableTypingIndicator = updatedConfig.enableTypingIndicator;
|
|
238
|
+
}
|
|
239
|
+
if (global.GoatBot && typeof global.GoatBot.config.typingDuration !== 'undefined') {
|
|
240
|
+
global.GoatBot.config.typingDuration = updatedConfig.typingDuration;
|
|
241
|
+
}
|
|
242
|
+
} catch (e) {
|
|
243
|
+
console.log('Failed to refresh fca config:', e);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
refreshFcaConfig();
|
|
248
|
+
ctx.refreshFcaConfig = refreshFcaConfig;
|
|
249
|
+
if (global.GoatBot) {
|
|
250
|
+
global.GoatBot.refreshFcaConfig = refreshFcaConfig;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
ctx.config = config;
|
|
174
254
|
var api = {
|
|
175
255
|
setOptions: setOptions.bind(null, globalOptions),
|
|
176
256
|
getAppState: () => utils.getAppState(jar),
|
|
@@ -215,354 +295,129 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
215
295
|
return null;
|
|
216
296
|
}
|
|
217
297
|
};
|
|
218
|
-
|
|
219
298
|
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); });
|
|
220
|
-
api.listen = api.listenMqtt;
|
|
221
|
-
return {
|
|
222
|
-
ctx,
|
|
223
|
-
defaultFuncs,
|
|
224
|
-
api
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Session keeper to prevent logout
|
|
229
|
-
function startSessionKeeper(api, ctx) {
|
|
230
|
-
// Keep session alive with random activity
|
|
231
|
-
const keepAliveInterval = setInterval(async () => {
|
|
232
|
-
try {
|
|
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
|
-
];
|
|
284
|
-
|
|
285
|
-
const randomApiKey = API_KEYS[Math.floor(Math.random() * API_KEYS.length)];
|
|
286
|
-
const [appId, clientToken] = randomApiKey.includes('|') ? randomApiKey.split('|') : ['350685531728', randomApiKey];
|
|
287
299
|
|
|
288
|
-
const
|
|
289
|
-
const adid = [...Array(16)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
|
|
290
|
-
const device_id = crypto.randomUUID();
|
|
291
|
-
const family_device_id = crypto.randomUUID();
|
|
292
|
-
const machine_id = crypto.randomBytes(16).toString('hex');
|
|
293
|
-
const session_id = crypto.randomBytes(12).toString('hex');
|
|
300
|
+
const originalSendMessage = api.sendMessage;
|
|
294
301
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
"pt_BR": { code: "BR", tz: "-180" }
|
|
302
|
+
api.sendMessage = async function(msg, threadID, callback, replyToMessage, isSingleUser) {
|
|
303
|
+
try {
|
|
304
|
+
return await originalSendMessage(msg, threadID, callback, replyToMessage, isSingleUser);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
console.log('sendMessage failed, using OldMessage fallback:', error.message);
|
|
307
|
+
return api.OldMessage(msg, threadID, callback, replyToMessage, isSingleUser);
|
|
308
|
+
}
|
|
303
309
|
};
|
|
304
310
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const localeData = locales[country_locale];
|
|
308
|
-
|
|
309
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
310
|
-
const connectionToken = `${appId}|${clientToken}`;
|
|
311
|
-
const jazoest = calculateJazoest(clientToken);
|
|
312
|
-
|
|
313
|
-
const data = {
|
|
314
|
-
adid: adid,
|
|
315
|
-
format: 'json',
|
|
316
|
-
device_id: device_id,
|
|
317
|
-
email: email,
|
|
318
|
-
enc_password: `#${pax}:0:${timestamp}:${password}`,
|
|
319
|
-
generate_analytics_claims: '1',
|
|
320
|
-
generate_session_cookies: '1',
|
|
321
|
-
generate_machine_id: '1',
|
|
322
|
-
machine_id: machine_id,
|
|
323
|
-
session_id: session_id,
|
|
324
|
-
credentials_type: 'password',
|
|
325
|
-
source: 'login',
|
|
326
|
-
error_detail_type: 'button_with_disabled',
|
|
327
|
-
enroll_misauth: 'false',
|
|
328
|
-
currently_logged_in_userid: '0',
|
|
329
|
-
locale: country_locale,
|
|
330
|
-
client_country_code: localeData.code,
|
|
331
|
-
timezone_offset: localeData.tz,
|
|
332
|
-
screen_resolution: '1920x1080',
|
|
333
|
-
available_screen_resolution: '1920x1040',
|
|
334
|
-
fb_api_req_friendly_name: 'authenticate',
|
|
335
|
-
api_key: clientToken,
|
|
336
|
-
access_token: connectionToken,
|
|
337
|
-
jazoest: jazoest,
|
|
338
|
-
meta_inf_fbmeta: '',
|
|
339
|
-
skip_api_login: 'false',
|
|
340
|
-
fb_api_caller_class: 'com.facebook.fblogin',
|
|
341
|
-
cpl: 'true',
|
|
342
|
-
try_num: '1',
|
|
343
|
-
family_device_id: family_device_id,
|
|
344
|
-
community_id: ''
|
|
311
|
+
api.sendMessageDM = function(msg, threadID, callback, replyToMessage) {
|
|
312
|
+
return api.OldMessage(msg, threadID, callback, replyToMessage, true);
|
|
345
313
|
};
|
|
346
314
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)];
|
|
354
|
-
|
|
355
|
-
const headers = {
|
|
356
|
-
'User-Agent': userAgent,
|
|
357
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
|
358
|
-
'Accept-Language': country_locale.replace('_', '-') + ',en-US;q=0.9',
|
|
359
|
-
'Accept-Encoding': 'gzip, deflate, br',
|
|
360
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
361
|
-
'Host': 'graph.facebook.com',
|
|
362
|
-
'Origin': 'https://www.facebook.com',
|
|
363
|
-
'Referer': 'https://www.facebook.com/',
|
|
364
|
-
'Connection': 'keep-alive',
|
|
365
|
-
'Sec-Fetch-Dest': 'empty',
|
|
366
|
-
'Sec-Fetch-Mode': 'cors',
|
|
367
|
-
'Sec-Fetch-Site': 'same-site',
|
|
368
|
-
'sec-ch-ua': '"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',
|
|
369
|
-
'sec-ch-ua-mobile': '?0',
|
|
370
|
-
'sec-ch-ua-platform': '"Windows"',
|
|
371
|
-
'Cache-Control': 'no-cache',
|
|
372
|
-
'Pragma': 'no-cache',
|
|
373
|
-
'X-FB-Net-HNI': String(Math.floor(Math.random() * 90000) + 10000),
|
|
374
|
-
'X-FB-SIM-HNI': String(Math.floor(Math.random() * 90000) + 10000),
|
|
375
|
-
'Authorization': `OAuth ${connectionToken}`,
|
|
376
|
-
'X-FB-Connection-Type': 'WIFI',
|
|
377
|
-
'X-Tigon-Is-Retry': 'False',
|
|
378
|
-
'x-fb-session-id': `nid=${session_id};pid=Main;tid=132;nc=1;fc=0;bc=0;cid=${clientToken}`,
|
|
379
|
-
'x-fb-device-group': '5120',
|
|
380
|
-
'X-FB-Friendly-Name': 'authenticate',
|
|
381
|
-
'X-FB-Request-Analytics-Tags': 'graphservice',
|
|
382
|
-
'X-FB-HTTP-Engine': 'Liger',
|
|
383
|
-
'X-FB-Client-IP': 'True',
|
|
384
|
-
'X-FB-Server-Cluster': 'True',
|
|
385
|
-
'x-fb-connection-token': connectionToken
|
|
315
|
+
api.listen = api.listenMqtt;
|
|
316
|
+
return {
|
|
317
|
+
ctx,
|
|
318
|
+
defaultFuncs,
|
|
319
|
+
api
|
|
386
320
|
};
|
|
387
|
-
|
|
388
|
-
log.info("login", "Attempting modern authentication...");
|
|
389
|
-
|
|
390
|
-
const response = await utils.post(
|
|
391
|
-
"https://b-graph.facebook.com/auth/login",
|
|
392
|
-
jar,
|
|
393
|
-
data,
|
|
394
|
-
loginOptions,
|
|
395
|
-
null,
|
|
396
|
-
headers
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
return response;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Handle 2FA checkpoint
|
|
403
|
-
async function handleCheckpoint(checkpointUrl, jar, loginOptions) {
|
|
404
|
-
log.info("login", "Login approvals are on. Expect an SMS shortly with a code to use for log in");
|
|
405
|
-
|
|
406
|
-
return new Promise((resolve, reject) => {
|
|
407
|
-
const submit2FA = async (code) => {
|
|
408
|
-
try {
|
|
409
|
-
const checkpointRes = await utils.get(checkpointUrl, jar, null, loginOptions);
|
|
410
|
-
const $ = cheerio.load(checkpointRes.body);
|
|
411
|
-
|
|
412
|
-
let checkpointForm = [];
|
|
413
|
-
$("form input").each((i, v) => checkpointForm.push({ val: $(v).val(), name: $(v).attr("name") }));
|
|
414
|
-
checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
|
|
415
|
-
const form = utils.arrToForm(checkpointForm);
|
|
416
|
-
|
|
417
|
-
form.approvals_code = code;
|
|
418
|
-
form['submit[Continue]'] = $("#checkpointSubmitButton").html() || "Continue";
|
|
419
|
-
|
|
420
|
-
const approvalRes = await utils.post(
|
|
421
|
-
checkpointUrl,
|
|
422
|
-
jar,
|
|
423
|
-
form,
|
|
424
|
-
loginOptions
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
await utils.saveCookies(jar)(approvalRes);
|
|
428
|
-
|
|
429
|
-
const $approval = cheerio.load(approvalRes.body);
|
|
430
|
-
const approvalError = $approval("#approvals_code").parent().attr("data-xui-error");
|
|
431
|
-
if (approvalError) {
|
|
432
|
-
reject(new Error("Invalid 2FA code."));
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
form.name_action_selected = 'save_device';
|
|
437
|
-
const finalRes = await utils.post(
|
|
438
|
-
checkpointUrl,
|
|
439
|
-
jar,
|
|
440
|
-
form,
|
|
441
|
-
loginOptions
|
|
442
|
-
);
|
|
443
|
-
|
|
444
|
-
await utils.saveCookies(jar)(finalRes);
|
|
445
|
-
resolve(true);
|
|
446
|
-
} catch (error) {
|
|
447
|
-
reject(error);
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
reject({
|
|
452
|
-
error: 'login-approval',
|
|
453
|
-
continue: submit2FA
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
321
|
}
|
|
457
322
|
|
|
458
323
|
function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
|
|
459
324
|
return async function (res) {
|
|
460
325
|
try {
|
|
461
326
|
const html = res.body;
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
327
|
+
const $ = cheerio.load(html);
|
|
328
|
+
let arr = [];
|
|
329
|
+
$("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
|
|
330
|
+
arr = arr.filter(v => v.val && v.val.length);
|
|
331
|
+
let form = utils.arrToForm(arr);
|
|
332
|
+
form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
|
|
333
|
+
form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
|
|
334
|
+
form.email = email;
|
|
335
|
+
form.pass = password;
|
|
336
|
+
form.default_persistent = '0';
|
|
337
|
+
form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
|
|
338
|
+
form.locale = 'en_US';
|
|
339
|
+
form.timezone = '240';
|
|
340
|
+
form.lgnjs = Math.floor(Date.now() / 1000);
|
|
341
|
+
const willBeCookies = html.split("\"_js_");
|
|
342
|
+
willBeCookies.slice(1).forEach(val => {
|
|
343
|
+
const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
|
|
344
|
+
jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
|
|
345
|
+
});
|
|
346
|
+
console.log("shadowx-FCA: Logging in...");
|
|
347
|
+
const loginRes = await utils.post(
|
|
348
|
+
"https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
|
|
349
|
+
jar,
|
|
350
|
+
form,
|
|
351
|
+
loginOptions
|
|
352
|
+
);
|
|
353
|
+
await utils.saveCookies(jar)(loginRes);
|
|
354
|
+
const headers = loginRes.headers;
|
|
355
|
+
if (!headers.location) throw new Error("Wrong username/password.");
|
|
356
|
+
if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
|
|
357
|
+
log.info("login", "You have login approvals turned on.");
|
|
358
|
+
const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
|
|
359
|
+
await utils.saveCookies(jar)(checkpointRes);
|
|
360
|
+
const checkpointHtml = checkpointRes.body;
|
|
361
|
+
const $ = cheerio.load(checkpointHtml);
|
|
362
|
+
let checkpointForm = [];
|
|
363
|
+
$("form input").each((i, v) => checkpointForm.push({ val: $(v).val(), name: $(v).attr("name") }));
|
|
364
|
+
checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
|
|
365
|
+
const form = utils.arrToForm(checkpointForm);
|
|
366
|
+
if (checkpointHtml.includes("checkpoint/?next")) {
|
|
367
|
+
return new Promise((resolve, reject) => {
|
|
368
|
+
const submit2FA = async (code) => {
|
|
369
|
+
try {
|
|
370
|
+
form.approvals_code = code;
|
|
371
|
+
form['submit[Continue]'] = $("#checkpointSubmitButton").html();
|
|
372
|
+
const approvalRes = await utils.post(
|
|
373
|
+
"https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
|
|
374
|
+
jar,
|
|
375
|
+
form,
|
|
376
|
+
loginOptions
|
|
377
|
+
);
|
|
378
|
+
await utils.saveCookies(jar)(approvalRes);
|
|
379
|
+
const approvalError = $("#approvals_code").parent().attr("data-xui-error");
|
|
380
|
+
if (approvalError) throw new Error("Invalid 2FA code.");
|
|
381
|
+
form.name_action_selected = 'dont_save';
|
|
382
|
+
const finalRes = await utils.post(
|
|
383
|
+
"https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
|
|
384
|
+
jar,
|
|
385
|
+
form,
|
|
386
|
+
loginOptions
|
|
387
|
+
);
|
|
388
|
+
await utils.saveCookies(jar)(finalRes);
|
|
389
|
+
const appState = utils.getAppState(jar);
|
|
390
|
+
resolve(await loginHelper(appState, email, password, loginOptions, callback));
|
|
391
|
+
} catch (error) {
|
|
392
|
+
reject(error);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
throw {
|
|
396
|
+
error: 'login-approval',
|
|
397
|
+
continue: submit2FA
|
|
398
|
+
};
|
|
484
399
|
});
|
|
485
|
-
loginSuccess = true;
|
|
486
|
-
log.info("login", "Modern authentication successful");
|
|
487
|
-
} else if (responseBody.error && responseBody.error.code === 401) {
|
|
488
|
-
log.info("login", "Modern auth failed, falling back to traditional login");
|
|
489
|
-
} else if (responseBody.login_approval_url) {
|
|
490
|
-
checkpointUrl = responseBody.login_approval_url;
|
|
491
|
-
}
|
|
492
|
-
} catch (e) {
|
|
493
|
-
log.info("login", "Modern auth error, falling back to traditional: " + e.message);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Handle checkpoint if needed
|
|
497
|
-
if (checkpointUrl) {
|
|
498
|
-
await handleCheckpoint(checkpointUrl, jar, loginOptions);
|
|
499
|
-
loginSuccess = true;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Fallback to traditional login if modern fails
|
|
503
|
-
if (!loginSuccess) {
|
|
504
|
-
const $ = cheerio.load(html);
|
|
505
|
-
let arr = [];
|
|
506
|
-
$("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
|
|
507
|
-
arr = arr.filter(v => v.val && v.val.length);
|
|
508
|
-
let form = utils.arrToForm(arr);
|
|
509
|
-
form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"");
|
|
510
|
-
form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
|
|
511
|
-
form.email = email;
|
|
512
|
-
form.pass = password;
|
|
513
|
-
form.default_persistent = '0';
|
|
514
|
-
form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
|
|
515
|
-
form.locale = 'en_US';
|
|
516
|
-
form.timezone = '240';
|
|
517
|
-
form.lgnjs = Math.floor(Date.now() / 1000);
|
|
518
|
-
|
|
519
|
-
const willBeCookies = html.split("\"_js_");
|
|
520
|
-
willBeCookies.slice(1).forEach(val => {
|
|
521
|
-
try {
|
|
522
|
-
const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
|
|
523
|
-
jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
|
|
524
|
-
} catch (e) {}
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
log.info("login", "Logging in via traditional method...");
|
|
528
|
-
const loginRes = await utils.post(
|
|
529
|
-
"https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
|
|
530
|
-
jar,
|
|
531
|
-
form,
|
|
532
|
-
loginOptions
|
|
533
|
-
);
|
|
534
|
-
await utils.saveCookies(jar)(loginRes);
|
|
535
|
-
|
|
536
|
-
const headers = loginRes.headers;
|
|
537
|
-
if (!headers.location) throw new Error("Wrong username/password.");
|
|
538
|
-
|
|
539
|
-
if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
|
|
540
|
-
await handleCheckpoint(headers.location, jar, loginOptions);
|
|
541
400
|
}
|
|
401
|
+
if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
|
|
402
|
+
form['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
|
|
403
|
+
await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
|
|
404
|
+
form.name_action_selected = 'save_device';
|
|
405
|
+
const reviewRes = await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
|
|
406
|
+
const appState = utils.getAppState(jar);
|
|
407
|
+
return await loginHelper(appState, email, password, loginOptions, callback);
|
|
542
408
|
}
|
|
543
|
-
|
|
544
|
-
// Final verification
|
|
545
409
|
await utils.get('https://www.facebook.com/', jar, null, loginOptions);
|
|
546
|
-
|
|
547
|
-
// Add delay to avoid rate limiting
|
|
548
|
-
await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 3000));
|
|
549
|
-
|
|
550
410
|
return await utils.saveCookies(jar);
|
|
551
|
-
|
|
552
411
|
} catch (error) {
|
|
553
|
-
if (error.error === 'login-approval') {
|
|
554
|
-
callback(error);
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
412
|
callback(error);
|
|
558
413
|
}
|
|
559
414
|
};
|
|
560
415
|
}
|
|
561
416
|
|
|
417
|
+
|
|
562
418
|
function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
|
|
563
419
|
let mainPromise = null;
|
|
564
420
|
const jar = utils.getJar();
|
|
565
|
-
|
|
566
421
|
if (appState) {
|
|
567
422
|
try {
|
|
568
423
|
appState = JSON.parse(appState);
|
|
@@ -608,7 +463,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
|
|
|
608
463
|
.then(res => {
|
|
609
464
|
const mobileAgentRegex = /MPageLoadClientMetrics/gs;
|
|
610
465
|
if (!mobileAgentRegex.test(res.body)) {
|
|
611
|
-
globalOptions.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
466
|
+
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
467
|
return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
|
|
613
468
|
}
|
|
614
469
|
return res;
|
|
@@ -634,11 +489,8 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
|
|
|
634
489
|
|
|
635
490
|
mainPromise
|
|
636
491
|
.then(async () => {
|
|
637
|
-
log
|
|
638
|
-
|
|
639
|
-
// Start session keeper to prevent logout
|
|
640
|
-
startSessionKeeper(api, ctx);
|
|
641
|
-
|
|
492
|
+
console.log('Shadowx-FCA: Connected ✔');
|
|
493
|
+
console.log('Shadowx-FCA: Listening...');
|
|
642
494
|
callback(null, api);
|
|
643
495
|
})
|
|
644
496
|
.catch(e => {
|
|
@@ -646,6 +498,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
|
|
|
646
498
|
});
|
|
647
499
|
}
|
|
648
500
|
|
|
501
|
+
|
|
649
502
|
function login(loginData, options, callback) {
|
|
650
503
|
if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
|
|
651
504
|
callback = options;
|
|
@@ -654,7 +507,7 @@ function login(loginData, options, callback) {
|
|
|
654
507
|
|
|
655
508
|
var globalOptions = {
|
|
656
509
|
selfListen: false,
|
|
657
|
-
listenEvents:
|
|
510
|
+
listenEvents: true,
|
|
658
511
|
listenTyping: false,
|
|
659
512
|
updatePresence: false,
|
|
660
513
|
forceLogin: false,
|
|
@@ -662,18 +515,16 @@ function login(loginData, options, callback) {
|
|
|
662
515
|
autoMarkRead: false,
|
|
663
516
|
autoReconnect: true,
|
|
664
517
|
logRecordSize: 100,
|
|
665
|
-
online:
|
|
518
|
+
online: false,
|
|
666
519
|
emitReady: false,
|
|
667
|
-
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
520
|
+
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
521
|
};
|
|
669
522
|
|
|
670
523
|
var prCallback = null;
|
|
671
|
-
var returnPromise = null;
|
|
672
|
-
|
|
673
524
|
if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
|
|
674
525
|
var rejectFunc = null;
|
|
675
526
|
var resolveFunc = null;
|
|
676
|
-
returnPromise = new Promise(function (resolve, reject) {
|
|
527
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
677
528
|
resolveFunc = resolve;
|
|
678
529
|
rejectFunc = reject;
|
|
679
530
|
});
|
|
@@ -688,7 +539,7 @@ function login(loginData, options, callback) {
|
|
|
688
539
|
setOptions(globalOptions, {
|
|
689
540
|
logLevel: "silent",
|
|
690
541
|
forceLogin: true,
|
|
691
|
-
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
542
|
+
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
543
|
});
|
|
693
544
|
loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
|
|
694
545
|
} else if (loginData.appState) {
|
|
@@ -698,4 +549,4 @@ function login(loginData, options, callback) {
|
|
|
698
549
|
return returnPromise;
|
|
699
550
|
}
|
|
700
551
|
|
|
701
|
-
module.exports = login;
|
|
552
|
+
module.exports = login;
|