@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,275 @@
1
+ "use strict";
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ let koffi;
7
+ let lib;
8
+ let fns;
9
+ let initialized = false;
10
+
11
+ function libPath() {
12
+ const base = path.join(__dirname, '../../build');
13
+ if (process.platform === 'win32') return path.join(base, 'messagix.dll');
14
+ if (process.platform === 'darwin') return path.join(base, 'messagix.dylib');
15
+ return path.join(base, 'messagix.so');
16
+ }
17
+
18
+ const LIB_PATH = libPath();
19
+
20
+ function init() {
21
+ if (initialized) return;
22
+ if (!fs.existsSync(LIB_PATH)) {
23
+ throw new Error(
24
+ `E2EE bridge library not found at ${LIB_PATH}.\n` +
25
+ `Build it with: npm run build:go\n` +
26
+ `Or set MESSAGIX_BUILD_FROM_SOURCE=true and reinstall.`
27
+ );
28
+ }
29
+ koffi = require('koffi');
30
+ lib = koffi.load(LIB_PATH);
31
+ const mk = (ret, name, args) => lib.func(name, ret, args);
32
+ fns = {
33
+ MxFreeCString: mk('void', 'MxFreeCString', ['char*']),
34
+ MxNewClient: mk('str', 'MxNewClient', ['str']),
35
+ MxConnect: mk('str', 'MxConnect', ['str']),
36
+ MxConnectE2EE: mk('str', 'MxConnectE2EE', ['str']),
37
+ MxDisconnect: mk('str', 'MxDisconnect', ['str']),
38
+ MxIsConnected: mk('str', 'MxIsConnected', ['str']),
39
+ MxSendMessage: mk('str', 'MxSendMessage', ['str']),
40
+ MxSendReaction: mk('str', 'MxSendReaction', ['str']),
41
+ MxEditMessage: mk('str', 'MxEditMessage', ['str']),
42
+ MxUnsendMessage: mk('str', 'MxUnsendMessage', ['str']),
43
+ MxSendTyping: mk('str', 'MxSendTyping', ['str']),
44
+ MxMarkRead: mk('str', 'MxMarkRead', ['str']),
45
+ MxPollEvents: mk('str', 'MxPollEvents', ['str']),
46
+ MxGetDeviceData: mk('str', 'MxGetDeviceData', ['str']),
47
+ MxSendE2EEMessage: mk('str', 'MxSendE2EEMessage', ['str']),
48
+ MxSendE2EEReaction: mk('str', 'MxSendE2EEReaction', ['str']),
49
+ MxSendE2EETyping: mk('str', 'MxSendE2EETyping', ['str']),
50
+ MxEditE2EEMessage: mk('str', 'MxEditE2EEMessage', ['str']),
51
+ MxUnsendE2EEMessage: mk('str', 'MxUnsendE2EEMessage', ['str']),
52
+ MxSendE2EEImage: mk('str', 'MxSendE2EEImage', ['str']),
53
+ MxSendE2EEVideo: mk('str', 'MxSendE2EEVideo', ['str']),
54
+ MxSendE2EEAudio: mk('str', 'MxSendE2EEAudio', ['str']),
55
+ MxSendE2EEDocument: mk('str', 'MxSendE2EEDocument', ['str']),
56
+ MxSendE2EESticker: mk('str', 'MxSendE2EESticker', ['str']),
57
+ MxDownloadE2EEMedia: mk('str', 'MxDownloadE2EEMedia', ['str']),
58
+ MxGetCookies: mk('str', 'MxGetCookies', ['str']),
59
+ MxUploadMedia: mk('str', 'MxUploadMedia', ['str']),
60
+ MxSendImage: mk('str', 'MxSendImage', ['str']),
61
+ MxSendVideo: mk('str', 'MxSendVideo', ['str']),
62
+ MxSendVoice: mk('str', 'MxSendVoice', ['str']),
63
+ MxSendFile: mk('str', 'MxSendFile', ['str']),
64
+ MxSendSticker: mk('str', 'MxSendSticker', ['str']),
65
+ MxGetUserInfo: mk('str', 'MxGetUserInfo', ['str']),
66
+ MxCreateThread: mk('str', 'MxCreateThread', ['str']),
67
+ MxSearchUsers: mk('str', 'MxSearchUsers', ['str']),
68
+ MxRenameThread: mk('str', 'MxRenameThread', ['str']),
69
+ MxMuteThread: mk('str', 'MxMuteThread', ['str']),
70
+ MxDeleteThread: mk('str', 'MxDeleteThread', ['str']),
71
+ MxSetGroupPhoto: mk('str', 'MxSetGroupPhoto', ['str']),
72
+ MxRegisterPushNotifications: mk('str', 'MxRegisterPushNotifications', ['str']),
73
+ };
74
+ initialized = true;
75
+ }
76
+
77
+ function serialize(obj) {
78
+ return JSON.stringify(obj, (_, v) =>
79
+ typeof v === 'bigint' ? Number(v) : v
80
+ );
81
+ }
82
+
83
+ function deserialize(str) {
84
+ return JSON.parse(str);
85
+ }
86
+
87
+ function call(fn, payload) {
88
+ init();
89
+ const input = serialize(payload);
90
+ const out = fns[fn](input);
91
+ const data = deserialize(out);
92
+ if (!data.ok) throw new Error(data.error || 'Unknown E2EE bridge error');
93
+ return data.data;
94
+ }
95
+
96
+ function callAsync(fn, payload) {
97
+ return new Promise((resolve, reject) => {
98
+ setImmediate(() => {
99
+ try { resolve(call(fn, payload)); }
100
+ catch (err) { reject(err); }
101
+ });
102
+ });
103
+ }
104
+
105
+ module.exports = {
106
+ isAvailable() {
107
+ try { init(); return true; } catch (_) { return false; }
108
+ },
109
+
110
+ newClient(cfg) {
111
+ return call('MxNewClient', cfg);
112
+ },
113
+
114
+ connect(handle) {
115
+ return callAsync('MxConnect', { handle });
116
+ },
117
+
118
+ connectE2EE(handle) {
119
+ return callAsync('MxConnectE2EE', { handle });
120
+ },
121
+
122
+ disconnect(handle) {
123
+ try { return call('MxDisconnect', { handle }); } catch (_) {}
124
+ },
125
+
126
+ isConnected(handle) {
127
+ try { return call('MxIsConnected', { handle }); }
128
+ catch (_) { return { connected: false, e2eeConnected: false }; }
129
+ },
130
+
131
+ getDeviceData(handle) {
132
+ return call('MxGetDeviceData', { handle });
133
+ },
134
+
135
+ pollEvents(handle, timeoutMs) {
136
+ return callAsync('MxPollEvents', { handle, timeoutMs: timeoutMs || 5000 });
137
+ },
138
+
139
+ sendMessage(handle, options) {
140
+ return callAsync('MxSendMessage', { handle, options });
141
+ },
142
+
143
+ sendReaction(handle, threadId, messageId, emoji) {
144
+ return callAsync('MxSendReaction', { handle, threadId, messageId, emoji });
145
+ },
146
+
147
+ editMessage(handle, messageId, newText) {
148
+ return callAsync('MxEditMessage', { handle, messageId, newText });
149
+ },
150
+
151
+ unsendMessage(handle, messageId) {
152
+ return callAsync('MxUnsendMessage', { handle, messageId });
153
+ },
154
+
155
+ sendTyping(handle, threadId, isTyping, isGroup, threadType) {
156
+ return callAsync('MxSendTyping', { handle, threadId, isTyping, isGroup, threadType });
157
+ },
158
+
159
+ markRead(handle, threadId, watermarkTs) {
160
+ return callAsync('MxMarkRead', { handle, threadId, watermarkTs: watermarkTs || 0 });
161
+ },
162
+
163
+ sendE2EEMessage(handle, chatJid, text, replyToId, replyToSenderJid) {
164
+ return callAsync('MxSendE2EEMessage', { handle, chatJid, text, replyToId, replyToSenderJid });
165
+ },
166
+
167
+ sendE2EEReaction(handle, chatJid, messageId, senderJid, emoji) {
168
+ return callAsync('MxSendE2EEReaction', { handle, chatJid, messageId, senderJid, emoji });
169
+ },
170
+
171
+ sendE2EETyping(handle, chatJid, isTyping) {
172
+ return callAsync('MxSendE2EETyping', { handle, chatJid, isTyping: !!isTyping });
173
+ },
174
+
175
+ editE2EEMessage(handle, chatJid, messageId, newText) {
176
+ return callAsync('MxEditE2EEMessage', { handle, chatJid, messageId, newText });
177
+ },
178
+
179
+ unsendE2EEMessage(handle, chatJid, messageId) {
180
+ return callAsync('MxUnsendE2EEMessage', { handle, chatJid, messageId });
181
+ },
182
+
183
+ sendE2EEImage(handle, options) {
184
+ return callAsync('MxSendE2EEImage', { handle, options });
185
+ },
186
+
187
+ sendE2EEVideo(handle, options) {
188
+ return callAsync('MxSendE2EEVideo', { handle, options });
189
+ },
190
+
191
+ sendE2EEAudio(handle, options) {
192
+ return callAsync('MxSendE2EEAudio', { handle, options });
193
+ },
194
+
195
+ sendE2EEDocument(handle, options) {
196
+ return callAsync('MxSendE2EEDocument', { handle, options });
197
+ },
198
+
199
+ sendE2EESticker(handle, options) {
200
+ return callAsync('MxSendE2EESticker', { handle, options });
201
+ },
202
+
203
+ downloadE2EEMedia(handle, options) {
204
+ return callAsync('MxDownloadE2EEMedia', { handle, options });
205
+ },
206
+
207
+ getCookies(handle) {
208
+ return call('MxGetCookies', { handle });
209
+ },
210
+
211
+ uploadMedia(handle, options) {
212
+ return callAsync('MxUploadMedia', { handle, options });
213
+ },
214
+
215
+ sendImage(handle, options) {
216
+ return callAsync('MxSendImage', { handle, options });
217
+ },
218
+
219
+ sendVideo(handle, options) {
220
+ return callAsync('MxSendVideo', { handle, options });
221
+ },
222
+
223
+ sendVoice(handle, options) {
224
+ return callAsync('MxSendVoice', { handle, options });
225
+ },
226
+
227
+ sendFile(handle, options) {
228
+ return callAsync('MxSendFile', { handle, options });
229
+ },
230
+
231
+ sendSticker(handle, options) {
232
+ return callAsync('MxSendSticker', { handle, options });
233
+ },
234
+
235
+ getUserInfo(handle, userId) {
236
+ return callAsync('MxGetUserInfo', { handle, options: { userId } });
237
+ },
238
+
239
+ createThread(handle, userId) {
240
+ return callAsync('MxCreateThread', { handle, options: { userId } });
241
+ },
242
+
243
+ searchUsers(handle, query) {
244
+ return callAsync('MxSearchUsers', { handle, options: { query } });
245
+ },
246
+
247
+ renameThread(handle, threadId, newName) {
248
+ return callAsync('MxRenameThread', { handle, options: { threadId, newName } });
249
+ },
250
+
251
+ muteThread(handle, threadId, muteSeconds) {
252
+ return callAsync('MxMuteThread', { handle, options: { threadId, muteSeconds } });
253
+ },
254
+
255
+ deleteThread(handle, threadId) {
256
+ return callAsync('MxDeleteThread', { handle, options: { threadId } });
257
+ },
258
+
259
+ setGroupPhoto(handle, threadId, data, mimeType) {
260
+ return callAsync('MxSetGroupPhoto', { handle, threadId, data, mimeType });
261
+ },
262
+
263
+ registerPushNotifications(handle, options) {
264
+ return callAsync('MxRegisterPushNotifications', { handle, options });
265
+ },
266
+
267
+ unload() {
268
+ if (lib) {
269
+ try { lib.unload(); } catch (_) {}
270
+ lib = null;
271
+ fns = null;
272
+ initialized = false;
273
+ }
274
+ }
275
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const bridge = require('./bridge');
6
+
7
+ const DEFAULT_DEVICE_PATH = path.join(process.cwd(), '.nkxfca_e2ee_device.json');
8
+
9
+ function extractCookies(jar) {
10
+ const cookies = {};
11
+ try {
12
+ const list = jar.getCookiesSync('https://www.facebook.com');
13
+ for (const c of list) cookies[c.key] = c.value;
14
+ const msgnList = jar.getCookiesSync('https://www.messenger.com');
15
+ for (const c of msgnList) {
16
+ if (!cookies[c.key]) cookies[c.key] = c.value;
17
+ }
18
+ } catch (_) {}
19
+ return cookies;
20
+ }
21
+
22
+ function detectPlatform(cookies) {
23
+ if (cookies.c_user || cookies.xs) return 'facebook';
24
+ return 'facebook';
25
+ }
26
+
27
+ function loadSavedDeviceData(devicePath) {
28
+ try {
29
+ if (fs.existsSync(devicePath)) {
30
+ return fs.readFileSync(devicePath, 'utf8');
31
+ }
32
+ } catch (_) {}
33
+ return null;
34
+ }
35
+
36
+ async function getOrCreateHandle(ctx, options) {
37
+ if (ctx._e2eeBridgeHandle != null) return ctx._e2eeBridgeHandle;
38
+
39
+ const cookies = extractCookies(ctx.jar);
40
+ const devicePath = (options && options.devicePath) || ctx._e2eeDevicePath || DEFAULT_DEVICE_PATH;
41
+
42
+ const cfg = {
43
+ cookies,
44
+ platform: detectPlatform(cookies),
45
+ logLevel: 'warn',
46
+ devicePath,
47
+ ...(options || {}),
48
+ };
49
+
50
+ if (cfg.deviceData === undefined && ctx._e2eeDeviceData) {
51
+ cfg.deviceData = ctx._e2eeDeviceData;
52
+ }
53
+
54
+ const { handle } = bridge.newClient(cfg);
55
+ ctx._e2eeBridgeHandle = handle;
56
+ ctx._e2eeDevicePath = devicePath;
57
+ return handle;
58
+ }
59
+
60
+ module.exports = { bridge, extractCookies, getOrCreateHandle, DEFAULT_DEVICE_PATH };
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+ const setOptionsModel = require('./models/setOptions');
5
+ const buildAPIModel = require('./models/buildAPI');
6
+ const loginHelperModel = require('./models/loginHelper');
7
+
8
+ let globalOptions = {};
9
+ let ctx = null;
10
+ let defaultFuncs = null;
11
+ let api = null;
12
+
13
+ const fbLink = (ext) => ("https://www.facebook.com" + (ext ? '/' + ext : ''));
14
+ const ERROR_RETRIEVING = "Error retrieving userID. This can be caused by many factors, including being blocked by Facebook for logging in from an unknown location. Try logging in with a browser to verify.";
15
+
16
+ /**
17
+ * Initiates the login process for a Facebook account.
18
+ *
19
+ * @param {object} credentials The user's login credentials (e.g., email/password or appState cookies).
20
+ * @param {object} [options={}] Optional login configurations.
21
+ * @param {function} [callback] Optional callback function. If omitted, returns a Promise.
22
+ * @returns {Promise|void} Returns Promise if no callback provided, otherwise void.
23
+ */
24
+ async function login(credentials, options, callback) {
25
+ if (typeof options === "function") {
26
+ callback = options;
27
+ options = {};
28
+ }
29
+ if (!options || typeof options !== "object") {
30
+ options = {};
31
+ }
32
+
33
+ let promiseCallback = null;
34
+ let rejectFunc = null;
35
+ let resolveFunc = null;
36
+ let returnPromise = null;
37
+
38
+ if (typeof callback !== "function") {
39
+ returnPromise = new Promise(function (resolve, reject) {
40
+ resolveFunc = resolve;
41
+ rejectFunc = reject;
42
+ });
43
+ promiseCallback = function (error, api) {
44
+ if (error) return rejectFunc(error);
45
+ return resolveFunc(api);
46
+ };
47
+ callback = promiseCallback;
48
+ }
49
+
50
+ if ('logging' in options) {
51
+ utils.logOptions(options.logging);
52
+ }
53
+ const defaultOptions = {
54
+ selfListen: false,
55
+ listenEvents: true,
56
+ listenTyping: false,
57
+ simulateTyping: true,
58
+ updatePresence: false,
59
+ forceLogin: false,
60
+ autoMarkDelivery: false,
61
+ autoMarkRead: true,
62
+ autoReconnect: true,
63
+ online: true,
64
+ emitReady: false,
65
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
66
+ };
67
+ Object.assign(globalOptions, defaultOptions, options);
68
+
69
+ await setOptionsModel(globalOptions, options);
70
+
71
+ loginHelperModel(
72
+ credentials,
73
+ globalOptions,
74
+ (loginError, loginApi) => {
75
+ if (loginError) {
76
+ return callback(loginError);
77
+ }
78
+ api = loginApi;
79
+ ctx = loginApi.ctx;
80
+ defaultFuncs = loginApi.defaultFuncs;
81
+ return callback(null, loginApi);
82
+ },
83
+ setOptionsModel,
84
+ buildAPIModel,
85
+ api,
86
+ fbLink,
87
+ ERROR_RETRIEVING
88
+ );
89
+
90
+ return returnPromise;
91
+ }
92
+
93
+ module.exports = {
94
+ login
95
+ };
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+
3
+ const utils = require('../../utils');
4
+ const SimpleCache = require('../../utils/cache');
5
+ const { globalValidator } = require('../../utils/validation');
6
+
7
+ /**
8
+ * Builds the core API context and default functions after successful login.
9
+ *
10
+ * @param {string} html The HTML body from the initial Facebook page.
11
+ * @param {object} jar The cookie jar.
12
+ * @param {Array<object>} netData Network data extracted from the HTML.
13
+ * @param {object} globalOptions The global options object.
14
+ * @param {function} fbLinkFunc A function to generate Facebook links.
15
+ * @param {string} errorRetrievingMsg The error message for retrieving user ID.
16
+ * @returns {Array<object>} An array containing [ctx, defaultFuncs, {}].
17
+ */
18
+ async function buildAPI(html, jar, netData, globalOptions, fbLinkFunc, errorRetrievingMsg) {
19
+ let userID;
20
+ const cookies = jar.getCookiesSync(fbLinkFunc());
21
+ const primaryProfile = cookies.find((val) => val.cookieString().startsWith("c_user="));
22
+ const secondaryProfile = cookies.find((val) => val.cookieString().startsWith("i_user="));
23
+ if (!primaryProfile && !secondaryProfile) {
24
+ throw new Error(errorRetrievingMsg);
25
+ }
26
+ userID = secondaryProfile?.cookieString().split("=")[1] || primaryProfile.cookieString().split("=")[1];
27
+
28
+ const findConfig = (key) => {
29
+ for (const scriptData of netData) {
30
+ if (scriptData.require) {
31
+ for (const req of scriptData.require) {
32
+ if (Array.isArray(req) && req[0] === key && req[2]) {
33
+ return req[2];
34
+ }
35
+ if (Array.isArray(req) && req[3] && req[3][0] && req[3][0].__bbox && req[3][0].__bbox.define) {
36
+ for (const def of req[3][0].__bbox.define) {
37
+ if (Array.isArray(def) && def[0].endsWith(key) && def[2]) {
38
+ return def[2];
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return null;
46
+ };
47
+
48
+ const dtsgData = findConfig("DTSGInitialData");
49
+ const dtsg = dtsgData ? dtsgData.token : utils.getFrom(html, '"token":"', '"');
50
+
51
+ const lsdData = findConfig("LSD");
52
+ const lsd = lsdData ? lsdData.token : utils.getFrom(html, '"LSD",[],{"token":"', '"');
53
+
54
+ // Extract additional DTSG AG token for better session persistence
55
+ const dtsgAgData = findConfig("DTSGAGInitialData");
56
+ const fb_dtsg_ag = dtsgAgData ? dtsgAgData.token : utils.getFrom(html, '"DTSGAGInitialData",[],{"token":"', '"');
57
+
58
+ // Extract spin parameters for consistency
59
+ const spinRMatch = html.match(/"__spin_r":(\d+)/);
60
+ const __spin_r = spinRMatch ? spinRMatch[1] : undefined;
61
+
62
+ const spinBMatch = html.match(/"__spin_b":"([^"]+)"/);
63
+ const __spin_b = spinBMatch ? spinBMatch[1] : undefined;
64
+
65
+ const spinTMatch = html.match(/"__spin_t":(\d+)/);
66
+ const __spin_t = spinTMatch ? spinTMatch[1] : undefined;
67
+
68
+ // Extract hsi (host session identifier)
69
+ const hsiMatch = html.match(/"hsi":"(\d+)"/);
70
+ const hsi = hsiMatch ? hsiMatch[1] : undefined;
71
+
72
+ // Extract dyn and csr for consistency
73
+ const dynMatch = html.match(/"dyn":"([^"]+)"/);
74
+ const dyn = dynMatch ? dynMatch[1] : undefined;
75
+
76
+ const csrMatch = html.match(/"csr":"([^"]+)"/);
77
+ const csr = csrMatch ? csrMatch[1] : undefined;
78
+
79
+ const dtsgResult = {
80
+ fb_dtsg: dtsg,
81
+ jazoest: `2${Array.from(dtsg).reduce((a, b) => a + b.charCodeAt(0), '')}`,
82
+ lsd: lsd,
83
+ fb_dtsg_ag: fb_dtsg_ag,
84
+ __spin_r: __spin_r,
85
+ __spin_b: __spin_b,
86
+ __spin_t: __spin_t,
87
+ hsi: hsi,
88
+ dyn: dyn,
89
+ csr: csr
90
+ };
91
+
92
+ const clientIDData = findConfig("MqttWebDeviceID");
93
+ const clientID = clientIDData ? clientIDData.clientID : undefined;
94
+
95
+ const mqttConfigData = findConfig("MqttWebConfig");
96
+ const mqttAppID = mqttConfigData ? mqttConfigData.appID : undefined;
97
+
98
+ const currentUserData = findConfig("CurrentUserInitialData");
99
+ const userAppID = currentUserData ? currentUserData.APP_ID : undefined;
100
+
101
+ let primaryAppID = userAppID || mqttAppID;
102
+
103
+ let mqttEndpoint = mqttConfigData ? mqttConfigData.endpoint : undefined;
104
+
105
+ let region;
106
+ if (mqttEndpoint) {
107
+ try {
108
+ region = new URL(mqttEndpoint).searchParams.get("region")?.toUpperCase();
109
+ } catch (_) {
110
+ // Malformed or missing MQTT endpoint — region stays undefined.
111
+ }
112
+ }
113
+ const irisSeqIDMatch = html.match(/irisSeqID:"(.+?)"/);
114
+ const irisSeqID = irisSeqIDMatch ? irisSeqIDMatch[1] : null;
115
+ if (globalOptions.bypassRegion && mqttEndpoint) {
116
+ const currentEndpoint = new URL(mqttEndpoint);
117
+ currentEndpoint.searchParams.set('region', globalOptions.bypassRegion.toLowerCase());
118
+ mqttEndpoint = currentEndpoint.toString();
119
+ region = globalOptions.bypassRegion.toUpperCase();
120
+ }
121
+
122
+ const ctx = {
123
+ userID,
124
+ jar,
125
+ clientID,
126
+ appID: primaryAppID,
127
+ mqttAppID: mqttAppID,
128
+ userAppID: userAppID,
129
+ globalOptions,
130
+ loggedIn: true,
131
+ access_token: "NONE",
132
+ clientMutationId: 0,
133
+ mqttClient: undefined,
134
+ lastSeqId: irisSeqID,
135
+ syncToken: undefined,
136
+ mqttEndpoint,
137
+ wsReqNumber: 0,
138
+ wsTaskNumber: 0,
139
+ reqCallbacks: {},
140
+ callback_Task: {},
141
+ region,
142
+ firstListen: true,
143
+ cache: new SimpleCache(),
144
+ validator: globalValidator,
145
+ ...dtsgResult,
146
+ };
147
+ const defaultFuncs = utils.makeDefaults(html, userID, ctx);
148
+
149
+ return [ctx, defaultFuncs, {}];
150
+ }
151
+
152
+ module.exports = buildAPI;