alicezetion 1.7.7 → 1.7.9

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