alicezetion 1.8.8 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,20 +1,16 @@
1
1
  "use strict";
2
2
 
3
3
  const utils = require("./utils");
4
- const cheerio = require("cheerio");
5
4
  const log = require("npmlog");
6
5
 
7
- let checkVerified = null;
6
+ const checkVerified = null;
8
7
 
9
8
  const defaultLogRecordSize = 100;
10
9
  log.maxRecordSize = defaultLogRecordSize;
11
10
 
12
11
  function setOptions(globalOptions, options) {
13
- Object.keys(options).map(function(key) {
12
+ Object.keys(options).map(function (key) {
14
13
  switch (key) {
15
- case 'pauseLog':
16
- if (options.pauseLog) log.pause();
17
- break;
18
14
  case 'online':
19
15
  globalOptions.online = Boolean(options.online);
20
16
  break;
@@ -29,6 +25,9 @@ function setOptions(globalOptions, options) {
29
25
  case 'selfListen':
30
26
  globalOptions.selfListen = Boolean(options.selfListen);
31
27
  break;
28
+ case 'selfListenEvent':
29
+ globalOptions.selfListenEvent = options.selfListenEvent;
30
+ break;
32
31
  case 'listenEvents':
33
32
  globalOptions.listenEvents = Boolean(options.listenEvents);
34
33
  break;
@@ -76,23 +75,27 @@ function setOptions(globalOptions, options) {
76
75
  }
77
76
 
78
77
  function buildAPI(globalOptions, html, jar) {
79
- const maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) {
78
+ const maybeCookie = jar.getCookies("https://www.facebook.com").filter(function (val) {
80
79
  return val.cookieString().split("=")[0] === "c_user";
81
80
  });
82
81
 
83
- const objCookie = jar.getCookies("https://www.facebook.com").reduce(function(obj, val) {
82
+ const objCookie = jar.getCookies("https://www.facebook.com").reduce(function (obj, val) {
84
83
  obj[val.cookieString().split("=")[0]] = val.cookieString().split("=")[1];
85
84
  return obj;
86
85
  }, {});
87
86
 
88
87
  if (maybeCookie.length === 0) {
89
- throw { error: "please check your facebook account and get new alicestate" };
88
+ 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." };
90
89
  }
90
+
91
91
  if (html.indexOf("/checkpoint/block/?next") > -1) {
92
- throw { error: "your facebook account has been ended please check it and get new alicestate"}
92
+ log.warn("login", "Checkpoint detected. Please log in with a browser to verify.");
93
93
  }
94
+
94
95
  const userID = maybeCookie[0].cookieString().split("=")[1].toString();
95
96
  const i_userID = objCookie.i_user || null;
97
+ log.info("login", `Logged in as ${userID}`);
98
+
96
99
  try {
97
100
  clearInterval(checkVerified);
98
101
  } catch (_) { }
@@ -110,18 +113,24 @@ function buildAPI(globalOptions, html, jar) {
110
113
  irisSeqID = oldFBMQTTMatch[1];
111
114
  mqttEndpoint = oldFBMQTTMatch[2];
112
115
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
116
+ log.info("login", `Got this account's message region: ${region}`);
113
117
  } else {
114
118
  const newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
115
119
  if (newFBMQTTMatch) {
116
120
  irisSeqID = newFBMQTTMatch[2];
117
121
  mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
118
122
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
123
+ log.info("login", `Got this account's message region: ${region}`);
119
124
  } else {
120
125
  const legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
121
126
  if (legacyFBMQTTMatch) {
122
127
  mqttEndpoint = legacyFBMQTTMatch[4];
123
128
  region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
129
+ log.warn("login", `Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...`);
130
+ log.info("login", `Got this account's message region: ${region}`);
131
+ log.info("login", `[Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`);
124
132
  } else {
133
+ log.warn("login", "Cannot get MQTT region & sequence ID.");
125
134
  noMqttData = html;
126
135
  }
127
136
  }
@@ -140,6 +149,8 @@ function buildAPI(globalOptions, html, jar) {
140
149
  mqttClient: undefined,
141
150
  lastSeqId: irisSeqID,
142
151
  syncToken: undefined,
152
+ wsReqNumber: 0,
153
+ wsTaskNumber: 0,
143
154
  mqttEndpoint,
144
155
  region,
145
156
  firstListen: true
@@ -150,7 +161,7 @@ function buildAPI(globalOptions, html, jar) {
150
161
  getAppState: function getAppState() {
151
162
  const appState = utils.getAppState(jar);
152
163
  // filter duplicate
153
- return appState.filter((item, index, self) => self.findIndex((t) => { return t.key === item.key }) === index);
164
+ return appState.filter((item, index, self) => self.findIndex((t) => { return t.key === item.key; }) === index);
154
165
  }
155
166
  };
156
167
 
@@ -159,6 +170,9 @@ function buildAPI(globalOptions, html, jar) {
159
170
  }
160
171
 
161
172
  const apiFuncNames = [
173
+ 'seen',
174
+ 'chat',
175
+ 'react',
162
176
  'addExternalModule',
163
177
  'addUserToGroup',
164
178
  'changeAdminStatus',
@@ -170,12 +184,10 @@ function buildAPI(globalOptions, html, jar) {
170
184
  'changeNickname',
171
185
  'changeThreadColor',
172
186
  'changeThreadEmoji',
173
- 'chat',
174
187
  'createNewGroup',
175
188
  'createPoll',
176
189
  'deleteMessage',
177
190
  'deleteThread',
178
- 'edit',
179
191
  'forwardAttachment',
180
192
  'getCurrentUserID',
181
193
  'getEmojiUrl',
@@ -195,21 +207,19 @@ function buildAPI(globalOptions, html, jar) {
195
207
  'markAsReadAll',
196
208
  'markAsSeen',
197
209
  'muteThread',
198
- 'react',
199
210
  'refreshFb_dtsg',
200
211
  'removeUserFromGroup',
201
212
  'resolvePhotoUrl',
202
213
  'searchForThread',
203
- 'seen',
204
214
  'sendMessage',
205
215
  'sendTypingIndicator',
206
216
  'setMessageReaction',
207
217
  'setPostReaction',
208
218
  'setTitle',
209
219
  'threadColors',
210
- 'token',
211
220
  'unsendMessage',
212
221
  'unfriend',
222
+ 'editMessage',
213
223
 
214
224
  // HTTP
215
225
  'httpGet',
@@ -222,8 +232,8 @@ function buildAPI(globalOptions, html, jar) {
222
232
  const defaultFuncs = utils.makeDefaults(html, i_userID || userID, ctx);
223
233
 
224
234
  // Load all api functions in a loop
225
- apiFuncNames.map(function(v) {
226
- api[v] = require('./leiamnash/' + v)(defaultFuncs, api, ctx);
235
+ apiFuncNames.map(function (v) {
236
+ api[v] = require('./src/' + v)(defaultFuncs, api, ctx);
227
237
  });
228
238
 
229
239
  //Removing original `listen` that uses pull.
@@ -233,255 +243,6 @@ function buildAPI(globalOptions, html, jar) {
233
243
  return [ctx, defaultFuncs, api];
234
244
  }
235
245
 
236
- function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
237
- return function(res) {
238
- const html = res.body;
239
- const $ = cheerio.load(html);
240
- let arr = [];
241
-
242
- // This will be empty, but just to be sure we leave it
243
- $("#login_form input").map(function(i, v) {
244
- arr.push({ val: $(v).val(), name: $(v).attr("name") });
245
- });
246
-
247
- arr = arr.filter(function(v) {
248
- return v.val && v.val.length;
249
- });
250
-
251
- const form = utils.arrToForm(arr);
252
- form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
253
- form.lgndim = Buffer.from("{\"w\":1440,\"h\":900,\"aw\":1440,\"ah\":834,\"c\":24}").toString('base64');
254
- form.email = email;
255
- form.pass = password;
256
- form.default_persistent = '0';
257
- form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
258
- form.locale = 'en_US';
259
- form.timezone = '240';
260
- form.lgnjs = ~~(Date.now() / 1000);
261
-
262
-
263
- // Getting cookies from the HTML page... (kill me now plz)
264
- // we used to get a bunch of cookies in the headers of the response of the
265
- // request, but FB changed and they now send those cookies inside the JS.
266
- // They run the JS which then injects the cookies in the page.
267
- // The "solution" is to parse through the html and find those cookies
268
- // which happen to be conveniently indicated with a _js_ in front of their
269
- // variable name.
270
- //
271
- // ---------- Very Hacky Part Starts -----------------
272
- const willBeCookies = html.split("\"_js_");
273
- willBeCookies.slice(1).map(function(val) {
274
- const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
275
- jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
276
- });
277
- // ---------- Very Hacky Part Ends -----------------
278
-
279
- return utils
280
- .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
281
- .then(utils.saveCookies(jar))
282
- .then(function(res) {
283
- const headers = res.headers;
284
- if (!headers.location) {
285
- throw { error: "Wrong username/password." };
286
- }
287
-
288
- // This means the account has login approvals turned on.
289
- if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
290
- log.info("login", "You have login approvals turned on.");
291
- const nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
292
-
293
- return utils
294
- .get(headers.location, jar, null, loginOptions)
295
- .then(utils.saveCookies(jar))
296
- .then(function(res) {
297
- const html = res.body;
298
- // Make the form in advance which will contain the fb_dtsg and nh
299
- const $ = cheerio.load(html);
300
- let arr = [];
301
- $("form input").map(function(i, v) {
302
- arr.push({ val: $(v).val(), name: $(v).attr("name") });
303
- });
304
-
305
- arr = arr.filter(function(v) {
306
- return v.val && v.val.length;
307
- });
308
-
309
- const form = utils.arrToForm(arr);
310
- if (html.indexOf("checkpoint/?next") > -1) {
311
- setTimeout(() => {
312
- checkVerified = setInterval((_form) => {
313
- /* utils
314
- .post("https://www.facebook.com/login/approvals/approved_machine_check/", jar, form, loginOptions, null, {
315
- "Referer": "https://www.facebook.com/checkpoint/?next"
316
- })
317
- .then(utils.saveCookies(jar))
318
- .then(res => {
319
- try {
320
- JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*()/, ""));
321
- } catch (ex) {
322
- clearInterval(checkVerified);
323
- log.info("login", "Verified from browser. Logging in...");
324
- return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
325
- }
326
- })
327
- .catch(ex => {
328
- log.error("login", ex);
329
- }); */
330
- }, 5000, {
331
- fb_dtsg: form.fb_dtsg,
332
- jazoest: form.jazoest,
333
- dpr: 1
334
- });
335
- }, 2500);
336
- throw {
337
- error: 'login-approval',
338
- continue: function submit2FA(code) {
339
- form.approvals_code = code;
340
- form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
341
- let prResolve = null;
342
- let prReject = null;
343
- const rtPromise = new Promise(function(resolve, reject) {
344
- prResolve = resolve;
345
- prReject = reject;
346
- });
347
- if (typeof code == "string") {
348
- utils
349
- .post(nextURL, jar, form, loginOptions)
350
- .then(utils.saveCookies(jar))
351
- .then(function(res) {
352
- const $ = cheerio.load(res.body);
353
- const error = $("#approvals_code").parent().attr("data-xui-error");
354
- if (error) {
355
- throw {
356
- error: 'login-approval',
357
- errordesc: "Invalid 2FA code.",
358
- lerror: error,
359
- continue: submit2FA
360
- };
361
- }
362
- })
363
- .then(function() {
364
- // Use the same form (safe I hope)
365
- delete form.no_fido;
366
- delete form.approvals_code;
367
- form.name_action_selected = 'dont_save'; //'save_device';
368
-
369
- return utils
370
- .post(nextURL, jar, form, loginOptions)
371
- .then(utils.saveCookies(jar));
372
- })
373
- .then(function(res) {
374
- const headers = res.headers;
375
- if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
376
- throw { error: "Something went wrong with login approvals." };
377
- }
378
-
379
- const appState = utils.getAppState(jar);
380
-
381
- if (callback === prCallback) {
382
- callback = function(err, api) {
383
- if (err) {
384
- return prReject(err);
385
- }
386
- return prResolve(api);
387
- };
388
- }
389
-
390
- // Simply call loginHelper because all it needs is the jar
391
- // and will then complete the login process
392
- return loginHelper(appState, email, password, loginOptions, callback);
393
- })
394
- .catch(function(err) {
395
- // Check if using Promise instead of callback
396
- if (callback === prCallback) {
397
- prReject(err);
398
- } else {
399
- callback(err);
400
- }
401
- });
402
- } else {
403
- utils
404
- .post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form, loginOptions, null, {
405
- "Referer": "https://www.facebook.com/checkpoint/?next"
406
- })
407
- .then(utils.saveCookies(jar))
408
- .then(res => {
409
- try {
410
- JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
411
- } catch (ex) {
412
- clearInterval(checkVerified);
413
-
414
- if (callback === prCallback) {
415
- callback = function(err, api) {
416
- if (err) {
417
- return prReject(err);
418
- }
419
- return prResolve(api);
420
- };
421
- }
422
- return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
423
- }
424
- })
425
- .catch(ex => {
426
- log.error("login", ex);
427
- if (callback === prCallback) {
428
- prReject(ex);
429
- } else {
430
- callback(ex);
431
- }
432
- });
433
- }
434
- return rtPromise;
435
- }
436
- };
437
- } else {
438
- if (!loginOptions.forceLogin) {
439
- throw { error: "Couldn't login. Facebook might have blocked this account. Please login with a browser or enable the option 'forceLogin' and try again." };
440
- }
441
- if (html.indexOf("Suspicious Login Attempt") > -1) {
442
- form['submit[This was me]'] = "This was me";
443
- } else {
444
- form['submit[This Is Okay]'] = "This Is Okay";
445
- }
446
-
447
- return utils
448
- .post(nextURL, jar, form, loginOptions)
449
- .then(utils.saveCookies(jar))
450
- .then(function() {
451
- // Use the same form (safe I hope)
452
- form.name_action_selected = 'save_device';
453
-
454
- return utils
455
- .post(nextURL, jar, form, loginOptions)
456
- .then(utils.saveCookies(jar));
457
- })
458
- .then(function(res) {
459
- const headers = res.headers;
460
-
461
- if (!headers.location && res.body.indexOf('Review Recent Login') > -1) {
462
- throw { error: "Something went wrong with review recent login." };
463
- }
464
-
465
- const appState = utils.getAppState(jar);
466
-
467
- // Simply call loginHelper because all it needs is the jar
468
- // and will then complete the login process
469
- return loginHelper(appState, email, password, loginOptions, callback);
470
- })
471
- .catch(function(e) {
472
- callback(e);
473
- });
474
- }
475
- });
476
- }
477
-
478
- return utils
479
- .get('https://www.facebook.com/', jar, null, loginOptions)
480
- .then(utils.saveCookies(jar));
481
- });
482
- };
483
- }
484
-
485
246
  // Helps the login
486
247
  function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
487
248
  let mainPromise = null;
@@ -490,7 +251,31 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
490
251
  // If we're given an appState we loop through it and save each cookie
491
252
  // back into the jar.
492
253
  if (appState) {
493
- appState.map(function(c) {
254
+ // check and convert cookie to appState
255
+ if (utils.getType(appState) === 'Array' && appState.some(c => c.name)) {
256
+ appState = appState.map(c => {
257
+ c.key = c.name;
258
+ delete c.name;
259
+ return c;
260
+ });
261
+ }
262
+ else if (utils.getType(appState) === 'String') {
263
+ const arrayAppState = [];
264
+ appState.split(';').forEach(c => {
265
+ const [key, value] = c.split('=');
266
+
267
+ arrayAppState.push({
268
+ key: (key || "").trim(),
269
+ value: (value || "").trim(),
270
+ domain: "facebook.com",
271
+ path: "/",
272
+ expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365
273
+ });
274
+ });
275
+ appState = arrayAppState;
276
+ }
277
+
278
+ appState.map(function (c) {
494
279
  const str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
495
280
  jar.setCookie(str, "http://" + c.domain);
496
281
  });
@@ -500,17 +285,12 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
500
285
  .get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
501
286
  .then(utils.saveCookies(jar));
502
287
  } else {
503
- // Open the main page, then we login with the given credentials and finally
504
- // load the main page again (it'll give us some IDs that we need)
505
- mainPromise = utils
506
- .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
507
- .then(utils.saveCookies(jar))
508
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
509
- .then(function() {
510
- return utils
511
- .get('https://www.facebook.com/', jar, null, globalOptions)
512
- .then(utils.saveCookies(jar));
513
- });
288
+ if (email) {
289
+ throw { error: "Currently, the login method by email and password is no longer supported, please use the login method by appState" };
290
+ }
291
+ else {
292
+ throw { error: "No appState given." };
293
+ }
514
294
  }
515
295
 
516
296
  let ctx = null;
@@ -518,7 +298,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
518
298
  let api = null;
519
299
 
520
300
  mainPromise = mainPromise
521
- .then(function(res) {
301
+ .then(function (res) {
522
302
  // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
523
303
  const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
524
304
  const redirect = reg.exec(res.body);
@@ -529,7 +309,7 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
529
309
  }
530
310
  return res;
531
311
  })
532
- .then(function(res) {
312
+ .then(function (res) {
533
313
  const html = res.body;
534
314
  const stuff = buildAPI(globalOptions, html, jar);
535
315
  ctx = stuff[0];
@@ -541,11 +321,11 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
541
321
  // given a pageID we log in as a page
542
322
  if (globalOptions.pageID) {
543
323
  mainPromise = mainPromise
544
- .then(function() {
324
+ .then(function () {
545
325
  return utils
546
326
  .get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
547
327
  })
548
- .then(function(resData) {
328
+ .then(function (resData) {
549
329
  let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
550
330
  url = url.substring(0, url.length - 1);
551
331
 
@@ -556,10 +336,11 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
556
336
 
557
337
  // At the end we call the callback or catch an exception
558
338
  mainPromise
559
- .then(function() {
339
+ .then(function () {
340
+ log.info("login", 'Done logging in.');
560
341
  return callback(null, api);
561
342
  })
562
- .catch(function(e) {
343
+ .catch(function (e) {
563
344
  log.error("login", e.error || e);
564
345
  callback(e);
565
346
  });
@@ -593,11 +374,11 @@ function alice(loginData, options, callback) {
593
374
  if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
594
375
  let rejectFunc = null;
595
376
  let resolveFunc = null;
596
- var returnPromise = new Promise(function(resolve, reject) {
377
+ var returnPromise = new Promise(function (resolve, reject) {
597
378
  resolveFunc = resolve;
598
379
  rejectFunc = reject;
599
380
  });
600
- prCallback = function(error, api) {
381
+ prCallback = function (error, api) {
601
382
  if (error) {
602
383
  return rejectFunc(error);
603
384
  }
@@ -609,4 +390,4 @@ function alice(loginData, options, callback) {
609
390
  return returnPromise;
610
391
  }
611
392
 
612
- module.exports = alice;
393
+ module.exports = alice;
@@ -244,9 +244,7 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
244
244
  }
245
245
 
246
246
  });
247
- mqttClient.on('close', function () {
248
- globalCallback("Connection closed.");
249
- });
247
+
250
248
  }
251
249
 
252
250
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
@@ -554,6 +552,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
554
552
  case "change_thread_theme":
555
553
  case "change_thread_nickname":
556
554
  case "change_thread_icon":
555
+ case "change_thread_quick_reaction":
557
556
  case "change_thread_admins":
558
557
  case "group_poll":
559
558
  case "joinable_group_link_mode_change":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alicezetion",
3
- "version": "1.8.8",
3
+ "version": "1.9.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "start": "node index.js"
@@ -19,7 +19,6 @@
19
19
  "author": "LeiamNash",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "bluebird": "^2.11.0",
23
22
  "cheerio": "^1.0.0-rc.12",
24
23
  "https-proxy-agent": "^5.0.1",
25
24
  "mqtt": "^4.3.7",