@cexy/hoonfca 1.0.0 → 1.0.1

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 (188) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +451 -43
  3. package/examples/login-with-cookies.js +102 -0
  4. package/examples/verify.js +70 -0
  5. package/index.js +1 -466
  6. package/package.json +98 -6
  7. package/src/apis/addExternalModule.js +24 -0
  8. package/src/apis/addUserToGroup.js +108 -0
  9. package/src/apis/changeAdminStatus.js +148 -0
  10. package/src/apis/changeArchivedStatus.js +61 -0
  11. package/src/apis/changeAvatar.js +103 -0
  12. package/src/apis/changeBio.js +69 -0
  13. package/src/apis/changeBlockedStatus.js +54 -0
  14. package/src/apis/changeGroupImage.js +136 -0
  15. package/src/apis/changeThreadColor.js +116 -0
  16. package/src/{changeThreadEmoji.js → apis/changeThreadEmoji.js} +7 -8
  17. package/src/apis/comment.js +207 -0
  18. package/src/apis/createAITheme.js +129 -0
  19. package/src/apis/createNewGroup.js +79 -0
  20. package/src/apis/createPoll.js +73 -0
  21. package/src/apis/deleteMessage.js +44 -0
  22. package/src/apis/deleteThread.js +52 -0
  23. package/src/apis/e2ee.js +17 -0
  24. package/src/apis/editMessage.js +70 -0
  25. package/src/apis/emoji.js +124 -0
  26. package/src/apis/fetchThemeData.js +82 -0
  27. package/src/apis/follow.js +81 -0
  28. package/src/apis/forwardMessage.js +52 -0
  29. package/src/apis/friend.js +243 -0
  30. package/src/apis/gcmember.js +122 -0
  31. package/src/apis/gcname.js +123 -0
  32. package/src/apis/gcrule.js +119 -0
  33. package/src/apis/getAccess.js +111 -0
  34. package/src/apis/getBotInfo.js +88 -0
  35. package/src/apis/getBotInitialData.js +43 -0
  36. package/src/apis/getFriendsList.js +79 -0
  37. package/src/apis/getMessage.js +423 -0
  38. package/src/apis/getTheme.js +95 -0
  39. package/src/apis/getThemeInfo.js +116 -0
  40. package/src/apis/getThreadHistory.js +239 -0
  41. package/src/apis/getThreadInfo.js +267 -0
  42. package/src/apis/getThreadList.js +232 -0
  43. package/src/apis/getThreadPictures.js +58 -0
  44. package/src/apis/getUserID.js +117 -0
  45. package/src/apis/getUserInfo.js +513 -0
  46. package/src/apis/getUserInfoV2.js +146 -0
  47. package/src/apis/handleMessageRequest.js +50 -0
  48. package/src/apis/httpGet.js +63 -0
  49. package/src/apis/httpPost.js +89 -0
  50. package/src/apis/httpPostFormData.js +69 -0
  51. package/src/apis/listenMqtt.js +1236 -0
  52. package/src/apis/listenSpeed.js +179 -0
  53. package/src/apis/logout.js +87 -0
  54. package/src/apis/markAsDelivered.js +47 -0
  55. package/src/apis/markAsRead.js +99 -0
  56. package/src/apis/markAsReadAll.js +40 -0
  57. package/src/apis/markAsSeen.js +70 -0
  58. package/src/apis/mqttDeltaValue.js +278 -0
  59. package/src/apis/muteThread.js +45 -0
  60. package/src/apis/nickname.js +132 -0
  61. package/src/apis/notes.js +163 -0
  62. package/src/apis/pinMessage.js +150 -0
  63. package/src/apis/produceMetaTheme.js +180 -0
  64. package/src/apis/realtime.js +182 -0
  65. package/src/apis/removeUserFromGroup.js +117 -0
  66. package/src/apis/resolvePhotoUrl.js +58 -0
  67. package/src/apis/searchForThread.js +154 -0
  68. package/src/apis/sendMessage.js +354 -0
  69. package/src/apis/sendMessageMqtt.js +249 -0
  70. package/src/apis/sendTypingIndicator.js +91 -0
  71. package/src/apis/setMessageReaction.js +27 -0
  72. package/src/apis/setMessageReactionMqtt.js +61 -0
  73. package/src/apis/setThreadTheme.js +260 -0
  74. package/src/apis/setThreadThemeMqtt.js +94 -0
  75. package/src/apis/share.js +107 -0
  76. package/src/apis/shareContact.js +66 -0
  77. package/src/apis/stickers.js +257 -0
  78. package/src/apis/story.js +181 -0
  79. package/src/apis/theme.js +233 -0
  80. package/src/apis/unfriend.js +47 -0
  81. package/src/apis/unsendMessage.js +17 -0
  82. package/src/engine/client.js +92 -0
  83. package/src/engine/models/buildAPI.js +152 -0
  84. package/src/engine/models/loginHelper.js +519 -0
  85. package/src/engine/models/setOptions.js +88 -0
  86. package/src/security/e2ee.js +109 -0
  87. package/src/types/index.d.ts +498 -0
  88. package/src/utils/antiSuspension.js +506 -0
  89. package/src/utils/auth-helpers.js +149 -0
  90. package/src/utils/autoReLogin.js +336 -0
  91. package/src/utils/axios.js +436 -0
  92. package/src/utils/cache.js +54 -0
  93. package/src/utils/clients.js +282 -0
  94. package/src/utils/constants.js +410 -0
  95. package/src/utils/formatters/data/formatAttachment.js +370 -0
  96. package/src/utils/formatters/data/formatDelta.js +109 -0
  97. package/src/utils/formatters/index.js +159 -0
  98. package/src/utils/formatters/value/formatCookie.js +91 -0
  99. package/src/utils/formatters/value/formatDate.js +36 -0
  100. package/src/utils/formatters/value/formatID.js +16 -0
  101. package/src/utils/formatters.js +1373 -0
  102. package/src/utils/headers.js +230 -0
  103. package/src/utils/index.js +153 -0
  104. package/src/utils/monitoring.js +333 -0
  105. package/src/utils/rateLimiter.js +319 -0
  106. package/src/utils/tokenRefresh.js +657 -0
  107. package/src/utils/user-agents.js +238 -0
  108. package/src/utils/validation.js +157 -0
  109. package/replit.nix +0 -3
  110. package/src/addExternalModule.js +0 -25
  111. package/src/addUserToGroup.js +0 -98
  112. package/src/changeAdminStatus.js +0 -98
  113. package/src/changeArchivedStatus.js +0 -51
  114. package/src/changeAvatar.js +0 -89
  115. package/src/changeBio.js +0 -74
  116. package/src/changeBlockedStatus.js +0 -45
  117. package/src/changeBlockedStatusMqtt.js +0 -65
  118. package/src/changeCover.js +0 -92
  119. package/src/changeGroupImage.js +0 -110
  120. package/src/changeName.js +0 -106
  121. package/src/changeNickname.js +0 -58
  122. package/src/changeThreadColor.js +0 -62
  123. package/src/changeUsername.js +0 -80
  124. package/src/createCommentPost.js +0 -196
  125. package/src/createNewGroup.js +0 -81
  126. package/src/createPoll.js +0 -64
  127. package/src/createPost.js +0 -285
  128. package/src/data/getThreadInfo.json +0 -1
  129. package/src/deleteMessage.js +0 -55
  130. package/src/deleteThread.js +0 -55
  131. package/src/editMessage.js +0 -66
  132. package/src/follow.js +0 -71
  133. package/src/forwardAttachment.js +0 -57
  134. package/src/getAccess.js +0 -130
  135. package/src/getAvatarUser.js +0 -88
  136. package/src/getBotInitialData.js +0 -59
  137. package/src/getCtx.js +0 -5
  138. package/src/getCurrentUserID.js +0 -5
  139. package/src/getEmojiUrl.js +0 -18
  140. package/src/getFriendsList.js +0 -81
  141. package/src/getMessage.js +0 -827
  142. package/src/getOptions.js +0 -5
  143. package/src/getRegion.js +0 -7
  144. package/src/getThreadHistory.js +0 -496
  145. package/src/getThreadHistoryDeprecated.js +0 -95
  146. package/src/getThreadInfo.js +0 -194
  147. package/src/getThreadInfoDeprecated.js +0 -77
  148. package/src/getThreadList.js +0 -219
  149. package/src/getThreadListDeprecated.js +0 -86
  150. package/src/getThreadPictures.js +0 -85
  151. package/src/getUserID.js +0 -67
  152. package/src/getUserInfo.js +0 -89
  153. package/src/handleFriendRequest.js +0 -56
  154. package/src/handleMessageRequest.js +0 -65
  155. package/src/httpGet.js +0 -53
  156. package/src/httpPost.js +0 -53
  157. package/src/httpPostFormData.js +0 -58
  158. package/src/listenMqtt.js +0 -683
  159. package/src/listenNotification.js +0 -96
  160. package/src/logout.js +0 -77
  161. package/src/markAsDelivered.js +0 -53
  162. package/src/markAsRead.js +0 -74
  163. package/src/markAsReadAll.js +0 -46
  164. package/src/markAsSeen.js +0 -57
  165. package/src/muteThread.js +0 -49
  166. package/src/pinMessage.js +0 -60
  167. package/src/refreshFb_dtsg.js +0 -75
  168. package/src/removeUserFromGroup.js +0 -59
  169. package/src/resolvePhotoUrl.js +0 -47
  170. package/src/searchForThread.js +0 -55
  171. package/src/searchStickers.js +0 -59
  172. package/src/sendMessage.js +0 -444
  173. package/src/sendMessageMqtt.js +0 -326
  174. package/src/sendTypingIndicator.js +0 -54
  175. package/src/setMessageReaction.js +0 -126
  176. package/src/setMessageReactionMqtt.js +0 -74
  177. package/src/setPostReaction.js +0 -103
  178. package/src/setProfileGuard.js +0 -66
  179. package/src/setStoryReaction.js +0 -97
  180. package/src/setTitle.js +0 -100
  181. package/src/shareContact.js +0 -101
  182. package/src/shareLink.js +0 -105
  183. package/src/stopListenMqtt.js +0 -47
  184. package/src/threadColors.js +0 -119
  185. package/src/unfriend.js +0 -58
  186. package/src/unsendMessage.js +0 -51
  187. package/src/uploadAttachment.js +0 -98
  188. package/utils.js +0 -919
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * Quick sanity check — verifies the library loads correctly and
6
+ * prints the anti-suspension configuration. Run with:
7
+ * node examples/verify.js
8
+ */
9
+
10
+ const fca = require('../index.js');
11
+ const { globalAntiSuspension } = require('../src/utils/antiSuspension');
12
+ const { globalRateLimiter } = require('../src/utils/rateLimiter');
13
+
14
+ console.log('nkxfca Library Verification');
15
+ console.log('================================\n');
16
+
17
+ console.log('Library entry point:', typeof fca.login === 'function' ? 'OK' : 'FAIL');
18
+
19
+ const config = globalAntiSuspension.getConfig();
20
+ console.log('\nAnti-Suspension Configuration:');
21
+ console.log(` Message Delay : ${config.messageDelayMs}ms`);
22
+ console.log(` Thread Delay : ${config.threadDelayMs}ms`);
23
+ console.log(` Max Login Tries : ${config.maxLoginAttempts}`);
24
+ console.log(` Login Cooldown : ${config.loginCooldownMs}ms`);
25
+ console.log(` Daily Msg Limit : ${config.dailyStats.maxDailyMessages}`);
26
+ console.log(` Hourly Msg Limit : ${config.hourlyStats.maxPerHour}`);
27
+
28
+ console.log('\nEnabled Features:');
29
+ Object.entries(config.features).forEach(([feature, enabled]) => {
30
+ console.log(` ${enabled ? '[x]' : '[ ]'} ${feature}`);
31
+ });
32
+
33
+ const activityPattern = globalAntiSuspension.getRealisticActivityPattern();
34
+ console.log('\nActivity Pattern:');
35
+ console.log(` Current activity : ${activityPattern.messageFrequency}`);
36
+ console.log(` Next action delay : ${activityPattern.nextActionDelayMs.toFixed(0)}ms`);
37
+ console.log(` Is active hours : ${activityPattern.isActiveHours}`);
38
+
39
+ console.log('\nCircuit Breaker:');
40
+ console.log(` Tripped : ${globalAntiSuspension.isCircuitBreakerTripped()}`);
41
+ console.log(` Signal count : ${globalAntiSuspension.suspensionCircuitBreaker.signalCount}`);
42
+
43
+ const rateLimiterStats = globalRateLimiter.getStats();
44
+ console.log('\nRate Limiter:');
45
+ console.log(` Max concurrent : ${rateLimiterStats.maxConcurrentRequests}`);
46
+ console.log(` Max per minute : ${rateLimiterStats.maxRequestsPerMinute}`);
47
+ console.log(` Requests (1 min) : ${rateLimiterStats.requestsInLastMinute}`);
48
+
49
+ // Test suspension signal detection
50
+ const testSignals = [
51
+ { text: 'Everything is fine, message sent', expectSuspicion: false },
52
+ { text: 'Your account has been suspended due to policy violation', expectSuspicion: true },
53
+ { text: 'checkpoint required to verify identity', expectSuspicion: true },
54
+ { text: 'Too many requests - rate limited', expectSuspicion: true },
55
+ { text: 'Unusual activity detected on your account', expectSuspicion: true },
56
+ ];
57
+ console.log('\nSuspension Signal Detection:');
58
+ testSignals.forEach(({ text, expectSuspicion }) => {
59
+ globalAntiSuspension.resetCircuitBreaker();
60
+ const detected = globalAntiSuspension.detectSuspensionSignal(text);
61
+ const passed = detected === expectSuspicion;
62
+ globalAntiSuspension.resetCircuitBreaker();
63
+ console.log(` ${passed ? '[x]' : '[!]'} "${text.substring(0, 40)}" → ${detected ? 'SUSPICIOUS' : 'CLEAN'}`);
64
+ });
65
+ globalAntiSuspension.resetCircuitBreaker();
66
+
67
+ console.log('\nAll checks passed. Library is ready to use.');
68
+ console.log('============================\n');
69
+
70
+ process.exit(0);
package/index.js CHANGED
@@ -1,467 +1,2 @@
1
1
  "use strict";
2
-
3
- const utils = require("./utils");
4
- const cheerio = require("cheerio");
5
- const log = require("npmlog");
6
-
7
- log.maxRecordSize = 100;
8
- const Boolean_Option = ['online', 'selfListen', 'listenEvents', 'updatePresence', 'forceLogin', 'autoMarkDelivery', 'autoMarkRead', 'listenTyping', 'autoReconnect', 'emitReady'];
9
- global.ditconmemay = false;
10
-
11
- function setOptions(globalOptions, options) {
12
- Object.keys(options).forEach(function (key) {
13
- switch (Boolean_Option.includes(key)) {
14
- case true: {
15
- globalOptions[key] = Boolean(options[key]);
16
- break;
17
- }
18
- case false: {
19
- switch (key) {
20
- case 'pauseLog': {
21
- if (options.pauseLog) log.pause();
22
- else log.resume();
23
- break;
24
- }
25
- case 'logLevel': {
26
- log.level = options.logLevel;
27
- globalOptions.logLevel = options.logLevel;
28
- break;
29
- }
30
- case 'logRecordSize': {
31
- log.maxRecordSize = options.logRecordSize;
32
- globalOptions.logRecordSize = options.logRecordSize;
33
- break;
34
- }
35
- case 'pageID': {
36
- globalOptions.pageID = options.pageID.toString();
37
- break;
38
- }
39
- case 'userAgent': {
40
- globalOptions.userAgent = (options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36');
41
- break;
42
- }
43
- case 'proxy': {
44
- if (typeof options.proxy !== "string") {
45
- delete globalOptions.proxy;
46
- utils.setProxy();
47
- } else {
48
- globalOptions.proxy = options.proxy;
49
- utils.setProxy(globalOptions.proxy);
50
- }
51
- break;
52
- }
53
- default: {
54
- log.warn("setOptions", "Unrecognized option given to setOptions: " + key);
55
- break;
56
- }
57
- }
58
- break;
59
- }
60
- }
61
- });
62
- }
63
-
64
- function buildAPI(globalOptions, html, jar) {
65
- let fb_dtsg = null;
66
- let irisSeqID = null;
67
-
68
- function extractFromHTML() {
69
- try {
70
- const $ = cheerio.load(html);
71
- const patterns = [
72
- /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
73
- /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
74
- /"token":"([^"]+)"/,
75
- /{\\"token\\":\\"([^\\]+)\\"/,
76
- /,\{"token":"([^"]+)"\},\d+\]/,
77
- /"async_get_token":"([^"]+)"/,
78
- /"dtsg":\{"token":"([^"]+)"/,
79
- /DTSGInitialData[^>]+>([^<]+)/
80
- ];
81
-
82
- const scripts = $('script').get();
83
- for (const script of scripts) {
84
- const scriptText = $(script).html() || '';
85
- for (const pattern of patterns) {
86
- const match = scriptText.match(pattern);
87
- if (match && match[1]) {
88
- fb_dtsg = match[1].includes('\\"') ? match[1].replace(/\\"/g, '"') : match[1];
89
- if (fb_dtsg.startsWith('{')) {
90
- try { fb_dtsg = JSON.parse(fb_dtsg).token || fb_dtsg; } catch(e){}
91
- }
92
- break;
93
- }
94
- }
95
- if (fb_dtsg) break;
96
- }
97
-
98
- if (!fb_dtsg) {
99
- const dtsgInput = $('input[name="fb_dtsg"]').val();
100
- if (dtsgInput) fb_dtsg = dtsgInput;
101
- }
102
-
103
- const seqMatches = html.match(/irisSeqID":"([^"]+)"/);
104
- if (seqMatches && seqMatches[1]) {
105
- irisSeqID = seqMatches[1];
106
- }
107
-
108
- if (!fb_dtsg) {
109
- const jsonMatches = html.match(/\{"dtsg":({[^}]+})/);
110
- if (jsonMatches && jsonMatches[1]) {
111
- try {
112
- const dtsgData = JSON.parse(jsonMatches[1]);
113
- if (dtsgData.token) fb_dtsg = dtsgData.token;
114
- } catch(e){}
115
- }
116
- }
117
-
118
- if (fb_dtsg) {
119
- console.log("Đã tìm thấy fb_dtsg");
120
- }
121
- } catch (e) {
122
- console.log("Lỗi khi tìm fb_dtsg:", e);
123
- }
124
- }
125
-
126
- extractFromHTML();
127
- let userID;
128
- const cookies = jar.getCookies("https://www.facebook.com");
129
- const userCookie = cookies.find(cookie => cookie.cookieString().startsWith("c_user="));
130
- const tiktikCookie = cookies.find(cookie => cookie.cookieString().startsWith("i_user="));
131
-
132
- if (!userCookie && !tiktikCookie) {
133
- return log.error('login', "Không tìm thấy cookie cho người dùng, vui lòng kiểm tra lại thông tin đăng nhập");
134
- }
135
- if (html.includes("/checkpoint/block/?next")) {
136
- return log.error('login', "Appstate die, vui lòng thay cái mới!", 'error');
137
- }
138
-
139
- userID = (tiktikCookie || userCookie).cookieString().split("=")[1];
140
- const clientID = (Math.random() * 2147483648 | 0).toString(16);
141
- let mqttEndpoint = `wss://edge-chat.facebook.com/chat?region=prn&sid=${userID}`;
142
- let region = "PRN";
143
-
144
- try {
145
- if (html.includes("601051028565049")) {
146
- console.log(`lỗi login vì dính tài khoản tự động`);
147
- global.ditconmemay = true;
148
- }
149
- const endpointMatch = html.match(/"endpoint":"([^"]+)"/);
150
- if (endpointMatch && endpointMatch[1]) {
151
- mqttEndpoint = endpointMatch[1].replace(/\\\//g, '/');
152
- const url = new URL(mqttEndpoint);
153
- region = url.searchParams.get('region')?.toUpperCase() || "PRN";
154
- }
155
- } catch (e) {
156
- console.log('Using default MQTT endpoint');
157
- }
158
-
159
- log.info('login', 'Fix fca by DongDev x Satoru, published By Team Calyx');
160
-
161
- const ctx = {
162
- userID: userID,
163
- jar: jar,
164
- clientID: clientID,
165
- globalOptions: globalOptions,
166
- loggedIn: true,
167
- access_token: 'NONE',
168
- clientMutationId: 0,
169
- mqttClient: undefined,
170
- lastSeqId: irisSeqID,
171
- syncToken: undefined,
172
- mqttEndpoint: mqttEndpoint,
173
- region: region,
174
- firstListen: true,
175
- fb_dtsg: fb_dtsg,
176
- req_ID: 0,
177
- callback_Task: {},
178
- wsReqNumber: 0,
179
- wsTaskNumber: 0,
180
- reqCallbacks: {}
181
- };
182
-
183
- const defaultFuncs = utils.makeDefaults(html, userID, ctx);
184
- const api = {
185
- setOptions: setOptions.bind(null, globalOptions),
186
- getAppState: () => utils.getAppState(jar),
187
- postFormData: function (url, body) {
188
- return defaultFuncs.postFormData(url, ctx.jar, body);
189
- }
190
- };
191
-
192
- api.getFreshDtsg = async function () {
193
- try {
194
- const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
195
- const $ = cheerio.load(res.body);
196
- let newDtsg;
197
- const patterns = [
198
- /\["DTSGInitialData",\[\],{"token":"([^"]+)"}]/,
199
- /\["DTSGInitData",\[\],{"token":"([^"]+)"/,
200
- /"token":"([^"]+)"/,
201
- /name="fb_dtsg" value="([^"]+)"/
202
- ];
203
-
204
- const scripts = $('script').get();
205
- for (const script of scripts) {
206
- const scriptText = $(script).html() || '';
207
- for (const pattern of patterns) {
208
- const match = scriptText.match(pattern);
209
- if (match && match[1]) {
210
- newDtsg = match[1];
211
- break;
212
- }
213
- }
214
- if (newDtsg) break;
215
- }
216
-
217
- if (!newDtsg) {
218
- newDtsg = $('input[name="fb_dtsg"]').val();
219
- }
220
-
221
- return newDtsg;
222
- } catch (e) {
223
- console.log("Error getting fresh dtsg:", e);
224
- return null;
225
- }
226
- };
227
-
228
- require('fs').readdirSync(__dirname + '/src/')
229
- .filter(v => v.endsWith('.js'))
230
- .forEach(v => {
231
- api[v.replace('.js', '')] = require(`./src/${v}`)(defaultFuncs, api, ctx);
232
- });
233
-
234
- api.listen = api.listenMqtt;
235
- return { ctx, defaultFuncs, api };
236
- }
237
-
238
- function makeLogin(jar, email, password, loginOptions, callback, prCallback) {
239
- return async function (res) {
240
- try {
241
- const html = res.body;
242
- const $ = cheerio.load(html);
243
- let arr = [];
244
- $("#login_form input").each((i, v) => arr.push({ val: $(v).val(), name: $(v).attr("name") }));
245
- arr = arr.filter(v => v.val && v.val.length);
246
- const form = utils.arrToForm(arr);
247
- form.lsd = utils.getFrom(html, "[\"LSD\",[],{\"token\":\"", "\"}");
248
- form.lgndim = Buffer.from(JSON.stringify({ w: 1440, h: 900, aw: 1440, ah: 834, c: 24 })).toString('base64');
249
- form.email = email;
250
- form.pass = password;
251
- form.default_persistent = '0';
252
- form.lgnrnd = utils.getFrom(html, "name=\"lgnrnd\" value=\"", "\"");
253
- form.locale = 'en_US';
254
- form.timezone = '240';
255
- form.lgnjs = Math.floor(Date.now() / 1000);
256
-
257
- const willBeCookies = html.split("\"_js_");
258
- willBeCookies.slice(1).forEach(val => {
259
- try {
260
- const cookieData = JSON.parse("[\"" + utils.getFrom(val, "", "]") + "]");
261
- jar.setCookie(utils.formatCookie(cookieData, "facebook"), "https://www.facebook.com");
262
- } catch(e){}
263
- });
264
-
265
- log.info("login", "Logging in...");
266
- const loginRes = await utils.post(
267
- "https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&lwv=110",
268
- jar,
269
- form,
270
- loginOptions
271
- );
272
- await utils.saveCookies(jar)(loginRes);
273
- const headers = loginRes.headers;
274
- if (!headers.location) throw new Error("Wrong username/password.");
275
-
276
- if (headers.location.includes('https://www.facebook.com/checkpoint/')) {
277
- log.info("login", "You have login approvals turned on.");
278
- const checkpointRes = await utils.get(headers.location, jar, null, loginOptions);
279
- await utils.saveCookies(jar)(checkpointRes);
280
- const checkpointHtml = checkpointRes.body;
281
- const $c = cheerio.load(checkpointHtml);
282
- let checkpointForm = [];
283
- $c("form input").each((i, v) => checkpointForm.push({ val: $c(v).val(), name: $c(v).attr("name") }));
284
- checkpointForm = checkpointForm.filter(v => v.val && v.val.length);
285
- const form2fa = utils.arrToForm(checkpointForm);
286
-
287
- if (checkpointHtml.includes("checkpoint/?next")) {
288
- return new Promise((resolve, reject) => {
289
- const submit2FA = async (code) => {
290
- try {
291
- form2fa.approvals_code = code;
292
- form2fa['submit[Continue]'] = $c("#checkpointSubmitButton").html();
293
- const approvalRes = await utils.post(
294
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
295
- jar,
296
- form2fa,
297
- loginOptions
298
- );
299
- await utils.saveCookies(jar)(approvalRes);
300
- const $a = cheerio.load(approvalRes.body);
301
- const approvalError = $a("#approvals_code").parent().attr("data-xui-error");
302
- if (approvalError) throw new Error("Invalid 2FA code.");
303
-
304
- form2fa.name_action_selected = 'dont_save';
305
- const finalRes = await utils.post(
306
- "https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php",
307
- jar,
308
- form2fa,
309
- loginOptions
310
- );
311
- await utils.saveCookies(jar)(finalRes);
312
- const appState = utils.getAppState(jar);
313
- resolve(await loginHelper(appState, email, password, loginOptions, callback, prCallback));
314
- } catch (error) {
315
- reject(error);
316
- }
317
- };
318
- throw {
319
- error: 'login-approval',
320
- continue: submit2FA
321
- };
322
- });
323
- }
324
- if (!loginOptions.forceLogin) throw new Error("Couldn't login. Facebook might have blocked this account.");
325
- form2fa['submit[This was me]'] = checkpointHtml.includes("Suspicious Login Attempt") ? "This was me" : "This Is Okay";
326
- await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form2fa, loginOptions);
327
- form2fa.name_action_selected = 'save_device';
328
- await utils.post("https://www.facebook.com/checkpoint/?next=https%3A%2F%2Fwww.facebook.com%2Fhome.php", jar, form2fa, loginOptions);
329
- const appState = utils.getAppState(jar);
330
- return await loginHelper(appState, email, password, loginOptions, callback, prCallback);
331
- }
332
- await utils.get('https://www.facebook.com/', jar, null, loginOptions);
333
- return await utils.saveCookies(jar)(loginRes);
334
- } catch (error) {
335
- callback(error);
336
- }
337
- };
338
- }
339
-
340
- function loginHelper(appState, email, password, globalOptions, callback, prCallback) {
341
- let mainPromise = null;
342
- const jar = utils.getJar();
343
- if (appState) {
344
- try {
345
- if (typeof appState === 'string') {
346
- appState = JSON.parse(appState);
347
- }
348
- } catch (e) {
349
- return callback(new Error("Failed to parse appState"));
350
- }
351
-
352
- try {
353
- appState.forEach(c => {
354
- const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
355
- jar.setCookie(str, "https://" + c.domain);
356
- });
357
- mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
358
- .then(utils.saveCookies(jar));
359
- } catch (e) {
360
- return callback(new Error("Failed to load appState cookies: " + e.message));
361
- }
362
- } else {
363
- mainPromise = utils
364
- .get("https://www.facebook.com/", null, null, globalOptions, { noRef: true })
365
- .then(utils.saveCookies(jar))
366
- .then(makeLogin(jar, email, password, globalOptions, callback, prCallback))
367
- .then(() => utils.get('https://www.facebook.com/', jar, null, globalOptions).then(utils.saveCookies(jar)));
368
- }
369
-
370
- function handleRedirect(res) {
371
- const reg = /<meta http-equiv="refresh" content="0;url=([^"]+)[^>]+>/;
372
- const redirect = reg.exec(res.body);
373
- if (redirect && redirect[1]) {
374
- return utils.get(redirect[1], jar, null, globalOptions).then(utils.saveCookies(jar));
375
- }
376
- return res;
377
- }
378
-
379
- mainPromise = mainPromise
380
- .then(handleRedirect)
381
- .then(res => {
382
- if (!/MPageLoadClientMetrics/gs.test(res.body)) {
383
- globalOptions.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36";
384
- return utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true }).then(utils.saveCookies(jar));
385
- }
386
- return res;
387
- })
388
- .then(handleRedirect)
389
- .then(res => {
390
- const Obj = buildAPI(globalOptions, res.body, jar);
391
- return Obj ? Obj.api : null;
392
- });
393
-
394
- if (globalOptions.pageID) {
395
- mainPromise = mainPromise
396
- .then((api) => utils.get(`https://www.facebook.com/${globalOptions.pageID}/messages/?section=messages&subsection=inbox`, jar, null, globalOptions).then(resData => ({api, resData})))
397
- .then(({api, resData}) => {
398
- let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
399
- url = url.substring(0, url.length - 1);
400
- return utils.get('https://www.facebook.com' + url, jar, null, globalOptions).then(() => api);
401
- });
402
- }
403
-
404
- mainPromise
405
- .then((api) => {
406
- if(api) {
407
- log.info('login', 'Đăng nhập thành công');
408
- callback(null, api);
409
- }
410
- })
411
- .catch(e => {
412
- callback(e);
413
- });
414
- }
415
-
416
- function login(loginData, options, callback) {
417
- if (utils.getType(options) === 'Function' || utils.getType(options) === 'AsyncFunction') {
418
- callback = options;
419
- options = {};
420
- }
421
-
422
- const globalOptions = {
423
- selfListen: false,
424
- listenEvents: true,
425
- listenTyping: false,
426
- updatePresence: false,
427
- forceLogin: false,
428
- autoMarkDelivery: false,
429
- autoMarkRead: false,
430
- autoReconnect: true,
431
- logRecordSize: 100,
432
- online: false,
433
- emitReady: false,
434
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
435
- };
436
-
437
- let prCallback = null;
438
- if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
439
- let rejectFunc = null;
440
- let resolveFunc = null;
441
- const returnPromise = new Promise(function (resolve, reject) {
442
- resolveFunc = resolve;
443
- rejectFunc = reject;
444
- });
445
- prCallback = function (error, api) {
446
- if (error) return rejectFunc(error);
447
- return resolveFunc(api);
448
- };
449
- callback = prCallback;
450
- }
451
-
452
- if (loginData.email && loginData.password) {
453
- setOptions(globalOptions, {
454
- logLevel: "silent",
455
- forceLogin: true,
456
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
457
- });
458
- loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
459
- } else if (loginData.appState) {
460
- setOptions(globalOptions, options);
461
- loginHelper(loginData.appState, loginData.email, loginData.password, globalOptions, callback, prCallback);
462
- }
463
-
464
- return prCallback ? returnPromise : null;
465
- }
466
-
467
- module.exports = login;
2
+ module.exports = require('./src/engine/client');
package/package.json CHANGED
@@ -1,12 +1,104 @@
1
1
  {
2
2
  "name": "@cexy/hoonfca",
3
- "version": "1.0.0",
4
- "description": "@cexy/hoonfca",
3
+ "version": "1.0.1",
4
+ "type": "commonjs",
5
+ "types": "src/types/index.d.ts",
6
+ "description": "Hinata FCA - Advanced Facebook Chat API",
5
7
  "main": "index.js",
8
+ "files": [
9
+ "index.js",
10
+ "src/",
11
+ "examples/",
12
+ "LICENSE",
13
+ "README.md"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/c9352220sketch/h.git"
18
+ },
19
+ "author": "c9352220sketch",
20
+ "contributors": [
21
+ "NeoKEX Team"
22
+ ],
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/c9352220sketch/hinata-fca/issues"
26
+ },
27
+ "homepage": "https://github.com/c9352220sketch/hinata-fca#readme",
28
+ "keywords": [
29
+ "facebook",
30
+ "messenger",
31
+ "chat",
32
+ "bot",
33
+ "fca",
34
+ "mqtt",
35
+ "messaging",
36
+ "api",
37
+ "automation",
38
+ "facebook-chat-api",
39
+ "nkxfca",
40
+ "neoaz07",
41
+ "anti-suspension",
42
+ "e2ee"
43
+ ],
44
+ "dependencies": {
45
+ "axios": "^1.9.0",
46
+ "axios-cookiejar-support": "^4.0.7",
47
+ "bluebird": "^3.7.2",
48
+ "cheerio": "^1.0.0",
49
+ "deepdash": "^5.3.9",
50
+ "duplexify": "^4.1.3",
51
+ "form-data": "^4.0.4",
52
+ "https-proxy-agent": "^7.0.6",
53
+ "jsonpath-plus": "^10.3.0",
54
+ "lodash": "^4.17.21",
55
+ "mqtt": "^4.3.8",
56
+ "node-cron": "^3.0.3",
57
+ "npmlog": "^7.0.1",
58
+ "totp-generator": "^2.0.1",
59
+ "tough-cookie": "^5.1.2",
60
+ "undici": "^7.8.0",
61
+ "uuid": "^11.1.0",
62
+ "ws": "^8.18.2"
63
+ },
64
+ "devDependencies": {
65
+ "@types/node": "^22.15.17",
66
+ "eslint": "^9.26.0",
67
+ "mocha": "^11.3.0",
68
+ "prettier": "^3.5.3",
69
+ "ts-node": "^10.9.2",
70
+ "typescript": "^5.8.3"
71
+ },
72
+ "engines": {
73
+ "node": ">=22.0.0"
74
+ },
6
75
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
76
+ "validate": "npm pack --dry-run",
77
+ "prepack": "echo 'Preparing package for npm...'",
78
+ "test": "echo 'No tests configured yet'",
79
+ "lint": "eslint src/",
80
+ "format": "prettier --write src/**/*.js"
8
81
  },
9
- "keywords": [],
10
- "author": "",
11
- "license": "ISC"
82
+ "overrides": {
83
+ "undici": "^7.8.0",
84
+ "ws": "^8.18.2",
85
+ "tough-cookie": "^5.1.2",
86
+ "glob": "^11.0.2",
87
+ "prebuild-install": "^7.1.3",
88
+ "npmlog": "^7.0.1",
89
+ "are-we-there-yet": "^4.0.2",
90
+ "gauge": "^5.0.2",
91
+ "serialize-javascript": "^6.0.2",
92
+ "cacache": "^18.0.4",
93
+ "make-fetch-happen": "^13.0.3",
94
+ "@tootallnate/once": "^3.0.1",
95
+ "mocha": {
96
+ "serialize-javascript": "^6.0.2",
97
+ "debug": "^4.4.0",
98
+ "diff": "^7.0.0",
99
+ "js-yaml": "^4.1.0",
100
+ "minimatch": "^10.0.1",
101
+ "glob": "^11.0.2"
102
+ }
103
+ }
12
104
  }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ const utils = require('../utils');
3
+
4
+ module.exports = function (defaultFuncs, api, ctx) {
5
+ return function addExternalModule(moduleObj) {
6
+ if (utils.getType(moduleObj) == "Object") {
7
+ for (const apiName in moduleObj) {
8
+ if (utils.getType(moduleObj[apiName]) == "Function") {
9
+ api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx);
10
+ } else {
11
+ throw new Error(
12
+ `Item "${apiName}" in moduleObj must be a function, not ${utils.getType(
13
+ moduleObj[apiName],
14
+ )}!`,
15
+ );
16
+ }
17
+ }
18
+ } else {
19
+ throw new Error(
20
+ `moduleObj must be an object, not ${utils.getType(moduleObj)}!`,
21
+ );
22
+ }
23
+ };
24
+ };