hridoy-ultimate 9.0.2 → 9.0.4
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 +45 -0
- package/DOCS.md +14 -6
- package/README.md +3 -2
- package/index.d.ts +5 -1
- package/module/config.js +14 -2
- package/module/login.js +15 -5
- package/module/loginHelper.js +48 -9
- package/package.json +18 -12
- package/src/api/action/enableAutoSaveAppState.js +8 -5
- package/src/api/action/getSafetyStatus.js +27 -0
- package/src/api/action/logout.js +70 -59
- package/src/api/action/logoutFromFacebook.js +86 -0
- package/src/api/action/refreshFb_dtsg.js +1 -1
- package/src/api/messaging/changeGroupImage.js +1 -0
- package/src/api/socket/OldMessage.js +4 -1
- package/src/api/socket/core/connectMqtt.js +18 -1
- package/src/api/socket/core/getSeqID.js +13 -2
- package/src/api/socket/listenMqtt.js +24 -15
- package/src/api/socket/sendMessage.js +4 -1
- package/src/api/users/getUserID.js +1 -0
- package/src/app/createFcaClient.js +1 -0
- package/src/utils/antiSuspension.js +84 -24
- package/src/utils/cookies.js +29 -1
- package/src/utils/fingerprint.js +75 -36
- package/src/utils/loginParser/parseAndCheckLogin.js +7 -18
package/src/utils/fingerprint.js
CHANGED
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
// Fallback fingerprint, used ONLY when no real browser User-Agent is configured.
|
|
4
|
+
//
|
|
5
|
+
// Real Chrome sends a "reduced" User-Agent (Chrome/<major>.0.0.0) since v101, so the
|
|
6
|
+
// major version is all a believable UA needs. A hard-coded list of versions goes
|
|
7
|
+
// stale within weeks (the old pool here was ~2 years behind and a stale browser build
|
|
8
|
+
// is itself a signal), so the major is estimated from today's date instead.
|
|
9
|
+
//
|
|
10
|
+
// The best option by far is still to pass the exact User-Agent of the browser the
|
|
11
|
+
// cookies were exported from: via the `userAgent` login option, or the FCA_USER_AGENT
|
|
12
|
+
// environment variable.
|
|
13
|
+
const MS_DAY = 24 * 60 * 60 * 1000;
|
|
14
|
+
// Anchors from Chrome's published schedule: 151 stable on 2026-07-28 (4-week cadence),
|
|
15
|
+
// 153 on 2026-09-08, then one major every 2 weeks.
|
|
16
|
+
const ANCHOR_151 = Date.UTC(2026, 6, 28);
|
|
17
|
+
const ANCHOR_153 = Date.UTC(2026, 8, 8);
|
|
18
|
+
|
|
19
|
+
function estimateStableMajor(now) {
|
|
20
|
+
const t = typeof now === "number" ? now : Date.now();
|
|
21
|
+
if (t >= ANCHOR_153) return 153 + Math.floor((t - ANCHOR_153) / (14 * MS_DAY));
|
|
22
|
+
if (t >= ANCHOR_151) return 151 + Math.floor((t - ANCHOR_151) / (28 * MS_DAY));
|
|
23
|
+
// before the anchors: count back one major per 4 weeks (never below 130)
|
|
24
|
+
return Math.max(130, 151 - Math.ceil((ANCHOR_151 - t) / (28 * MS_DAY)));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Real users are usually a release behind (staged auto-update), so use stable - 1.
|
|
28
|
+
function pickChromeMajor(now) {
|
|
29
|
+
return estimateStableMajor(now) - 1;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
|
-
function buildUserAgent(
|
|
22
|
-
|
|
32
|
+
function buildUserAgent(major) {
|
|
33
|
+
// Reduced UA format used by real Chrome: Chrome/<major>.0.0.0
|
|
34
|
+
return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
|
|
23
35
|
}
|
|
24
36
|
|
|
25
37
|
// Chrome's Sec-Ch-Ua "GREASE" brand slot rotates through a small set of
|
|
@@ -47,30 +59,54 @@ function fingerprintFile() {
|
|
|
47
59
|
return path.join(process.cwd(), "data", "session", "fca-fingerprint.json");
|
|
48
60
|
}
|
|
49
61
|
|
|
62
|
+
function fromUserAgentString(ua, source) {
|
|
63
|
+
const m = String(ua || "").match(/Chrome\/(\d+)\.(\d+)\.(\d+)\.(\d+)/);
|
|
64
|
+
return {
|
|
65
|
+
userAgent: String(ua).trim(),
|
|
66
|
+
version: m ? m[0].split("/")[1] : "",
|
|
67
|
+
major: m ? parseInt(m[1], 10) : 0,
|
|
68
|
+
source
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
50
72
|
function getFingerprint() {
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
major: parseInt(saved.version.split(".")[0], 10)
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
} catch (_) { /* first run */ }
|
|
73
|
+
if (cachedFingerprint) return cachedFingerprint;
|
|
74
|
+
|
|
75
|
+
// 1) explicit environment override (same meaning as the userAgent login option)
|
|
76
|
+
const envUA = process.env.FCA_USER_AGENT;
|
|
77
|
+
if (envUA && envUA.trim()) {
|
|
78
|
+
cachedFingerprint = fromUserAgentString(envUA, "env");
|
|
79
|
+
return cachedFingerprint;
|
|
62
80
|
}
|
|
81
|
+
|
|
82
|
+
const wanted = pickChromeMajor();
|
|
83
|
+
|
|
84
|
+
// 2) the fingerprint saved by an earlier run, as long as it is not far behind a
|
|
85
|
+
// current browser (a few majors behind is normal; two years behind is not)
|
|
86
|
+
try {
|
|
87
|
+
const saved = JSON.parse(fs.readFileSync(fingerprintFile(), "utf8"));
|
|
88
|
+
const savedMajor = saved && parseInt(String(saved.major || saved.version || "").split(".")[0], 10);
|
|
89
|
+
if (savedMajor && wanted - savedMajor <= 6 && savedMajor <= wanted + 1) {
|
|
90
|
+
cachedFingerprint = {
|
|
91
|
+
userAgent: buildUserAgent(savedMajor),
|
|
92
|
+
version: savedMajor + ".0.0.0",
|
|
93
|
+
major: savedMajor,
|
|
94
|
+
source: "saved"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
} catch (_) { /* first run */ }
|
|
98
|
+
|
|
99
|
+
// 3) estimate from the date and remember it
|
|
63
100
|
if (!cachedFingerprint) {
|
|
64
|
-
const version = pickChromeVersion();
|
|
65
|
-
const major = parseInt(version.split(".")[0], 10);
|
|
66
101
|
cachedFingerprint = {
|
|
67
|
-
userAgent: buildUserAgent(
|
|
68
|
-
version,
|
|
69
|
-
major
|
|
102
|
+
userAgent: buildUserAgent(wanted),
|
|
103
|
+
version: wanted + ".0.0.0",
|
|
104
|
+
major: wanted,
|
|
105
|
+
source: "estimated"
|
|
70
106
|
};
|
|
71
107
|
try {
|
|
72
108
|
fs.mkdirSync(path.dirname(fingerprintFile()), { recursive: true });
|
|
73
|
-
fs.writeFileSync(fingerprintFile(), JSON.stringify({
|
|
109
|
+
fs.writeFileSync(fingerprintFile(), JSON.stringify({ major: wanted }), "utf8");
|
|
74
110
|
} catch (_) { /* read-only fs: fall back to per-process */ }
|
|
75
111
|
}
|
|
76
112
|
return cachedFingerprint;
|
|
@@ -125,5 +161,8 @@ function clientHintsFromUA(ua) {
|
|
|
125
161
|
module.exports = {
|
|
126
162
|
getDefaultUserAgent,
|
|
127
163
|
getFingerprint,
|
|
128
|
-
clientHintsFromUA
|
|
164
|
+
clientHintsFromUA,
|
|
165
|
+
estimateStableMajor,
|
|
166
|
+
pickChromeMajor,
|
|
167
|
+
_resetForTests: () => { cachedFingerprint = null; }
|
|
129
168
|
};
|
|
@@ -186,24 +186,13 @@ function parseAndCheckLogin(ctx, http, retryCount = 0) {
|
|
|
186
186
|
) {
|
|
187
187
|
globalAntiSuspension.detectSuspensionSignal("automated behavior checkpoint scraping warning");
|
|
188
188
|
emit("checkpoint", { type: "scraping_warning", res: resData });
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
__user: ctx.userID,
|
|
197
|
-
fb_dtsg: ctx.fb_dtsg || "",
|
|
198
|
-
fb_api_caller_class: "RelayModern",
|
|
199
|
-
fb_api_req_friendly_name: "FBScrapingWarningMutation",
|
|
200
|
-
server_timestamps: "true",
|
|
201
|
-
doc_id: "6339492849481770",
|
|
202
|
-
variables: "{}"
|
|
203
|
-
}, ctx.globalOptions, ctx)
|
|
204
|
-
.then(() => logger("Dismissed automated-behavior warning", "info"))
|
|
205
|
-
.catch((e) => logger(`Dismissing automated-behavior warning failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn"));
|
|
206
|
-
return await maybeAutoLogin(resData, res?.config);
|
|
189
|
+
logger("Facebook automated-behavior warning detected. Automatic dismissal is disabled; stop the bot and review the account manually.", "error");
|
|
190
|
+
// This is NOT a logged-out session. The old code ran the "session expired" path here,
|
|
191
|
+
// which made the bot declare itself logged out and restart (a fresh login) for nothing.
|
|
192
|
+
const err = new Error("Facebook showed an automated-behavior warning (needs a human to dismiss it)");
|
|
193
|
+
err.error = "automation_warning";
|
|
194
|
+
err.res = resData;
|
|
195
|
+
throw err;
|
|
207
196
|
}
|
|
208
197
|
if (
|
|
209
198
|
resStr.includes("https://www.facebook.com/login.php?") ||
|