@dongdev/fca-unofficial 2.0.12 → 2.0.14
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/CHANGELOG.md +6 -0
- package/README.md +9 -4
- package/func/checkUpdate.js +32 -28
- package/module/login.js +19 -7
- package/module/loginHelper.js +88 -101
- package/package.json +1 -1
- package/src/api/messaging/sendMessage.js +53 -63
- package/src/api/messaging/sendTypingIndicator.js +61 -104
- package/src/api/messaging/setMessageReaction.js +66 -95
- package/src/api/socket/core/connectMqtt.js +10 -12
- package/src/api/socket/listenMqtt.js +88 -34
- package/src/utils/client.js +63 -7
- package/func/login.js +0 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
## ⚠️ Important Disclaimer
|
9
9
|
|
10
10
|
**We are not responsible if your account gets banned for spammy activities such as:**
|
11
|
+
|
11
12
|
- Sending lots of messages to people you don't know
|
12
13
|
- Sending messages very quickly
|
13
14
|
- Sending spammy looking URLs
|
@@ -15,13 +16,14 @@
|
|
15
16
|
|
16
17
|
**Recommendation:** Use Firefox browser or [this website](https://fca.dongdev.id.vn) to reduce logout issues, especially for iOS users.
|
17
18
|
|
18
|
-
**Support:** If you encounter errors, contact us [here](https://www.facebook.com/
|
19
|
+
**Support:** If you encounter errors, contact us [here](https://www.facebook.com/mdong.dev)
|
19
20
|
|
20
21
|
## 🔍 Introduction
|
21
22
|
|
22
23
|
Facebook now has an [official API for chat bots](https://developers.facebook.com/docs/messenger-platform), however it's only available for Facebook Pages.
|
23
24
|
|
24
25
|
`@dongdev/fca-unofficial` is the only API that allows you to automate chat functionalities on a **user account** by emulating the browser. This means:
|
26
|
+
|
25
27
|
- Making the exact same GET/POST requests as a browser
|
26
28
|
- Does not work with auth tokens
|
27
29
|
- Requires Facebook account credentials (email/password) or AppState
|
@@ -109,13 +111,13 @@ login({ appState: [] }, (err, api) => {
|
|
109
111
|
|
110
112
|
## 📝 Message Types
|
111
113
|
|
112
|
-
| Type
|
113
|
-
|
|
114
|
+
| Type | Usage |
|
115
|
+
| ---------------------- | ----------------------------------------------------------------- |
|
114
116
|
| **Regular text** | `{ body: "message text" }` |
|
115
117
|
| **Sticker** | `{ sticker: "sticker_id" }` |
|
116
118
|
| **File/Image** | `{ attachment: fs.createReadStream(path) }` or array of streams |
|
117
119
|
| **URL** | `{ url: "https://example.com" }` |
|
118
|
-
| **Large emoji** | `{ emoji: "👍", emojiSize: "large" }` (small/medium/large)
|
120
|
+
| **Large emoji** | `{ emoji: "👍", emojiSize: "large" }` (small/medium/large) |
|
119
121
|
|
120
122
|
**Note:** A message can only be a regular message (which can be empty) and optionally **one of the following**: a sticker, an attachment, or a URL.
|
121
123
|
|
@@ -228,6 +230,7 @@ api.setOptions({
|
|
228
230
|
```
|
229
231
|
|
230
232
|
**By default:**
|
233
|
+
|
231
234
|
- `listenEvents` is `false` - won't receive events like joining/leaving chat, title changes
|
232
235
|
- `selfListen` is `false` - will ignore messages sent by the current account
|
233
236
|
|
@@ -252,6 +255,7 @@ api.setOptions({
|
|
252
255
|
## 📚 Full API Documentation
|
253
256
|
|
254
257
|
See [DOCS.md](./DOCS.md) for detailed information about:
|
258
|
+
|
255
259
|
- All available API methods
|
256
260
|
- Parameters and options
|
257
261
|
- Event types
|
@@ -291,6 +295,7 @@ api.setMessageReaction(reaction, messageID, callback);
|
|
291
295
|
## 🤝 Contributing
|
292
296
|
|
293
297
|
Contributions are welcome! Please:
|
298
|
+
|
294
299
|
1. Fork the repository
|
295
300
|
2. Create a new branch (`git checkout -b feature/AmazingFeature`)
|
296
301
|
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
package/func/checkUpdate.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
// func/checkUpdate.js
|
1
2
|
const logger = require("./logger");
|
2
3
|
const fs = require("fs");
|
3
4
|
const { exec } = require("child_process");
|
@@ -21,38 +22,41 @@ function getInstalledVersion() {
|
|
21
22
|
}
|
22
23
|
}
|
23
24
|
|
24
|
-
async function
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
async function _checkAndUpdateVersionImpl() {
|
26
|
+
logger("Checking version...", "info");
|
27
|
+
const latest = (await execPromise(`npm view ${pkgName} version`)).stdout.trim();
|
28
|
+
const installed = getInstalledVersion();
|
29
|
+
if (!installed || installed !== latest) {
|
30
|
+
logger(`New version available (${latest}). Current version (${installed || "not installed"}). Updating...`, "info");
|
31
|
+
try {
|
32
|
+
const { stderr } = await execPromise(`npm i ${pkgName}@latest`);
|
33
|
+
if (stderr) logger(stderr, "error");
|
34
|
+
logger(`Updated fca to the latest version: ${latest}, Restart to apply`, "info");
|
35
|
+
process.exit(1);
|
36
|
+
} catch (e) {
|
37
|
+
logger(`Error running npm install: ${e.error || e}. Trying to install from GitHub...`, "error");
|
31
38
|
try {
|
32
|
-
const { stderr } = await execPromise(
|
39
|
+
const { stderr } = await execPromise("npm i https://github.com/Donix-VN/fca-unofficial");
|
33
40
|
if (stderr) logger(stderr, "error");
|
34
|
-
logger(`
|
35
|
-
|
36
|
-
} catch (
|
37
|
-
logger(`Error
|
38
|
-
|
39
|
-
const { stderr } = await execPromise("npm i https://github.com/Donix-VN/fca-unofficial");
|
40
|
-
if (stderr) logger(stderr, "error");
|
41
|
-
logger(`Installed from GitHub successfully: ${latest}`, "info");
|
42
|
-
callback(null);
|
43
|
-
} catch (gitErr) {
|
44
|
-
logger(`Error installing from GitHub: ${gitErr.error || gitErr}`, "error");
|
45
|
-
callback(gitErr.error || gitErr);
|
46
|
-
}
|
41
|
+
logger(`Installed from GitHub successfully: ${latest}`, "info");
|
42
|
+
return;
|
43
|
+
} catch (gitErr) {
|
44
|
+
logger(`Error installing from GitHub: ${gitErr.error || gitErr}`, "error");
|
45
|
+
throw (gitErr.error || gitErr);
|
47
46
|
}
|
48
|
-
} else {
|
49
|
-
logger(`You're already on the latest version - ${latest}`, "info");
|
50
|
-
callback(null);
|
51
47
|
}
|
52
|
-
}
|
53
|
-
logger(`
|
54
|
-
|
48
|
+
} else {
|
49
|
+
logger(`You're already on the latest version - ${latest}`, "info");
|
50
|
+
return;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
function checkAndUpdateVersion(callback) {
|
55
|
+
if (typeof callback === "function") {
|
56
|
+
_checkAndUpdateVersionImpl().then(() => callback(null)).catch(err => callback(err));
|
57
|
+
return;
|
55
58
|
}
|
59
|
+
return _checkAndUpdateVersionImpl();
|
56
60
|
}
|
57
61
|
|
58
|
-
module.exports
|
62
|
+
module.exports = { checkAndUpdateVersion };
|
package/module/login.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
"use strict";
|
2
1
|
const { getType } = require("../src/utils/format");
|
3
2
|
const { setOptions } = require("./options");
|
4
3
|
const { loadConfig } = require("./config");
|
4
|
+
const { checkAndUpdateVersion } = require("../func/checkUpdate");
|
5
|
+
const loginHelper = require("./loginHelper");
|
6
|
+
|
5
7
|
const { config } = loadConfig();
|
6
|
-
if (config.autoUpdate) require("../func/checkUpdate").checkAndUpdateVersion(() => {});
|
7
8
|
global.fca = { config };
|
8
|
-
const loginHelper = require("./loginHelper");
|
9
9
|
|
10
10
|
function login(loginData, options, callback) {
|
11
11
|
if (getType(options) === "Function" || getType(options) === "AsyncFunction") {
|
@@ -28,10 +28,11 @@ function login(loginData, options, callback) {
|
|
28
28
|
};
|
29
29
|
setOptions(globalOptions, options);
|
30
30
|
let prCallback = null;
|
31
|
+
let rejectFunc = null;
|
32
|
+
let resolveFunc = null;
|
33
|
+
let returnPromise = null;
|
31
34
|
if (getType(callback) !== "Function" && getType(callback) !== "AsyncFunction") {
|
32
|
-
|
33
|
-
let resolveFunc = null;
|
34
|
-
var returnPromise = new Promise(function (resolve, reject) {
|
35
|
+
returnPromise = new Promise(function (resolve, reject) {
|
35
36
|
resolveFunc = resolve;
|
36
37
|
rejectFunc = reject;
|
37
38
|
});
|
@@ -41,7 +42,18 @@ function login(loginData, options, callback) {
|
|
41
42
|
};
|
42
43
|
callback = prCallback;
|
43
44
|
}
|
44
|
-
loginHelper(loginData.appState, loginData.Cookie,loginData.email, loginData.password, globalOptions, callback, prCallback);
|
45
|
+
const proceed = () => loginHelper(loginData.appState, loginData.Cookie, loginData.email, loginData.password, globalOptions, callback, prCallback);
|
46
|
+
if (config && config.autoUpdate) {
|
47
|
+
const p = checkAndUpdateVersion();
|
48
|
+
if (p && typeof p.then === "function") {
|
49
|
+
p.then(proceed).catch(err => callback(err));
|
50
|
+
} else {
|
51
|
+
proceed();
|
52
|
+
}
|
53
|
+
} else {
|
54
|
+
proceed();
|
55
|
+
}
|
45
56
|
return returnPromise;
|
46
57
|
}
|
58
|
+
|
47
59
|
module.exports = login;
|
package/module/loginHelper.js
CHANGED
@@ -127,6 +127,35 @@ const genTotp = async secret => {
|
|
127
127
|
return typeof r === "object" ? r.otp : r;
|
128
128
|
};
|
129
129
|
|
130
|
+
function normalizeCookieHeaderString(s) {
|
131
|
+
let str = String(s || "").trim();
|
132
|
+
if (!str) return [];
|
133
|
+
if (/^cookie\s*:/i.test(str)) str = str.replace(/^cookie\s*:/i, "").trim();
|
134
|
+
str = str.replace(/\r?\n/g, " ").replace(/\s*;\s*/g, ";");
|
135
|
+
const parts = str.split(";").map(v => v.trim()).filter(Boolean);
|
136
|
+
const out = [];
|
137
|
+
for (const p of parts) {
|
138
|
+
const eq = p.indexOf("=");
|
139
|
+
if (eq <= 0) continue;
|
140
|
+
const k = p.slice(0, eq).trim();
|
141
|
+
const v = p.slice(eq + 1).trim().replace(/^"(.*)"$/, "$1");
|
142
|
+
if (!k) continue;
|
143
|
+
out.push(`${k}=${v}`);
|
144
|
+
}
|
145
|
+
return out;
|
146
|
+
}
|
147
|
+
|
148
|
+
function setJarFromPairs(j, pairs, domain) {
|
149
|
+
const expires = new Date(Date.now() + 31536e6).toUTCString();
|
150
|
+
for (const kv of pairs) {
|
151
|
+
const cookieStr = `${kv}; expires=${expires}; domain=${domain}; path=/;`;
|
152
|
+
try {
|
153
|
+
if (typeof j.setCookieSync === "function") j.setCookieSync(cookieStr, "https://www.facebook.com");
|
154
|
+
else j.setCookie(cookieStr, "https://www.facebook.com");
|
155
|
+
} catch { }
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
130
159
|
function cookieHeaderFromJar(j) {
|
131
160
|
const urls = ["https://www.facebook.com", "https://www.messenger.com"];
|
132
161
|
const seen = new Set();
|
@@ -135,7 +164,7 @@ function cookieHeaderFromJar(j) {
|
|
135
164
|
let s = "";
|
136
165
|
try {
|
137
166
|
s = typeof j.getCookieStringSync === "function" ? j.getCookieStringSync(u) : "";
|
138
|
-
} catch {}
|
167
|
+
} catch { }
|
139
168
|
if (!s) continue;
|
140
169
|
for (const kv of s.split(";")) {
|
141
170
|
const t = kv.trim();
|
@@ -174,7 +203,7 @@ async function ensureUniqueIndex(sequelize) {
|
|
174
203
|
if (uniqueIndexEnsured) return;
|
175
204
|
try {
|
176
205
|
await sequelize.getQueryInterface().addIndex("app_state_backups", ["userID", "type"], { unique: true, name: "app_state_user_type_unique" });
|
177
|
-
} catch {}
|
206
|
+
} catch { }
|
178
207
|
uniqueIndexEnsured = true;
|
179
208
|
}
|
180
209
|
|
@@ -231,7 +260,7 @@ async function getLatestBackupAny(type) {
|
|
231
260
|
async function tokens(username, password, twofactor = null) {
|
232
261
|
const t0 = process.hrtime.bigint();
|
233
262
|
if (!username || !password) {
|
234
|
-
logger("Missing email or password",
|
263
|
+
logger("Missing email or password", "error");
|
235
264
|
return { status: false, message: "Please provide email and password" };
|
236
265
|
}
|
237
266
|
logger(`AUTO-LOGIN: Initialize login ${mask(username, 2)}`, "info");
|
@@ -263,13 +292,13 @@ async function tokens(username, password, twofactor = null) {
|
|
263
292
|
if (code) logger(`AUTO-LOGIN: Error on request #1 ${code} ${message}`, "warn");
|
264
293
|
logger("AUTO-LOGIN: Processing twofactor...", "info");
|
265
294
|
if (code === 401) return { status: false, message: message || "Unauthorized" };
|
266
|
-
if (
|
267
|
-
logger("AUTO-LOGIN: 2FA required but secret missing",
|
295
|
+
if (!config.credentials?.twofactor) {
|
296
|
+
logger("AUTO-LOGIN: 2FA required but secret missing", "warn");
|
268
297
|
return { status: false, message: "Please provide the 2FA secret!" };
|
269
298
|
}
|
270
299
|
try {
|
271
300
|
const dataErr = e && e.data && e.data.error && e.data.error.error_data ? e.data.error.error_data : {};
|
272
|
-
const codeTotp = await genTotp(twofactor);
|
301
|
+
const codeTotp = await genTotp(config.credentials.twofactor);
|
273
302
|
logger(`AUTO-LOGIN: Performing 2FA ${mask(codeTotp, 2)}`, "info");
|
274
303
|
const form2 = { ...baseForm, twofactor_code: codeTotp, encrypted_msisdn: "", userid: dataErr.uid || "", machine_id: dataErr.machine_id || baseForm.machine_id, first_factor: dataErr.login_first_factor || "", credentials_type: "two_factor" };
|
275
304
|
form2.sig = encodeSig(sortObject(form2));
|
@@ -284,58 +313,12 @@ async function tokens(username, password, twofactor = null) {
|
|
284
313
|
logger(`AUTO-LOGIN: Done success login with 2FA ${Math.round(t1)}ms`, "info");
|
285
314
|
return { status: true, cookies };
|
286
315
|
} catch {
|
287
|
-
logger("AUTO-LOGIN: 2FA failed",
|
316
|
+
logger("AUTO-LOGIN: 2FA failed", "error");
|
288
317
|
return { status: false, message: "Invalid two-factor code!" };
|
289
318
|
}
|
290
319
|
}
|
291
320
|
}
|
292
321
|
|
293
|
-
function normalizeCookieHeaderString(s) {
|
294
|
-
let str = String(s || "").trim();
|
295
|
-
if (!str) return [];
|
296
|
-
if (/^cookie\s*:/i.test(str)) str = str.replace(/^cookie\s*:/i, "").trim();
|
297
|
-
str = str.replace(/\r?\n/g, " ").replace(/\s*;\s*/g, ";");
|
298
|
-
const parts = str.split(";").map(v => v.trim()).filter(Boolean);
|
299
|
-
const out = [];
|
300
|
-
for (const p of parts) {
|
301
|
-
const eq = p.indexOf("=");
|
302
|
-
if (eq <= 0) continue;
|
303
|
-
const k = p.slice(0, eq).trim();
|
304
|
-
const v = p.slice(eq + 1).trim().replace(/^"(.*)"$/, "$1");
|
305
|
-
if (!k) continue;
|
306
|
-
out.push(`${k}=${v}`);
|
307
|
-
}
|
308
|
-
return out;
|
309
|
-
}
|
310
|
-
|
311
|
-
function setJarFromPairs(j, pairs, domain) {
|
312
|
-
const expires = new Date(Date.now() + 31536e6).toUTCString();
|
313
|
-
for (const kv of pairs) {
|
314
|
-
const cookieStr = `${kv}; expires=${expires}; domain=${domain}; path=/;`;
|
315
|
-
try {
|
316
|
-
if (typeof j.setCookieSync === "function") j.setCookieSync(cookieStr, "https://www.facebook.com");
|
317
|
-
else j.setCookie(cookieStr, "https://www.facebook.com");
|
318
|
-
} catch {}
|
319
|
-
}
|
320
|
-
}
|
321
|
-
|
322
|
-
function makeLogin(j, email, password, globalOptions, callback, prCallback) {
|
323
|
-
return async function () {
|
324
|
-
const u = email || config.credentials.email;
|
325
|
-
const p = password || config.credentials.password;
|
326
|
-
const tf = config.credentials.twofactor || null;
|
327
|
-
if (!u || !p) return;
|
328
|
-
const r = await tokens(u, p, tf);
|
329
|
-
if (r && r.status && Array.isArray(r.cookies)) {
|
330
|
-
const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
|
331
|
-
setJarFromPairs(j, pairs, ".facebook.com");
|
332
|
-
await get("https://www.facebook.com/", j, null, globalOptions).then(saveCookies(j));
|
333
|
-
} else {
|
334
|
-
throw new Error(r && r.message ? r.message : "Login failed");
|
335
|
-
}
|
336
|
-
};
|
337
|
-
}
|
338
|
-
|
339
322
|
async function hydrateJarFromDB(userID) {
|
340
323
|
try {
|
341
324
|
let ck = null;
|
@@ -358,7 +341,7 @@ async function hydrateJarFromDB(userID) {
|
|
358
341
|
let parsed = null;
|
359
342
|
try {
|
360
343
|
parsed = JSON.parse(app);
|
361
|
-
} catch {}
|
344
|
+
} catch { }
|
362
345
|
if (Array.isArray(parsed)) {
|
363
346
|
const pairs = parsed.map(c => [c.name || c.key, c.value].join("="));
|
364
347
|
setJarFromPairs(jar, pairs, ".facebook.com");
|
@@ -377,10 +360,8 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
|
|
377
360
|
cs.find(c => c.key === "c_user")?.value ||
|
378
361
|
cs.find(c => c.name === "i_user")?.value ||
|
379
362
|
cs.find(c => c.name === "c_user")?.value;
|
380
|
-
|
381
363
|
let userID = getUID(currentCookies);
|
382
364
|
if (userID) return { html: currentHtml, cookies: currentCookies, userID };
|
383
|
-
|
384
365
|
const hydrated = await hydrateJarFromDB(null);
|
385
366
|
if (hydrated) {
|
386
367
|
logger("AppState backup live — proceeding to login", "info");
|
@@ -391,12 +372,11 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
|
|
391
372
|
const uidB = getUID(cookiesB);
|
392
373
|
if (uidB) return { html: htmlB, cookies: cookiesB, userID: uidB };
|
393
374
|
}
|
394
|
-
|
395
375
|
if (config.autoLogin !== true) throw new Error("AppState backup die — Auto-login is disabled");
|
396
376
|
logger("AppState backup die — proceeding to email/password login", "warn");
|
397
|
-
const u = config.credentials
|
398
|
-
const p = config.credentials
|
399
|
-
const tf = config.credentials
|
377
|
+
const u = config.credentials?.email;
|
378
|
+
const p = config.credentials?.password;
|
379
|
+
const tf = config.credentials?.twofactor || null;
|
400
380
|
if (!u || !p) throw new Error("Missing user cookie");
|
401
381
|
const r = await tokens(u, p, tf);
|
402
382
|
if (!(r && r.status && Array.isArray(r.cookies))) throw new Error(r && r.message ? r.message : "Login failed");
|
@@ -411,9 +391,25 @@ async function tryAutoLoginIfNeeded(currentHtml, currentCookies, globalOptions)
|
|
411
391
|
return { html: html2, cookies: cookies2, userID: uid2 };
|
412
392
|
}
|
413
393
|
|
414
|
-
function
|
394
|
+
function makeLogin(j, email, password, globalOptions) {
|
395
|
+
return async function () {
|
396
|
+
const u = email || config.credentials?.email;
|
397
|
+
const p = password || config.credentials?.password;
|
398
|
+
const tf = config.credentials?.twofactor || null;
|
399
|
+
if (!u || !p) return;
|
400
|
+
const r = await tokens(u, p, tf);
|
401
|
+
if (r && r.status && Array.isArray(r.cookies)) {
|
402
|
+
const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
|
403
|
+
setJarFromPairs(j, pairs, ".facebook.com");
|
404
|
+
await get("https://www.facebook.com/", j, null, globalOptions).then(saveCookies(j));
|
405
|
+
} else {
|
406
|
+
throw new Error(r && r.message ? r.message : "Login failed");
|
407
|
+
}
|
408
|
+
};
|
409
|
+
}
|
410
|
+
|
411
|
+
function loginHelper(appState, Cookie, email, password, globalOptions, callback) {
|
415
412
|
try {
|
416
|
-
let main;
|
417
413
|
const domain = ".facebook.com";
|
418
414
|
try {
|
419
415
|
if (appState) {
|
@@ -421,7 +417,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
421
417
|
let parsed = appState;
|
422
418
|
try {
|
423
419
|
parsed = JSON.parse(appState);
|
424
|
-
} catch {}
|
420
|
+
} catch { }
|
425
421
|
if (Array.isArray(parsed)) {
|
426
422
|
const pairs = parsed.map(c => [c.name || c.key, c.value].join("="));
|
427
423
|
setJarFromPairs(jar, pairs, domain);
|
@@ -449,7 +445,6 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
449
445
|
} catch (e) {
|
450
446
|
return callback(e);
|
451
447
|
}
|
452
|
-
|
453
448
|
(async () => {
|
454
449
|
if (appState || Cookie) {
|
455
450
|
return get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
|
@@ -462,7 +457,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
462
457
|
logger("AppState backup die — proceeding to email/password login", "warn");
|
463
458
|
return get("https://www.facebook.com/", null, null, globalOptions)
|
464
459
|
.then(saveCookies(jar))
|
465
|
-
.then(makeLogin(jar, email, password, globalOptions
|
460
|
+
.then(makeLogin(jar, email, password, globalOptions))
|
466
461
|
.then(function () {
|
467
462
|
return get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
|
468
463
|
});
|
@@ -475,34 +470,20 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
475
470
|
cookies.find(c => c.key === "c_user")?.value ||
|
476
471
|
cookies.find(c => c.name === "i_user")?.value ||
|
477
472
|
cookies.find(c => c.name === "c_user")?.value;
|
478
|
-
|
479
|
-
try {
|
480
|
-
const userDataMatch = String(html).match(/\["CurrentUserInitialData",\[\],({.*?}),\d+\]/);
|
481
|
-
if (userDataMatch) {
|
482
|
-
const info = JSON.parse(userDataMatch[1]);
|
483
|
-
logger(`Đăng nhập tài khoản: ${info.NAME} (${info.USER_ID})`, "info");
|
484
|
-
} else if (userID) {
|
485
|
-
logger(`ID người dùng: ${userID}`, "info");
|
486
|
-
}
|
487
|
-
} catch {}
|
488
|
-
|
489
473
|
if (!userID) {
|
490
474
|
const retried = await tryAutoLoginIfNeeded(html, cookies, globalOptions);
|
491
475
|
html = retried.html;
|
492
476
|
cookies = retried.cookies;
|
493
477
|
userID = retried.userID;
|
494
478
|
}
|
495
|
-
|
496
479
|
if (html.includes("/checkpoint/block/?next")) {
|
497
480
|
logger("Appstate die, vui lòng thay cái mới!", "error");
|
498
481
|
throw new Error("Checkpoint");
|
499
482
|
}
|
500
|
-
|
501
483
|
let mqttEndpoint;
|
502
484
|
let region = "PRN";
|
503
485
|
let fb_dtsg;
|
504
486
|
let irisSeqID;
|
505
|
-
|
506
487
|
try {
|
507
488
|
const m1 = html.match(/"endpoint":"([^"]+)"/);
|
508
489
|
const m2 = m1 ? null : html.match(/endpoint\\":\\"([^\\"]+)\\"/);
|
@@ -526,11 +507,9 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
526
507
|
} catch { }
|
527
508
|
const tokenMatch = html.match(/DTSGInitialData.*?token":"(.*?)"/);
|
528
509
|
if (tokenMatch) fb_dtsg = tokenMatch[1];
|
529
|
-
|
530
510
|
try {
|
531
511
|
if (userID) await backupAppStateSQL(jar, userID);
|
532
|
-
} catch {}
|
533
|
-
|
512
|
+
} catch { }
|
534
513
|
Promise.resolve()
|
535
514
|
.then(function () {
|
536
515
|
if (models && models.sequelize && typeof models.sequelize.authenticate === "function") {
|
@@ -546,9 +525,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
546
525
|
console.error(error);
|
547
526
|
console.error("Database connection failed:", error && error.message ? error.message : String(error));
|
548
527
|
});
|
549
|
-
|
550
528
|
logger("FCA fix/update by DongDev (Donix-VN)", "info");
|
551
|
-
|
552
529
|
const ctx = {
|
553
530
|
userID,
|
554
531
|
jar,
|
@@ -566,9 +543,25 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
566
543
|
clientID: ((Math.random() * 2147483648) | 0).toString(16),
|
567
544
|
clientId: getFrom(html, '["MqttWebDeviceID",[],{"clientID":"', '"}') || "",
|
568
545
|
wsReqNumber: 0,
|
569
|
-
wsTaskNumber: 0
|
546
|
+
wsTaskNumber: 0,
|
547
|
+
tasks: new Map()
|
548
|
+
};
|
549
|
+
ctx.performAutoLogin = async () => {
|
550
|
+
try {
|
551
|
+
const u = config.credentials?.email || email;
|
552
|
+
const p = config.credentials?.password || password;
|
553
|
+
const tf = config.credentials?.twofactor || null;
|
554
|
+
if (!u || !p) return false;
|
555
|
+
const r = await tokens(u, p, tf);
|
556
|
+
if (!(r && r.status && Array.isArray(r.cookies))) return false;
|
557
|
+
const pairs = r.cookies.map(c => `${c.key || c.name}=${c.value}`);
|
558
|
+
setJarFromPairs(jar, pairs, ".facebook.com");
|
559
|
+
await get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
|
560
|
+
return true;
|
561
|
+
} catch {
|
562
|
+
return false;
|
563
|
+
}
|
570
564
|
};
|
571
|
-
|
572
565
|
const api = {
|
573
566
|
setOptions: require("./options").setOptions.bind(null, globalOptions),
|
574
567
|
getCookies: function () {
|
@@ -585,7 +578,6 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
585
578
|
return await getLatestBackup(uid, "cookie");
|
586
579
|
}
|
587
580
|
};
|
588
|
-
|
589
581
|
const defaultFuncs = makeDefaults(html, userID, ctx);
|
590
582
|
const srcRoot = path.join(__dirname, "../src/api");
|
591
583
|
let loaded = 0;
|
@@ -605,23 +597,18 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback,
|
|
605
597
|
loaded++;
|
606
598
|
});
|
607
599
|
});
|
608
|
-
|
609
600
|
logger(`Loaded ${loaded} FCA API methods${skipped ? `, skipped ${skipped} duplicates` : ""}`);
|
610
|
-
|
611
|
-
api.
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
.
|
616
|
-
.then(function () {
|
617
|
-
logger("Successfully refreshed fb_dtsg", "[ FCA-UNO ] >");
|
618
|
-
})
|
619
|
-
.catch(function () {
|
601
|
+
if (api.listenMqtt) api.listen = api.listenMqtt;
|
602
|
+
if (api.refreshFb_dtsg) {
|
603
|
+
setInterval(function () {
|
604
|
+
api.refreshFb_dtsg().then(function () {
|
605
|
+
logger("Successfully refreshed fb_dtsg");
|
606
|
+
}).catch(function () {
|
620
607
|
logger("An error occurred while refreshing fb_dtsg", "error");
|
621
608
|
});
|
622
|
-
|
623
|
-
|
624
|
-
logger("Login successful!"
|
609
|
+
}, 86400000);
|
610
|
+
}
|
611
|
+
logger("Login successful!");
|
625
612
|
callback(null, api);
|
626
613
|
})
|
627
614
|
.catch(function (e) {
|