alicezetion 1.8.4 → 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/modules.stamp +1 -0
  3. package/.cache/replit/nix/env.json +1 -1
  4. package/index.js +375 -210
  5. package/leiamnash/addExternalModule.js +15 -0
  6. package/leiamnash/addUserToGroup.js +77 -0
  7. package/leiamnash/changeAdminStatus.js +47 -0
  8. package/leiamnash/changeArchivedStatus.js +41 -0
  9. package/leiamnash/changeAvatar.js +127 -0
  10. package/leiamnash/changeBio.js +64 -0
  11. package/leiamnash/changeBlockedStatus.js +36 -0
  12. package/leiamnash/changeGroupImage.js +105 -0
  13. package/leiamnash/changeNickname.js +43 -0
  14. package/leiamnash/changeThreadColor.js +61 -0
  15. package/leiamnash/changeThreadEmoji.js +41 -0
  16. package/{src → leiamnash}/chat.js +3 -28
  17. package/leiamnash/createNewGroup.js +70 -0
  18. package/leiamnash/createPoll.js +59 -0
  19. package/leiamnash/deleteMessage.js +44 -0
  20. package/leiamnash/deleteThread.js +42 -0
  21. package/leiamnash/forwardAttachment.js +47 -0
  22. package/leiamnash/forwardMessage.js +0 -0
  23. package/leiamnash/getCurrentUserID.js +7 -0
  24. package/leiamnash/getEmojiUrl.js +27 -0
  25. package/leiamnash/getFriendsList.js +73 -0
  26. package/leiamnash/getInfoVideo.js +134 -0
  27. package/leiamnash/getThreadHistory.js +537 -0
  28. package/leiamnash/getThreadHistoryDeprecated.js +71 -0
  29. package/{src → leiamnash}/getThreadInfo.js +54 -70
  30. package/leiamnash/getThreadInfoDeprecated.js +56 -0
  31. package/leiamnash/getThreadList.js +213 -0
  32. package/leiamnash/getThreadListDeprecated.js +46 -0
  33. package/leiamnash/getThreadPictures.js +59 -0
  34. package/leiamnash/getUserID.js +61 -0
  35. package/leiamnash/getUserInfo.js +66 -0
  36. package/leiamnash/handleFriendRequest.js +46 -0
  37. package/leiamnash/handleMessageRequest.js +47 -0
  38. package/leiamnash/httpGet.js +47 -0
  39. package/leiamnash/httpPost.js +47 -0
  40. package/leiamnash/httpPostFormData.js +42 -0
  41. package/{src → leiamnash}/listenMqtt.js +6 -16
  42. package/leiamnash/logout.js +68 -0
  43. package/leiamnash/markAsDelivered.js +47 -0
  44. package/leiamnash/markAsRead.js +70 -0
  45. package/leiamnash/markAsReadAll.js +40 -0
  46. package/leiamnash/markAsSeen.js +48 -0
  47. package/leiamnash/muteThread.js +45 -0
  48. package/leiamnash/react.js +109 -0
  49. package/{src → leiamnash}/refreshFb_dtsg.js +1 -1
  50. package/leiamnash/removeUserFromGroup.js +45 -0
  51. package/leiamnash/resolvePhotoUrl.js +36 -0
  52. package/leiamnash/searchForThread.js +42 -0
  53. package/leiamnash/seen.js +40 -0
  54. package/leiamnash/sendMessage.js +315 -0
  55. package/leiamnash/sendTypingIndicator.js +70 -0
  56. package/leiamnash/setMessageReaction.js +103 -0
  57. package/leiamnash/setPostReaction.js +63 -0
  58. package/leiamnash/setTitle.js +70 -0
  59. package/leiamnash/threadColors.js +41 -0
  60. package/leiamnash/unfriend.js +42 -0
  61. package/leiamnash/unsendMessage.js +39 -0
  62. package/leiamnash/uploadAttachment.js +96 -0
  63. package/package.json +3 -6
  64. package/replit.nix +4 -4
  65. package/utils.js +176 -135
  66. package/src/addExternalModule.js +0 -17
  67. package/src/addUserToGroup.js +0 -113
  68. package/src/changeAdminStatus.js +0 -79
  69. package/src/changeArchivedStatus.js +0 -55
  70. package/src/changeAvatar.js +0 -93
  71. package/src/changeBio.js +0 -77
  72. package/src/changeBlockedStatus.js +0 -47
  73. package/src/changeCover.js +0 -73
  74. package/src/changeGroupImage.js +0 -132
  75. package/src/changeName.js +0 -79
  76. package/src/changeNickname.js +0 -59
  77. package/src/changeThreadColor.js +0 -65
  78. package/src/changeThreadEmoji.js +0 -55
  79. package/src/createNewGroup.js +0 -86
  80. package/src/createPoll.js +0 -71
  81. package/src/data/getThreadInfo.json +0 -1
  82. package/src/deleteMessage.js +0 -56
  83. package/src/deleteThread.js +0 -56
  84. package/src/forwardAttachment.js +0 -60
  85. package/src/getAccess.js +0 -112
  86. package/src/getAvatarUser.js +0 -78
  87. package/src/getCurrentUserID.js +0 -7
  88. package/src/getEmojiUrl.js +0 -29
  89. package/src/getFriendsList.js +0 -83
  90. package/src/getThreadHistory.js +0 -666
  91. package/src/getThreadList.js +0 -237
  92. package/src/getThreadPictures.js +0 -79
  93. package/src/getUserID.js +0 -66
  94. package/src/getUserInfo.js +0 -163
  95. package/src/handleFriendRequest.js +0 -61
  96. package/src/handleMessageRequest.js +0 -65
  97. package/src/httpGet.js +0 -57
  98. package/src/httpPost.js +0 -57
  99. package/src/httpPostFormData.js +0 -63
  100. package/src/listenNotification.js +0 -88
  101. package/src/logout.js +0 -275
  102. package/src/markAsDelivered.js +0 -58
  103. package/src/markAsRead.js +0 -80
  104. package/src/markAsReadAll.js +0 -50
  105. package/src/markAsSeen.js +0 -59
  106. package/src/muteThread.js +0 -52
  107. package/src/react.js +0 -117
  108. package/src/removeUserFromGroup.js +0 -79
  109. package/src/resolvePhotoUrl.js +0 -45
  110. package/src/searchForThread.js +0 -53
  111. package/src/searchStickers.js +0 -52
  112. package/src/seen.js +0 -50
  113. package/src/sendMessage.js +0 -477
  114. package/src/sendMessageMqtt.js +0 -316
  115. package/src/sendTypingIndicator.js +0 -103
  116. package/src/setMessageReaction.js +0 -117
  117. package/src/setPostReaction.js +0 -109
  118. package/src/setTitle.js +0 -86
  119. package/src/threadColors.js +0 -131
  120. package/src/unfriend.js +0 -52
  121. package/src/unsendMessage.js +0 -49
  122. /package/{src → leiamnash}/getMessage.js +0 -0
package/index.js CHANGED
@@ -1,14 +1,20 @@
1
1
  "use strict";
2
2
 
3
- var utils = require("./utils");
4
- var cheerio = require("cheerio");
5
- var log = require('npmlog');
6
- var defaultLogRecordSize = 100;
3
+ const utils = require("./utils");
4
+ const cheerio = require("cheerio");
5
+ const log = require("npmlog");
6
+
7
+ let checkVerified = null;
8
+
9
+ const defaultLogRecordSize = 100;
7
10
  log.maxRecordSize = defaultLogRecordSize;
8
11
 
9
12
  function setOptions(globalOptions, options) {
10
13
  Object.keys(options).map(function(key) {
11
14
  switch (key) {
15
+ case 'pauseLog':
16
+ if (options.pauseLog) log.pause();
17
+ break;
12
18
  case 'online':
13
19
  globalOptions.online = Boolean(options.online);
14
20
  break;
@@ -23,9 +29,6 @@ function setOptions(globalOptions, options) {
23
29
  case 'selfListen':
24
30
  globalOptions.selfListen = Boolean(options.selfListen);
25
31
  break;
26
- case 'selfListenEvent':
27
- globalOptions.selfListenEvent = options.selfListenEvent;
28
- break;
29
32
  case 'listenEvents':
30
33
  globalOptions.listenEvents = Boolean(options.listenEvents);
31
34
  break;
@@ -62,6 +65,9 @@ function setOptions(globalOptions, options) {
62
65
  case 'autoReconnect':
63
66
  globalOptions.autoReconnect = Boolean(options.autoReconnect);
64
67
  break;
68
+ case 'emitReady':
69
+ globalOptions.emitReady = Boolean(options.emitReady);
70
+ break;
65
71
  default:
66
72
  log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
67
73
  break;
@@ -69,63 +75,67 @@ function setOptions(globalOptions, options) {
69
75
  });
70
76
  }
71
77
 
72
- function buildAPI(globalOptions, html, token, jar) {
73
- var { c_user, i_user } = jar.getCookies('https://www.facebook.com').reduce(function(form, val) {
74
- var [name, value] = val.cookieString().split('=');
75
- form[name] = value;
76
- return form;
78
+ function buildAPI(globalOptions, html, jar) {
79
+ const maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) {
80
+ return val.cookieString().split("=")[0] === "c_user";
81
+ });
82
+
83
+ const objCookie = jar.getCookies("https://www.facebook.com").reduce(function(obj, val) {
84
+ obj[val.cookieString().split("=")[0]] = val.cookieString().split("=")[1];
85
+ return obj;
77
86
  }, {});
78
87
 
79
- if (!i_user && !c_user) {
80
- throw { error: "" };
88
+ if (maybeCookie.length === 0) {
89
+ throw { error: "please check your facebook account and get new alicestate" };
90
+ }
91
+ if (html.indexOf("/checkpoint/block/?next") > -1) {
92
+ throw { error: "your facebook account has been ended please check it and get new alicestate"}
81
93
  }
94
+ const userID = maybeCookie[0].cookieString().split("=")[1].toString();
95
+ const i_userID = objCookie.i_user || null;
96
+ try {
97
+ clearInterval(checkVerified);
98
+ } catch (_) { }
82
99
 
83
- if (html.indexOf("/checkpoint/block/?next") > -1) return;
100
+ const clientID = (Math.random() * 2147483648 | 0).toString(16);
84
101
 
85
- var userID = i_user || c_user;
86
- var clientID = (Math.random() * 2147483648 | 0).toString(16);
87
- var api = {
88
- setOptions: setOptions.bind(null, globalOptions),
89
- getAppState: function getAppState() {
90
- return utils.getAppState(jar);
91
- }
92
- }
93
102
 
94
- let oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
103
+ const oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
95
104
  let mqttEndpoint = null;
96
105
  let region = null;
97
106
  let irisSeqID = null;
107
+ let noMqttData = null;
98
108
 
99
- if (token == 'NONE') return;
100
109
  if (oldFBMQTTMatch) {
101
110
  irisSeqID = oldFBMQTTMatch[1];
102
111
  mqttEndpoint = oldFBMQTTMatch[2];
103
112
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
104
113
  } else {
105
- let newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
114
+ const newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
106
115
  if (newFBMQTTMatch) {
107
116
  irisSeqID = newFBMQTTMatch[2];
108
117
  mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
109
118
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
110
119
  } else {
111
- let legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
120
+ const legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
112
121
  if (legacyFBMQTTMatch) {
113
122
  mqttEndpoint = legacyFBMQTTMatch[4];
114
123
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
115
- return;
116
124
  } else {
117
- api.htmlData = html;
125
+ noMqttData = html;
118
126
  }
119
127
  }
120
128
  }
121
-
122
- var ctx = {
123
- userID,
124
- jar,
125
- clientID,
126
- globalOptions,
129
+
130
+ // All data available to api functions
131
+ const ctx = {
132
+ userID: userID,
133
+ i_userID: i_userID,
134
+ jar: jar,
135
+ clientID: clientID,
136
+ globalOptions: globalOptions,
127
137
  loggedIn: true,
128
- access_token: token,
138
+ access_token: 'NONE',
129
139
  clientMutationId: 0,
130
140
  mqttClient: undefined,
131
141
  lastSeqId: irisSeqID,
@@ -135,24 +145,99 @@ function buildAPI(globalOptions, html, token, jar) {
135
145
  firstListen: true
136
146
  };
137
147
 
138
- var http = utils.makeDefaults(html, userID, ctx);
148
+ const api = {
149
+ setOptions: setOptions.bind(null, globalOptions),
150
+ getAppState: function getAppState() {
151
+ const appState = utils.getAppState(jar);
152
+ // filter duplicate
153
+ return appState.filter((item, index, self) => self.findIndex((t) => { return t.key === item.key }) === index);
154
+ }
155
+ };
139
156
 
140
- require('node:fs')
141
- .readdirSync(__dirname + '/src/')
142
- .filter((v) => v.endsWith('.js'))
143
- .map(function(v) {
144
- api[v.replace('.js', '')] = require('./src/' + v)(http, api, ctx);
145
- });
157
+ if (noMqttData) {
158
+ api["htmlData"] = noMqttData;
159
+ }
160
+
161
+ const apiFuncNames = [
162
+ 'addExternalModule',
163
+ 'addUserToGroup',
164
+ 'changeAdminStatus',
165
+ 'changeArchivedStatus',
166
+ 'changeAvatar',
167
+ 'changeBio',
168
+ 'changeBlockedStatus',
169
+ 'changeGroupImage',
170
+ 'changeNickname',
171
+ 'changeThreadColor',
172
+ 'changeThreadEmoji',
173
+ 'chat',
174
+ 'createNewGroup',
175
+ 'createPoll',
176
+ 'deleteMessage',
177
+ 'deleteThread',
178
+ 'forwardAttachment',
179
+ 'getCurrentUserID',
180
+ 'getEmojiUrl',
181
+ 'getFriendsList',
182
+ 'getMessage',
183
+ 'getThreadHistory',
184
+ 'getThreadInfo',
185
+ 'getThreadList',
186
+ 'getThreadPictures',
187
+ 'getUserID',
188
+ 'getUserInfo',
189
+ 'handleMessageRequest',
190
+ 'listenMqtt',
191
+ 'logout',
192
+ 'markAsDelivered',
193
+ 'markAsRead',
194
+ 'markAsReadAll',
195
+ 'markAsSeen',
196
+ 'muteThread',
197
+ 'react',
198
+ 'refreshFb_dtsg',
199
+ 'removeUserFromGroup',
200
+ 'resolvePhotoUrl',
201
+ 'searchForThread',
202
+ 'seen',
203
+ 'sendMessage',
204
+ 'sendTypingIndicator',
205
+ 'setMessageReaction',
206
+ 'setPostReaction',
207
+ 'setTitle',
208
+ 'threadColors',
209
+ 'unsendMessage',
210
+ 'unfriend',
211
+
212
+ // HTTP
213
+ 'httpGet',
214
+ 'httpPost',
215
+ 'httpPostFormData',
216
+
217
+ 'uploadAttachment'
218
+ ];
219
+
220
+ const defaultFuncs = utils.makeDefaults(html, i_userID || userID, ctx);
221
+
222
+ // Load all api functions in a loop
223
+ apiFuncNames.map(function(v) {
224
+ api[v] = require('./leiamnash/' + v)(defaultFuncs, api, ctx);
225
+ });
226
+
227
+ //Removing original `listen` that uses pull.
228
+ //Map it to listenMqtt instead for backward compatibly.
146
229
  api.listen = api.listenMqtt;
147
230
 
148
- return [ctx, http, api];
231
+ return [ctx, defaultFuncs, api];
149
232
  }
150
233
 
151
234
  function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
152
235
  return function(res) {
153
- var html = res.body;
154
- var $ = cheerio.load(html);
155
- var arr = [];
236
+ const html = res.body;
237
+ const $ = cheerio.load(html);
238
+ let arr = [];
239
+
240
+ // This will be empty, but just to be sure we leave it
156
241
  $("#login_form input").map(function(i, v) {
157
242
  arr.push({ val: $(v).val(), name: $(v).attr("name") });
158
243
  });
@@ -161,7 +246,7 @@ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
161
246
  return v.val && v.val.length;
162
247
  });
163
248
 
164
- var form = utils.arrToForm(arr);
249
+ const form = utils.arrToForm(arr);
165
250
  form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
166
251
  form.lgndim = Buffer.from("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
167
252
  form.email = email;
@@ -172,194 +257,269 @@ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
172
257
  form.timezone = '240';
173
258
  form.lgnjs = ~~(Date.now() / 1000);
174
259
 
175
- var willBeCookies = html.split("\"_js_");
260
+
261
+ // Getting cookies from the HTML page... (kill me now plz)
262
+ // we used to get a bunch of cookies in the headers of the response of the
263
+ // request, but FB changed and they now send those cookies inside the JS.
264
+ // They run the JS which then injects the cookies in the page.
265
+ // The "solution" is to parse through the html and find those cookies
266
+ // which happen to be conveniently indicated with a _js_ in front of their
267
+ // variable name.
268
+ //
269
+ // ---------- Very Hacky Part Starts -----------------
270
+ const willBeCookies = html.split("\"_js_");
176
271
  willBeCookies.slice(1).map(function(val) {
177
- var cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
272
+ const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
178
273
  jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
179
274
  });
275
+ // ---------- Very Hacky Part Ends -----------------
276
+
180
277
  return utils
181
278
  .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
182
279
  .then(utils.saveCookies(jar))
183
280
  .then(function(res) {
184
- var headers = res.headers;
185
- if (!headers.location)
186
- throw { error: "Wrong username/password." };
187
-
188
- if (headers.location.includes('.com/checkpoint/')) {
189
- if (callback == prCallback)
190
- throw { error: 'Promise is not supported for login code verification' };
191
- var Referer = headers.location;
281
+ const 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
+ const nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
290
+
192
291
  return utils
193
- .get(Referer, jar, null, loginOptions)
292
+ .get(headers.location, jar, null, loginOptions)
194
293
  .then(utils.saveCookies(jar))
195
294
  .then(function(res) {
196
- var html = res.body;
197
- var $ = cheerio.load(html);
198
- var arr = [];
295
+ const html = res.body;
296
+ // Make the form in advance which will contain the fb_dtsg and nh
297
+ const $ = cheerio.load(html);
298
+ let arr = [];
199
299
  $("form input").map(function(i, v) {
200
- arr.push({ val: $(v).val(), name: $(v).attr("name") });
300
+ arr.push({ val: $(v).val(), name: $(v).attr("name") });
201
301
  });
302
+
202
303
  arr = arr.filter(function(v) {
203
304
  return v.val && v.val.length;
204
305
  });
205
- var form = utils.arrToForm(arr);
206
- if (html.includes('.com/checkpoint/?next')) {
207
- function submit2FA(code) {
208
- var cb;
209
- var rtPromise = new Promise(function(resolve) {
210
- cb = function(err, api) {
211
- resolve(callback(err, api));
212
- }
213
- });
214
306
 
215
- form.approvals_code = code;
216
- form['submit[Continue]'] = $("#checkpointSubmitButton").html();
217
- if (typeof code == 'string') {
218
- utils
219
- .post(Referer, jar, form, loginOptions, null, { Referer })
220
- .then(utils.saveCookies(jar))
221
- .then(function(res) {
222
- var html = res.body;
223
- var $ = cheerio.load(html);
224
- var error = $("#approvals_code").parent().attr("data-xui-error");
225
- if (error)
226
- throw {
227
- error: 'submit2FA',
228
- errordesc: "Invalid 2FA code.",
229
- lerror: error,
230
- continue: submit2FA
231
- }
232
- })
233
- .then(function() {
234
- delete form.no_fido;
235
- delete form.approvals_code;
236
- form.name_action_selected = 'save_device';
237
-
238
- return utils
239
- .post(Referer, jar, form, loginOptions, null, { Referer })
240
- .then(utils.saveCookies(jar));
307
+ const 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"
241
314
  })
242
- .then(function(res) {
243
- var { headers, body: html } = res;
244
- if (!headers.location && html.indexOf('Review Recent Login') > -1)
245
- throw { error: "Something went wrong with login approvals." }
246
- var appState = utils.getAppState(jar);
247
- return loginHelper(appState, email, password, loginOptions, cb);
248
- }).catch(function(err) {});
249
- }
250
- else {
251
- utils
252
- .post(Referer, jar, form, loginOptions, null, { Referer })
253
315
  .then(utils.saveCookies(jar))
254
- .then(function(res) {
316
+ .then(res => {
255
317
  try {
256
- var maybeObject = res.body.split(';').pop();
257
- JSON.parse(maybeObject);
258
- } catch (_) {
259
- var appState = utils.getAppState(jar);
260
- return loginHelper(appState, email, password, loginOptions, cb);
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);
261
323
  }
262
324
  })
263
- .catch(function(err) {});
264
- }
265
-
266
- return rtPromise;
267
- }
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);
268
334
  throw {
269
- error: 'submit2FA',
270
- continue: submit2FA
335
+ error: 'login-approval',
336
+ continue: function submit2FA(code) {
337
+ form.approvals_code = code;
338
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
339
+ let prResolve = null;
340
+ let prReject = null;
341
+ const 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
+ const $ = cheerio.load(res.body);
351
+ const 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
+ const 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
+ const 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
+
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." };
271
438
  }
272
- }
273
- else {
274
- if (!loginOptions.forceLogin)
275
- throw { error: "" };
276
- if (html.indexOf("Suspicious Login Attempt") > -1)
439
+ if (html.indexOf("Suspicious Login Attempt") > -1) {
277
440
  form['submit[This was me]'] = "This was me";
278
- else
441
+ } else {
279
442
  form['submit[This Is Okay]'] = "This Is Okay";
443
+ }
280
444
 
281
- function submitNot2FA() {
282
- var cb;
283
- var rtPromise = new Promise(function(resolve) {
284
- cb = function(err, api) {
285
- resolve(callback(err, api));
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
+ const 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." };
286
461
  }
287
- });
288
462
 
289
- utils
290
- .post(Referer, jar, form, loginOptions)
291
- .then(utils.saveCookies(jar))
292
- .then(function() {
293
-
294
- form.name_action_selected = 'save_device';
295
- return utils
296
- .post(Referer, jar, form, loginOptions)
297
- .then(utils.saveCookies(jar));
298
- })
299
- .then(function(res) {
300
- var headers = res.headers;
301
- if (!headers.location && res.body.includes('Review Recent Login'))
302
- throw { error: "Something went wrong with review recent login." };
303
- var appState = utils.getAppState(jar);
304
-
305
- return loginHelper(appState, email, password, loginOptions, cb);
306
- })
307
- .catch(function(e) {
308
- return cb(e);
309
- });
310
- return rtPromise;
311
- }
312
- throw {
313
- error: 'submitNot2FA',
314
- continue: submitNot2FA()
315
- }
463
+ const 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
+ });
316
472
  }
317
473
  });
318
474
  }
319
475
 
320
- setOptions(loginOptions, {
321
- 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"
322
- });
323
476
  return utils
324
- .get('https://www.facebook.com/', jar, null, loginOptions, null, { noRef: true })
477
+ .get('https://www.facebook.com/', jar, null, loginOptions)
325
478
  .then(utils.saveCookies(jar));
326
479
  });
327
- }
480
+ };
328
481
  }
329
482
 
483
+ // Helps the login
330
484
  function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
331
- var mainPromise = null;
332
- var jar = utils.getJar();
333
- if (appState) {
334
- setOptions(globalOptions, {
335
- 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"
336
- });
485
+ let mainPromise = null;
486
+ const 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) {
337
491
  appState.map(function(c) {
338
- var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
492
+ const str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
339
493
  jar.setCookie(str, "http://" + c.domain);
340
494
  });
341
495
 
496
+ // Load the main page.
342
497
  mainPromise = utils
343
- .get('https://www.facebook.com/', jar, null, globalOptions, null, { noRef: true })
498
+ .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
344
499
  .then(utils.saveCookies(jar));
345
500
  } else {
346
- setOptions(globalOptions, {
347
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
348
- });
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)
349
503
  mainPromise = utils
350
- .get("https://www.facebook.com/", null, null, globalOptions, null, { noRef: true })
504
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
351
505
  .then(utils.saveCookies(jar))
352
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback));
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
+ });
353
512
  }
354
513
 
355
- var ctx = null;
356
- var _defaultFuncs = null;
357
- var api = null;
514
+ let ctx = null;
515
+ let _defaultFuncs = null;
516
+ let api = null;
358
517
 
359
518
  mainPromise = mainPromise
360
519
  .then(function(res) {
361
- var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
362
- var redirect = reg.exec(res.body);
520
+ // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
521
+ const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
522
+ const redirect = reg.exec(res.body);
363
523
  if (redirect && redirect[1]) {
364
524
  return utils
365
525
  .get(redirect[1], jar, null, globalOptions)
@@ -367,16 +527,16 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
367
527
  }
368
528
  return res;
369
529
  })
370
- .then(utils.createAccess_token(jar, globalOptions))
371
530
  .then(function(res) {
372
- var [html, token] = res;
373
- var stuff = buildAPI(globalOptions, html.body, token, jar);
531
+ const html = res.body;
532
+ const stuff = buildAPI(globalOptions, html, jar);
374
533
  ctx = stuff[0];
375
534
  _defaultFuncs = stuff[1];
376
535
  api = stuff[2];
377
536
  return res;
378
537
  });
379
-
538
+
539
+ // given a pageID we log in as a page
380
540
  if (globalOptions.pageID) {
381
541
  mainPromise = mainPromise
382
542
  .then(function() {
@@ -384,7 +544,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
384
544
  .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
385
545
  })
386
546
  .then(function(resData) {
387
- var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
547
+ let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
388
548
  url = url.substring(0, url.length - 1);
389
549
 
390
550
  return utils
@@ -392,53 +552,58 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
392
552
  });
393
553
  }
394
554
 
555
+ // At the end we call the callback or catch an exception
395
556
  mainPromise
396
557
  .then(function() {
397
- return callback(null, api);
558
+ return callback(null, api);
398
559
  })
399
560
  .catch(function(e) {
400
- return callback(e);
561
+ log.error("login", e.error || e);
562
+ callback(e);
401
563
  });
402
564
  }
403
565
 
404
566
  function alice(loginData, options, callback) {
405
- var prCallback;
406
- var returnPromise = new Promise(function(resolve, reject) {
407
- prCallback = (error, api) => api ? resolve(api) : reject(error);
408
- });
409
-
410
- if (typeof options == 'function') {
567
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
411
568
  callback = options;
412
569
  options = {};
413
570
  }
414
- if (typeof callback == 'function') prCallback = null;
415
- else callback = prCallback;
416
- if (options == undefined) options = {};
417
571
 
418
- var globalOptions = {
572
+ const globalOptions = {
419
573
  selfListen: false,
420
574
  selfListenEvent: false,
421
- listenEvents: true,
575
+ listenEvents: false,
422
576
  listenTyping: false,
423
- updatePresence: true,
577
+ updatePresence: false,
424
578
  forceLogin: false,
425
579
  autoMarkDelivery: true,
426
- autoMarkRead: true,
580
+ autoMarkRead: false,
427
581
  autoReconnect: true,
428
582
  logRecordSize: defaultLogRecordSize,
429
583
  online: true,
430
- emitReady: false
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"
431
586
  };
587
+
432
588
  setOptions(globalOptions, options);
433
589
 
434
- if (parseInt(process.versions.node) < 14) {
435
- return callback({
436
- error: 'nodeDeprecated',
437
- lerror: 'node version must be 14.x or higher, recommended version: 16.7.0'
590
+ let prCallback = null;
591
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
592
+ let rejectFunc = null;
593
+ let resolveFunc = null;
594
+ var returnPromise = new Promise(function(resolve, reject) {
595
+ resolveFunc = resolve;
596
+ rejectFunc = reject;
438
597
  });
598
+ prCallback = function(error, api) {
599
+ if (error) {
600
+ return rejectFunc(error);
601
+ }
602
+ return resolveFunc(api);
603
+ };
604
+ callback = prCallback;
439
605
  }
440
606
  loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
441
-
442
607
  return returnPromise;
443
608
  }
444
609