rapido-fca 0.0.2 → 0.0.3

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 (3) hide show
  1. package/index.js +419 -415
  2. package/package.json +1 -1
  3. package/utils.js +2732 -1401
package/index.js CHANGED
@@ -3,454 +3,458 @@
3
3
  var utils = require("./utils");
4
4
  var cheerio = require("cheerio");
5
5
  var log = require("npmlog");
6
+ /*var { getThemeColors } = require("../../func/utils/log.js");
7
+ var logger = require("../../func/utils/log.js");
8
+ var { cra, cv, cb, co } = getThemeColors();*/
6
9
  log.maxRecordSize = 100;
7
10
  var checkVerified = null;
8
11
  const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
9
12
  global.ditconmemay = false;
10
13
 
11
14
  function setOptions(globalOptions, options) {
12
- Object.keys(options).map(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
- });
15
+ Object.keys(options).map(function (key) {
16
+ switch (Boolean_Option.includes(key)) {
17
+ case true: {
18
+ globalOptions[key] = Boolean(options[key]);
19
+ break;
20
+ }
21
+ case false: {
22
+ switch (key) {
23
+ case 'pauseLog': {
24
+ if (options.pauseLog) log.pause();
25
+ else log.resume();
26
+ break;
27
+ }
28
+ case 'logLevel': {
29
+ log.level = options.logLevel;
30
+ globalOptions.logLevel = options.logLevel;
31
+ break;
32
+ }
33
+ case 'logRecordSize': {
34
+ log.maxRecordSize = options.logRecordSize;
35
+ globalOptions.logRecordSize = options.logRecordSize;
36
+ break;
37
+ }
38
+ case 'pageID': {
39
+ globalOptions.pageID = options.pageID.toString();
40
+ break;
41
+ }
42
+ case 'userAgent': {
43
+ 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');
44
+ break;
45
+ }
46
+ case 'proxy': {
47
+ if (typeof options.proxy != "string") {
48
+ delete globalOptions.proxy;
49
+ utils.setProxy();
50
+ } else {
51
+ globalOptions.proxy = options.proxy;
52
+ utils.setProxy(globalOptions.proxy);
53
+ }
54
+ break;
55
+ }
56
+ default: {
57
+ log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
58
+ break;
59
+ }
60
+ }
61
+ break;
62
+ }
63
+ }
64
+ });
62
65
  }
63
66
 
64
67
  function buildAPI(globalOptions, html, jar) {
65
- let fb_dtsg = null;
66
- let irisSeqID = null;
67
- function extractFromHTML() {
68
- try {
69
- const $ = cheerio.load(html);
70
- $('script').each((i, script) => {
71
- if (!fb_dtsg) {
72
- const scriptText = $(script).html() || '';
73
- const patterns = [
74
- /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
75
- /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
76
- /"token":"([^"]+)"/,
77
- /{\\"token\\":\\"([^\\]+)\\"/,
78
- /,\{"token":"([^"]+)"\},\d+\]/,
79
- /"async_get_token":"([^"]+)"/,
80
- /"dtsg":\{"token":"([^"]+)"/,
81
- /DTSGInitialData[^>]+>([^<]+)/
82
- ];
83
- for (const pattern of patterns) {
84
- const match = scriptText.match(pattern);
85
- if (match && match[1]) {
86
- try {
87
- const possibleJson = match[1].replace(/\\"/g, '"');
88
- const parsed = JSON.parse(possibleJson);
89
- fb_dtsg = parsed.token || parsed;
90
- } catch {
91
- fb_dtsg = match[1];
92
- }
93
- if (fb_dtsg) break;
94
- }
95
- }
96
- }
97
- });
98
- if (!fb_dtsg) {
99
- const dtsgInput = $('input[name="fb_dtsg"]').val();
100
- if (dtsgInput) fb_dtsg = dtsgInput;
101
- }
102
- const seqMatches = html.match(/irisSeqID":"([^"]+)"/);
103
- if (seqMatches && seqMatches[1]) {
104
- irisSeqID = seqMatches[1];
105
- }
106
- try {
107
- const jsonMatches = html.match(/\{"dtsg":({[^}]+})/);
108
- if (jsonMatches && jsonMatches[1]) {
109
- const dtsgData = JSON.parse(jsonMatches[1]);
110
- if (dtsgData.token) fb_dtsg = dtsgData.token;
111
- }
112
- } catch { }
113
- if (fb_dtsg) {
114
- log.info("✅ | Found fb_Dtsg");
115
- }
116
- } catch (e) {
117
- console.log("Error finding fb_dtsg:", e);
118
- }
119
- }
120
- extractFromHTML();
121
- var userID;
122
- var cookies = jar.getCookies("https://www.facebook.com");
123
- var userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
124
- var tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
125
- if (!userCookie && !tiktikCookie) {
126
- return log.error('login', "No cookie found for user, please check login information again");
127
- }
128
- if (html.includes("/checkpoint/block/?next")) {
129
- return log.error('login', "Appstate dead, please replace with a new one!", 'error');
130
- }
131
- userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
132
-
133
- try { clearInterval(checkVerified); } catch (_) { }
134
- const clientID = (Math.random() * 2147483648 | 0).toString(16);
135
- let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=prn&sid=${userID}`;
136
- let region = "PRN";
68
+ let fb_dtsg = null;
69
+ let irisSeqID = null;
70
+ function extractFromHTML() {
71
+ try {
72
+ const $ = cheerio.load(html);
73
+ $('script').each((i, script) => {
74
+ if (!fb_dtsg) {
75
+ const scriptText = $(script).html() || '';
76
+ const patterns = [
77
+ /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
78
+ /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
79
+ /"token":"([^"]+)"/,
80
+ /{\\"token\\":\\"([^\\]+)\\"/,
81
+ /,\{"token":"([^"]+)"\},\d+\]/,
82
+ /"async_get_token":"([^"]+)"/,
83
+ /"dtsg":\{"token":"([^"]+)"/,
84
+ /DTSGInitialData[^>]+>([^<]+)/
85
+ ];
86
+ for (const pattern of patterns) {
87
+ const match = scriptText.match(pattern);
88
+ if (match && match[1]) {
89
+ try {
90
+ const possibleJson = match[1].replace(/\\"/g, '"');
91
+ const parsed = JSON.parse(possibleJson);
92
+ fb_dtsg = parsed.token || parsed;
93
+ } catch {
94
+ fb_dtsg = match[1];
95
+ }
96
+ if (fb_dtsg) break;
97
+ }
98
+ }
99
+ }
100
+ });
101
+ if (!fb_dtsg) {
102
+ const dtsgInput = $('input[name="fb_dtsg"]').val();
103
+ if (dtsgInput) fb_dtsg = dtsgInput;
104
+ }
105
+ const seqMatches = html.match(/irisSeqID":"([^"]+)"/);
106
+ if (seqMatches && seqMatches[1]) {
107
+ irisSeqID = seqMatches[1];
108
+ }
109
+ try {
110
+ const jsonMatches = html.match(/\{"dtsg":({[^}]+})/);
111
+ if (jsonMatches && jsonMatches[1]) {
112
+ const dtsgData = JSON.parse(jsonMatches[1]);
113
+ if (dtsgData.token) fb_dtsg = dtsgData.token;
114
+ }
115
+ } catch { }
116
+ if (fb_dtsg) {
117
+ console.log("Found fb_dtsg!");
118
+ }
119
+ } catch (e) {
120
+ console.log("Error finding fb_dtsg:", e);
121
+ }
122
+ }
123
+ extractFromHTML();
124
+ var userID;
125
+ var cookies = jar.getCookies("https://www.facebook.com");
126
+ var userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
127
+ var tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
128
+ if (!userCookie && !tiktikCookie) {
129
+ return log.error("Error! Your cookiestate is not valid!");
130
+ }
131
+ if (html.includes("/checkpoint/block/?next")) {
132
+ return log.error('error', "Appstate is dead rechange it!", 'error');
133
+ }
134
+ userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
135
+ //logger.log(`${cra(`[ CONNECT ]`)} Logged in as ${userID}`, "DATABASE");
136
+ try { clearInterval(checkVerified); } catch (_) { }
137
+ const clientID = (Math.random() * 2147483648 | 0).toString(16);
138
+ let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=prn&sid=${userID}`;
139
+ let region = "PRN";
137
140
 
138
- try {
139
- const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
140
- if (endpointMatch.input.includes("601051028565049")) {
141
- console.log(`login error due to automatic account`);
142
- ditconmemay = true;
143
- }
144
- if (endpointMatch) {
145
- mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
146
- const url = new URL(mqttEndpoint);
147
- region = url.searchParams.get('region')?.toUpperCase() || "PRN";
148
- }
149
- } catch (e) {
150
- console.log('Using default MQTT endpoint');
151
- }
152
- var ctx = {
153
- userID: userID,
154
- jar: jar,
155
- clientID: clientID,
156
- globalOptions: globalOptions,
157
- loggedIn: true,
158
- access_token: 'NONE',
159
- clientMutationId: 0,
160
- mqttClient: undefined,
161
- lastSeqId: irisSeqID,
162
- syncToken: undefined,
163
- mqttEndpoint: mqttEndpoint,
164
- region: region,
165
- firstListen: true,
166
- fb_dtsg: fb_dtsg,
167
- req_ID: 0,
168
- callback_Task: {},
169
- wsReqNumber: 0,
170
- wsTaskNumber: 0,
171
- reqCallbacks: {}
172
- };
173
- var api = {
174
- setOptions: setOptions.bind(null, globalOptions),
175
- getAppState: () => utils.getAppState(jar),
176
- postFormData: (url, body) => utils.makeDefaults(html, userID, ctx).postFormData(url, ctx.jar, body)
177
- };
178
- var defaultFuncs = utils.makeDefaults(html, userID, ctx);
179
- api.postFormData = function (url, body) {
180
- return defaultFuncs.postFormData(url, ctx.jar, body);
181
- };
182
- api.getFreshDtsg = async function () {
183
- try {
184
- const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
185
- const $ = cheerio.load(res.body);
186
- let newDtsg;
187
- const patterns = [
188
- /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
189
- /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
190
- /"token":"([^"]+)"/,
191
- /name="fb_dtsg" value="([^"]+)"/
192
- ];
141
+ try {
142
+ const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
143
+ if (endpointMatch.input.includes("601051028565049")) {
144
+ console.log(`login error.`);
145
+ ditconmemay = true;
146
+ }
147
+ if (endpointMatch) {
148
+ mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
149
+ const url = new URL(mqttEndpoint);
150
+ region = url.searchParams.get('region')?.toUpperCase() || "PRN";
151
+ }
152
+ } catch (e) {
153
+ console.log('Using default MQTT endpoint');
154
+ }
155
+ log.info('Logging in...');
156
+ var ctx = {
157
+ userID: userID,
158
+ jar: jar,
159
+ clientID: clientID,
160
+ globalOptions: globalOptions,
161
+ loggedIn: true,
162
+ access_token: 'NONE',
163
+ clientMutationId: 0,
164
+ mqttClient: undefined,
165
+ lastSeqId: irisSeqID,
166
+ syncToken: undefined,
167
+ mqttEndpoint: mqttEndpoint,
168
+ region: region,
169
+ firstListen: true,
170
+ fb_dtsg: fb_dtsg,
171
+ req_ID: 0,
172
+ callback_Task: {},
173
+ wsReqNumber: 0,
174
+ wsTaskNumber: 0,
175
+ reqCallbacks: {}
176
+ };
177
+ var api = {
178
+ setOptions: setOptions.bind(null, globalOptions),
179
+ getAppState: () => utils.getAppState(jar),
180
+ postFormData: (url, body) => utils.makeDefaults(html, userID, ctx).postFormData(url, ctx.jar, body)
181
+ };
182
+ var defaultFuncs = utils.makeDefaults(html, userID, ctx);
183
+ api.postFormData = function (url, body) {
184
+ return defaultFuncs.postFormData(url, ctx.jar, body);
185
+ };
186
+ api.getFreshDtsg = async function () {
187
+ try {
188
+ const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
189
+ const $ = cheerio.load(res.body);
190
+ let newDtsg;
191
+ const patterns = [
192
+ /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
193
+ /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
194
+ /"token":"([^"]+)"/,
195
+ /name="fb_dtsg" value="([^"]+)"/
196
+ ];
193
197
 
194
- $('script').each((i, script) => {
195
- if (!newDtsg) {
196
- const scriptText = $(script).html() || '';
197
- for (const pattern of patterns) {
198
- const match = scriptText.match(pattern);
199
- if (match && match[1]) {
200
- newDtsg = match[1];
201
- break;
202
- }
203
- }
204
- }
205
- });
198
+ $('script').each((i, script) => {
199
+ if (!newDtsg) {
200
+ const scriptText = $(script).html() || '';
201
+ for (const pattern of patterns) {
202
+ const match = scriptText.match(pattern);
203
+ if (match && match[1]) {
204
+ newDtsg = match[1];
205
+ break;
206
+ }
207
+ }
208
+ }
209
+ });
206
210
 
207
- if (!newDtsg) {
208
- newDtsg = $('input[name="fb_dtsg"]').val();
209
- }
211
+ if (!newDtsg) {
212
+ newDtsg = $('input[name="fb_dtsg"]').val();
213
+ }
210
214
 
211
- return newDtsg;
212
- } catch (e) {
213
- console.log("Error getting fresh dtsg:", e);
214
- return null;
215
- }
216
- };
217
-
218
- 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); });
219
- api.listen = api.listenMqtt;
220
- return {
221
- ctx,
222
- defaultFuncs,
223
- api
224
- };
215
+ return newDtsg;
216
+ } catch (e) {
217
+ console.log("Error getting fresh dtsg:", e);
218
+ return null;
219
+ }
220
+ };
221
+ //if (noMqttData) api.htmlData = noMqttData;
222
+ 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); });
223
+ api.listen = api.listenMqtt;
224
+ return {
225
+ ctx,
226
+ defaultFuncs,
227
+ api
228
+ };
225
229
  }
226
230
 
227
231
  function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
228
- return async function (res) {
229
- try {
230
- const html = res.body;
231
- const $ = cheerio.load(html);
232
- let arr = [];
233
- $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
234
- arr = arr.filter(v => v.val && v.val.length);
235
- let form = utils.arrToForm(arr);
236
- form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
237
- form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
238
- form.email = email;
239
- form.pass = password;
240
- form.default_persistent = '0';
241
- form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
242
- form.locale = 'en_US';
243
- form.timezone = '240';
244
- form.lgnjs = Math.floor(Date.now() / 1000);
245
- const willBeCookies = html.split("\"_js_");
246
- willBeCookies.slice(1).forEach(val => {
247
- const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
248
- jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
249
- });
250
- log.info("login", "Logging in...");
251
- const loginRes = await utils.post(
252
- "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
253
- jar,
254
- form,
255
- loginOptions
256
- );
257
- await utils.saveCookies(jar)(loginRes);
258
- const headers = loginRes.headers;
259
- if (!headers.location) throw new Error("Wrong username/password.");
260
- if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
261
- log.info("login", "You have login approvals turned on.");
262
- const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
263
- await utils.saveCookies(jar)(checkpointRes);
264
- const checkpointHtml = checkpointRes.body;
265
- const $ = cheerio.load(checkpointHtml);
266
- let checkpointForm = [];
267
- $("form input").each((i, v) => checkpointForm.push({ val: $(v).val(), name: $(v).attr("name") }));
268
- checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
269
- const form = utils.arrToForm(checkpointForm);
270
- if (checkpointHtml.includes("checkpoint/?next")) {
271
- return new Promise((resolve, reject) => {
272
- const submit2FA = async (code) => {
273
- try {
274
- form.approvals_code = code;
275
- form['submit[Continue]'] = $("#checkpointSubmitButton").html();
276
- const approvalRes = await utils.post(
277
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
278
- jar,
279
- form,
280
- loginOptions
281
- );
282
- await utils.saveCookies(jar)(approvalRes);
283
- const approvalError = $("#approvals_code").parent().attr("data-xui-error");
284
- if (approvalError) throw new Error("Invalid 2FA code.");
285
- form.name_action_selected = 'dont_save';
286
- const finalRes = await utils.post(
287
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
288
- jar,
289
- form,
290
- loginOptions
291
- );
292
- await utils.saveCookies(jar)(finalRes);
293
- const appState = utils.getAppState(jar);
294
- resolve(await loginHelper(appState, email, password, loginOptions, callback));
295
- } catch (error) {
296
- reject(error);
297
- }
298
- };
299
- throw {
300
- error: 'login-approval',
301
- continue: submit2FA
302
- };
303
- });
304
- }
305
- if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
306
- form['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
307
- await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
308
- form.name_action_selected = 'save_device';
309
- const reviewRes = await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
310
- const appState = utils.getAppState(jar);
311
- return await loginHelper(appState, email, password, loginOptions, callback);
312
- }
313
- await utils.get('https://www.facebook.com/', jar, null, loginOptions);
314
- return await utils.saveCookies(jar);
315
- } catch (error) {
316
- callback(error);
317
- }
318
- };
232
+ return async function (res) {
233
+ try {
234
+ const html = res.body;
235
+ const $ = cheerio.load(html);
236
+ let arr = [];
237
+ $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
238
+ arr = arr.filter(v => v.val && v.val.length);
239
+ let form = utils.arrToForm(arr);
240
+ form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
241
+ form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
242
+ form.email = email;
243
+ form.pass = password;
244
+ form.default_persistent = '0';
245
+ form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
246
+ form.locale = 'en_US';
247
+ form.timezone = '240';
248
+ form.lgnjs = Math.floor(Date.now() / 1000);
249
+ const willBeCookies = html.split("\"_js_");
250
+ willBeCookies.slice(1).forEach(val => {
251
+ const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
252
+ jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
253
+ });
254
+ log.info("Logging in...");
255
+ const loginRes = await utils.post(
256
+ "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
257
+ jar,
258
+ form,
259
+ loginOptions
260
+ );
261
+ await utils.saveCookies(jar)(loginRes);
262
+ const headers = loginRes.headers;
263
+ if (!headers.location) throw new Error("Wrong username/password.");
264
+ if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
265
+ log.info("login", "You have login approvals turned on.");
266
+ const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
267
+ await utils.saveCookies(jar)(checkpointRes);
268
+ const checkpointHtml = checkpointRes.body;
269
+ const $ = cheerio.load(checkpointHtml);
270
+ let checkpointForm = [];
271
+ $("form input").each((i, v) => checkpointForm.push({ val: $(v).val(), name: $(v).attr("name") }));
272
+ checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
273
+ const form = utils.arrToForm(checkpointForm);
274
+ if (checkpointHtml.includes("checkpoint/?next")) {
275
+ return new Promise((resolve, reject) => {
276
+ const submit2FA = async (code) => {
277
+ try {
278
+ form.approvals_code = code;
279
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html();
280
+ const approvalRes = await utils.post(
281
+ "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
282
+ jar,
283
+ form,
284
+ loginOptions
285
+ );
286
+ await utils.saveCookies(jar)(approvalRes);
287
+ const approvalError = $("#approvals_code").parent().attr("data-xui-error");
288
+ if (approvalError) throw new Error("Invalid 2FA code.");
289
+ form.name_action_selected = 'dont_save';
290
+ const finalRes = await utils.post(
291
+ "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
292
+ jar,
293
+ form,
294
+ loginOptions
295
+ );
296
+ await utils.saveCookies(jar)(finalRes);
297
+ const appState = utils.getAppState(jar);
298
+ resolve(await loginHelper(appState, email, password, loginOptions, callback));
299
+ } catch (error) {
300
+ reject(error);
301
+ }
302
+ };
303
+ throw {
304
+ error: 'login-approval',
305
+ continue: submit2FA
306
+ };
307
+ });
308
+ }
309
+ if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
310
+ form['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
311
+ await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
312
+ form.name_action_selected = 'save_device';
313
+ const reviewRes = await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions);
314
+ const appState = utils.getAppState(jar);
315
+ return await loginHelper(appState, email, password, loginOptions, callback);
316
+ }
317
+ await utils.get('https://www.facebook.com/', jar, null, loginOptions);
318
+ return await utils.saveCookies(jar);
319
+ } catch (error) {
320
+ callback(error);
321
+ }
322
+ };
319
323
  }
320
324
 
321
325
 
322
326
  function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
323
- let mainPromise = null;
324
- const jar = utils.getJar();
325
- if (appState) {
326
- try {
327
- appState = JSON.parse(appState);
328
- } catch (e) {
329
- try {
330
- appState = appState;
331
- } catch (e) {
332
- return callback(new Error("Failed to parse appState"));
333
- }
334
- }
327
+ let mainPromise = null;
328
+ const jar = utils.getJar();
329
+ if (appState) {
330
+ try {
331
+ appState = JSON.parse(appState);
332
+ } catch (e) {
333
+ try {
334
+ appState = appState;
335
+ } catch (e) {
336
+ return callback(new Error("Failed to parse appState"));
337
+ }
338
+ }
335
339
 
336
- try {
337
- appState.forEach(c => {
338
- const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
339
- jar.setCookie(str, "http://" + c.domain);
340
- });
340
+ try {
341
+ appState.forEach(c => {
342
+ const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
343
+ jar.setCookie(str, "http://" + c.domain);
344
+ });
341
345
 
342
- mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
343
- .then(utils.saveCookies(jar));
344
- } catch (e) {
345
- process.exit(0);
346
- }
347
- } else {
348
- mainPromise = utils
349
- .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
350
- .then(utils.saveCookies(jar))
351
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
352
- .then(() => utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar)));
353
- }
346
+ mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
347
+ .then(utils.saveCookies(jar));
348
+ } catch (e) {
349
+ process.exit(0);
350
+ }
351
+ } else {
352
+ mainPromise = utils
353
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
354
+ .then(utils.saveCookies(jar))
355
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
356
+ .then(() => utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar)));
357
+ }
354
358
 
355
- function handleRedirect(res) {
356
- const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
357
- const redirect = reg.exec(res.body);
358
- if (redirect && redirect[1]) {
359
- return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
360
- }
361
- return res;
362
- }
359
+ function handleRedirect(res) {
360
+ const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
361
+ const redirect = reg.exec(res.body);
362
+ if (redirect && redirect[1]) {
363
+ return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
364
+ }
365
+ return res;
366
+ }
363
367
 
364
- let ctx, api;
365
- mainPromise = mainPromise
366
- .then(handleRedirect)
367
- .then(res => {
368
- const mobileAgentRegex = /MPageLoadClientMetrics/gs;
369
- if (!mobileAgentRegex.test(res.body)) {
370
- 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";
371
- return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
372
- }
373
- return res;
374
- })
375
- .then(handleRedirect)
376
- .then(res => {
377
- const html = res.body;
378
- const Obj = buildAPI(globalOptions, html, jar);
379
- ctx = Obj.ctx;
380
- api = Obj.api;
381
- return res;
382
- });
368
+ let ctx, api;
369
+ mainPromise = mainPromise
370
+ .then(handleRedirect)
371
+ .then(res => {
372
+ const mobileAgentRegex = /MPageLoadClientMetrics/gs;
373
+ if (!mobileAgentRegex.test(res.body)) {
374
+ 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";
375
+ return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
376
+ }
377
+ return res;
378
+ })
379
+ .then(handleRedirect)
380
+ .then(res => {
381
+ const html = res.body;
382
+ const Obj = buildAPI(globalOptions, html, jar);
383
+ ctx = Obj.ctx;
384
+ api = Obj.api;
385
+ return res;
386
+ });
383
387
 
384
- if (globalOptions.pageID) {
385
- mainPromise = mainPromise
386
- .then(() => utils.get(`https://www.facebook.com/${globalOptions.pageID}/messages/?section=messages&subsection=inbox`, jar, null, globalOptions))
387
- .then(resData => {
388
- let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
389
- url = url.substring(0, url.length - 1);
390
- return utils.get('https://www.facebook.com' + url, jar, null, globalOptions);
391
- });
392
- }
388
+ if (globalOptions.pageID) {
389
+ mainPromise = mainPromise
390
+ .then(() => utils.get(`https://www.facebook.com/${globalOptions.pageID}/messages/?section=messages&subsection=inbox`, jar, null, globalOptions))
391
+ .then(resData => {
392
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
393
+ url = url.substring(0, url.length - 1);
394
+ return utils.get('https://www.facebook.com' + url, jar, null, globalOptions);
395
+ });
396
+ }
393
397
 
394
- mainPromise
395
- .then(async () => {
396
- log.info('Login successful');
397
- callback(null, api);
398
- })
399
- .catch(e => {
400
- callback(e);
401
- });
398
+ mainPromise
399
+ .then(async () => {
400
+ log.info('Login successful');
401
+ callback(null, api);
402
+ })
403
+ .catch(e => {
404
+ callback(e);
405
+ });
402
406
  }
403
407
 
404
408
 
405
409
  function login(loginData, options, callback) {
406
- if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
407
- callback = options;
408
- options = {};
409
- }
410
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
411
+ callback = options;
412
+ options = {};
413
+ }
410
414
 
411
- var globalOptions = {
412
- selfListen: false,
413
- listenEvents: false,
414
- listenTyping: false,
415
- updatePresence: false,
416
- forceLogin: false,
417
- autoMarkDelivery: false,
418
- autoMarkRead: false,
419
- autoReconnect: true,
420
- logRecordSize: 100,
421
- online: true,
422
- emitReady: false,
423
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
424
- };
415
+ var globalOptions = {
416
+ selfListen: false,
417
+ listenEvents: true,
418
+ listenTyping: false,
419
+ updatePresence: false,
420
+ forceLogin: false,
421
+ autoMarkDelivery: false,
422
+ autoMarkRead: false,
423
+ autoReconnect: true,
424
+ logRecordSize: 100,
425
+ online: false,
426
+ emitReady: false,
427
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
428
+ };
425
429
 
426
- var prCallback = null;
427
- if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
428
- var rejectFunc = null;
429
- var resolveFunc = null;
430
- var returnPromise = new Promise(function (resolve, reject) {
431
- resolveFunc = resolve;
432
- rejectFunc = reject;
433
- });
434
- prCallback = function (error, api) {
435
- if (error) return rejectFunc(error);
436
- return resolveFunc(api);
437
- };
438
- callback = prCallback;
439
- }
430
+ var prCallback = null;
431
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
432
+ var rejectFunc = null;
433
+ var resolveFunc = null;
434
+ var returnPromise = new Promise(function (resolve, reject) {
435
+ resolveFunc = resolve;
436
+ rejectFunc = reject;
437
+ });
438
+ prCallback = function (error, api) {
439
+ if (error) return rejectFunc(error);
440
+ return resolveFunc(api);
441
+ };
442
+ callback = prCallback;
443
+ }
440
444
 
441
- if (loginData.email && loginData.password) {
442
- setOptions(globalOptions, {
443
- logLevel: "silent",
444
- forceLogin: true,
445
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
446
- });
447
- loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
448
- } else if (loginData.appState) {
449
- setOptions(globalOptions, options);
450
- return loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
451
- }
452
- return returnPromise;
445
+ if (loginData.email && loginData.password) {
446
+ setOptions(globalOptions, {
447
+ logLevel: "silent",
448
+ forceLogin: true,
449
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
450
+ });
451
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
452
+ } else if (loginData.appState) {
453
+ setOptions(globalOptions, options);
454
+ return loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
455
+ }
456
+ return returnPromise;
453
457
  }
454
458
 
455
459
 
456
- module.exports = login;
460
+ module.exports = login;