fb-nextgen 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fb-nextgen might be problematic. Click here for more details.

Files changed (76) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -0
  2. package/.cache/replit/nix/env.json +1 -0
  3. package/.config/configstore/update-notifier-npm.json +4 -0
  4. package/.github/workflows/nodejs.yml +26 -0
  5. package/.github/workflows/npmpublish.yml +30 -0
  6. package/.travis.yml +6 -0
  7. package/LICENSE-MIT +21 -0
  8. package/README.md +216 -0
  9. package/index.js +613 -0
  10. package/package.json +108 -0
  11. package/replit.nix +6 -0
  12. package/src/addExternalModule.js +19 -0
  13. package/src/addUserToGroup.js +113 -0
  14. package/src/changeAdminStatus.js +79 -0
  15. package/src/changeArchivedStatus.js +55 -0
  16. package/src/changeBio.js +77 -0
  17. package/src/changeBlockedStatus.js +47 -0
  18. package/src/changeGroupImage.js +129 -0
  19. package/src/changeNickname.js +59 -0
  20. package/src/changeThreadColor.js +71 -0
  21. package/src/changeThreadEmoji.js +55 -0
  22. package/src/createNewGroup.js +86 -0
  23. package/src/createPoll.js +71 -0
  24. package/src/deleteMessage.js +56 -0
  25. package/src/deleteThread.js +56 -0
  26. package/src/forwardAttachment.js +60 -0
  27. package/src/getCurrentUserID.js +7 -0
  28. package/src/getEmojiUrl.js +29 -0
  29. package/src/getFriendsList.js +84 -0
  30. package/src/getThreadHistory.js +645 -0
  31. package/src/getThreadHistoryDeprecated.js +93 -0
  32. package/src/getThreadInfo.js +148 -0
  33. package/src/getThreadInfoDeprecated.js +80 -0
  34. package/src/getThreadList.js +238 -0
  35. package/src/getThreadListDeprecated.js +75 -0
  36. package/src/getThreadPictures.js +79 -0
  37. package/src/getUserID.js +66 -0
  38. package/src/getUserInfo.js +76 -0
  39. package/src/handleFriendRequest.js +61 -0
  40. package/src/handleMessageRequest.js +65 -0
  41. package/src/httpGet.js +52 -0
  42. package/src/httpPost.js +52 -0
  43. package/src/listenMqtt.js +788 -0
  44. package/src/logout.js +75 -0
  45. package/src/markAsDelivered.js +58 -0
  46. package/src/markAsRead.js +80 -0
  47. package/src/markAsReadAll.js +50 -0
  48. package/src/markAsSeen.js +59 -0
  49. package/src/muteThread.js +52 -0
  50. package/src/removeUserFromGroup.js +79 -0
  51. package/src/resolvePhotoUrl.js +37 -0
  52. package/src/searchForThread.js +53 -0
  53. package/src/sendMessage.js +383 -0
  54. package/src/sendTypingIndicator.js +103 -0
  55. package/src/setMessageReaction.js +117 -0
  56. package/src/setPostReaction.js +76 -0
  57. package/src/setTitle.js +86 -0
  58. package/src/threadColors.js +57 -0
  59. package/src/unfriend.js +52 -0
  60. package/src/unsendMessage.js +49 -0
  61. package/src-cmd/bard.js +5048 -0
  62. package/src-cmd/gptdm.js +4175 -0
  63. package/src-cmd/gptgo.js +4253 -0
  64. package/src-cmd/gscholar.js +3747 -0
  65. package/src-cmd/openai.js +7370 -0
  66. package/src-cmd/playstore.js +1 -0
  67. package/src-cmd/skibiditoilet.js +4034 -0
  68. package/test/data/shareAttach.js +146 -0
  69. package/test/data/something.mov +0 -0
  70. package/test/data/test.png +0 -0
  71. package/test/data/test.txt +7 -0
  72. package/test/example-config.json +18 -0
  73. package/test/test-page.js +140 -0
  74. package/test/test.js +385 -0
  75. package/uptime.js +1 -0
  76. package/utils.js +1241 -0
package/index.js ADDED
@@ -0,0 +1,613 @@
1
+ "use strict";
2
+
3
+ var utils = require("./utils");
4
+ var cheerio = require("cheerio");
5
+ var log = require("npmlog");
6
+
7
+ var checkVerified = null;
8
+
9
+ var defaultLogRecordSize = 100;
10
+ log.maxRecordSize = defaultLogRecordSize;
11
+
12
+ function setOptions(globalOptions, options) {
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);
60
+ }
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
+ });
73
+ }
74
+
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
+ });
79
+
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
+ }
83
+
84
+ if (html.indexOf("/checkpoint/block/?next") > -1) {
85
+ log.warn("login", "Checkpoint detected. Please log in with a browser to verify.");
86
+ }
87
+
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
+ }
130
+
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);
152
+ }
153
+ };
154
+
155
+ if (noMqttData) {
156
+ api["htmlData"] = noMqttData;
157
+ }
158
+
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
+ 'httpGet',
202
+ 'httpPost',
203
+ "getThreadListDeprecated",
204
+ 'getThreadHistoryDeprecated',
205
+ 'getThreadInfoDeprecated'
206
+ ];
207
+
208
+ const apiFuncNamesCmd = [
209
+ 'openai',
210
+ 'gptdm',
211
+ 'skibiditoilet',
212
+ 'gptgo',
213
+ 'bard',
214
+ 'gscholar',
215
+ 'playstore'
216
+ ];
217
+
218
+ var defaultFuncs = utils.makeDefaults(html, userID, ctx);
219
+
220
+ apiFuncNames.map(function (v) {
221
+ api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
222
+ });
223
+
224
+ apiFuncNamesCmd.map(function (v) {
225
+ api[v] = require('./src-cmd/' + v)(defaultFuncs, api, ctx);
226
+ });
227
+
228
+ api.listen = api.listenMqtt;
229
+
230
+ return [ctx, defaultFuncs, api];
231
+ }
232
+
233
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
234
+ return function (res) {
235
+ var html = res.body;
236
+ var $ = cheerio.load(html);
237
+ var arr = [];
238
+
239
+ // This will be empty, but just to be sure we leave it
240
+ $("#login_form input").map(function (i, v) {
241
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
242
+ });
243
+
244
+ arr = arr.filter(function (v) {
245
+ return v.val && v.val.length;
246
+ });
247
+
248
+ var form = utils.arrToForm(arr);
249
+ form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
250
+ form.lgndim = Buffer.from("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
251
+ form.email = email;
252
+ form.pass = password;
253
+ form.default_persistent = '0';
254
+ form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
255
+ form.locale = 'en_US';
256
+ form.timezone = '240';
257
+ form.lgnjs = ~~(Date.now() / 1000);
258
+
259
+
260
+ // Getting cookies from the HTML page... (kill me now plz)
261
+ // we used to get a bunch of cookies in the headers of the response of the
262
+ // request, but FB changed and they now send those cookies inside the JS.
263
+ // They run the JS which then injects the cookies in the page.
264
+ // The "solution" is to parse through the html and find those cookies
265
+ // which happen to be conveniently indicated with a _js_ in front of their
266
+ // variable name.
267
+ //
268
+ // ---------- Very Hacky Part Starts -----------------
269
+ var willBeCookies = html.split("\"_js_");
270
+ willBeCookies.slice(1).map(function (val) {
271
+ var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
272
+ jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
273
+ });
274
+ // ---------- Very Hacky Part Ends -----------------
275
+
276
+ log.info("login", "Logging in...");
277
+ return utils
278
+ .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
279
+ .then(utils.saveCookies(jar))
280
+ .then(function (res) {
281
+ var headers = res.headers;
282
+ if (!headers.location) {
283
+ throw { error: "Wrong username/password." };
284
+ }
285
+
286
+ // This means the account has login approvals turned on.
287
+ if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
288
+ log.info("login", "You have login approvals turned on.");
289
+ var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
290
+
291
+ return utils
292
+ .get(headers.location, jar, null, loginOptions)
293
+ .then(utils.saveCookies(jar))
294
+ .then(function (res) {
295
+ var html = res.body;
296
+ // Make the form in advance which will contain the fb_dtsg and nh
297
+ var $ = cheerio.load(html);
298
+ var arr = [];
299
+ $("form input").map(function (i, v) {
300
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
301
+ });
302
+
303
+ arr = arr.filter(function (v) {
304
+ return v.val && v.val.length;
305
+ });
306
+
307
+ var form = utils.arrToForm(arr);
308
+ if (html.indexOf("checkpoint/?next") > -1) {
309
+ setTimeout(() => {
310
+ checkVerified = setInterval((_form) => {
311
+ /* utils
312
+ .post("https://www.facebook.com/login/approvals/approved_machine_check/", jar, form, loginOptions, null, {
313
+ "Referer": "https://www.facebook.com/checkpoint/?next"
314
+ })
315
+ .then(utils.saveCookies(jar))
316
+ .then(res => {
317
+ try {
318
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*()/, ""));
319
+ } catch (ex) {
320
+ clearInterval(checkVerified);
321
+ log.info("login", "Verified from browser. Logging in...");
322
+ return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
323
+ }
324
+ })
325
+ .catch(ex => {
326
+ log.error("login", ex);
327
+ }); */
328
+ }, 5000, {
329
+ fb_dtsg: form.fb_dtsg,
330
+ jazoest: form.jazoest,
331
+ dpr: 1
332
+ });
333
+ }, 2500);
334
+ throw {
335
+ error: 'login-approval',
336
+ continue: function submit2FA(code) {
337
+ form.approvals_code = code;
338
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
339
+ var prResolve = null;
340
+ var prReject = null;
341
+ var rtPromise = new Promise(function (resolve, reject) {
342
+ prResolve = resolve;
343
+ prReject = reject;
344
+ });
345
+ if (typeof code == "string") {
346
+ utils
347
+ .post(nextURL, jar, form, loginOptions)
348
+ .then(utils.saveCookies(jar))
349
+ .then(function (res) {
350
+ var $ = cheerio.load(res.body);
351
+ var error = $("#approvals_code").parent().attr("data-xui-error");
352
+ if (error) {
353
+ throw {
354
+ error: 'login-approval',
355
+ errordesc: "Invalid 2FA code.",
356
+ lerror: error,
357
+ continue: submit2FA
358
+ };
359
+ }
360
+ })
361
+ .then(function () {
362
+ // Use the same form (safe I hope)
363
+ delete form.no_fido;
364
+ delete form.approvals_code;
365
+ form.name_action_selected = 'dont_save'; //'save_device';
366
+
367
+ return utils
368
+ .post(nextURL, jar, form, loginOptions)
369
+ .then(utils.saveCookies(jar));
370
+ })
371
+ .then(function (res) {
372
+ var headers = res.headers;
373
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
374
+ throw { error: "Something went wrong with login approvals." };
375
+ }
376
+
377
+ var appState = utils.getAppState(jar);
378
+
379
+ if (callback === prCallback) {
380
+ callback = function (err, api) {
381
+ if (err) {
382
+ return prReject(err);
383
+ }
384
+ return prResolve(api);
385
+ };
386
+ }
387
+
388
+ // Simply call loginHelper because all it needs is the jar
389
+ // and will then complete the login process
390
+ return loginHelper(appState, email, password, loginOptions, callback);
391
+ })
392
+ .catch(function (err) {
393
+ // Check if using Promise instead of callback
394
+ if (callback === prCallback) {
395
+ prReject(err);
396
+ } else {
397
+ callback(err);
398
+ }
399
+ });
400
+ } else {
401
+ utils
402
+ .post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions, null, {
403
+ "Referer": "https://www.facebook.com/checkpoint/?next"
404
+ })
405
+ .then(utils.saveCookies(jar))
406
+ .then(res => {
407
+ try {
408
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
409
+ } catch (ex) {
410
+ clearInterval(checkVerified);
411
+ log.info("login", "Verified from browser. Logging in...");
412
+ if (callback === prCallback) {
413
+ callback = function (err, api) {
414
+ if (err) {
415
+ return prReject(err);
416
+ }
417
+ return prResolve(api);
418
+ };
419
+ }
420
+ return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
421
+ }
422
+ })
423
+ .catch(ex => {
424
+ log.error("login", ex);
425
+ if (callback === prCallback) {
426
+ prReject(ex);
427
+ } else {
428
+ callback(ex);
429
+ }
430
+ });
431
+ }
432
+ return rtPromise;
433
+ }
434
+ };
435
+ } else {
436
+ if (!loginOptions.forceLogin) {
437
+ throw { error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again." };
438
+ }
439
+ if (html.indexOf("Suspicious Login Attempt") > -1) {
440
+ form['submit[This was me]'] = "This was me";
441
+ } else {
442
+ form['submit[This Is Okay]'] = "This Is Okay";
443
+ }
444
+
445
+ return utils
446
+ .post(nextURL, jar, form, loginOptions)
447
+ .then(utils.saveCookies(jar))
448
+ .then(function () {
449
+ // Use the same form (safe I hope)
450
+ form.name_action_selected = 'save_device';
451
+
452
+ return utils
453
+ .post(nextURL, jar, form, loginOptions)
454
+ .then(utils.saveCookies(jar));
455
+ })
456
+ .then(function (res) {
457
+ var headers = res.headers;
458
+
459
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
460
+ throw { error: "Something went wrong with review recent login." };
461
+ }
462
+
463
+ var appState = utils.getAppState(jar);
464
+
465
+ // Simply call loginHelper because all it needs is the jar
466
+ // and will then complete the login process
467
+ return loginHelper(appState, email, password, loginOptions, callback);
468
+ })
469
+ .catch(function (e) {
470
+ callback(e);
471
+ });
472
+ }
473
+ });
474
+ }
475
+
476
+ return utils
477
+ .get('https://www.facebook.com/', jar, null, loginOptions)
478
+ .then(utils.saveCookies(jar));
479
+ });
480
+ };
481
+ }
482
+
483
+ // Helps the login
484
+ function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
485
+ var mainPromise = null;
486
+ var jar = utils.getJar();
487
+
488
+ // If we're given an appState we loop through it and save each cookie
489
+ // back into the jar.
490
+ if (appState) {
491
+ appState.map(function (c) {
492
+ var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
493
+ jar.setCookie(str, "http://" + c.domain);
494
+ });
495
+
496
+ // Load the main page.
497
+ mainPromise = utils
498
+ .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
499
+ .then(utils.saveCookies(jar));
500
+ } else {
501
+ // Open the main page, then we login with the given credentials and finally
502
+ // load the main page again (it'll give us some IDs that we need)
503
+ mainPromise = utils
504
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
505
+ .then(utils.saveCookies(jar))
506
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
507
+ .then(function () {
508
+ return utils
509
+ .get('https://www.facebook.com/', jar, null, globalOptions)
510
+ .then(utils.saveCookies(jar));
511
+ });
512
+ }
513
+
514
+ var ctx = null;
515
+ var _defaultFuncs = null;
516
+ var api = null;
517
+
518
+ mainPromise = mainPromise
519
+ .then(function (res) {
520
+ // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
521
+ var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
522
+ var redirect = reg.exec(res.body);
523
+ if (redirect && redirect[1]) {
524
+ return utils
525
+ .get(redirect[1], jar, null, globalOptions)
526
+ .then(utils.saveCookies(jar));
527
+ }
528
+ return res;
529
+ })
530
+ .then(function (res) {
531
+ var html = res.body;
532
+ var stuff = buildAPI(globalOptions, html, jar);
533
+ ctx = stuff[0];
534
+ _defaultFuncs = stuff[1];
535
+ api = stuff[2];
536
+ return res;
537
+ });
538
+
539
+ // given a pageID we log in as a page
540
+ if (globalOptions.pageID) {
541
+ mainPromise = mainPromise
542
+ .then(function () {
543
+ return utils
544
+ .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
545
+ })
546
+ .then(function (resData) {
547
+ var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
548
+ url = url.substring(0, url.length - 1);
549
+
550
+ return utils
551
+ .get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
552
+ });
553
+ }
554
+
555
+ // At the end we call the callback or catch an exception
556
+ mainPromise
557
+ .then(function () {
558
+ log.info("login", 'Done logging in.');
559
+ return callback(null, api);
560
+ })
561
+ .catch(function (e) {
562
+ log.error("login", e.error || e);
563
+ callback(e);
564
+ });
565
+ }
566
+
567
+ function login(loginData, options, callback) {
568
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
569
+ callback = options;
570
+ options = {};
571
+ }
572
+
573
+ var globalOptions = {
574
+ selfListen: false,
575
+ listenEvents: false,
576
+ listenTyping: false,
577
+ updatePresence: false,
578
+ forceLogin: false,
579
+ autoMarkDelivery: true,
580
+ autoMarkRead: false,
581
+ autoReconnect: true,
582
+ logRecordSize: defaultLogRecordSize,
583
+ online: true,
584
+ emitReady: false,
585
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18"
586
+ };
587
+
588
+ setOptions(globalOptions, options);
589
+
590
+ var prCallback = null;
591
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
592
+ var rejectFunc = null;
593
+ var resolveFunc = null;
594
+ var returnPromise = new Promise(function (resolve, reject) {
595
+ resolveFunc = resolve;
596
+ rejectFunc = reject;
597
+ });
598
+ prCallback = function (error, api) {
599
+ if (error) {
600
+ return rejectFunc(error);
601
+ }
602
+ return resolveFunc(api);
603
+ };
604
+ callback = prCallback;
605
+ }
606
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
607
+ return returnPromise;
608
+ }
609
+
610
+ module.exports = login;
611
+
612
+
613
+