@lazyneoaz/testfca 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/COOKIE_LOGIN.md +208 -0
  3. package/LICENSE +3 -0
  4. package/README.md +492 -0
  5. package/index.js +2 -0
  6. package/package.json +120 -0
  7. package/scripts/build-go.mjs +54 -0
  8. package/scripts/detect-platform.mjs +36 -0
  9. package/scripts/download-prebuilt.mjs +119 -0
  10. package/scripts/package.mjs +6 -0
  11. package/scripts/postinstall.mjs +113 -0
  12. package/src/apis/addExternalModule.js +24 -0
  13. package/src/apis/addUserToGroup.js +108 -0
  14. package/src/apis/changeAdminStatus.js +148 -0
  15. package/src/apis/changeArchivedStatus.js +61 -0
  16. package/src/apis/changeAvatar.js +103 -0
  17. package/src/apis/changeBio.js +69 -0
  18. package/src/apis/changeBlockedStatus.js +54 -0
  19. package/src/apis/changeGroupImage.js +136 -0
  20. package/src/apis/changeThreadColor.js +116 -0
  21. package/src/apis/changeThreadEmoji.js +53 -0
  22. package/src/apis/comment.js +207 -0
  23. package/src/apis/createAITheme.js +129 -0
  24. package/src/apis/createNewGroup.js +79 -0
  25. package/src/apis/createPoll.js +73 -0
  26. package/src/apis/deleteMessage.js +52 -0
  27. package/src/apis/deleteThread.js +52 -0
  28. package/src/apis/e2ee.js +170 -0
  29. package/src/apis/editMessage.js +78 -0
  30. package/src/apis/emoji.js +124 -0
  31. package/src/apis/fetchThemeData.js +82 -0
  32. package/src/apis/follow.js +81 -0
  33. package/src/apis/forwardMessage.js +52 -0
  34. package/src/apis/friend.js +243 -0
  35. package/src/apis/gcmember.js +122 -0
  36. package/src/apis/gcname.js +123 -0
  37. package/src/apis/gcrule.js +119 -0
  38. package/src/apis/getAccess.js +111 -0
  39. package/src/apis/getBotInfo.js +88 -0
  40. package/src/apis/getBotInitialData.js +43 -0
  41. package/src/apis/getFriendsList.js +79 -0
  42. package/src/apis/getMessage.js +423 -0
  43. package/src/apis/getTheme.js +95 -0
  44. package/src/apis/getThemeInfo.js +116 -0
  45. package/src/apis/getThreadHistory.js +239 -0
  46. package/src/apis/getThreadInfo.js +267 -0
  47. package/src/apis/getThreadList.js +232 -0
  48. package/src/apis/getThreadPictures.js +58 -0
  49. package/src/apis/getUserID.js +117 -0
  50. package/src/apis/getUserInfo.js +513 -0
  51. package/src/apis/getUserInfoV2.js +146 -0
  52. package/src/apis/handleMessageRequest.js +50 -0
  53. package/src/apis/httpGet.js +63 -0
  54. package/src/apis/httpPost.js +89 -0
  55. package/src/apis/httpPostFormData.js +69 -0
  56. package/src/apis/listenMqtt.js +1236 -0
  57. package/src/apis/listenSpeed.js +179 -0
  58. package/src/apis/logout.js +93 -0
  59. package/src/apis/markAsDelivered.js +47 -0
  60. package/src/apis/markAsRead.js +115 -0
  61. package/src/apis/markAsReadAll.js +40 -0
  62. package/src/apis/markAsSeen.js +70 -0
  63. package/src/apis/mqttDeltaValue.js +250 -0
  64. package/src/apis/muteThread.js +45 -0
  65. package/src/apis/nickname.js +132 -0
  66. package/src/apis/notes.js +163 -0
  67. package/src/apis/pinMessage.js +150 -0
  68. package/src/apis/produceMetaTheme.js +180 -0
  69. package/src/apis/realtime.js +182 -0
  70. package/src/apis/removeUserFromGroup.js +117 -0
  71. package/src/apis/resolvePhotoUrl.js +58 -0
  72. package/src/apis/searchForThread.js +154 -0
  73. package/src/apis/sendMessage.js +346 -0
  74. package/src/apis/sendMessageMqtt.js +248 -0
  75. package/src/apis/sendTypingIndicator.js +105 -0
  76. package/src/apis/setMessageReaction.js +38 -0
  77. package/src/apis/setMessageReactionMqtt.js +61 -0
  78. package/src/apis/setThreadTheme.js +260 -0
  79. package/src/apis/setThreadThemeMqtt.js +94 -0
  80. package/src/apis/share.js +107 -0
  81. package/src/apis/shareContact.js +66 -0
  82. package/src/apis/stickers.js +257 -0
  83. package/src/apis/story.js +181 -0
  84. package/src/apis/theme.js +233 -0
  85. package/src/apis/unfriend.js +47 -0
  86. package/src/apis/unsendMessage.js +25 -0
  87. package/src/database/appStateBackup.js +298 -0
  88. package/src/database/models/index.js +56 -0
  89. package/src/database/models/thread.js +31 -0
  90. package/src/database/models/user.js +32 -0
  91. package/src/database/threadData.js +101 -0
  92. package/src/database/userData.js +90 -0
  93. package/src/e2ee/bridge.js +275 -0
  94. package/src/e2ee/index.js +60 -0
  95. package/src/engine/client.js +95 -0
  96. package/src/engine/models/buildAPI.js +152 -0
  97. package/src/engine/models/loginHelper.js +574 -0
  98. package/src/engine/models/setOptions.js +88 -0
  99. package/src/types/index.d.ts +574 -0
  100. package/src/utils/antiSuspension.js +529 -0
  101. package/src/utils/auth-helpers.js +149 -0
  102. package/src/utils/autoReLogin.js +336 -0
  103. package/src/utils/axios.js +436 -0
  104. package/src/utils/cache.js +54 -0
  105. package/src/utils/clients.js +282 -0
  106. package/src/utils/constants.js +410 -0
  107. package/src/utils/formatters/data/formatAttachment.js +370 -0
  108. package/src/utils/formatters/data/formatDelta.js +109 -0
  109. package/src/utils/formatters/index.js +159 -0
  110. package/src/utils/formatters/value/formatCookie.js +91 -0
  111. package/src/utils/formatters/value/formatDate.js +36 -0
  112. package/src/utils/formatters/value/formatID.js +16 -0
  113. package/src/utils/formatters.js +1373 -0
  114. package/src/utils/headers.js +235 -0
  115. package/src/utils/index.js +153 -0
  116. package/src/utils/monitoring.js +333 -0
  117. package/src/utils/rateLimiter.js +319 -0
  118. package/src/utils/tokenRefresh.js +680 -0
  119. package/src/utils/user-agents.js +238 -0
  120. package/src/utils/validation.js +157 -0
@@ -0,0 +1,336 @@
1
+ "use strict";
2
+
3
+ const utils = require('./index');
4
+
5
+ // Network error codes and patterns that indicate a transient connectivity
6
+ // issue rather than a genuine Facebook session expiry.
7
+ const NETWORK_ERROR_PATTERNS = [
8
+ 'ECONNRESET', 'ETIMEDOUT', 'ECONNREFUSED', 'ENETUNREACH',
9
+ 'EHOSTUNREACH', 'EAI_AGAIN', 'ENOTFOUND', 'ESOCKETTIMEDOUT',
10
+ 'socket hang up', 'network error', 'connect ETIMEDOUT',
11
+ 'read ECONNRESET', 'write ECONNRESET'
12
+ ];
13
+
14
+ function isNetworkError(err) {
15
+ if (!err) return false;
16
+ const msg = (err.message || String(err || '')).toLowerCase();
17
+ const code = err.code || '';
18
+ return NETWORK_ERROR_PATTERNS.some(p => msg.includes(p.toLowerCase()) || code === p);
19
+ }
20
+
21
+ class AutoReLoginManager {
22
+ constructor() {
23
+ this.credentials = null;
24
+ this.loginOptions = null;
25
+ this.loginCallback = null;
26
+ this.isReLoggingIn = false;
27
+ this.pendingRequests = [];
28
+ this.maxRetries = 5;
29
+ this.retryCount = 0;
30
+ // Track when the last failure occurred so we can decay retryCount
31
+ // automatically after a long quiet period (e.g. temporary FB outage).
32
+ this.lastFailureAt = 0;
33
+ // If last re-login failure was longer than this ago, reset retryCount.
34
+ // Prevents the bot from being permanently dead after a single outage.
35
+ this.retryCountDecayMs = 2 * 60 * 60 * 1000; // 2 hours
36
+ this.onReLoginSuccess = null;
37
+ this.onReLoginFailure = null;
38
+ this.enabled = false;
39
+ this.reLoginInterval = 1000 * 60 * 60 * 24; // 24 hours
40
+ this.sessionMonitorInterval = null;
41
+ this.sessionCheckInterval = 1000 * 60 * 30; // 30 minutes
42
+ // Lock mechanism to prevent race conditions in re-login
43
+ this._reauthLock = null;
44
+ this._reauthLockPromise = null;
45
+ }
46
+
47
+ setCredentials(credentials, options, callback) {
48
+ this.credentials = credentials;
49
+ this.loginOptions = options || {};
50
+ this.loginCallback = callback;
51
+ this.enabled = true;
52
+ // Reset retry counter on fresh credential set so old failures
53
+ // from a previous session do not permanently lock re-login.
54
+ this.retryCount = 0;
55
+ // Do NOT call startSessionMonitoring() here — the api object is not
56
+ // available yet. loginHelper calls startSessionMonitoring(api) once
57
+ // all api methods are registered.
58
+ }
59
+
60
+ startSessionMonitoring(api) {
61
+ if (this.sessionMonitorInterval) {
62
+ clearInterval(this.sessionMonitorInterval);
63
+ }
64
+
65
+ if (!this.enabled || !api) return;
66
+
67
+ this.sessionMonitorInterval = setInterval(async () => {
68
+ if (this.isReLoggingIn) return;
69
+
70
+ try {
71
+ const isValid = await api.isSessionValid();
72
+ if (isValid === 'network_error') {
73
+ // Transient connectivity issue — session is probably fine.
74
+ utils.warn("AutoReLogin", "Session check returned network error — skipping re-login (transient)");
75
+ return;
76
+ }
77
+ if (!isValid) {
78
+ utils.warn("AutoReLogin", "Session health check failed, attempting token refresh first...");
79
+
80
+ let refreshed = false;
81
+ try {
82
+ if (api.tokenRefreshManager && typeof api.tokenRefreshManager.refreshTokens === 'function') {
83
+ refreshed = await api.tokenRefreshManager.refreshTokens(
84
+ api.ctx,
85
+ api.defaultFuncs,
86
+ 'https://www.facebook.com'
87
+ );
88
+ }
89
+ } catch (refreshErr) {
90
+ if (isNetworkError(refreshErr)) {
91
+ utils.warn("AutoReLogin", "Token refresh failed with network error — skipping re-login (transient):", refreshErr.message);
92
+ return;
93
+ }
94
+ utils.warn("AutoReLogin", "Token refresh failed:", refreshErr.message);
95
+ }
96
+
97
+ if (!refreshed) {
98
+ utils.warn("AutoReLogin", "Token refresh unsuccessful, triggering automatic re-login");
99
+ await this.handleSessionExpiry(api, 'https://www.facebook.com', "Session expired during monitoring");
100
+ } else {
101
+ utils.log("AutoReLogin", "Token refresh successful, session restored without re-login");
102
+ }
103
+ }
104
+ } catch (error) {
105
+ if (isNetworkError(error)) {
106
+ utils.warn("AutoReLogin", "Session monitoring skipped — network error (transient):", error.message);
107
+ return;
108
+ }
109
+ utils.error("AutoReLogin", "Session monitoring error:", error.message);
110
+ }
111
+ }, this.sessionCheckInterval);
112
+
113
+ utils.log("AutoReLogin", `Session monitoring started (interval: ${this.sessionCheckInterval}ms)`);
114
+ }
115
+
116
+ stopSessionMonitoring() {
117
+ if (this.sessionMonitorInterval) {
118
+ clearInterval(this.sessionMonitorInterval);
119
+ this.sessionMonitorInterval = null;
120
+ utils.log("AutoReLogin", "Session monitoring stopped");
121
+ }
122
+ }
123
+
124
+ isEnabled() {
125
+ return this.enabled && this.credentials !== null;
126
+ }
127
+
128
+ async handleSessionExpiry(api, fbLinkOrFunc, ERROR_RETRIEVING) {
129
+ if (!this.isEnabled()) {
130
+ utils.warn("AutoReLogin", "Auto re-login not enabled. Credentials not stored.");
131
+ return false;
132
+ }
133
+
134
+ // Convert string to function if needed
135
+ const fbLinkFunc = typeof fbLinkOrFunc === 'function' ? fbLinkOrFunc : () => fbLinkOrFunc;
136
+
137
+ // Acquire lock to prevent concurrent re-login attempts.
138
+ // If a re-login is already running, wait for it to finish and return
139
+ // its result directly — do NOT start a second parallel re-login.
140
+ if (this._reauthLock || this.isReLoggingIn) {
141
+ utils.log("AutoReLogin", "Re-login already in progress. Waiting for it to complete...");
142
+ return new Promise((resolve, reject) => {
143
+ this.pendingRequests.push({ resolve, reject });
144
+ });
145
+ }
146
+
147
+ // Time-based decay: if the last failure was long enough ago (e.g. a
148
+ // temporary Facebook/network outage that has since resolved), reset
149
+ // retryCount so the bot can try again rather than staying permanently dead.
150
+ if (this.retryCount >= this.maxRetries && this.lastFailureAt > 0) {
151
+ const timeSinceLastFailure = Date.now() - this.lastFailureAt;
152
+ if (timeSinceLastFailure >= this.retryCountDecayMs) {
153
+ utils.log("AutoReLogin",
154
+ `Resetting retryCount (${this.retryCount}) — last failure was ${Math.round(timeSinceLastFailure / 60000)} min ago (decay window: ${this.retryCountDecayMs / 60000} min)`
155
+ );
156
+ this.retryCount = 0;
157
+ }
158
+ }
159
+
160
+ if (this.retryCount >= this.maxRetries) {
161
+ utils.error("AutoReLogin", `Maximum re-login attempts (${this.maxRetries}) exceeded`);
162
+ if (this.onReLoginFailure) {
163
+ this.onReLoginFailure(new Error("Max re-login retries exceeded"));
164
+ }
165
+ return false;
166
+ }
167
+
168
+ // Set lock
169
+ this.isReLoggingIn = true;
170
+ let releaseLock;
171
+ this._reauthLockPromise = new Promise((resolve) => {
172
+ releaseLock = resolve;
173
+ });
174
+ this._reauthLock = true;
175
+
176
+ this.retryCount++;
177
+ utils.log("AutoReLogin", `Starting automatic re-login (attempt ${this.retryCount}/${this.maxRetries})...`);
178
+
179
+ try {
180
+ await this.pauseAPIRequests();
181
+
182
+ const loginHelperModel = require('../engine/models/loginHelper');
183
+ const setOptionsModel = require('../engine/models/setOptions');
184
+ const buildAPIModel = require('../engine/models/buildAPI');
185
+
186
+ await new Promise((resolve, reject) => {
187
+ loginHelperModel(
188
+ this.credentials,
189
+ this.loginOptions,
190
+ (loginError, newApi) => {
191
+ if (loginError) {
192
+ reject(loginError);
193
+ return;
194
+ }
195
+
196
+ if (api) {
197
+ api.ctx = newApi.ctx;
198
+ api.defaultFuncs = newApi.defaultFuncs;
199
+
200
+ if (api.tokenRefreshManager) {
201
+ api.tokenRefreshManager.resetFailureCount();
202
+ }
203
+ }
204
+
205
+ resolve(newApi);
206
+ },
207
+ setOptionsModel,
208
+ buildAPIModel,
209
+ api,
210
+ fbLinkFunc, // Use the function we created
211
+ ERROR_RETRIEVING
212
+ );
213
+ });
214
+
215
+ utils.log("AutoReLogin", "Re-login successful! Session restored.");
216
+ this.retryCount = 0;
217
+ this.isReLoggingIn = false;
218
+
219
+ this.resolvePendingRequests(true);
220
+
221
+ if (this.onReLoginSuccess) {
222
+ this.onReLoginSuccess();
223
+ }
224
+
225
+ try {
226
+ if (api && api.listenMqtt && api.ctx && api.ctx._listeningActive) {
227
+ try {
228
+ if (typeof api.stopListening === 'function') {
229
+ try { api.stopListening(); } catch (_) {}
230
+ }
231
+ const cb = api.ctx._lastListenCallback || null;
232
+ if (cb) {
233
+ api.listenMqtt(cb);
234
+ } else {
235
+ api.listenMqtt();
236
+ }
237
+ } catch (_) {}
238
+ }
239
+ } catch (_) {}
240
+
241
+ return true;
242
+ } catch (error) {
243
+ utils.error("AutoReLogin", `Re-login failed:`, error.message);
244
+ this.isReLoggingIn = false;
245
+ this.lastFailureAt = Date.now();
246
+
247
+ if (this.retryCount >= this.maxRetries) {
248
+ this.resolvePendingRequests(false);
249
+ if (this.onReLoginFailure) {
250
+ this.onReLoginFailure(error);
251
+ }
252
+ // Release lock before returning so waiters are unblocked.
253
+ this._reauthLock = false;
254
+ if (releaseLock) releaseLock();
255
+ return false;
256
+ }
257
+
258
+ const backoffDelay = Math.min(30000, Math.pow(2, this.retryCount) * 1000);
259
+ utils.log("AutoReLogin", `Retrying re-login in ${backoffDelay}ms...`);
260
+
261
+ // Release the lock BEFORE the retry so the recursive call can
262
+ // acquire it. Without this the recursive call sees _reauthLock=true
263
+ // and deadlocks waiting for a promise that never resolves.
264
+ this._reauthLock = false;
265
+ if (releaseLock) releaseLock();
266
+
267
+ await new Promise(resolve => setTimeout(resolve, backoffDelay));
268
+
269
+ return await this.handleSessionExpiry(api, fbLinkOrFunc, ERROR_RETRIEVING);
270
+ } finally {
271
+ // Always ensure the lock is released (covers early returns from try block).
272
+ if (this._reauthLock) {
273
+ this._reauthLock = false;
274
+ if (releaseLock) releaseLock();
275
+ }
276
+ }
277
+ }
278
+
279
+ async pauseAPIRequests() {
280
+ utils.log("AutoReLogin", "Pausing API requests during re-login...");
281
+ await new Promise(resolve => setTimeout(resolve, 1000));
282
+ }
283
+
284
+ resolvePendingRequests(success) {
285
+ utils.log("AutoReLogin", `Resolving ${this.pendingRequests.length} pending requests (success: ${success})`);
286
+
287
+ this.pendingRequests.forEach(({ resolve, reject }) => {
288
+ if (success) {
289
+ resolve(true);
290
+ } else {
291
+ reject(new Error("Re-login failed"));
292
+ }
293
+ });
294
+
295
+ this.pendingRequests = [];
296
+ }
297
+
298
+ setReLoginSuccessCallback(callback) {
299
+ this.onReLoginSuccess = callback;
300
+ }
301
+
302
+ setReLoginFailureCallback(callback) {
303
+ this.onReLoginFailure = callback;
304
+ }
305
+
306
+ updateAppState(appState) {
307
+ if (!this.credentials) return;
308
+ if (!Array.isArray(appState) || appState.length === 0) return;
309
+ if (!this.credentials.appState || Array.isArray(this.credentials.appState) || typeof this.credentials.appState === "string") {
310
+ this.credentials.appState = appState;
311
+ }
312
+ }
313
+
314
+ disable() {
315
+ this.enabled = false;
316
+ this.stopSessionMonitoring();
317
+ this.credentials = null;
318
+ this.loginOptions = null;
319
+ this.loginCallback = null;
320
+ utils.log("AutoReLogin", "Auto re-login disabled and credentials cleared");
321
+ }
322
+
323
+ reset() {
324
+ this.retryCount = 0;
325
+ this.isReLoggingIn = false;
326
+ this.pendingRequests = [];
327
+ }
328
+ }
329
+
330
+ const globalAutoReLoginManager = new AutoReLoginManager();
331
+
332
+ module.exports = {
333
+ AutoReLoginManager,
334
+ globalAutoReLoginManager,
335
+ isNetworkError
336
+ };