alicezetion 1.0.0 → 1.0.2

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 (62) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/nix/env.json +1 -1
  3. package/alice/addExternalModule.js +19 -0
  4. package/alice/{add.js → addUserToGroup.js} +16 -2
  5. package/alice/{admin.js → changeAdminStatus.js} +17 -3
  6. package/alice/{archive.js → changeArchivedStatus.js} +16 -2
  7. package/alice/changeBio.js +77 -0
  8. package/alice/changeBlockedStatus.js +47 -0
  9. package/alice/{gcimage.js → changeGroupImage.js} +16 -2
  10. package/alice/{nickname.js → changeNickname.js} +17 -2
  11. package/alice/changeThreadColor.js +71 -0
  12. package/alice/{emoji.js → changeThreadEmoji.js} +16 -2
  13. package/alice/createNewGroup.js +86 -0
  14. package/alice/{poll.js → createPoll.js} +18 -2
  15. package/alice/{deletemsg.js → deleteMessage.js} +15 -2
  16. package/alice/{deletegc.js → deleteThread.js} +15 -2
  17. package/alice/{forward.js → forwardAttachment.js} +16 -3
  18. package/alice/{id.js → getCurrentUserID.js} +1 -1
  19. package/alice/{friend.js → getFriendsList.js} +17 -3
  20. package/alice/{history.js → getThreadHistory.js} +19 -6
  21. package/alice/{gchistorydeprecated.js → getThreadHistoryDeprecated.js} +18 -1
  22. package/alice/{gcinfo.js → getThreadInfo.js} +49 -13
  23. package/alice/{gcinfodeprecated.js → getThreadInfoDeprecated.js} +17 -2
  24. package/alice/{gclist.js → getThreadList.js} +27 -9
  25. package/alice/{gclistdeprecated.js → getThreadListDeprecated.js} +1 -1
  26. package/alice/{gcimg.js → getThreadPictures.js} +15 -2
  27. package/alice/{userid.js → getUserID.js} +16 -2
  28. package/alice/{userinfo.js → getUserInfo.js} +18 -3
  29. package/alice/handleFriendRequest.js +61 -0
  30. package/alice/{msgrequest.js → handleMessageRequest.js} +16 -2
  31. package/alice/httpGet.js +52 -0
  32. package/alice/httpPost.js +52 -0
  33. package/alice/listenMqtt.js +363 -134
  34. package/alice/logout.js +18 -2
  35. package/alice/{delivered.js → markAsDelivered.js} +19 -2
  36. package/alice/markAsRead.js +80 -0
  37. package/alice/{seen.js → markAsReadAll.js} +16 -2
  38. package/alice/markAsSeen.js +59 -0
  39. package/alice/{mute.js → muteThread.js} +16 -2
  40. package/alice/{kick.js → removeUserFromGroup.js} +16 -2
  41. package/alice/{resolveimgurl.js → resolvePhotoUrl.js} +16 -2
  42. package/alice/{gcsearch.js → searchForThread.js} +16 -2
  43. package/alice/{chat.js → sendMessage.js} +78 -34
  44. package/alice/sendTypingIndicator.js +103 -0
  45. package/alice/{react.js → setMessageReaction.js} +39 -4
  46. package/alice/setPostReaction.js +76 -0
  47. package/alice/{title.js → setTitle.js} +16 -3
  48. package/alice/threadColors.js +57 -0
  49. package/alice/unfriend.js +52 -0
  50. package/alice/{unsend.js → unsendMessage.js} +16 -2
  51. package/index.js +324 -143
  52. package/package.json +27 -18
  53. package/utils.js +137 -61
  54. package/.cache/replit/modules.stamp +0 -0
  55. package/README.md +0 -40
  56. package/alice/block.js +0 -72
  57. package/alice/color.js +0 -53
  58. package/alice/gcolor.js +0 -22
  59. package/alice/listen.js +0 -553
  60. package/alice/read.js +0 -52
  61. package/alice/typeindicator.js +0 -77
  62. /package/alice/{emojiurl.js → getEmojiUrl.js} +0 -0
package/index.js CHANGED
@@ -4,12 +4,17 @@ var utils = require("./utils");
4
4
  var cheerio = require("cheerio");
5
5
  var log = require("npmlog");
6
6
 
7
+ var checkVerified = null;
8
+
7
9
  var defaultLogRecordSize = 100;
8
10
  log.maxRecordSize = defaultLogRecordSize;
9
11
 
10
12
  function setOptions(globalOptions, options) {
11
- Object.keys(options).map(function(key) {
13
+ Object.keys(options).map(function (key) {
12
14
  switch (key) {
15
+ case 'online':
16
+ globalOptions.online = Boolean(options.online);
17
+ break;
13
18
  case 'logLevel':
14
19
  log.level = options.logLevel;
15
20
  globalOptions.logLevel = options.logLevel;
@@ -19,28 +24,46 @@ function setOptions(globalOptions, options) {
19
24
  globalOptions.logRecordSize = options.logRecordSize;
20
25
  break;
21
26
  case 'selfListen':
22
- globalOptions.selfListen = options.selfListen;
27
+ globalOptions.selfListen = Boolean(options.selfListen);
23
28
  break;
24
29
  case 'listenEvents':
25
- globalOptions.listenEvents = options.listenEvents;
30
+ globalOptions.listenEvents = Boolean(options.listenEvents);
26
31
  break;
27
32
  case 'pageID':
28
33
  globalOptions.pageID = options.pageID.toString();
29
34
  break;
30
35
  case 'updatePresence':
31
- globalOptions.updatePresence = options.updatePresence;
36
+ globalOptions.updatePresence = Boolean(options.updatePresence);
32
37
  break;
33
38
  case 'forceLogin':
34
- globalOptions.forceLogin = options.forceLogin;
39
+ globalOptions.forceLogin = Boolean(options.forceLogin);
35
40
  break;
36
41
  case 'userAgent':
37
42
  globalOptions.userAgent = options.userAgent;
38
43
  break;
39
44
  case 'autoMarkDelivery':
40
- globalOptions.autoMarkDelivery = options.autoMarkDelivery;
45
+ globalOptions.autoMarkDelivery = Boolean(options.autoMarkDelivery);
41
46
  break;
42
47
  case 'autoMarkRead':
43
- globalOptions.autoMarkRead = options.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);
44
67
  break;
45
68
  default:
46
69
  log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
@@ -50,19 +73,61 @@ function setOptions(globalOptions, options) {
50
73
  }
51
74
 
52
75
  function buildAPI(globalOptions, html, jar) {
53
- var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) {
76
+ var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function (val) {
54
77
  return val.cookieString().split("=")[0] === "c_user";
55
78
  });
56
79
 
57
- if(maybeCookie.length === 0) {
58
- 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."};
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.");
59
86
  }
60
87
 
61
88
  var userID = maybeCookie[0].cookieString().split("=")[1].toString();
62
- log.info("login", "Logged in");
89
+ log.info("login", `Logged in as ${userID}`);
90
+
91
+ try {
92
+ clearInterval(checkVerified);
93
+ } catch (_) { }
63
94
 
64
95
  var clientID = (Math.random() * 2147483648 | 0).toString(16);
65
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
+
66
131
  // All data available to api functions
67
132
  var ctx = {
68
133
  userID: userID,
@@ -73,83 +138,103 @@ function buildAPI(globalOptions, html, jar) {
73
138
  access_token: 'NONE',
74
139
  clientMutationId: 0,
75
140
  mqttClient: undefined,
76
- lastSeqId: 0,
77
- syncToken: undefined
141
+ lastSeqId: irisSeqID,
142
+ syncToken: undefined,
143
+ mqttEndpoint,
144
+ region,
145
+ firstListen: true
78
146
  };
79
147
 
80
- var bot = {
148
+ var api = {
81
149
  setOptions: setOptions.bind(null, globalOptions),
82
150
  getAppState: function getAppState() {
83
151
  return utils.getAppState(jar);
84
- },
152
+ }
85
153
  };
86
154
 
155
+ if (noMqttData) {
156
+ api["htmlData"] = noMqttData;
157
+ }
158
+
87
159
  const apiFuncNames = [
88
- "add",
89
- "admin",
90
- "archive",
91
- "block",
92
- "chat",
93
- "color",
94
- "deletegc",
95
- "deletemsg",
96
- "delivered",
97
- "emoji",
98
- "emojiurl",
99
- "forward",
100
- "friend",
101
- "gchistorydeprecated",
102
- "gcimage",
103
- "gcimg",
104
- "gcinfo",
105
- "gcinfodeprecated",
106
- "gclist",
107
- "gclistdeprecated",
108
- "gcolor",
109
- "gcsearch",
110
- "history",
111
- "id",
112
- "kick",
113
- "listen",
114
- "listenMqtt",
115
- "logout",
116
- "magrequest",
117
- "mute",
118
- "nickname",
119
- "poll",
120
- "react",
121
- "read",
122
- "resolveimgurl",
123
- "seen",
124
- "title",
125
- "typeindicator",
126
- "unsend",
127
- "userid",
128
- "userinfo"
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',
129
210
  ];
130
211
 
131
212
  var defaultFuncs = utils.makeDefaults(html, userID, ctx);
132
213
 
133
214
  // Load all api functions in a loop
134
- apiFuncNames.map(function(v) {
135
- bot[v] = require('./alice/' + v)(defaultFuncs, bot, ctx);
215
+ apiFuncNames.map(function (v) {
216
+ api[v] = require('./alice/' + v)(defaultFuncs, api, ctx);
136
217
  });
137
218
 
138
- return [ctx, defaultFuncs, bot];
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];
139
224
  }
140
225
 
141
- function makeLogin(jar, email, password, loginOptions, callback) {
142
- return function(res) {
226
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
227
+ return function (res) {
143
228
  var html = res.body;
144
229
  var $ = cheerio.load(html);
145
230
  var arr = [];
146
231
 
147
232
  // This will be empty, but just to be sure we leave it
148
- $("#login_form input").map(function(i, v){
149
- arr.push({val: $(v).val(), name: $(v).attr("name")});
233
+ $("#login_form input").map(function (i, v) {
234
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
150
235
  });
151
236
 
152
- arr = arr.filter(function(v) {
237
+ arr = arr.filter(function (v) {
153
238
  return v.val && v.val.length;
154
239
  });
155
240
 
@@ -160,7 +245,7 @@ function makeLogin(jar, email, password, loginOptions, callback) {
160
245
  form.pass = password;
161
246
  form.default_persistent = '0';
162
247
  form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
163
- form.locale = 'fil_PH';
248
+ form.locale = 'en_US';
164
249
  form.timezone = '240';
165
250
  form.lgnjs = ~~(Date.now() / 1000);
166
251
 
@@ -175,7 +260,7 @@ function makeLogin(jar, email, password, loginOptions, callback) {
175
260
  //
176
261
  // ---------- Very Hacky Part Starts -----------------
177
262
  var willBeCookies = html.split("\"_js_");
178
- willBeCookies.slice(1).map(function(val) {
263
+ willBeCookies.slice(1).map(function (val) {
179
264
  var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
180
265
  jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
181
266
  });
@@ -183,12 +268,12 @@ function makeLogin(jar, email, password, loginOptions, callback) {
183
268
 
184
269
  log.info("login", "Logging in...");
185
270
  return utils
186
- .post("https://www.facebook.com/login.php?login_attempt=1&lwv=110", jar, form, loginOptions)
271
+ .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
187
272
  .then(utils.saveCookies(jar))
188
- .then(function(res) {
273
+ .then(function (res) {
189
274
  var headers = res.headers;
190
275
  if (!headers.location) {
191
- throw {error: "Wrong username/password."};
276
+ throw { error: "Wrong username/password." };
192
277
  }
193
278
 
194
279
  // This means the account has login approvals turned on.
@@ -199,57 +284,150 @@ function makeLogin(jar, email, password, loginOptions, callback) {
199
284
  return utils
200
285
  .get(headers.location, jar, null, loginOptions)
201
286
  .then(utils.saveCookies(jar))
202
- .then(function(res) {
287
+ .then(function (res) {
203
288
  var html = res.body;
204
289
  // Make the form in advance which will contain the fb_dtsg and nh
205
290
  var $ = cheerio.load(html);
206
291
  var arr = [];
207
- $("form input").map(function(i, v){
208
- arr.push({val: $(v).val(), name: $(v).attr("name")});
292
+ $("form input").map(function (i, v) {
293
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
209
294
  });
210
295
 
211
- arr = arr.filter(function(v) {
296
+ arr = arr.filter(function (v) {
212
297
  return v.val && v.val.length;
213
298
  });
214
299
 
215
300
  var form = utils.arrToForm(arr);
216
301
  if (html.indexOf("checkpoint/?next") > -1) {
217
- throw {
218
- error: 'login-approval',
219
- continue: function(code) {
220
- form.approvals_code = code;
221
- form['submit[Continue]'] = 'Continue';
222
- return utils
223
- .post(nextURL, jar, form, loginOptions)
224
- .then(utils.saveCookies(jar))
225
- .then(function() {
226
- // Use the same form (safe I hope)
227
- form.name_action_selected = 'save_device';
228
-
229
- return utils
230
- .post(nextURL, jar, form, loginOptions)
231
- .then(utils.saveCookies(jar));
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"
232
307
  })
233
- .then(function(res) {
234
- var headers = res.headers;
235
- if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
236
- throw {error: "Something went wrong with login approvals."};
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);
237
316
  }
238
-
239
- var appState = utils.getAppState(jar);
240
-
241
- // Simply call loginHelper because all it needs is the jar
242
- // and will then complete the login process
243
- return loginHelper(appState, email, password, loginOptions, callback);
244
317
  })
245
- .catch(function(err) {
246
- callback(err);
247
- });
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
+ }
369
+
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, {
396
+ "Referer": "https://www.facebook.com/checkpoint/?next"
397
+ })
398
+ .then(utils.saveCookies(jar))
399
+ .then(res => {
400
+ try {
401
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
402
+ } catch (ex) {
403
+ clearInterval(checkVerified);
404
+ log.info("login", "Verified from browser. Logging in...");
405
+ if (callback === prCallback) {
406
+ callback = function (err, api) {
407
+ if (err) {
408
+ return prReject(err);
409
+ }
410
+ return prResolve(api);
411
+ };
412
+ }
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
+ });
424
+ }
425
+ return rtPromise;
248
426
  }
249
427
  };
250
428
  } else {
251
429
  if (!loginOptions.forceLogin) {
252
- throw {error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again."};
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." };
253
431
  }
254
432
  if (html.indexOf("Suspicious Login Attempt") > -1) {
255
433
  form['submit[This was me]'] = "This was me";
@@ -260,7 +438,7 @@ function makeLogin(jar, email, password, loginOptions, callback) {
260
438
  return utils
261
439
  .post(nextURL, jar, form, loginOptions)
262
440
  .then(utils.saveCookies(jar))
263
- .then(function() {
441
+ .then(function () {
264
442
  // Use the same form (safe I hope)
265
443
  form.name_action_selected = 'save_device';
266
444
 
@@ -268,11 +446,11 @@ function makeLogin(jar, email, password, loginOptions, callback) {
268
446
  .post(nextURL, jar, form, loginOptions)
269
447
  .then(utils.saveCookies(jar));
270
448
  })
271
- .then(function(res) {
449
+ .then(function (res) {
272
450
  var headers = res.headers;
273
451
 
274
452
  if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
275
- throw {error: "Something went wrong with review recent login."};
453
+ throw { error: "Something went wrong with review recent login." };
276
454
  }
277
455
 
278
456
  var appState = utils.getAppState(jar);
@@ -281,7 +459,7 @@ function makeLogin(jar, email, password, loginOptions, callback) {
281
459
  // and will then complete the login process
282
460
  return loginHelper(appState, email, password, loginOptions, callback);
283
461
  })
284
- .catch(function(e) {
462
+ .catch(function (e) {
285
463
  callback(e);
286
464
  });
287
465
  }
@@ -296,30 +474,30 @@ function makeLogin(jar, email, password, loginOptions, callback) {
296
474
  }
297
475
 
298
476
  // Helps the login
299
- function loginHelper(appState, email, password, globalOptions, callback) {
477
+ function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
300
478
  var mainPromise = null;
301
479
  var jar = utils.getJar();
302
480
 
303
481
  // If we're given an appState we loop through it and save each cookie
304
482
  // back into the jar.
305
- if(appState) {
306
- appState.map(function(c) {
483
+ if (appState) {
484
+ appState.map(function (c) {
307
485
  var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
308
486
  jar.setCookie(str, "http://" + c.domain);
309
487
  });
310
488
 
311
489
  // Load the main page.
312
490
  mainPromise = utils
313
- .get('https://www.facebook.com/', jar, null, globalOptions)
491
+ .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
314
492
  .then(utils.saveCookies(jar));
315
493
  } else {
316
494
  // Open the main page, then we login with the given credentials and finally
317
495
  // load the main page again (it'll give us some IDs that we need)
318
496
  mainPromise = utils
319
- .get("https://www.facebook.com/", null, null, globalOptions)
497
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
320
498
  .then(utils.saveCookies(jar))
321
- .then(makeLogin(jar, email, password, globalOptions, callback))
322
- .then(function() {
499
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
500
+ .then(function () {
323
501
  return utils
324
502
  .get('https://www.facebook.com/', jar, null, globalOptions)
325
503
  .then(utils.saveCookies(jar));
@@ -327,11 +505,11 @@ function loginHelper(appState, email, password, globalOptions, callback) {
327
505
  }
328
506
 
329
507
  var ctx = null;
330
- var defaultFuncs = null;
331
- var bot = null;
508
+ var _defaultFuncs = null;
509
+ var api = null;
332
510
 
333
511
  mainPromise = mainPromise
334
- .then(function(res) {
512
+ .then(function (res) {
335
513
  // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
336
514
  var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
337
515
  var redirect = reg.exec(res.body);
@@ -342,41 +520,23 @@ function loginHelper(appState, email, password, globalOptions, callback) {
342
520
  }
343
521
  return res;
344
522
  })
345
- .then(function(res) {
523
+ .then(function (res) {
346
524
  var html = res.body;
347
525
  var stuff = buildAPI(globalOptions, html, jar);
348
526
  ctx = stuff[0];
349
- defaultFuncs = stuff[1];
527
+ _defaultFuncs = stuff[1];
350
528
  api = stuff[2];
351
529
  return res;
352
- })
353
- .then(function() {
354
- var form = {
355
- reason: 6
356
- };
357
- log.info("login", 'Request to reconnect');
358
- return defaultFuncs
359
- .get("https://www.facebook.com/ajax/presence/reconnect.php", ctx.jar, form)
360
- .then(utils.saveCookies(ctx.jar));
361
- })
362
- .then(function() {
363
- var presence = utils.generatePresence(ctx.userID);
364
- ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
365
- ctx.jar.setCookie("presence=" + presence + "; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
366
- ctx.jar.setCookie("locale=fil_PH; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
367
- ctx.jar.setCookie("locale=fil_PH; path=/; domain=.messenger.com; secure", "https://www.messenger.com");
368
- ctx.jar.setCookie("a11y=" + utils.generateAccessiblityCookie() + "; path=/; domain=.facebook.com; secure", "https://www.facebook.com");
369
- return true;
370
530
  });
371
531
 
372
532
  // given a pageID we log in as a page
373
533
  if (globalOptions.pageID) {
374
534
  mainPromise = mainPromise
375
- .then(function() {
535
+ .then(function () {
376
536
  return utils
377
537
  .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
378
538
  })
379
- .then(function(resData) {
539
+ .then(function (resData) {
380
540
  var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
381
541
  url = url.substring(0, url.length - 1);
382
542
 
@@ -387,18 +547,18 @@ function loginHelper(appState, email, password, globalOptions, callback) {
387
547
 
388
548
  // At the end we call the callback or catch an exception
389
549
  mainPromise
390
- .then(function() {
550
+ .then(function () {
391
551
  log.info("login", 'Done logging in.');
392
552
  return callback(null, api);
393
553
  })
394
- .catch(function(e) {
554
+ .catch(function (e) {
395
555
  log.error("login", e.error || e);
396
556
  callback(e);
397
557
  });
398
558
  }
399
559
 
400
560
  function login(loginData, options, callback) {
401
- if(utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
561
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
402
562
  callback = options;
403
563
  options = {};
404
564
  }
@@ -406,17 +566,38 @@ function login(loginData, options, callback) {
406
566
  var globalOptions = {
407
567
  selfListen: false,
408
568
  listenEvents: false,
569
+ listenTyping: false,
409
570
  updatePresence: false,
410
571
  forceLogin: false,
411
572
  autoMarkDelivery: true,
412
573
  autoMarkRead: false,
574
+ autoReconnect: true,
413
575
  logRecordSize: defaultLogRecordSize,
414
- 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"
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"
415
579
  };
416
580
 
417
581
  setOptions(globalOptions, options);
418
582
 
419
- loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback);
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);
596
+ };
597
+ callback = prCallback;
598
+ }
599
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
600
+ return returnPromise;
420
601
  }
421
602
 
422
603
  module.exports = login;