alicezetion 1.6.1 → 1.6.3

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