hridoy-ultimate 9.0.0 → 9.0.2
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 +346 -69
- package/{docs/UPSTREAM_API_DOCS.md → DOCS.md} +3 -3
- package/README.md +536 -161
- package/func/checkUpdate.js +1 -0
- package/index.d.ts +13 -74
- package/index.js +0 -6
- package/module/config.js +2 -5
- package/module/login.js +1 -2
- package/module/loginHelper.js +9 -41
- package/module/options.js +6 -6
- package/package.json +44 -39
- package/src/api/action/logout.js +0 -19
- package/src/api/messaging/sendMessage.js +1 -1
- package/src/api/messaging/sessionGuard.js +8 -0
- package/src/api/messaging/setMessageReaction.js +2 -7
- package/src/api/socket/core/connectMqtt.js +72 -99
- package/src/api/socket/core/emitAuth.js +17 -9
- package/src/api/socket/e2ee/index.js +15 -33
- package/src/api/socket/e2ee/native/NOTICE.md +2 -2
- package/src/api/socket/e2ee/native/lib/index.mjs +1 -2
- package/src/api/socket/e2ee/native/nativeMediaBridge.js +4 -4
- package/src/api/socket/listenE2EE.js +1 -3
- package/src/api/socket/listenMqtt.js +60 -67
- package/src/utils/antiSuspension.js +3 -3
- package/src/utils/fingerprint.js +35 -16
- package/src/utils/headers.js +1 -1
- package/src/utils/versionCheck.js +47 -0
- package/LICENSE +0 -23
- package/MERGE_REPORT.md +0 -54
- package/THIRD_PARTY_NOTICES.md +0 -36
- package/docs/TEST_RESULTS.md +0 -68
- package/scripts/run-tests.js +0 -19
- package/scripts/syntax-check.js +0 -22
- package/src/api/socket/core/lifecycle.js +0 -117
- package/src/api/socket/e2ee/proto/proto-writer.ts +0 -76
- package/src/utils/typingIndicator.js +0 -202
- package/test/helpers/stub-modules.js +0 -122
- package/test/integration/logout.test.js +0 -69
- package/test/integration/mqtt-lifecycle.test.js +0 -195
- package/test/integration/package.test.js +0 -116
- package/test/integration/typing-wiring.test.js +0 -71
- package/test/unit/fingerprint.test.js +0 -19
- package/test/unit/humanizer.test.js +0 -32
- package/test/unit/lifecycle.test.js +0 -92
- package/test/unit/parsers.test.js +0 -43
- package/test/unit/typing.test.js +0 -136
package/func/checkUpdate.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// (dongdev / EryXenX) typings. Newer / internal methods are declared loosely (any) on purpose.
|
|
1
|
+
declare module '@dongdev/fca-unofficial' {
|
|
3
2
|
import type EventEmitter from "events";
|
|
4
3
|
import type { Duplex, Readable, Transform } from "stream";
|
|
5
4
|
|
|
@@ -13,7 +12,7 @@
|
|
|
13
12
|
// Login Function
|
|
14
13
|
// ============================================================================
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
function login(
|
|
17
16
|
credentials: Partial<{
|
|
18
17
|
email: string;
|
|
19
18
|
password: string;
|
|
@@ -23,7 +22,7 @@ declare function login(
|
|
|
23
22
|
options: Partial<IFCAU_Options>,
|
|
24
23
|
callback: (err: Error | null, api: IFCAU_API) => void
|
|
25
24
|
): void;
|
|
26
|
-
|
|
25
|
+
function login(
|
|
27
26
|
credentials: Partial<{
|
|
28
27
|
email: string;
|
|
29
28
|
password: string;
|
|
@@ -32,7 +31,7 @@ declare function login(
|
|
|
32
31
|
}>,
|
|
33
32
|
options: Partial<IFCAU_Options>
|
|
34
33
|
): Promise<IFCAU_API>;
|
|
35
|
-
|
|
34
|
+
function login(
|
|
36
35
|
credentials: Partial<{
|
|
37
36
|
email: string;
|
|
38
37
|
password: string;
|
|
@@ -41,7 +40,7 @@ declare function login(
|
|
|
41
40
|
}>,
|
|
42
41
|
callback: (err: Error | null, api: IFCAU_API) => void
|
|
43
42
|
): void;
|
|
44
|
-
|
|
43
|
+
function login(
|
|
45
44
|
credentials: Partial<{
|
|
46
45
|
email: string;
|
|
47
46
|
password: string;
|
|
@@ -94,14 +93,14 @@ declare function login(
|
|
|
94
93
|
// Send Message Function
|
|
95
94
|
// ============================================================================
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
function sendMessage(
|
|
98
97
|
message: string | MessageObject,
|
|
99
98
|
threadID: string | string[],
|
|
100
99
|
callback?: (err?: Error, data?: { threadID: string; messageID: string; timestamp: number }) => void,
|
|
101
100
|
replyMessageID?: string,
|
|
102
101
|
isGroup?: boolean
|
|
103
102
|
): Promise<{ threadID: string; messageID: string; timestamp: number }>;
|
|
104
|
-
|
|
103
|
+
function sendMessage(
|
|
105
104
|
message: string | MessageObject,
|
|
106
105
|
threadID: string | string[],
|
|
107
106
|
replyMessageID?: string,
|
|
@@ -146,39 +145,9 @@ declare function sendMessage(
|
|
|
146
145
|
// Reactions & Interactions
|
|
147
146
|
setMessageReaction: (reaction: string, messageID: string, threadID: string, callback?: (err?: Error) => void, forceCustomReaction?: boolean) => Promise<void>;
|
|
148
147
|
setMessageReactionMqtt: (reaction: string, messageID: string, threadID: string, callback?: (err?: Error) => void) => Promise<void>;
|
|
149
|
-
sendTypingIndicator: (threadID: string
|
|
148
|
+
sendTypingIndicator: (threadID: string, callback?: (err?: Error) => void) => Promise<void>;
|
|
150
149
|
sendTypingIndicatorMqtt: (isTyping: boolean, threadID: string, callback?: (err?: Error) => void) => Promise<void>;
|
|
151
150
|
|
|
152
|
-
// Typing indicator controller (hridoy-ultimate 9.0.0)
|
|
153
|
-
getTypingIndicator: () => IFCAU_TypingIndicator;
|
|
154
|
-
setTypingIndicator: (option: boolean | IFCAU_TypingIndicatorOptions) => IFCAU_TypingIndicatorOptions;
|
|
155
|
-
withTyping: <T>(threadID: string, fn: () => T | Promise<T>) => Promise<T>;
|
|
156
|
-
|
|
157
|
-
// Previously undeclared methods (typed loosely on purpose; see README "Known limitations")
|
|
158
|
-
OldMessage: (...args: any[]) => any;
|
|
159
|
-
sendMessageMqtt: (...args: any[]) => any;
|
|
160
|
-
listenE2EE: (callback: (err: Error | null, event: any) => void) => any;
|
|
161
|
-
getMessage: (...args: any[]) => any;
|
|
162
|
-
getUserInfoV2: (...args: any[]) => any;
|
|
163
|
-
searchForThread: (...args: any[]) => any;
|
|
164
|
-
shareContact: (...args: any[]) => any;
|
|
165
|
-
uploadAttachment: (...args: any[]) => any;
|
|
166
|
-
sendBroadcast: (...args: any[]) => any;
|
|
167
|
-
sessionGuard: (...args: any[]) => any;
|
|
168
|
-
refreshFb_dtsg: (...args: any[]) => any;
|
|
169
|
-
httpGet: (...args: any[]) => any;
|
|
170
|
-
httpPost: (...args: any[]) => any;
|
|
171
|
-
postFormData: (...args: any[]) => any;
|
|
172
|
-
addExternalModule: (...args: any[]) => any;
|
|
173
|
-
changeAvatar: (...args: any[]) => any;
|
|
174
|
-
changeBio: (...args: any[]) => any;
|
|
175
|
-
createThemeAI: (...args: any[]) => any;
|
|
176
|
-
getThemePictures: (...args: any[]) => any;
|
|
177
|
-
dismissScrapingWarning: (...args: any[]) => any;
|
|
178
|
-
handleFriendRequest: (...args: any[]) => any;
|
|
179
|
-
setPostReaction: (...args: any[]) => any;
|
|
180
|
-
unfriend: (...args: any[]) => any;
|
|
181
|
-
|
|
182
151
|
// Polls
|
|
183
152
|
createPoll: (title: string, threadID: string, options?: { [item: string]: boolean }, callback?: (err?: Error) => void) => Promise<void>;
|
|
184
153
|
|
|
@@ -216,10 +185,10 @@ declare function sendMessage(
|
|
|
216
185
|
listenMqtt: (callback?: (err: Error | null, message: IFCAU_ListenMessage) => void) => EventEmitter & { stopListening: (callback?: () => void) => void };
|
|
217
186
|
|
|
218
187
|
// Lifecycle & Remote Events
|
|
219
|
-
on: (event: string, listener: (...args: any[]) => void) =>
|
|
220
|
-
once: (event: string, listener: (...args: any[]) => void) =>
|
|
221
|
-
off: (event: string, listener: (...args: any[]) => void) =>
|
|
222
|
-
removeAllListeners: (event?: string) =>
|
|
188
|
+
on: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
|
|
189
|
+
once: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
|
|
190
|
+
off: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
|
|
191
|
+
removeAllListeners: (event?: string) => IFCAU_Api;
|
|
223
192
|
|
|
224
193
|
// Middleware System
|
|
225
194
|
useMiddleware: (middleware: IFCAU_Middleware | string, fn?: IFCAU_Middleware) => () => void;
|
|
@@ -778,35 +747,5 @@ declare function sendMessage(
|
|
|
778
747
|
autoMarkRead: boolean;
|
|
779
748
|
proxy: string;
|
|
780
749
|
online: boolean;
|
|
781
|
-
/** Opt-in command anti-spam (reply delay + cooldown). Off by default. */
|
|
782
|
-
humanize: boolean | Record<string, any>;
|
|
783
|
-
/** Typing indicator. Default ON; false disables; object fine-tunes it. */
|
|
784
|
-
typingIndicator: boolean | IFCAU_TypingIndicatorOptions;
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
export type IFCAU_TypingIndicatorOptions = {
|
|
788
|
-
enabled?: boolean;
|
|
789
|
-
/** Only type for command-like messages (GoatBot prefix, "/", "!", "."). Default true. */
|
|
790
|
-
onlyCommands?: boolean;
|
|
791
|
-
/** Extra command prefixes. */
|
|
792
|
-
commands?: string[];
|
|
793
|
-
/** Safety stop in ms when no reply is sent. Default 8000. */
|
|
794
|
-
maxMs?: number;
|
|
795
|
-
/** Do not re-send typing for the same thread inside this window. Default 1500. */
|
|
796
|
-
minGapMs?: number;
|
|
797
|
-
groups?: boolean;
|
|
798
|
-
dms?: boolean;
|
|
799
750
|
};
|
|
800
|
-
|
|
801
|
-
export type IFCAU_TypingSendOptions = { duration?: number; autoStop?: boolean; type?: number };
|
|
802
|
-
|
|
803
|
-
export interface IFCAU_TypingIndicator {
|
|
804
|
-
readonly enabled: boolean;
|
|
805
|
-
options: Required<IFCAU_TypingIndicatorOptions>;
|
|
806
|
-
configure(option: boolean | IFCAU_TypingIndicatorOptions): IFCAU_TypingIndicatorOptions;
|
|
807
|
-
isTyping(threadID: string): boolean;
|
|
808
|
-
start(threadID: string): boolean;
|
|
809
|
-
stop(threadID: string): boolean;
|
|
810
|
-
stopAll(): void;
|
|
811
|
-
withTyping<T>(threadID: string, fn: () => T | Promise<T>): Promise<T>;
|
|
812
|
-
}
|
|
751
|
+
}
|
package/index.js
CHANGED
|
@@ -22,12 +22,6 @@ module.exports.MessengerContext = MessengerContext;
|
|
|
22
22
|
module.exports.attachThreadInfoRealtimeSync = attachThreadInfoRealtimeSync;
|
|
23
23
|
module.exports.applyThreadInfoRealtimeEvent = applyThreadInfoRealtimeEvent;
|
|
24
24
|
|
|
25
|
-
// Typing indicator (default on)
|
|
26
|
-
const typingIndicator = require("./src/utils/typingIndicator");
|
|
27
|
-
module.exports.TypingIndicator = typingIndicator.TypingIndicator;
|
|
28
|
-
module.exports.createTypingIndicator = typingIndicator.createTypingIndicator;
|
|
29
|
-
module.exports.typingIndicator = typingIndicator;
|
|
30
|
-
|
|
31
25
|
// Command anti-spam / humanizer
|
|
32
26
|
module.exports.CommandHumanizer = humanizer.CommandHumanizer;
|
|
33
27
|
module.exports.createCommandHumanizer = humanizer.createCommandHumanizer;
|
package/module/config.js
CHANGED
|
@@ -2,16 +2,13 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const logger = require("../func/logger");
|
|
4
4
|
const defaultConfig = {
|
|
5
|
-
autoUpdate:
|
|
5
|
+
autoUpdate: true,
|
|
6
6
|
mqtt: { enabled: true, reconnectInterval: 3600 },
|
|
7
7
|
// Opt-in only: auto re-login with credentials (via the third-party API)
|
|
8
8
|
// after a checkpoint/session failure is itself a strong suspicious-login
|
|
9
9
|
// signal and invalidates every other live session on the account.
|
|
10
10
|
autoLogin: false,
|
|
11
|
-
|
|
12
|
-
// external API sends email/password/2FA secret to that host, so it only
|
|
13
|
-
// runs when YOU set apiServer to a server you control or trust.
|
|
14
|
-
apiServer: "",
|
|
11
|
+
apiServer: "https://minhdong.site",
|
|
15
12
|
apiKey: "",
|
|
16
13
|
credentials: { email: "", password: "", twofactor: "" },
|
|
17
14
|
antiGetInfo: {
|
package/module/login.js
CHANGED
|
@@ -100,8 +100,7 @@ function login(loginData, options, callback) {
|
|
|
100
100
|
online: true,
|
|
101
101
|
emitReady: false,
|
|
102
102
|
userAgent: getDefaultUserAgent(),
|
|
103
|
-
humanize: undefined
|
|
104
|
-
typingIndicator: undefined
|
|
103
|
+
humanize: undefined
|
|
105
104
|
};
|
|
106
105
|
setOptions(globalOptions, options);
|
|
107
106
|
let prCallback = null;
|
package/module/loginHelper.js
CHANGED
|
@@ -9,7 +9,6 @@ const { saveCookies, getAppState } = require("../src/utils/client");
|
|
|
9
9
|
const { getFrom } = require("../src/utils/constants");
|
|
10
10
|
const { loadConfig } = require("./config");
|
|
11
11
|
const { createRemoteClient } = require("../src/remote/remoteClient");
|
|
12
|
-
const { getDefaultUserAgent } = require("../src/utils/fingerprint");
|
|
13
12
|
const { config } = loadConfig();
|
|
14
13
|
const axiosBase = require("axios");
|
|
15
14
|
const regions = [
|
|
@@ -54,18 +53,13 @@ function mask(s, keep = 3) {
|
|
|
54
53
|
* @param {string} email - Email hoặc số điện thoại
|
|
55
54
|
* @param {string} password - Mật khẩu
|
|
56
55
|
* @param {string|null} twoFactor - Secret Base32 cho 2FA (không phải mã 6 số)
|
|
57
|
-
* @param {string|null} apiBaseUrl - Base URL của API server (
|
|
56
|
+
* @param {string|null} apiBaseUrl - Base URL của API server (mặc định: https://minhdong.site)
|
|
58
57
|
* @param {string|null} apiKey - API key để xác thực (x-api-key header)
|
|
59
58
|
* @returns {Promise<{ok: boolean, uid?: string, access_token?: string, cookies?: Array, cookie?: string, message?: string}>}
|
|
60
59
|
*/
|
|
61
60
|
async function loginViaAPI(email, password, twoFactor = null, apiBaseUrl = null, apiKey = null) {
|
|
62
61
|
try {
|
|
63
|
-
const baseUrl = apiBaseUrl || config.apiServer;
|
|
64
|
-
if (!baseUrl) {
|
|
65
|
-
const msg = "Credential login needs an explicit apiServer (fca-config.json or argument); none is configured. Use appState/cookies instead.";
|
|
66
|
-
logger(`API-LOGIN: ${msg}`, "error");
|
|
67
|
-
return { ok: false, message: msg };
|
|
68
|
-
}
|
|
62
|
+
const baseUrl = apiBaseUrl || config.apiServer || "https://minhdong.site";
|
|
69
63
|
const endpoint = `${baseUrl}/api/v1/facebook/login_ios`;
|
|
70
64
|
const xApiKey = apiKey || config.apiKey || null;
|
|
71
65
|
|
|
@@ -886,10 +880,10 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
|
|
|
886
880
|
// inconsistent to Facebook.
|
|
887
881
|
const bodyStr = typeof initial?.data === "string" ? initial.data : String(initial?.data ?? "");
|
|
888
882
|
if (!/MPageLoadClientMetrics/.test(bodyStr)) {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
883
|
+
// Do NOT swap the User-Agent mid-session: a session that starts as
|
|
884
|
+
// one browser and continues as another is exactly what gets
|
|
885
|
+
// cookies invalidated. Keep one UA and tell the user how to fix it.
|
|
886
|
+
logger("Initial page load doesn't match the expected rendering for this User-Agent. Set the exact User-Agent of the browser your cookies came from (facebookAccount.userAgent in config.json).", "warn");
|
|
893
887
|
}
|
|
894
888
|
return (await ctx.bypassAutomation(initial, jar)) || initial;
|
|
895
889
|
}
|
|
@@ -1138,7 +1132,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
|
|
|
1138
1132
|
logger(`Database connection failed: ${errorMsg}`, "warn");
|
|
1139
1133
|
}
|
|
1140
1134
|
});
|
|
1141
|
-
logger("⚡
|
|
1135
|
+
logger("⚡ hridoy-ultimate | Powered by HR ID OY | github.com/hridoyhossen48360", "info");
|
|
1142
1136
|
const emitter = new EventEmitter();
|
|
1143
1137
|
const ctxMain = {
|
|
1144
1138
|
userID,
|
|
@@ -1355,43 +1349,17 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
|
|
|
1355
1349
|
logger(`sendMessage nexca override failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
|
|
1356
1350
|
}
|
|
1357
1351
|
|
|
1358
|
-
// Typing indicator (default ON, zero added latency): shows "typing..." as soon as a
|
|
1359
|
-
// command-like message arrives, clears it when the reply goes out. Must exist before
|
|
1360
|
-
// the listenMqtt override below because that is where its middleware is installed.
|
|
1361
|
-
try {
|
|
1362
|
-
const { createTypingIndicator, wrapSendMessage } = require("../src/utils/typingIndicator");
|
|
1363
|
-
const typing = createTypingIndicator(api, ctxMain, ctxMain.globalOptions && ctxMain.globalOptions.typingIndicator, logger);
|
|
1364
|
-
ctxMain._typing = typing;
|
|
1365
|
-
wrapSendMessage(api, typing);
|
|
1366
|
-
api.getTypingIndicator = () => typing;
|
|
1367
|
-
api.setTypingIndicator = (opt) => typing.configure(opt);
|
|
1368
|
-
api.withTyping = (threadID, fn) => typing.withTyping(threadID, fn);
|
|
1369
|
-
} catch (e) {
|
|
1370
|
-
logger(`typing indicator init failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
1352
|
// listenMqtt override with nexca version (better MQTT stability)
|
|
1374
1353
|
try {
|
|
1375
1354
|
api.listenMqtt = require("../src/api/socket/listenMqtt")(defaultFuncs, api, ctxMain);
|
|
1376
1355
|
api.listen = api.listenMqtt;
|
|
1377
|
-
// Refresh the "raw" MQTT reference listenE2EE.js uses internally.
|
|
1378
|
-
// It was captured earlier (right after base FCA methods loaded,
|
|
1379
|
-
// before this nexca override existed), so it was pointing at the
|
|
1380
|
-
// pre-humanizer listener. Once E2EE connects and swaps
|
|
1381
|
-
// api.listenMqtt to listenE2EE, that stale reference meant every
|
|
1382
|
-
// message routed through the MQTT side of E2EE mode skipped the
|
|
1383
|
-
// humanizer entirely — no delay, no typing, on literally every
|
|
1384
|
-
// message while E2EE was active.
|
|
1385
|
-
api._listenMqttRaw = api.listenMqtt;
|
|
1386
1356
|
} catch (e) {
|
|
1387
1357
|
logger(`listenMqtt nexca override failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
|
|
1388
1358
|
}
|
|
1389
1359
|
|
|
1390
1360
|
try {
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
// package (this fork ships as @eryxenx/fca), so it always
|
|
1394
|
-
// produced a bogus/misleading version diff.
|
|
1361
|
+
const { checkForUpdate } = require("../src/utils/versionCheck");
|
|
1362
|
+
checkForUpdate(logger);
|
|
1395
1363
|
} catch (_) {}
|
|
1396
1364
|
logger("🚀 Login successful! Bot is ready.");
|
|
1397
1365
|
callback(null, api);
|
package/module/options.js
CHANGED
|
@@ -25,14 +25,14 @@ function setOptions(globalOptions, options) {
|
|
|
25
25
|
globalOptions.userAgent = options.userAgent || getDefaultUserAgent();
|
|
26
26
|
break;
|
|
27
27
|
}
|
|
28
|
-
case "
|
|
29
|
-
|
|
28
|
+
case "acceptLanguage": {
|
|
29
|
+
if (typeof options.acceptLanguage === "string" && options.acceptLanguage.trim()) {
|
|
30
|
+
globalOptions.acceptLanguage = options.acceptLanguage.trim();
|
|
31
|
+
}
|
|
30
32
|
break;
|
|
31
33
|
}
|
|
32
|
-
case "
|
|
33
|
-
|
|
34
|
-
// (see src/utils/typingIndicator.js DEFAULTS)
|
|
35
|
-
globalOptions.typingIndicator = options.typingIndicator;
|
|
34
|
+
case "humanize": {
|
|
35
|
+
globalOptions.humanize = options.humanize;
|
|
36
36
|
break;
|
|
37
37
|
}
|
|
38
38
|
case "proxy": {
|
package/package.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hridoy-ultimate",
|
|
3
|
-
"version": "9.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "9.0.2",
|
|
4
|
+
"description": "Facebook Chat API by HR ID OY | Stable • Auto Re-login • Full E2EE Support — send messages, media, reactions & more in encrypted chats, hassle-free",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"types": "./index.d.ts",
|
|
10
9
|
"require": "./index.js",
|
|
11
|
-
"default": "./index.js"
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
"default": "./index.js",
|
|
11
|
+
"types": "./index.d.ts"
|
|
12
|
+
}
|
|
14
13
|
},
|
|
15
14
|
"files": [
|
|
16
15
|
"index.js",
|
|
@@ -18,80 +17,86 @@
|
|
|
18
17
|
"module/",
|
|
19
18
|
"func/",
|
|
20
19
|
"src/",
|
|
21
|
-
"
|
|
22
|
-
"test/",
|
|
23
|
-
"docs/",
|
|
20
|
+
"DOCS.md",
|
|
24
21
|
"README.md",
|
|
25
|
-
"CHANGELOG.md",
|
|
26
|
-
"MERGE_REPORT.md",
|
|
27
22
|
"LICENSE",
|
|
28
|
-
"
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"src/app/"
|
|
29
25
|
],
|
|
30
26
|
"scripts": {
|
|
31
|
-
"test": "
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
27
|
+
"test": "mocha",
|
|
28
|
+
"lint": "eslint ."
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/hridoyhossen48360/hridoy-ultimate.git"
|
|
36
33
|
},
|
|
37
34
|
"keywords": [
|
|
38
35
|
"facebook",
|
|
39
|
-
"messenger",
|
|
40
36
|
"chat",
|
|
41
37
|
"api",
|
|
42
|
-
"
|
|
43
|
-
"mqtt",
|
|
38
|
+
"messenger",
|
|
44
39
|
"bot",
|
|
45
40
|
"unofficial",
|
|
41
|
+
"fca",
|
|
46
42
|
"hridoy-ultimate",
|
|
47
|
-
"
|
|
48
|
-
"e2ee"
|
|
43
|
+
"hridoy"
|
|
49
44
|
],
|
|
50
45
|
"author": {
|
|
51
|
-
"name": "HR ID OY"
|
|
46
|
+
"name": "HR ID OY",
|
|
47
|
+
"url": "https://github.com/hridoyhossen48360"
|
|
52
48
|
},
|
|
53
|
-
"maintainers": [
|
|
54
|
-
{
|
|
55
|
-
"name": "HR ID OY"
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
49
|
"contributors": [
|
|
59
50
|
{
|
|
60
|
-
"name": "
|
|
51
|
+
"name": "HR ID OY",
|
|
61
52
|
"url": "https://github.com/hridoyhossen48360"
|
|
62
53
|
},
|
|
63
54
|
{
|
|
64
|
-
"name": "
|
|
55
|
+
"name": "EryXenX (Base fork)",
|
|
56
|
+
"url": "https://github.com/EryXenX"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "DongDev (Original)",
|
|
65
60
|
"url": "https://github.com/dongp06"
|
|
66
61
|
}
|
|
67
62
|
],
|
|
68
63
|
"license": "MIT",
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/hridoyhossen48360/hridoy-ultimate/issues"
|
|
66
|
+
},
|
|
67
|
+
"homepage": "https://github.com/hridoyhossen48360/hridoy-ultimate#readme",
|
|
69
68
|
"engines": {
|
|
70
|
-
"node": ">=
|
|
69
|
+
"node": ">=12.0.0"
|
|
71
70
|
},
|
|
72
71
|
"dependencies": {
|
|
73
72
|
"axios": "^1.13.5",
|
|
74
73
|
"axios-cookiejar-support": "^5.0.5",
|
|
75
74
|
"bluebird": "^3.7.2",
|
|
76
75
|
"chalk": "^4.1.2",
|
|
77
|
-
"
|
|
76
|
+
"cheerio": "1.0.0-rc.12",
|
|
78
77
|
"duplexify": "^4.1.3",
|
|
79
78
|
"gradient-string": "^2.0.2",
|
|
80
79
|
"https-proxy-agent": "^4.0.0",
|
|
81
80
|
"mqtt": "^5.10.1",
|
|
82
|
-
"request": "^2.88.2",
|
|
83
81
|
"sequelize": "^6.37.6",
|
|
84
82
|
"sqlite3": "^5.1.7",
|
|
85
|
-
"
|
|
86
|
-
"ws": "^8.18.0"
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
"totp-generator": "^1.0.0",
|
|
84
|
+
"ws": "^8.18.0",
|
|
85
|
+
"@noble/curves": "^2.2.0",
|
|
86
|
+
"@noble/hashes": "^2.2.0",
|
|
89
87
|
"@signalapp/libsignal-client": "0.70.0",
|
|
90
|
-
"protobufjs": "^8.4.0",
|
|
91
88
|
"mime": "^3.0.0",
|
|
89
|
+
"protobufjs": "^8.4.0",
|
|
92
90
|
"koffi": "^3.0.2",
|
|
93
91
|
"yumi-json-bigint": "^1.0.0",
|
|
94
|
-
"undici": "^6.0.0",
|
|
95
92
|
"fca-unofficial": "github:VangBanLaNhat/fca-unofficial"
|
|
93
|
+
},
|
|
94
|
+
"devDependencies": {
|
|
95
|
+
"eslint": "^8.50.0",
|
|
96
|
+
"mocha": "^10.2.0"
|
|
97
|
+
},
|
|
98
|
+
"publishConfig": {
|
|
99
|
+
"access": "public",
|
|
100
|
+
"registry": "https://registry.npmjs.org/"
|
|
96
101
|
}
|
|
97
102
|
}
|
package/src/api/action/logout.js
CHANGED
|
@@ -4,7 +4,6 @@ const log = require("../../../func/logAdapter");
|
|
|
4
4
|
const { parseAndCheckLogin } = require("../../utils/client");
|
|
5
5
|
const { getFrom } = require("../../utils/constants");
|
|
6
6
|
const { saveCookies } = require("../../utils/client");
|
|
7
|
-
const lifecycle = require("../socket/core/lifecycle");
|
|
8
7
|
module.exports = function(defaultFuncs, api, ctx) {
|
|
9
8
|
return function logout(callback) {
|
|
10
9
|
let resolveFunc = function() {};
|
|
@@ -63,25 +62,7 @@ module.exports = function(defaultFuncs, api, ctx) {
|
|
|
63
62
|
.then(saveCookies(ctx.jar));
|
|
64
63
|
})
|
|
65
64
|
.then(function() {
|
|
66
|
-
// Release everything this session owns: no pending reconnect may
|
|
67
|
-
// revive the listener, and no timer may outlive the login.
|
|
68
65
|
ctx.loggedIn = false;
|
|
69
|
-
ctx._stopped = true;
|
|
70
|
-
lifecycle.clearListenerTimers(ctx, true);
|
|
71
|
-
if (ctx._typing && typeof ctx._typing.stopAll === "function") ctx._typing.stopAll();
|
|
72
|
-
const steps = [];
|
|
73
|
-
if (typeof api.stopListening === "function") {
|
|
74
|
-
steps.push(new Promise(function(resolve) { api.stopListening(resolve); }));
|
|
75
|
-
}
|
|
76
|
-
const e2ee = ctx.e2ee || api.e2ee;
|
|
77
|
-
if (e2ee && typeof e2ee.disconnect === "function") {
|
|
78
|
-
steps.push(Promise.resolve(e2ee.disconnect()).catch(function(e) {
|
|
79
|
-
log.warn("logout", "E2EE disconnect failed: " + (e && e.message ? e.message : String(e)));
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
82
|
-
return Promise.all(steps);
|
|
83
|
-
})
|
|
84
|
-
.then(function() {
|
|
85
66
|
log.info("logout", "Logged out successfully.");
|
|
86
67
|
callback();
|
|
87
68
|
})
|
|
@@ -86,6 +86,14 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
86
86
|
return result;
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
+
// Save the freshest cookies when the process exits (restart, crash
|
|
90
|
+
// handler, Ctrl+C). Facebook rotates cookies while the bot runs; if
|
|
91
|
+
// the last periodic save is older than that rotation, the next start
|
|
92
|
+
// would load already-superseded cookies and look "expired".
|
|
93
|
+
process.once("exit", function () {
|
|
94
|
+
try { saveToDisk(appStatePath); } catch (_) {}
|
|
95
|
+
});
|
|
96
|
+
|
|
89
97
|
// Expose manual save
|
|
90
98
|
api.saveSession = function (customPath) {
|
|
91
99
|
return saveToDisk(customPath || appStatePath);
|
|
@@ -5,7 +5,7 @@ const { generateOfflineThreadingID, getCurrentTimestamp } = require("../../utils
|
|
|
5
5
|
|
|
6
6
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
7
|
return function setMessageReaction(reaction, messageID, threadID, callback, forceCustomReaction) {
|
|
8
|
-
// ✅
|
|
8
|
+
// ✅ HR ID OY Fix: threadID is now optional (backward compatible)
|
|
9
9
|
if (typeof threadID === "function") {
|
|
10
10
|
forceCustomReaction = callback;
|
|
11
11
|
callback = threadID;
|
|
@@ -23,7 +23,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
23
23
|
// threadID না থাকলে e2ee bridge এর ম্যাপ থেকে বের করার চেষ্টা, তারপর ctx fallback
|
|
24
24
|
const resolvedThreadID = threadID ||
|
|
25
25
|
(api.e2ee && typeof api.e2ee.getThreadIdForMessage === "function" ? api.e2ee.getThreadIdForMessage(messageID) : null);
|
|
26
|
-
const finalThreadID = resolvedThreadID || ctx.lastThreadID
|
|
26
|
+
const finalThreadID = resolvedThreadID || ctx.lastThreadID || "0";
|
|
27
27
|
|
|
28
28
|
const isE2EEDM = ctx.threadTypes && ctx.threadTypes[String(finalThreadID)] === 'dm' &&
|
|
29
29
|
api.e2ee && typeof api.e2ee.isConnected === "function" && api.e2ee.isConnected();
|
|
@@ -48,11 +48,6 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
48
48
|
if (cb) cb(err);
|
|
49
49
|
return reject(err);
|
|
50
50
|
}
|
|
51
|
-
if (!finalThreadID) {
|
|
52
|
-
const err = new Error("setMessageReaction: threadID is required and could not be resolved from messageID");
|
|
53
|
-
if (cb) cb(err);
|
|
54
|
-
return reject(err);
|
|
55
|
-
}
|
|
56
51
|
if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
|
|
57
52
|
if (typeof ctx.wsTaskNumber !== "number") ctx.wsTaskNumber = 0;
|
|
58
53
|
const reqID = ++ctx.wsReqNumber;
|