node-ainzfb 0.0.1-security → 1.3.3-beta

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of node-ainzfb might be problematic. Click here for more details.

Files changed (76) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/dependabot.yml +11 -0
  3. package/.github/workflows/nodejs.yml +26 -0
  4. package/.github/workflows/npmpublish.yml +30 -0
  5. package/CHANGELOG.md +2 -0
  6. package/DOCS.md +1738 -0
  7. package/Extra/Database/index.js +399 -0
  8. package/Extra/Database/methods.js +286 -0
  9. package/Extra/ExtraAddons.js +213 -0
  10. package/Extra/ExtraGetThread.js +1 -0
  11. package/Extra/ExtraUptimeRobot.js +59 -0
  12. package/Extra/PM2/ecosystem.config.js +23 -0
  13. package/Extra/Src/Last-Run.js +48 -0
  14. package/LICENSE-MIT +21 -0
  15. package/Language/index.json +151 -0
  16. package/README.md +225 -3
  17. package/StateCrypt.js +22 -0
  18. package/broadcast.js +42 -0
  19. package/index-backup.js +1079 -0
  20. package/index.js +1083 -0
  21. package/logger.js +21 -0
  22. package/package.json +87 -3
  23. package/src/addExternalModule.js +16 -0
  24. package/src/addUserToGroup.js +78 -0
  25. package/src/changeAdminStatus.js +79 -0
  26. package/src/changeArchivedStatus.js +41 -0
  27. package/src/changeBio.js +65 -0
  28. package/src/changeBlockedStatus.js +36 -0
  29. package/src/changeGroupImage.js +106 -0
  30. package/src/changeNickname.js +45 -0
  31. package/src/changeThreadColor.js +62 -0
  32. package/src/changeThreadEmoji.js +42 -0
  33. package/src/createNewGroup.js +70 -0
  34. package/src/createPoll.js +60 -0
  35. package/src/deleteMessage.js +45 -0
  36. package/src/deleteThread.js +43 -0
  37. package/src/forwardAttachment.js +48 -0
  38. package/src/getAccessToken.js +31 -0
  39. package/src/getCurrentUserID.js +7 -0
  40. package/src/getEmojiUrl.js +27 -0
  41. package/src/getFriendsList.js +73 -0
  42. package/src/getMessage.js +80 -0
  43. package/src/getThreadHistory.js +537 -0
  44. package/src/getThreadHistoryDeprecated.js +71 -0
  45. package/src/getThreadInfo.js +197 -0
  46. package/src/getThreadInfoDeprecated.js +56 -0
  47. package/src/getThreadList.js +213 -0
  48. package/src/getThreadListDeprecated.js +46 -0
  49. package/src/getThreadPictures.js +59 -0
  50. package/src/getUserID.js +62 -0
  51. package/src/getUserInfo.js +65 -0
  52. package/src/getUserInfoV2.js +35 -0
  53. package/src/handleFriendRequest.js +46 -0
  54. package/src/handleMessageRequest.js +49 -0
  55. package/src/httpGet.js +49 -0
  56. package/src/httpPost.js +48 -0
  57. package/src/httpPostFormData.js +41 -0
  58. package/src/listenMqtt.js +633 -0
  59. package/src/logout.js +68 -0
  60. package/src/markAsDelivered.js +48 -0
  61. package/src/markAsRead.js +70 -0
  62. package/src/markAsReadAll.js +43 -0
  63. package/src/markAsSeen.js +51 -0
  64. package/src/muteThread.js +47 -0
  65. package/src/removeUserFromGroup.js +49 -0
  66. package/src/resolvePhotoUrl.js +37 -0
  67. package/src/searchForThread.js +43 -0
  68. package/src/sendMessage.js +342 -0
  69. package/src/sendTypingIndicator.js +80 -0
  70. package/src/setMessageReaction.js +109 -0
  71. package/src/setPostReaction.js +102 -0
  72. package/src/setTitle.js +74 -0
  73. package/src/threadColors.js +39 -0
  74. package/src/unfriend.js +43 -0
  75. package/src/unsendMessage.js +40 -0
  76. package/utils.js +1240 -0
@@ -0,0 +1,1079 @@
1
+ 'use strict';
2
+
3
+ /!-[ Max Cpu Speed ]-!/
4
+
5
+ process.env.UV_THREADPOOL_SIZE = require('os').cpus().length;
6
+
7
+ /!-[ Global Set ]-!/
8
+
9
+ global.isThread = new Array();
10
+ global.isUser = new Array();
11
+ global.startTime = Date.now();
12
+
13
+ /!-[ Require All Package Need Use ]-!/
14
+
15
+ var utils = require("./utils"),
16
+ cheerio = require("cheerio"),
17
+ log = require("npmlog"),
18
+ { getAccessToken } = require('./Extra/ExtraAddons'),
19
+ logger = require('./logger'),
20
+ fs = require('fs-extra'),
21
+ getText = require('gettext.js')(),
22
+ logger = require('./logger'),
23
+ Fetch = require('got'),
24
+ fs = require('fs-extra'),
25
+ StateCrypt = require('./StateCrypt'),
26
+ Client = require("@replit/database"),
27
+ languageFile = require('./Language/index.json'),
28
+ ObjFastConfig = {
29
+ "Language": "en",
30
+ "MainColor": "#9900FF",
31
+ "BroadCast": true,
32
+ "EncryptFeature": true,
33
+ "PreKey": ""
34
+ };
35
+
36
+
37
+ /!-[ Check File To Run Process ]-!/
38
+
39
+ try {
40
+ if (!fs.existsSync('./FastConfigFca.json')) {
41
+ fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
42
+ process.exit(1);
43
+ } else if (fs.existsSync('./FastConfigFca.json')) {
44
+ try {
45
+ var DataLanguageSetting = require("../../FastConfigFca.json");
46
+ } catch (e) {
47
+ logger("Invalid Config Settings, Restoring Default...");
48
+ fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
49
+ process.exit(1);
50
+ }
51
+ try {
52
+ if (DataLanguageSetting && !DataLanguageSetting.PreKey) {
53
+ DataLanguageSetting.PreKey = "";
54
+ fs.writeFileSync("./FastConfigFca.json", JSON.stringify(DataLanguageSetting, null, "\t"));
55
+ }
56
+ } catch (e) {
57
+ console.log(e);
58
+ }
59
+ if (!languageFile.some(i => i.Language == DataLanguageSetting.Language)) {
60
+ logger("Not Support Language: " + DataLanguageSetting.Language + " Only 'en' and 'vi'", "[ FCA-SUS ]");
61
+ process.exit(0);
62
+ }
63
+ var Language = languageFile.find(i => i.Language == DataLanguageSetting.Language).Folder.Index;
64
+ } else process.exit(1);
65
+ if (utils.getType(DataLanguageSetting.BroadCast) != "Boolean" && DataLanguageSetting.BroadCast != undefined) {
66
+ log.warn("FastConfig-BroadCast", getText.gettext(Language.IsNotABoolean, DataLanguageSetting.BroadCast));
67
+ process.exit(0)
68
+ } else if (DataLanguageSetting.BroadCast == undefined) {
69
+ fs.writeFileSync("./FastConfigFca.json", JSON.stringify(ObjFastConfig, null, "\t"));
70
+ process.exit(1);
71
+ }
72
+ } catch (e) {
73
+ console.log(e);
74
+ logger.Error();
75
+ }
76
+
77
+ /!-[ Set Variable For Process ]-!/
78
+
79
+ log.maxRecordSize = 100;
80
+ var checkVerified = null;
81
+
82
+ /!-[ Function setOptions ]-!/
83
+
84
+ function setOptions(globalOptions, options) {
85
+ Object.keys(options).map(function(key) {
86
+ switch (key) {
87
+ case 'pauseLog':
88
+ if (options.pauseLog) log.pause();
89
+ break;
90
+ case 'online':
91
+ globalOptions.online = Boolean(options.online);
92
+ break;
93
+ case 'logLevel':
94
+ log.level = options.logLevel;
95
+ globalOptions.logLevel = options.logLevel;
96
+ break;
97
+ case 'logRecordSize':
98
+ log.maxRecordSize = options.logRecordSize;
99
+ globalOptions.logRecordSize = options.logRecordSize;
100
+ break;
101
+ case 'selfListen':
102
+ globalOptions.selfListen = Boolean(options.selfListen);
103
+ break;
104
+ case 'listenEvents':
105
+ globalOptions.listenEvents = Boolean(options.listenEvents);
106
+ break;
107
+ case 'pageID':
108
+ globalOptions.pageID = options.pageID.toString();
109
+ break;
110
+ case 'updatePresence':
111
+ globalOptions.updatePresence = Boolean(options.updatePresence);
112
+ break;
113
+ case 'forceLogin':
114
+ globalOptions.forceLogin = Boolean(options.forceLogin);
115
+ break;
116
+ case 'userAgent':
117
+ globalOptions.userAgent = options.userAgent;
118
+ break;
119
+ case 'autoMarkDelivery':
120
+ globalOptions.autoMarkDelivery = Boolean(options.autoMarkDelivery);
121
+ break;
122
+ case 'autoMarkRead':
123
+ globalOptions.autoMarkRead = Boolean(options.autoMarkRead);
124
+ break;
125
+ case 'listenTyping':
126
+ globalOptions.listenTyping = Boolean(options.listenTyping);
127
+ break;
128
+ case 'proxy':
129
+ if (typeof options.proxy != "string") {
130
+ delete globalOptions.proxy;
131
+ utils.setProxy();
132
+ } else {
133
+ globalOptions.proxy = options.proxy;
134
+ utils.setProxy(globalOptions.proxy);
135
+ }
136
+ break;
137
+ case 'autoReconnect':
138
+ globalOptions.autoReconnect = Boolean(options.autoReconnect);
139
+ break;
140
+ case 'emitReady':
141
+ globalOptions.emitReady = Boolean(options.emitReady);
142
+ break;
143
+ default:
144
+ log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
145
+ break;
146
+ }
147
+ });
148
+ }
149
+
150
+ /!-[ Function BuildAPI ]-!/
151
+
152
+ async function buildAPI(globalOptions, html, jar) {
153
+ var maybeCookie = jar.getCookies("https://www.facebook.com").filter(function(val) { return val.cookieString().split("=")[0] === "c_user"; });
154
+
155
+ if (maybeCookie.length === 0) throw { error: Language.ErrAppState };
156
+
157
+ if (html.indexOf("/checkpoint/block/?next") > -1) log.warn("login", Language.CheckPointLevelI);
158
+
159
+ var userID = maybeCookie[0].cookieString().split("=")[1].toString();
160
+ logger(getText.gettext(Language.UID, userID), "[ FCA-SUS ]");
161
+ process.env['UID'] = userID;
162
+
163
+ try {
164
+ clearInterval(checkVerified);
165
+ } catch (e) {
166
+ console.log(e);
167
+ }
168
+
169
+ var clientID = (Math.random() * 2147483648 | 0).toString(16);
170
+
171
+ let oldFBMQTTMatch = html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/);
172
+ let mqttEndpoint = null;
173
+ let region = null;
174
+ let irisSeqID = null;
175
+ var noMqttData = null;
176
+
177
+ if (oldFBMQTTMatch) {
178
+ irisSeqID = oldFBMQTTMatch[1];
179
+ mqttEndpoint = oldFBMQTTMatch[2];
180
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
181
+ logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
182
+ } else {
183
+ let newFBMQTTMatch = html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/);
184
+ if (newFBMQTTMatch) {
185
+ irisSeqID = newFBMQTTMatch[2];
186
+ mqttEndpoint = newFBMQTTMatch[1].replace(/\\\//g, "/");
187
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
188
+ logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
189
+ } else {
190
+ let legacyFBMQTTMatch = html.match(/(\["MqttWebConfig",\[\],{fbid:")(.+?)(",appID:219994525426954,endpoint:")(.+?)(",pollingEndpoint:")(.+?)(3790])/);
191
+ if (legacyFBMQTTMatch) {
192
+ mqttEndpoint = legacyFBMQTTMatch[4];
193
+ region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
194
+ log.warn("login", `Cannot get sequence ID with new RegExp. Fallback to old RegExp (without seqID)...`);
195
+ logger(getText.gettext(Language.Area, region), "[ FCA-SUS ]");
196
+ logger("login", `[Unused] Polling endpoint: ${legacyFBMQTTMatch[6]}`);
197
+ } else {
198
+ log.warn("login", getText.gettext(Language.NoAreaData));
199
+ noMqttData = html;
200
+ }
201
+ }
202
+ }
203
+
204
+ var ctx = {
205
+ userID: userID,
206
+ jar: jar,
207
+ clientID: clientID,
208
+ globalOptions: globalOptions,
209
+ loggedIn: true,
210
+ access_token: await getAccessToken(),
211
+ clientMutationId: 0,
212
+ mqttClient: undefined,
213
+ lastSeqId: irisSeqID,
214
+ syncToken: undefined,
215
+ mqttEndpoint,
216
+ region,
217
+ firstListen: true
218
+ };
219
+
220
+ var api = {
221
+ setOptions: setOptions.bind(null, globalOptions),
222
+ getAppState: function getAppState() {
223
+ return utils.getAppState(jar);
224
+ }
225
+ };
226
+
227
+ if (noMqttData) api["htmlData"] = noMqttData;
228
+
229
+ const apiFuncNames = fs.readdirSync(__dirname + "/src").filter((File) => File.endsWith(".js") && !File.includes('Dev'));
230
+
231
+ var defaultFuncs = utils.makeDefaults(html, userID, ctx);
232
+
233
+ // Load all api functions in a loop
234
+ apiFuncNames.map(v => api[v.replace(".js", "")] = require('./src/' + v)(defaultFuncs, api, ctx));
235
+ return [ctx, defaultFuncs, api];
236
+ }
237
+
238
+ function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
239
+ return function(res) {
240
+ var html = res.body;
241
+ var $ = cheerio.load(html);
242
+ var arr = [];
243
+
244
+ // This will be empty, but just to be sure we leave it
245
+ $("#login_form input").map((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
246
+
247
+ arr = arr.filter(function(v) {
248
+ return v.val && v.val.length;
249
+ });
250
+
251
+ var 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
+ var willBeCookies = html.split("\"_js_");
273
+ willBeCookies.slice(1).map(function(val) {
274
+ var 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
+ logger(Language.OnLogin, "[ FCA-SUS ]");
280
+ return utils
281
+ .post("https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110", jar, form, loginOptions)
282
+ .then(utils.saveCookies(jar))
283
+ .then(function(res) {
284
+ var headers = res.headers;
285
+ if (!headers.location) throw { error: Language.InvaildAccount };
286
+
287
+ // This means the account has login approvals turned on.
288
+ if (headers.location.indexOf('https://www.facebook.com/checkpoint/') > -1) {
289
+ logger(Language.TwoAuth, "[ FCA-SUS ]");
290
+ var nextURL = 'https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php';
291
+
292
+ return utils
293
+ .get(headers.location, jar, null, loginOptions)
294
+ .then(utils.saveCookies(jar))
295
+ .then(function(res) {
296
+ var html = res.body;
297
+ // Make the form in advance which will contain the fb_dtsg and nh
298
+ var $ = cheerio.load(html);
299
+ var arr = [];
300
+ $("form input").map((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
301
+
302
+ arr = arr.filter(function(v) {
303
+ return v.val && v.val.length;
304
+ });
305
+
306
+ var form = utils.arrToForm(arr);
307
+ if (html.indexOf("checkpoint/?next") > -1) {
308
+ setTimeout(() => {
309
+ checkVerified = setInterval((_form) => {}, 5000, {
310
+ fb_dtsg: form.fb_dtsg,
311
+ jazoest: form.jazoest,
312
+ dpr: 1
313
+ });
314
+ }, 2500);
315
+ throw {
316
+ error: 'login-approval',
317
+ continue: function submit2FA(code) {
318
+ form.approvals_code = code;
319
+ form['submit[Continue]'] = $("#checkpointSubmitButton").html(); //'Continue';
320
+ var prResolve = null;
321
+ var prReject = null;
322
+ var rtPromise = new Promise(function(resolve, reject) {
323
+ prResolve = resolve;
324
+ prReject = reject;
325
+ });
326
+ if (typeof code == "string") {
327
+ utils
328
+ .post(nextURL, jar, form, loginOptions)
329
+ .then(utils.saveCookies(jar))
330
+ .then(function(res) {
331
+ var $ = cheerio.load(res.body);
332
+ var error = $("#approvals_code").parent().attr("data-xui-error");
333
+ if (error) {
334
+ throw {
335
+ error: 'login-approval',
336
+ errordesc: Language.InvaildTwoAuthCode,
337
+ lerror: error,
338
+ continue: submit2FA
339
+ };
340
+ }
341
+ })
342
+ .then(function() {
343
+ // Use the same form (safe I hope)
344
+ delete form.no_fido;
345
+ delete form.approvals_code;
346
+ form.name_action_selected = 'save_device'; //'save_device' || 'dont_save;
347
+
348
+ return utils.post(nextURL, jar, form, loginOptions).then(utils.saveCookies(jar));
349
+ })
350
+ .then(function(res) {
351
+ var headers = res.headers;
352
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) throw { error: Language.ApprovalsErr };
353
+
354
+ var appState = utils.getAppState(jar);
355
+
356
+ if (callback === prCallback) {
357
+ callback = function(err, api) {
358
+ if (err) return prReject(err);
359
+ return prResolve(api);
360
+ };
361
+ }
362
+
363
+ // Simply call loginHelper because all it needs is the jar
364
+ // and will then complete the login process
365
+ return loginHelper(appState, email, password, loginOptions, callback);
366
+ })
367
+ .catch(function(err) {
368
+ // Check if using Promise instead of callback
369
+ if (callback === prCallback) prReject(err);
370
+ else callback(err);
371
+ });
372
+ } else {
373
+ utils
374
+ .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" })
375
+ .then(utils.saveCookies(jar))
376
+ .then(res => {
377
+ try {
378
+ JSON.parse(res.body.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, ""));
379
+ } catch (ex) {
380
+ clearInterval(checkVerified);
381
+ logger(Language.VerifiedCheck, "[ FCA-SUS ]");
382
+ if (callback === prCallback) {
383
+ callback = function(err, api) {
384
+ if (err) return prReject(err);
385
+ return prResolve(api);
386
+ };
387
+ }
388
+ return loginHelper(utils.getAppState(jar), email, password, loginOptions, callback);
389
+ }
390
+ })
391
+ .catch(ex => {
392
+ log.error("login", ex);
393
+ if (callback === prCallback) prReject(ex);
394
+ else callback(ex);
395
+ });
396
+ }
397
+ return rtPromise;
398
+ }
399
+ };
400
+ } else {
401
+ if (!loginOptions.forceLogin) throw { error: Language.ForceLoginNotEnable };
402
+
403
+ if (html.indexOf("Suspicious Login Attempt") > -1) form['submit[This was me]'] = "This was me";
404
+ else form['submit[This Is Okay]'] = "This Is Okay";
405
+
406
+ return utils
407
+ .post(nextURL, jar, form, loginOptions)
408
+ .then(utils.saveCookies(jar))
409
+ .then(function() {
410
+ // Use the same form (safe I hope)
411
+ form.name_action_selected = 'save_device';
412
+
413
+ return utils.post(nextURL, jar, form, loginOptions).then(utils.saveCookies(jar));
414
+ })
415
+ .then(function(res) {
416
+ var headers = res.headers;
417
+
418
+ if (!headers.location && res.body.indexOf('Review Recent Login') > -1) throw { error: "Something went wrong with review recent login." };
419
+
420
+ var appState = utils.getAppState(jar);
421
+
422
+ // Simply call loginHelper because all it needs is the jar
423
+ // and will then complete the login process
424
+ return loginHelper(appState, email, password, loginOptions, callback);
425
+ })
426
+ .catch(e => callback(e));
427
+ }
428
+ });
429
+ }
430
+
431
+ return utils.get('https://www.facebook.com/', jar, null, loginOptions).then(utils.saveCookies(jar));
432
+ });
433
+ };
434
+ }
435
+
436
+ function makeid(length) {
437
+ var result = '';
438
+ var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
439
+ var charactersLength = characters.length;
440
+ for (var i = 0; i < length; i++) {
441
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
442
+ }
443
+ return result;
444
+ }
445
+
446
+
447
+ // Helps the login
448
+ async function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
449
+ var mainPromise = null;
450
+ var jar = utils.getJar();
451
+
452
+ // If we're given an appState we loop through it and save each cookie
453
+ // back into the jar.
454
+ try {
455
+ if (appState) {
456
+ //const readline = require("readline");
457
+ //const chalk = require("chalk");
458
+ //const figlet = require("figlet");
459
+ //const os = require("os");
460
+ //const { execSync } = require('child_process');
461
+ // let rl = readline.createInterface({
462
+ // input: process.stdin,
463
+ // output: process.stdout,
464
+ // prompt: chalk.hex('#00CCCC').bold('[FCA-SUS] • ')
465
+ // });
466
+ // let type = {
467
+ // 1: {
468
+ // "name": "Tạo Mật Khẩu Cho Appstate",
469
+ // onRun: async function() {
470
+ // try {
471
+ // rl.question("Hãy Nhập Mật Khẩu Bạn Muốn Đặt Cho Appstate !", (answer) => {
472
+ // console.log("Được Rồi Mật Khẩu Của Bạn Là: " + answer + ", Bạn Hãy Nhớ Kĩ Nhé !");
473
+ // process.env["FBKEY"] = answer;
474
+ // fs.writeFile('../.env', `FBKEY=${answer}`, function (err) {
475
+ // if (err) {
476
+ // submiterr(err)
477
+ // logger("Tạo File ENV Thất Bại !", "[ FCA-SUS ]")
478
+ // rl.pause();
479
+ // }
480
+ // else logger("Tạo Thành Công File ENV !","[ FCA-SUS ]")
481
+ // rl.pause();
482
+ // });
483
+ // })
484
+ // }
485
+ // catch (e) {
486
+ // console.log(e);
487
+ // logger("Đã Có Lỗi Khi Đang Try Tạo Ra Câu Hỏi =))", "[ FCA-SUS ]");
488
+ // rl.pause();
489
+ // }
490
+ // }
491
+ // },
492
+ // 2: {
493
+ // "name": "Tiếp Tục Chạy Fca Mà Không Cần Mã Hóa AppState",
494
+ // onRun: async function () {
495
+ // rl.pause();
496
+ // }
497
+ // },
498
+ // 3: {
499
+ // "name": "Đổi Mật Khẩu AppState (Comming Soon..)",
500
+ // onRun: async function () {
501
+ // console.log(chalk.red.bold("Đã bảo là comming soon rồi mà >:v"));
502
+ // }
503
+ // }
504
+ // }
505
+ // const localbrand = JSON.parse(readFileSync('./package.json')).name;
506
+ // const localbrand2 = JSON.parse(readFileSync('./node_modules/fca-sus/package.json')).version;
507
+ // var axios = require('axios');
508
+ // axios.get('https://raw.githubusercontent.com/amogusdevlol/fca-sus/main/package.json').then(async (res) => {
509
+ // if (localbrand.toUpperCase() == 'HORIZON') {
510
+ // console.group(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'))
511
+ // console.log(chalk.bold.hex('#00FFCC')("[</>]") + chalk.bold.yellow(' => ') + "Hệ Điều Hành: " + chalk.bold.red(os.type()));
512
+ // console.log(chalk.bold.hex('#00FFCC')("[</>]") + chalk.bold.yellow(' => ') + "Thông Tin Máy: " + chalk.bold.red(os.version()));
513
+ // console.log(chalk.bold.hex('#00FFCC')("[</>]") + chalk.bold.yellow(' => ') + "Phiên Bản Hiện Tại: " + chalk.bold.red(localbrand2));
514
+ // console.log(chalk.bold.hex('#00FFCC')("[</>]") + chalk.bold.yellow(' => ') + "Phiên Bản Mới Nhất: " + chalk.bold.red(res.data.version));
515
+ // console.groupEnd();
516
+ // }
517
+ // else {
518
+ // console.clear();
519
+ // console.log(figlet.textSync('TeamHorizon', {font: 'ANSI Shadow',horizontalLayout: 'default',verticalLayout: 'default',width: 0,whitespaceBreak: true }))
520
+ // console.log(chalk.hex('#9966CC')(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`));
521
+ // }
522
+ // });
523
+
524
+ logger(Language.OnProcess, "[ FCA-SUS ]");
525
+ var backup = async(data) => {
526
+ if (fs.existsSync('./appstate.json')) {
527
+ try {
528
+ fs.writeFileSync('./appstate.json', data);
529
+ } catch (e) {
530
+ fs.writeFileSync('./appstate.json', JSON.stringify(data, null, "\t"));
531
+ }
532
+ logger(Language.BackupNoti, "[ FCA-SUS ]");
533
+ await new Promise(resolve => setTimeout(resolve, 5 * 1000));
534
+ process.exit(1);
535
+ } else if (fs.existsSync('./Facebook.json')) {
536
+ try {
537
+ fs.writeFileSync('./Facebook.json', data);
538
+ } catch (e) {
539
+ fs.writeFileSync('./Facebook.json', JSON.stringify(data, null, "\t"));
540
+ }
541
+ logger(Language.BackupNoti, "[ FCA-SUS ]");
542
+ await new Promise(resolve => setTimeout(resolve, 5 * 1000));
543
+ process.exit(1);
544
+ } else if (fs.existsSync('fbstate.json')) {
545
+ try {
546
+ fs.writeFileSync('./fbstate.json', data);
547
+ } catch (e) {
548
+ fs.writeFileSync('./fbstate.json', JSON.stringify(data), null, "\t");
549
+ }
550
+ logger(Language.BackupNoti, "[ FCA-SUS ]");
551
+ await new Promise(resolve => setTimeout(resolve, 5 * 1000));
552
+ process.exit(1);
553
+ } else return logger.Error();
554
+ }
555
+
556
+ switch (process.platform) {
557
+ case "win32":
558
+ {
559
+ try {
560
+ var { body } = await Fetch('https://decrypt-appstate-production.up.railway.app/getKey');
561
+ process.env['FBKEY'] = JSON.parse(body).Data;
562
+ } catch (e) {
563
+ logger(Language.ErrGetPassWord);
564
+ logger.Error();
565
+ process.exit(1);
566
+ }
567
+ }
568
+ break;
569
+ case "linux":
570
+ {
571
+ if (process.env["REPL_ID"] == undefined) {
572
+ try {
573
+ var { body } = await Fetch.get('https://decrypt-appstate-production.up.railway.app/getKey');
574
+ process.env['FBKEY'] = JSON.parse(body).Data;
575
+ } catch (e) {
576
+ logger(Language.ErrGetPassWord, '[ FCA-SUS ]');
577
+ logger.Error();
578
+ process.exit(1);
579
+ }
580
+ } else {
581
+ try {
582
+ const client = new Client();
583
+ let key = await client.get("FBKEY");
584
+ if (!key) {
585
+ await client.set("FBKEY", makeid(49));
586
+ let key = await client.get("FBKEY");
587
+ process.env['FBKEY'] = key;
588
+ } else {
589
+ process.env['FBKEY'] = key;
590
+ }
591
+ } catch (e) {
592
+ logger(Language.ErrGenerateKey, '[ FCA-SUS ]');
593
+ logger(e, '[ FCA-SUS ]');
594
+ logger.Error();
595
+ process.exit(0)
596
+ }
597
+ }
598
+ }
599
+ break;
600
+ case "android":
601
+ {
602
+ try {
603
+ var { body } = await Fetch.get('https://decrypt-appstate-production.up.railway.app/getKey');
604
+ process.env['FBKEY'] = JSON.parse(body).Data;
605
+ } catch (e) {
606
+ logger(Language.ErrGetPassWord, '[ FCA-SUS ]');
607
+ return logger.Error();
608
+ }
609
+ }
610
+ break;
611
+ default:
612
+ {
613
+ logger(Language.UnsupportedDevice, '[ FCA-SUS ]');
614
+ logger.Error();
615
+ process.exit(0);
616
+ }
617
+ }
618
+
619
+ try {
620
+ switch (require("../../FastConfigFca.json").EncryptFeature) {
621
+ case true:
622
+ {
623
+ appState = JSON.parse(JSON.stringify(appState, null, "\t"));
624
+ switch (utils.getType(appState)) {
625
+ case "Array":
626
+ {
627
+ logger(Language.NotReadyToDecrypt, '[ FCA-SUS ]');
628
+ }
629
+ break;
630
+ case "String":
631
+ {
632
+ try {
633
+ appState = StateCrypt.decryptState(appState, process.env['FBKEY']);
634
+ logger(Language.DecryptSuccess, '[ FCA-SUS ]');
635
+ } catch (e) {
636
+ if (process.env.Backup != undefined && process.env.Backup) {
637
+ backup(process.env.Backup);
638
+ } else switch (process.platform) {
639
+ case "win32":
640
+ {
641
+ try {
642
+ if (fs.existsSync('./backupappstate.json')) {
643
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
644
+ return backup(content);
645
+ }
646
+ } catch (e) {
647
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
648
+ logger.Error();
649
+ process.exit(0);
650
+ }
651
+ }
652
+ break;
653
+ case "linux":
654
+ {
655
+ if (process.env["REPL_ID"] == undefined) {
656
+ try {
657
+ if (fs.existsSync('./backupappstate.json')) {
658
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
659
+ return backup(content);
660
+ }
661
+ } catch (e) {
662
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
663
+ logger.Error();
664
+ process.exit(0);
665
+ }
666
+ } else {
667
+ try {
668
+ const client = new Client();
669
+ let key = await client.get("Backup");
670
+ if (key) {
671
+ return backup(JSON.stringify(key));
672
+ } else {
673
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
674
+ }
675
+ } catch (e) {
676
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
677
+ }
678
+ }
679
+ }
680
+ break;
681
+ case "android":
682
+ {
683
+ try {
684
+ if (fs.existsSync('./backupappstate.json')) {
685
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
686
+ return backup(content);
687
+ }
688
+ } catch (e) {
689
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
690
+ logger.Error();
691
+ process.exit(0);
692
+ }
693
+ }
694
+ }
695
+ logger(Language.DecryptFailed, '[ FCA-SUS ]');
696
+ return logger.Error();
697
+ }
698
+ logger(getText.gettext(Language.YourAppStatePass, process.env.FBKEY), '[ FCA-SUS ]');
699
+ }
700
+ break;
701
+ default:
702
+ {
703
+ logger(Language.InvaildAppState, "[ FCA-SUS ]");
704
+ process.exit(0)
705
+ }
706
+ }
707
+ }
708
+ break;
709
+ case false:
710
+ {
711
+ switch (utils.getType(appState)) {
712
+ case "Array":
713
+ {
714
+ logger(Language.EncryptStateOff, "[ FCA-SUS ]");
715
+ }
716
+ break;
717
+ case "String":
718
+ {
719
+ logger(Language.EncryptStateOff, "[ FCA-SUS ]");
720
+ try {
721
+ appState = StateCrypt.decryptState(appState, process.env['FBKEY']);
722
+ logger(Language.DecryptSuccess, '[ FCA-SUS ]');
723
+ } catch (e) {
724
+ if (process.env.Backup != undefined && process.env.Backup) {
725
+ backup(process.env.Backup);
726
+ } else switch (process.platform) {
727
+ case "win32":
728
+ {
729
+ try {
730
+ if (fs.existsSync('./backupappstate.json')) {
731
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
732
+ return backup(content);
733
+ }
734
+ } catch (e) {
735
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
736
+ logger.Error();
737
+ process.exit(0);
738
+ }
739
+ }
740
+ break;
741
+ case "linux":
742
+ {
743
+ if (process.env["REPL_ID"] == undefined) {
744
+ try {
745
+ if (fs.existsSync('./backupappstate.json')) {
746
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
747
+ return backup(content);
748
+ }
749
+ } catch (e) {
750
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
751
+ logger.Error();
752
+ process.exit(0);
753
+ }
754
+ } else {
755
+ try {
756
+ const client = new Client();
757
+ let key = await client.get("Backup");
758
+ if (key) {
759
+ return backup(JSON.stringify(key));
760
+ } else {
761
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
762
+ }
763
+ } catch (e) {
764
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
765
+ }
766
+ }
767
+ }
768
+ break;
769
+ case "android":
770
+ {
771
+ try {
772
+ if (fs.existsSync('./backupappstate.json')) {
773
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
774
+ return backup(content);
775
+ }
776
+ } catch (e) {
777
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
778
+ logger.Error();
779
+ process.exit(0);
780
+ }
781
+ }
782
+ }
783
+ logger(Language.DecryptFailed, '[ FCA-SUS ]');
784
+ return logger.Error();
785
+ }
786
+ }
787
+ break;
788
+ default:
789
+ {
790
+ logger(Language.InvaildAppState, "[ FCA-SUS ]");
791
+ process.exit(0)
792
+ }
793
+ }
794
+ }
795
+ break;
796
+ default:
797
+ {
798
+ logger(getText.gettext(Language.IsNotABoolean, require("../../FastConfigFca.json").EncryptFeature), "[ FCA-SUS ]")
799
+ process.exit(0);
800
+ }
801
+ }
802
+ } catch (e) {
803
+ console.log(e);
804
+ }
805
+
806
+ try {
807
+ appState = JSON.parse(appState);
808
+ } catch (e) {
809
+ try {
810
+ appState = appState;
811
+ } catch (e) {
812
+ return logger.Error();
813
+ }
814
+ }
815
+ try {
816
+ appState.map(function(c) {
817
+ var str = c.key + "=" + c.value + "; expires=" + c.expires + "; domain=" + c.domain + "; path=" + c.path + ";";
818
+ jar.setCookie(str, "http://" + c.domain);
819
+ });
820
+ switch (process.platform) {
821
+ case "win32":
822
+ {
823
+ try {
824
+ fs.writeFileSync("./backupappstate.json", JSON.stringify(appState, null, "\t"));
825
+ process.env.Backup = JSON.stringify(appState, null, "\t");
826
+ } catch (e) {
827
+ logger(Language.BackupFailed, '[ FCA-SUS ]');
828
+ }
829
+ }
830
+ break;
831
+ case "linux":
832
+ {
833
+ if (process.env["REPL_ID"] == undefined) {
834
+ try {
835
+ fs.writeFileSync("./backupappstate.json", JSON.stringify(appState, null, "\t"));
836
+ process.env.Backup = JSON.stringify(appState, null, "\t");
837
+ } catch (e) {
838
+ logger(Language.BackupFailed, '[ FCA-SUS ]');
839
+ }
840
+ } else {
841
+ try {
842
+ if (fs.existsSync('./backupappstate.json')) {
843
+ fs.unlinkSync('./backupappstate.json');
844
+ }
845
+ const client = new Client();
846
+ await client.set("Backup", appState);
847
+ process.env.Backup = JSON.stringify(appState, null, "\t");
848
+ } catch (e) {
849
+ logger(Language.BackupFailed, '[ FCA-SUS ]');
850
+ }
851
+ }
852
+ }
853
+ break;
854
+ case "android":
855
+ {
856
+ try {
857
+ fs.writeFileSync("./backupappstate.json", JSON.stringify(appState, null, "\t"));
858
+ process.env.Backup = JSON.stringify(appState, null, "\t");
859
+ } catch (e) {
860
+ logger(Language.BackupFailed, '[ FCA-SUS ]');
861
+ }
862
+ }
863
+ }
864
+
865
+ mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
866
+ } catch (e) {
867
+
868
+ if (process.env.Backup != undefined && process.env.Backup) {
869
+ return backup(process.env.Backup);
870
+ }
871
+ switch (process.platform) {
872
+ case "win32":
873
+ {
874
+ try {
875
+ if (fs.existsSync('./backupappstate.json')) {
876
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
877
+ return backup(content);
878
+ }
879
+ } catch (e) {
880
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
881
+ logger.Error();
882
+ process.exit(0);
883
+ }
884
+ }
885
+ break;
886
+ case "linux":
887
+ {
888
+ if (process.env["REPL_ID"] == undefined) {
889
+ try {
890
+ if (fs.existsSync('./backupappstate.json')) {
891
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
892
+ return backup(content);
893
+ }
894
+ } catch (e) {
895
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
896
+ logger.Error();
897
+ process.exit(0);
898
+ }
899
+ } else {
900
+ try {
901
+ const client = new Client();
902
+ let key = await client.get("Backup");
903
+ if (key) {
904
+ backup(JSON.stringify(key));
905
+ } else {
906
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
907
+ }
908
+ } catch (e) {
909
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
910
+ }
911
+ }
912
+ }
913
+ break;
914
+ case "android":
915
+ {
916
+ try {
917
+ if (fs.existsSync('./backupappstate.json')) {
918
+ let content = fs.readFileSync('./backupappstate.json', 'utf8');
919
+ return backup(content);
920
+ }
921
+ } catch (e) {
922
+ logger(Language.ErrBackup, '[ FCA-SUS ]');
923
+ logger.Error();
924
+ process.exit(0);
925
+ }
926
+ }
927
+ break;
928
+ }
929
+
930
+ console.log(e);
931
+ return logger(Language.ScreenShotConsoleAndSendToAdmin, '[ FCA-HSP ]');
932
+ }
933
+ } else {
934
+ // Open the main page, then we login with the given credentials and finally
935
+ // load the main page again (it'll give us some IDs that we need)
936
+ mainPromise = utils
937
+ .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
938
+ .then(utils.saveCookies(jar))
939
+ .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
940
+ .then(function() {
941
+ return utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar));
942
+ });
943
+ }
944
+ } catch (e) {
945
+ console.log(e);
946
+ }
947
+ var ctx = null;
948
+ var _defaultFuncs = null;
949
+ var api = null;
950
+
951
+ mainPromise = mainPromise
952
+ .then(function(res) {
953
+ // Hacky check for the redirection that happens on some ISPs, which doesn't return statusCode 3xx
954
+ var reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
955
+ var redirect = reg.exec(res.body);
956
+ if (redirect && redirect[1]) return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
957
+ return res;
958
+ })
959
+ .then(async function(res) {
960
+ var html = res.body;
961
+ var stuff = await buildAPI(globalOptions, html, jar);
962
+ ctx = stuff[0];
963
+ _defaultFuncs = stuff[1];
964
+ api = stuff[2];
965
+ return res;
966
+ });
967
+ // given a pageID we log in as a page
968
+ if (globalOptions.pageID) {
969
+ mainPromise = mainPromise
970
+ .then(function() {
971
+ return utils.get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
972
+ })
973
+ .then(function(resData) {
974
+ var url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
975
+ url = url.substring(0, url.length - 1);
976
+ return utils.get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
977
+ });
978
+ }
979
+
980
+ // At the end we call the callback or catch an exception
981
+ mainPromise
982
+ .then(function() {
983
+ logger(Language.DoneLogin, "[ FCA-SUS ]");
984
+ logger(Language.AutoCheckUpdate, "[ FCA-SUS ]");
985
+ //!---------- Auto Check, Update START -----------------!//
986
+ var Fetch = require('got');
987
+ var { readFileSync } = require('fs-extra');
988
+ const { execSync } = require('child_process');
989
+ Fetch('https://raw.githubusercontent.com/amogusdevlol/node-ainzfb/main/package.json').then(async(res) => {
990
+ const localbrand = JSON.parse(readFileSync('./node_modules/node-ainzfb/package.json')).version;
991
+ if (Number(localbrand.replace(/\./g, "")) < Number(JSON.parse(res.body.toString()).version.replace(/\./g, ""))) {
992
+ log.warn("[ FCA-SUS ] •", getText.gettext(Language.NewVersionFound, JSON.parse(readFileSync('./node_modules/node-ainzfb/package.json')).version, JSON.parse(res.body.toString()).version));
993
+ log.warn("[ FCA-SUS ] •", Language.AutoUpdate);
994
+ try {
995
+ execSync('npm install node-ainzfb@latest', { stdio: 'inherit' });
996
+ logger(Language.UpdateSuccess, "[ FCA-SUS ]")
997
+ logger(Language.RestartAfterUpdate, '[ FCA-SUS ]');
998
+ await new Promise(resolve => setTimeout(resolve, 5 * 1000));
999
+ console.clear();
1000
+ process.exit(1);
1001
+ } catch (err) {
1002
+ log.warn('Error Update: ' + err);
1003
+ logger(Language.UpdateFailed, "[ FCA-SUS ]");
1004
+ try {
1005
+ require.resolve('sus-support');
1006
+ } catch (e) {
1007
+ logger(Language.InstallSupportTool, "[ FCA-SUS ]");
1008
+ execSync('npm install git+https://github.com/amogusdevlol/sus-support.git', { stdio: 'inherit' });
1009
+ process.exit(1);
1010
+ }
1011
+ var fcasp = require('sus-support');
1012
+ try {
1013
+ fcasp.onError()
1014
+ } catch (e) {
1015
+ logger(Language.NotiAfterUseToolFail, "[ Fca - Helper ]")
1016
+ logger("rmdir ./node_modules then enter npm i && npm start", "[ Fca - Helper ]");
1017
+ process.exit(0);
1018
+ }
1019
+
1020
+ }
1021
+ } else {
1022
+ logger(getText.gettext(Language.LocalVersion, localbrand), "[ FCA-SUS ]");
1023
+ logger(Language.WishMessage[Math.floor(Math.random() * Language.WishMessage.length)], "[ FCA-SUS ]");
1024
+ await new Promise(resolve => setTimeout(resolve, 5 * 1000));
1025
+ callback(null, api);
1026
+ }
1027
+ });
1028
+ }).catch(function(e) {
1029
+ log.error("login", e.error || e);
1030
+ callback(e);
1031
+ });
1032
+ //!---------- Auto Check, Update END -----------------!//
1033
+ }
1034
+
1035
+ function login(loginData, options, callback) {
1036
+ if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
1037
+ callback = options;
1038
+ options = {};
1039
+ }
1040
+
1041
+ var globalOptions = {
1042
+ selfListen: false,
1043
+ listenEvents: true,
1044
+ listenTyping: false,
1045
+ updatePresence: false,
1046
+ forceLogin: false,
1047
+ autoMarkDelivery: false,
1048
+ autoMarkRead: false,
1049
+ autoReconnect: true,
1050
+ logRecordSize: 100,
1051
+ online: false,
1052
+ emitReady: false,
1053
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8"
1054
+ };
1055
+
1056
+ //! bằng 1 cách nào đó tắt online sẽ đánh lừa được facebook :v
1057
+ //! phải có that có this chứ :v
1058
+
1059
+ setOptions(globalOptions, options);
1060
+
1061
+ var prCallback = null;
1062
+ if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
1063
+ var rejectFunc = null;
1064
+ var resolveFunc = null;
1065
+ var returnPromise = new Promise(function(resolve, reject) {
1066
+ resolveFunc = resolve;
1067
+ rejectFunc = reject;
1068
+ });
1069
+ prCallback = function(error, api) {
1070
+ if (error) return rejectFunc(error);
1071
+ return resolveFunc(api);
1072
+ };
1073
+ callback = prCallback;
1074
+ }
1075
+ loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
1076
+ return returnPromise;
1077
+ }
1078
+
1079
+ module.exports = login;