node-ainzfb-new 1.5.1 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/index.js +545 -579
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,396 +1,407 @@
1
- 'use strict';
2
-
3
- /!-[ Max Cpu Speed ]-!/
4
-
5
- process.env.UV_THREADPOOL_SIZE = require('os').cpus().length;
6
-
7
- /!-[ Global Set ]-!/
8
-
9
- global.isThread = new Array();
10
- global.isUser = new Array();
11
- global.startTime = Date.now();
12
- global.getText = require('gettext.js')();
13
-
14
- /!-[ Require All Package Need Use ]-!/
15
- /*globalThis.Fca = new Object({
16
- test: console,log("test"),
17
- Require: new Object({})
18
- });*/
19
- var utils = require("./utils"),
20
- cheerio = require("cheerio"),
21
- log = require("npmlog"),
22
- //{ getAccessToken } = require('./Extra/ExtraAddons'),
23
- logger = require('./logger'),
24
- fs = require('fs-extra'),
25
- getText = require('gettext.js')(),
26
- logger = require('./logger'),
27
- Fetch = require('got'),
28
- fs = require('fs-extra'),
29
- StateCrypt = require('./StateCrypt'),
30
- Client = require("@replit/database"),
31
- languageFile = require('./Language/index.json'),
32
- ObjFastConfig = {
33
- "Language": "en",
34
- "MainColor": "#9900FF",
35
- "BroadCast": true,
36
- "EncryptFeature": true,
37
- "PreKey": "",
38
- "Uptime": false
39
- };
40
-
41
- var defaultLogRecordSize = 100;
42
- log.maxRecordSize = defaultLogRecordSize;
43
-
44
- /!-[ Check File To Run Process ]-!/
45
-
46
- try {
47
- if (!fs.existsSync('./FastConfigFca.json')) {
48
- fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
49
- process.exit(1);
50
- } else if (fs.existsSync('./FastConfigFca.json')) {
51
- try {
52
- var DataLanguageSetting = require("../../FastConfigFca.json");
53
- } catch (e) {
54
- logger("Invalid Config Settings, Restoring Default...");
55
- fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
56
- process.exit(1);
57
- }
58
- try {
59
- if (DataLanguageSetting && !DataLanguageSetting.PreKey) {
60
- DataLanguageSetting.PreKey = "";
61
- fs.writeFileSync("./FastConfigFca.json", JSON.stringify(DataLanguageSetting, null, "\t"));
62
- }
63
- } catch (e) {
64
- console.log(e);
65
- }
66
- if (!languageFile.some(i => i.Language == DataLanguageSetting.Language)) {
67
- logger("Not Support Language: " + DataLanguageSetting.Language + " Only 'en' and 'vi'", "[ FCA-SUS ]");
68
- process.exit(0);
69
- }
70
- var Language = languageFile.find(i => i.Language == DataLanguageSetting.Language).Folder.Index;
71
- } else process.exit(1);
72
- if (utils.getType(DataLanguageSetting.BroadCast) != "Boolean" && DataLanguageSetting.BroadCast != undefined) {
73
- log.warn("FastConfig-BroadCast", getText.gettext(Language.IsNotABoolean, DataLanguageSetting.BroadCast));
74
- process.exit(0)
75
- } else if (DataLanguageSetting.BroadCast == undefined) {
76
- fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
77
- process.exit(1);
78
- }
79
-
80
- global.FastConfig = DataLanguageSetting;
81
-
82
- } catch (e) {
83
- console.log(e);
84
- logger.Error();
85
- }
1
+ "use strict";
86
2
 
87
- /!-[ Set Variable For Process ]-!/
3
+ var utils = require("./utils");
4
+ var cheerio = require("cheerio");
5
+ var log = require("npmlog");
88
6
 
89
- log.maxRecordSize = 100;
90
7
  var checkVerified = null;
91
8
 
92
- /!-[ Function setOptions ]-!/
9
+ var defaultLogRecordSize = 100;
10
+ log.maxRecordSize = defaultLogRecordSize;
93
11
 
94
12
  function setOptions(globalOptions, options) {
95
- Object.keys(options).map(function(key) {
96
- switch (key) {
97
- case 'pauseLog':
98
- if (options.pauseLog) log.pause();
99
- break;
100
- case 'online':
101
- globalOptions.online = Boolean(options.online);
102
- break;
103
- case 'logLevel':
104
- log.level = options.logLevel;
105
- globalOptions.logLevel = options.logLevel;
106
- break;
107
- case 'logRecordSize':
108
- log.maxRecordSize = options.logRecordSize;
109
- globalOptions.logRecordSize = options.logRecordSize;
110
- break;
111
- case 'selfListen':
112
- globalOptions.selfListen = Boolean(options.selfListen);
113
- break;
114
- case 'listenEvents':
115
- globalOptions.listenEvents = Boolean(options.listenEvents);
116
- break;
117
- case 'pageID':
118
- globalOptions.pageID = options.pageID.toString();
119
- break;
120
- case 'updatePresence':
121
- globalOptions.updatePresence = Boolean(options.updatePresence);
122
- break;
123
- case 'forceLogin':
124
- globalOptions.forceLogin = Boolean(options.forceLogin);
125
- break;
126
- case 'userAgent':
127
- globalOptions.userAgent = options.userAgent;
128
- break;
129
- case 'autoMarkDelivery':
130
- globalOptions.autoMarkDelivery = Boolean(options.autoMarkDelivery);
131
- break;
132
- case 'autoMarkRead':
133
- globalOptions.autoMarkRead = Boolean(options.autoMarkRead);
134
- break;
135
- case 'listenTyping':
136
- globalOptions.listenTyping = Boolean(options.listenTyping);
137
- break;
138
- case 'proxy':
139
- if (typeof options.proxy != "string") {
140
- delete globalOptions.proxy;
141
- utils.setProxy();
142
- } else {
143
- globalOptions.proxy = options.proxy;
144
- utils.setProxy(globalOptions.proxy);
145
- }
146
- break;
147
- case 'autoReconnect':
148
- globalOptions.autoReconnect = Boolean(options.autoReconnect);
149
- break;
150
- case 'emitReady':
151
- globalOptions.emitReady = Boolean(options.emitReady);
152
- break;
153
- default:
154
- log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
155
- break;
13
+ Object.keys(options).map(function (key) {
14
+ switch (key) {
15
+ case 'online':
16
+ globalOptions.online = Boolean(options.online);
17
+ break;
18
+ case 'logLevel':
19
+ log.level = options.logLevel;
20
+ globalOptions.logLevel = options.logLevel;
21
+ break;
22
+ case 'logRecordSize':
23
+ log.maxRecordSize = options.logRecordSize;
24
+ globalOptions.logRecordSize = options.logRecordSize;
25
+ break;
26
+ case 'selfListen':
27
+ globalOptions.selfListen = Boolean(options.selfListen);
28
+ break;
29
+ case 'listenEvents':
30
+ globalOptions.listenEvents = Boolean(options.listenEvents);
31
+ break;
32
+ case 'pageID':
33
+ globalOptions.pageID = options.pageID.toString();
34
+ break;
35
+ case 'updatePresence':
36
+ globalOptions.updatePresence = Boolean(options.updatePresence);
37
+ break;
38
+ case 'forceLogin':
39
+ globalOptions.forceLogin = Boolean(options.forceLogin);
40
+ break;
41
+ case 'userAgent':
42
+ globalOptions.userAgent = options.userAgent;
43
+ break;
44
+ case 'autoMarkDelivery':
45
+ globalOptions.autoMarkDelivery = Boolean(options.autoMarkDelivery);
46
+ break;
47
+ case 'autoMarkRead':
48
+ globalOptions.autoMarkRead = Boolean(options.autoMarkRead);
49
+ break;
50
+ case 'listenTyping':
51
+ globalOptions.listenTyping = Boolean(options.listenTyping);
52
+ break;
53
+ case 'proxy':
54
+ if (typeof options.proxy != "string") {
55
+ delete globalOptions.proxy;
56
+ utils.setProxy();
57
+ } else {
58
+ globalOptions.proxy = options.proxy;
59
+ utils.setProxy(globalOptions.proxy);
156
60
  }
157
- });
61
+ break;
62
+ case 'autoReconnect':
63
+ globalOptions.autoReconnect = Boolean(options.autoReconnect);
64
+ break;
65
+ case 'emitReady':
66
+ globalOptions.emitReady = Boolean(options.emitReady);
67
+ break;
68
+ default:
69
+ log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
70
+ break;
71
+ }
72
+ });
158
73
  }
159
74
 
160
- /!-[ Function BuildAPI ]-!/
161
-
162
- async function buildAPI(globalOptions, html, jar) {
163
- var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) { return val.cookieString().split("=")[0] === "c_user"; });
75
+ function buildAPI(globalOptions, html, jar) {
76
+ var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function (val) {
77
+ return val.cookieString().split("=")[0] === "c_user";
78
+ });
164
79
 
165
- if (maybeCookie.length === 0) throw { error: Language.ErrAppState };
80
+ if (maybeCookie.length === 0) {
81
+ throw { error: "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." };
82
+ }
166
83
 
167
- if (html.indexOf("/checkpoint/block/?next") > -1) log.warn("login", Language.CheckPointLevelI);
84
+ if (html.indexOf("/checkpoint/block/?next") > -1) {
85
+ log.warn("login", "Checkpoint detected. Please log in with a browser to verify.");
86
+ }
168
87
 
169
- var userID = maybeCookie[0].cookieString().split("=")[1].toString();
170
- logger(getText.gettext(Language.UID, userID), "[ FCA-SUS ]");
171
- process.env['UID'] = userID;
88
+ var userID = maybeCookie[0].cookieString().split("=")[1].toString();
89
+ log.info("login", `Logged in as ${userID}`);
90
+
91
+ try {
92
+ clearInterval(checkVerified);
93
+ } catch (_) { }
94
+
95
+ var clientID = (Math.random() * 2147483648 | 0).toString(16);
96
+
97
+
98
+ let oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
99
+ let mqttEndpoint = null;
100
+ let region = null;
101
+ let irisSeqID = null;
102
+ var noMqttData = null;
103
+
104
+ if (oldFBMQTTMatch) {
105
+ irisSeqID = oldFBMQTTMatch[1];
106
+ mqttEndpoint = oldFBMQTTMatch[2];
107
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
108
+ log.info("login", `Got this account's message region: ${region}`);
109
+ } else {
110
+ let newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
111
+ if (newFBMQTTMatch) {
112
+ irisSeqID = newFBMQTTMatch[2];
113
+ mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
114
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
115
+ log.info("login", `Got this account's message region: ${region}`);
116
+ } else {
117
+ let legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
118
+ if (legacyFBMQTTMatch) {
119
+ mqttEndpoint = legacyFBMQTTMatch[4];
120
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
121
+ log.warn("login", `Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...`);
122
+ log.info("login", `Got this account's message region: ${region}`);
123
+ log.info("login", `[Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`);
124
+ } else {
125
+ log.warn("login", "Cannot get MQTT region & sequence ID.");
126
+ noMqttData = html;
127
+ }
128
+ }
129
+ }
172
130
 
173
- try {
174
- clearInterval(checkVerified);
175
- } catch (e) {
176
- console.log(e);
131
+ // All data available to api functions
132
+ var ctx = {
133
+ userID: userID,
134
+ jar: jar,
135
+ clientID: clientID,
136
+ globalOptions: globalOptions,
137
+ loggedIn: true,
138
+ access_token: 'NONE',
139
+ clientMutationId: 0,
140
+ mqttClient: undefined,
141
+ lastSeqId: irisSeqID,
142
+ syncToken: undefined,
143
+ mqttEndpoint,
144
+ region,
145
+ firstListen: true
146
+ };
147
+
148
+ var api = {
149
+ setOptions: setOptions.bind(null, globalOptions),
150
+ getAppState: function getAppState() {
151
+ return utils.getAppState(jar);
177
152
  }
153
+ };
178
154
 
179
- var clientID = (Math.random() * 2147483648 | 0).toString(16);
155
+ if (noMqttData) {
156
+ api["htmlData"] = noMqttData;
157
+ }
180
158
 
181
- let oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
182
- let mqttEndpoint = null;
183
- let region = null;
184
- let irisSeqID = null;
185
- var noMqttData = null;
159
+ const apiFuncNames = [
160
+ 'addExternalModule',
161
+ 'addUserToGroup',
162
+ 'changeAdminStatus',
163
+ 'changeArchivedStatus',
164
+ 'changeBio',
165
+ 'changeBlockedStatus',
166
+ 'changeGroupImage',
167
+ 'changeNickname',
168
+ 'changeThreadColor',
169
+ 'changeThreadEmoji',
170
+ 'createNewGroup',
171
+ 'createPoll',
172
+ 'deleteMessage',
173
+ 'deleteThread',
174
+ 'forwardAttachment',
175
+ 'getCurrentUserID',
176
+ 'getEmojiUrl',
177
+ 'getFriendsList',
178
+ 'getThreadHistory',
179
+ 'getThreadInfo',
180
+ 'getThreadList',
181
+ 'getThreadPictures',
182
+ 'getUserID',
183
+ 'getUserInfo',
184
+ 'handleMessageRequest',
185
+ 'listenMqtt',
186
+ 'logout',
187
+ 'markAsDelivered',
188
+ 'markAsRead',
189
+ 'markAsReadAll',
190
+ 'markAsSeen',
191
+ 'muteThread',
192
+ 'removeUserFromGroup',
193
+ 'resolvePhotoUrl',
194
+ 'searchForThread',
195
+ 'sendMessage',
196
+ 'sendTypingIndicator',
197
+ 'setMessageReaction',
198
+ 'setTitle',
199
+ 'threadColors',
200
+ 'unsendMessage',
201
+
202
+ // HTTP
203
+ 'httpGet',
204
+ 'httpPost',
205
+
206
+ // Deprecated features
207
+ "getThreadListDeprecated",
208
+ 'getThreadHistoryDeprecated',
209
+ 'getThreadInfoDeprecated',
210
+ ];
211
+
212
+ var defaultFuncs = utils.makeDefaults(html, userID, ctx);
213
+
214
+ // Load all api functions in a loop
215
+ apiFuncNames.map(function (v) {
216
+ api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
217
+ });
218
+
219
+ //Removing original `listen` that uses pull.
220
+ //Map it to listenMqtt instead for backward compatibly.
221
+ api.listen = api.listenMqtt;
222
+
223
+ return [ctx, defaultFuncs, api];
224
+ }
186
225
 
187
- if (oldFBMQTTMatch) {
188
- irisSeqID = oldFBMQTTMatch[1];
189
- mqttEndpoint = oldFBMQTTMatch[2];
190
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
191
- logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
192
- } else {
193
- let newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
194
- if (newFBMQTTMatch) {
195
- irisSeqID = newFBMQTTMatch[2];
196
- mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
197
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
198
- logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
199
- } else {
200
- let legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
201
- if (legacyFBMQTTMatch) {
202
- mqttEndpoint = legacyFBMQTTMatch[4];
203
- region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
204
- log.warn("login", `Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...`);
205
- logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
206
- logger("login", `[Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`);
207
- } else {
208
- log.warn("login", getText.gettext(Language.NoAreaData));
209
- noMqttData = html;
210
- }
211
- }
212
- }
226
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
227
+ return function (res) {
228
+ var html = res.body;
229
+ var $ = cheerio.load(html);
230
+ var arr = [];
231
+
232
+ // This will be empty, but just to be sure we leave it
233
+ $("#login_form input").map(function (i, v) {
234
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
235
+ });
213
236
 
214
- var ctx = {
215
- userID: userID,
216
- jar: jar,
217
- clientID: clientID,
218
- globalOptions: globalOptions,
219
- loggedIn: true,
220
- access_token: 'none',
221
- clientMutationId: 0,
222
- mqttClient: undefined,
223
- lastSeqId: irisSeqID,
224
- syncToken: undefined,
225
- mqttEndpoint,
226
- region,
227
- firstListen: true
228
- };
237
+ arr = arr.filter(function (v) {
238
+ return v.val && v.val.length;
239
+ });
229
240
 
230
- var api = {
231
- setOptions: setOptions.bind(null, globalOptions),
232
- getAppState: function getAppState() {
233
- return utils.getAppState(jar);
241
+ var form = utils.arrToForm(arr);
242
+ form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
243
+ form.lgndim = Buffer.from("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
244
+ form.email = email;
245
+ form.pass = password;
246
+ form.default_persistent = '0';
247
+ form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
248
+ form.locale = 'en_US';
249
+ form.timezone = '240';
250
+ form.lgnjs = ~~(Date.now() / 1000);
251
+
252
+
253
+ // Getting cookies from the HTML page... (kill me now plz)
254
+ // we used to get a bunch of cookies in the headers of the response of the
255
+ // request, but FB changed and they now send those cookies inside the JS.
256
+ // They run the JS which then injects the cookies in the page.
257
+ // The "solution" is to parse through the html and find those cookies
258
+ // which happen to be conveniently indicated with a _js_ in front of their
259
+ // variable name.
260
+ //
261
+ // ---------- Very Hacky Part Starts -----------------
262
+ var willBeCookies = html.split("\"_js_");
263
+ willBeCookies.slice(1).map(function (val) {
264
+ var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
265
+ jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
266
+ });
267
+ // ---------- Very Hacky Part Ends -----------------
268
+
269
+ log.info("login", "Logging in...");
270
+ return utils
271
+ .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
272
+ .then(utils.saveCookies(jar))
273
+ .then(function (res) {
274
+ var headers = res.headers;
275
+ if (!headers.location) {
276
+ throw { error: "Wrong username/password." };
234
277
  }
235
- };
236
278
 
237
- if (noMqttData) api["htmlData"] = noMqttData;
279
+ // This means the account has login approvals turned on.
280
+ if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
281
+ log.info("login", "You have login approvals turned on.");
282
+ var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
238
283
 
239
- const apiFuncNames = fs.readdirSync(__dirname + "/src").filter((File) => File.endsWith(".js") && !File.includes('Dev'));
284
+ return utils
285
+ .get(headers.location, jar, null, loginOptions)
286
+ .then(utils.saveCookies(jar))
287
+ .then(function (res) {
288
+ var html = res.body;
289
+ // Make the form in advance which will contain the fb_dtsg and nh
290
+ var $ = cheerio.load(html);
291
+ var arr = [];
292
+ $("form input").map(function (i, v) {
293
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
294
+ });
240
295
 
241
- var defaultFuncs = utils.makeDefaults(html, userID, ctx);
296
+ arr = arr.filter(function (v) {
297
+ return v.val && v.val.length;
298
+ });
242
299
 
243
- // Load all api functions in a loop
244
- apiFuncNames.map(v => api[v.replace(".js", "")] = require('./src/' + v)(defaultFuncs, api, ctx));
245
- return [ctx, defaultFuncs, api];
246
- }
300
+ var form = utils.arrToForm(arr);
301
+ if (html.indexOf("checkpoint/?next") > -1) {
302
+ setTimeout(() => {
303
+ checkVerified = setInterval((_form) => {
304
+ /* utils
305
+ .post("https://www.facebook.com/login/approvals/approved_machine_check/", jar, form, loginOptions, null, {
306
+ "Referer": "https://www.facebook.com/checkpoint/?next"
307
+ })
308
+ .then(utils.saveCookies(jar))
309
+ .then(res => {
310
+ try {
311
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*()/, ""));
312
+ } catch (ex) {
313
+ clearInterval(checkVerified);
314
+ log.info("login", "Verified from browser. Logging in...");
315
+ return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
316
+ }
317
+ })
318
+ .catch(ex => {
319
+ log.error("login", ex);
320
+ }); */
321
+ }, 5000, {
322
+ fb_dtsg: form.fb_dtsg,
323
+ jazoest: form.jazoest,
324
+ dpr: 1
325
+ });
326
+ }, 2500);
327
+ throw {
328
+ error: 'login-approval',
329
+ continue: function submit2FA(code) {
330
+ form.approvals_code = code;
331
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
332
+ var prResolve = null;
333
+ var prReject = null;
334
+ var rtPromise = new Promise(function (resolve, reject) {
335
+ prResolve = resolve;
336
+ prReject = reject;
337
+ });
338
+ if (typeof code == "string") {
339
+ utils
340
+ .post(nextURL, jar, form, loginOptions)
341
+ .then(utils.saveCookies(jar))
342
+ .then(function (res) {
343
+ var $ = cheerio.load(res.body);
344
+ var error = $("#approvals_code").parent().attr("data-xui-error");
345
+ if (error) {
346
+ throw {
347
+ error: 'login-approval',
348
+ errordesc: "Invalid 2FA code.",
349
+ lerror: error,
350
+ continue: submit2FA
351
+ };
352
+ }
353
+ })
354
+ .then(function () {
355
+ // Use the same form (safe I hope)
356
+ delete form.no_fido;
357
+ delete form.approvals_code;
358
+ form.name_action_selected = 'dont_save'; //'save_device';
359
+
360
+ return utils
361
+ .post(nextURL, jar, form, loginOptions)
362
+ .then(utils.saveCookies(jar));
363
+ })
364
+ .then(function (res) {
365
+ var headers = res.headers;
366
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
367
+ throw { error: "Something went wrong with login approvals." };
368
+ }
247
369
 
248
- function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
249
- return function (res) {
250
- var html = res.body;
251
- var $ = cheerio.load(html);
252
- var arr = [];
253
-
254
- // This will be empty, but just to be sure we leave it
255
- $("#login_form input").map(function (i, v) {
256
- arr.push({ val: $(v).val(), name: $(v).attr("name") });
257
- });
258
-
259
- arr = arr.filter(function (v) {
260
- return v.val && v.val.length;
261
- });
262
-
263
- var form = utils.arrToForm(arr);
264
- form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
265
- form.lgndim = Buffer.from("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
266
- form.email = email;
267
- form.pass = password;
268
- form.default_persistent = '0';
269
- form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
270
- form.locale = 'en_US';
271
- form.timezone = '240';
272
- form.lgnjs = ~~(Date.now() / 1000);
273
-
274
-
275
- // Getting cookies from the HTML page... (kill me now plz)
276
- // we used to get a bunch of cookies in the headers of the response of the
277
- // request, but FB changed and they now send those cookies inside the JS.
278
- // They run the JS which then injects the cookies in the page.
279
- // The "solution" is to parse through the html and find those cookies
280
- // which happen to be conveniently indicated with a _js_ in front of their
281
- // variable name.
282
- //
283
- // ---------- Very Hacky Part Starts -----------------
284
- var willBeCookies = html.split("\"_js_");
285
- willBeCookies.slice(1).map(function (val) {
286
- var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
287
- jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
288
- });
289
- // ---------- Very Hacky Part Ends -----------------
290
-
291
- log.info("login", "Logging in...");
292
- return utils
293
- .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
294
- .then(utils.saveCookies(jar))
295
- .then(function (res) {
296
- var headers = res.headers;
297
- if (!headers.location) {
298
- throw { error: "Wrong username/password." };
299
- }
300
-
301
- // This means the account has login approvals turned on.
302
- if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
303
- log.info("login", "You have login approvals turned on.");
304
- var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
305
-
306
- return utils
307
- .get(headers.location, jar, null, loginOptions)
308
- .then(utils.saveCookies(jar))
309
- .then(function (res) {
310
- var html = res.body;
311
- // Make the form in advance which will contain the fb_dtsg and nh
312
- var $ = cheerio.load(html);
313
- var arr = [];
314
- $("form input").map(function (i, v) {
315
- arr.push({ val: $(v).val(), name: $(v).attr("name") });
316
- });
317
-
318
- arr = arr.filter(function (v) {
319
- return v.val && v.val.length;
320
- });
321
-
322
- var form = utils.arrToForm(arr);
323
- if (html.indexOf("checkpoint/?next") > -1) {
324
- setTimeout(() => {
325
- checkVerified = setInterval((_form) => {
326
- /* utils
327
- .post("https://www.facebook.com/login/approvals/approved_machine_check/", jar, form, loginOptions, null, {
370
+ var appState = utils.getAppState(jar);
371
+
372
+ if (callback === prCallback) {
373
+ callback = function (err, api) {
374
+ if (err) {
375
+ return prReject(err);
376
+ }
377
+ return prResolve(api);
378
+ };
379
+ }
380
+
381
+ // Simply call loginHelper because all it needs is the jar
382
+ // and will then complete the login process
383
+ return loginHelper(appState, email, password, loginOptions, callback);
384
+ })
385
+ .catch(function (err) {
386
+ // Check if using Promise instead of callback
387
+ if (callback === prCallback) {
388
+ prReject(err);
389
+ } else {
390
+ callback(err);
391
+ }
392
+ });
393
+ } else {
394
+ utils
395
+ .post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions, null, {
328
396
  "Referer": "https://www.facebook.com/checkpoint/?next"
329
397
  })
330
398
  .then(utils.saveCookies(jar))
331
399
  .then(res => {
332
400
  try {
333
- JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*()/, ""));
401
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
334
402
  } catch (ex) {
335
403
  clearInterval(checkVerified);
336
404
  log.info("login", "Verified from browser. Logging in...");
337
- return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
338
- }
339
- })
340
- .catch(ex => {
341
- log.error("login", ex);
342
- }); */
343
- }, 5000, {
344
- fb_dtsg: form.fb_dtsg,
345
- jazoest: form.jazoest,
346
- dpr: 1
347
- });
348
- }, 2500);
349
- throw {
350
- error: 'login-approval',
351
- continue: function submit2FA(code) {
352
- form.approvals_code = code;
353
- form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
354
- var prResolve = null;
355
- var prReject = null;
356
- var rtPromise = new Promise(function (resolve, reject) {
357
- prResolve = resolve;
358
- prReject = reject;
359
- });
360
- if (typeof code == "string") {
361
- utils
362
- .post(nextURL, jar, form, loginOptions)
363
- .then(utils.saveCookies(jar))
364
- .then(function (res) {
365
- var $ = cheerio.load(res.body);
366
- var error = $("#approvals_code").parent().attr("data-xui-error");
367
- if (error) {
368
- throw {
369
- error: 'login-approval',
370
- errordesc: "Invalid 2FA code.",
371
- lerror: error,
372
- continue: submit2FA
373
- };
374
- }
375
- })
376
- .then(function () {
377
- // Use the same form (safe I hope)
378
- delete form.no_fido;
379
- delete form.approvals_code;
380
- form.name_action_selected = 'dont_save'; //'save_device';
381
-
382
- return utils
383
- .post(nextURL, jar, form, loginOptions)
384
- .then(utils.saveCookies(jar));
385
- })
386
- .then(function (res) {
387
- var headers = res.headers;
388
- if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
389
- throw { error: "Something went wrong with login approvals." };
390
- }
391
-
392
- var appState = utils.getAppState(jar);
393
-
394
405
  if (callback === prCallback) {
395
406
  callback = function (err, api) {
396
407
  if (err) {
@@ -399,239 +410,194 @@ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
399
410
  return prResolve(api);
400
411
  };
401
412
  }
402
-
403
- // Simply call loginHelper because all it needs is the jar
404
- // and will then complete the login process
405
- return loginHelper(appState, email, password, loginOptions, callback);
406
- })
407
- .catch(function (err) {
408
- // Check if using Promise instead of callback
409
- if (callback === prCallback) {
410
- prReject(err);
411
- } else {
412
- callback(err);
413
- }
414
- });
415
- } else {
416
- utils
417
- .post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions, null, {
418
- "Referer": "https://www.facebook.com/checkpoint/?next"
419
- })
420
- .then(utils.saveCookies(jar))
421
- .then(res => {
422
- try {
423
- JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
424
- } catch (ex) {
425
- clearInterval(checkVerified);
426
- log.info("login", "Verified from browser. Logging in...");
427
- if (callback === prCallback) {
428
- callback = function (err, api) {
429
- if (err) {
430
- return prReject(err);
431
- }
432
- return prResolve(api);
433
- };
434
- }
435
- return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
436
- }
437
- })
438
- .catch(ex => {
439
- log.error("login", ex);
440
- if (callback === prCallback) {
441
- prReject(ex);
442
- } else {
443
- callback(ex);
444
- }
445
- });
446
- }
447
- return rtPromise;
413
+ return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
414
+ }
415
+ })
416
+ .catch(ex => {
417
+ log.error("login", ex);
418
+ if (callback === prCallback) {
419
+ prReject(ex);
420
+ } else {
421
+ callback(ex);
422
+ }
423
+ });
448
424
  }
449
- };
450
- } else {
451
- if (!loginOptions.forceLogin) {
452
- throw { error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again." };
453
- }
454
- if (html.indexOf("Suspicious Login Attempt") > -1) {
455
- form['submit[This was me]'] = "This was me";
456
- } else {
457
- form['submit[This Is Okay]'] = "This Is Okay";
425
+ return rtPromise;
458
426
  }
459
-
460
- return utils
461
- .post(nextURL, jar, form, loginOptions)
462
- .then(utils.saveCookies(jar))
463
- .then(function () {
464
- // Use the same form (safe I hope)
465
- form.name_action_selected = 'save_device';
466
-
467
- return utils
468
- .post(nextURL, jar, form, loginOptions)
469
- .then(utils.saveCookies(jar));
470
- })
471
- .then(function (res) {
472
- var headers = res.headers;
473
-
474
- if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
475
- throw { error: "Something went wrong with review recent login." };
476
- }
477
-
478
- var appState = utils.getAppState(jar);
479
-
480
- // Simply call loginHelper because all it needs is the jar
481
- // and will then complete the login process
482
- return loginHelper(appState, email, password, loginOptions, callback);
483
- })
484
- .catch(function (e) {
485
- callback(e);
486
- });
427
+ };
428
+ } else {
429
+ if (!loginOptions.forceLogin) {
430
+ throw { error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again." };
431
+ }
432
+ if (html.indexOf("Suspicious Login Attempt") > -1) {
433
+ form['submit[This was me]'] = "This was me";
434
+ } else {
435
+ form['submit[This Is Okay]'] = "This Is Okay";
487
436
  }
488
- });
489
- }
490
-
491
- return utils
492
- .get('https://www.facebook.com/', jar, null, loginOptions)
493
- .then(utils.saveCookies(jar));
494
- });
495
- };
496
- }
497
437
 
498
- function makeid(length) {
499
- var result = '';
500
- var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
501
- var charactersLength = characters.length;
502
- for (var i = 0; i < length; i++) {
503
- result += characters.charAt(Math.floor(Math.random() * charactersLength));
504
- }
505
- return result;
506
- }
438
+ return utils
439
+ .post(nextURL, jar, form, loginOptions)
440
+ .then(utils.saveCookies(jar))
441
+ .then(function () {
442
+ // Use the same form (safe I hope)
443
+ form.name_action_selected = 'save_device';
444
+
445
+ return utils
446
+ .post(nextURL, jar, form, loginOptions)
447
+ .then(utils.saveCookies(jar));
448
+ })
449
+ .then(function (res) {
450
+ var headers = res.headers;
451
+
452
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
453
+ throw { error: "Something went wrong with review recent login." };
454
+ }
455
+
456
+ var appState = utils.getAppState(jar);
457
+
458
+ // Simply call loginHelper because all it needs is the jar
459
+ // and will then complete the login process
460
+ return loginHelper(appState, email, password, loginOptions, callback);
461
+ })
462
+ .catch(function (e) {
463
+ callback(e);
464
+ });
465
+ }
466
+ });
467
+ }
507
468
 
469
+ return utils
470
+ .get('https://www.facebook.com/', jar, null, loginOptions)
471
+ .then(utils.saveCookies(jar));
472
+ });
473
+ };
474
+ }
508
475
 
509
476
  // Helps the login
510
477
  function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
511
- var mainPromise = null;
512
- var jar = utils.getJar();
513
-
514
- // If we're given an appState we loop through it and save each cookie
515
- // back into the jar.
516
- if (appState) {
517
- appState.map(function (c) {
518
- var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
519
- jar.setCookie(str, "http://" + c.domain);
478
+ var mainPromise = null;
479
+ var jar = utils.getJar();
480
+
481
+ // If we're given an appState we loop through it and save each cookie
482
+ // back into the jar.
483
+ if (appState) {
484
+ appState.map(function (c) {
485
+ var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
486
+ jar.setCookie(str, "http://" + c.domain);
487
+ });
488
+
489
+ // Load the main page.
490
+ mainPromise = utils
491
+ .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
492
+ .then(utils.saveCookies(jar));
493
+ } else {
494
+ // Open the main page, then we login with the given credentials and finally
495
+ // load the main page again (it'll give us some IDs that we need)
496
+ mainPromise = utils
497
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
498
+ .then(utils.saveCookies(jar))
499
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
500
+ .then(function () {
501
+ return utils
502
+ .get('https://www.facebook.com/', jar, null, globalOptions)
503
+ .then(utils.saveCookies(jar));
520
504
  });
521
-
522
- // Load the main page.
523
- mainPromise = utils
524
- .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
525
- .then(utils.saveCookies(jar));
526
- } else {
527
- // Open the main page, then we login with the given credentials and finally
528
- // load the main page again (it'll give us some IDs that we need)
529
- mainPromise = utils
530
- .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
531
- .then(utils.saveCookies(jar))
532
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
533
- .then(function () {
534
- return utils
535
- .get('https://www.facebook.com/', jar, null, globalOptions)
536
- .then(utils.saveCookies(jar));
537
- });
538
- }
539
-
540
- var ctx = null;
541
- var _defaultFuncs = null;
542
- var api = null;
543
-
505
+ }
506
+
507
+ var ctx = null;
508
+ var _defaultFuncs = null;
509
+ var api = null;
510
+
511
+ mainPromise = mainPromise
512
+ .then(function (res) {
513
+ // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
514
+ var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
515
+ var redirect = reg.exec(res.body);
516
+ if (redirect && redirect[1]) {
517
+ return utils
518
+ .get(redirect[1], jar, null, globalOptions)
519
+ .then(utils.saveCookies(jar));
520
+ }
521
+ return res;
522
+ })
523
+ .then(function (res) {
524
+ var html = res.body;
525
+ var stuff = buildAPI(globalOptions, html, jar);
526
+ ctx = stuff[0];
527
+ _defaultFuncs = stuff[1];
528
+ api = stuff[2];
529
+ return res;
530
+ });
531
+
532
+ // given a pageID we log in as a page
533
+ if (globalOptions.pageID) {
544
534
  mainPromise = mainPromise
545
- .then(function (res) {
546
- // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
547
- var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
548
- var redirect = reg.exec(res.body);
549
- if (redirect && redirect[1]) {
550
- return utils
551
- .get(redirect[1], jar, null, globalOptions)
552
- .then(utils.saveCookies(jar));
553
- }
554
- return res;
555
- })
556
- .then(function (res) {
557
- var html = res.body;
558
- var stuff = buildAPI(globalOptions, html, jar);
559
- ctx = stuff[0];
560
- _defaultFuncs = stuff[1];
561
- api = stuff[2];
562
- return res;
563
- });
564
-
565
- // given a pageID we log in as a page
566
- if (globalOptions.pageID) {
567
- mainPromise = mainPromise
568
- .then(function () {
569
- return utils
570
- .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
571
- })
572
- .then(function (resData) {
573
- var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
574
- url = url.substring(0, url.length - 1);
575
-
576
- return utils
577
- .get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
578
- });
579
- }
580
-
581
- // At the end we call the callback or catch an exception
582
- mainPromise
583
535
  .then(function () {
584
- log.info("login", 'Done logging in.');
585
- return callback(null, api);
536
+ return utils
537
+ .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
586
538
  })
587
- .catch(function (e) {
588
- log.error("login", e.error || e);
589
- callback(e);
539
+ .then(function (resData) {
540
+ var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
541
+ url = url.substring(0, url.length - 1);
542
+
543
+ return utils
544
+ .get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
590
545
  });
591
546
  }
592
547
 
593
- function login(loginData, options, callback) {
594
- if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
595
- callback = options;
596
- options = {};
597
- }
598
-
599
- var globalOptions = {
600
- selfListen: false,
601
- listenEvents: false,
602
- listenTyping: false,
603
- updatePresence: false,
604
- forceLogin: false,
605
- autoMarkDelivery: true,
606
- autoMarkRead: false,
607
- autoReconnect: true,
608
- logRecordSize: defaultLogRecordSize,
609
- online: true,
610
- emitReady: false,
611
- userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8"
548
+ // At the end we call the callback or catch an exception
549
+ mainPromise
550
+ .then(function () {
551
+ log.info("login", 'Done logging in.');
552
+ return callback(null, api);
553
+ })
554
+ .catch(function (e) {
555
+ log.error("login", e.error || e);
556
+ callback(e);
557
+ });
558
+ }
559
+
560
+ function login(loginData, options, callback) {
561
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
562
+ callback = options;
563
+ options = {};
564
+ }
565
+
566
+ var globalOptions = {
567
+ selfListen: false,
568
+ listenEvents: false,
569
+ listenTyping: false,
570
+ updatePresence: false,
571
+ forceLogin: false,
572
+ autoMarkDelivery: true,
573
+ autoMarkRead: false,
574
+ autoReconnect: true,
575
+ logRecordSize: defaultLogRecordSize,
576
+ online: true,
577
+ emitReady: false,
578
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8"
579
+ };
580
+
581
+ setOptions(globalOptions, options);
582
+
583
+ var prCallback = null;
584
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
585
+ var rejectFunc = null;
586
+ var resolveFunc = null;
587
+ var returnPromise = new Promise(function (resolve, reject) {
588
+ resolveFunc = resolve;
589
+ rejectFunc = reject;
590
+ });
591
+ prCallback = function (error, api) {
592
+ if (error) {
593
+ return rejectFunc(error);
594
+ }
595
+ return resolveFunc(api);
612
596
  };
613
-
614
- setOptions(globalOptions, options);
615
-
616
- var prCallback = null;
617
- if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
618
- var rejectFunc = null;
619
- var resolveFunc = null;
620
- var returnPromise = new Promise(function (resolve, reject) {
621
- resolveFunc = resolve;
622
- rejectFunc = reject;
623
- });
624
- prCallback = function (error, api) {
625
- if (error) {
626
- return rejectFunc(error);
627
- }
628
- return resolveFunc(api);
629
- };
630
- callback = prCallback;
631
- }
632
- loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
633
- return returnPromise;
597
+ callback = prCallback;
634
598
  }
635
-
636
- module.exports = login;
637
-
599
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
600
+ return returnPromise;
601
+ }
602
+
603
+ module.exports = login;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-ainzfb-new",
3
- "version": "1.5.1",
3
+ "version": "1.5.4",
4
4
  "description": "A Facebook chat API that doesn't rely on XMPP. Will NOT be deprecated after April 30th 2015.",
5
5
  "scripts": {
6
6
  "test": "mocha",