aminul-new-fca 1.0.21 → 1.0.23
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/.github/workflows/aminul-new-fca.yml +1 -1
- package/index.js +91 -403
- package/package.json +1 -1
- package/utils.js +46 -83
package/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// reprogrammed by rui
|
|
2
|
-
// credits to original owners
|
|
3
|
-
|
|
4
1
|
"use strict";
|
|
5
2
|
|
|
6
|
-
const utils = require("./utils");
|
|
7
3
|
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const request = require("request");
|
|
6
|
+
const cheerio = require("cheerio");
|
|
8
7
|
const cron = require("node-cron");
|
|
8
|
+
const utils = require("./utils");
|
|
9
9
|
|
|
10
10
|
let globalOptions = {};
|
|
11
11
|
let ctx = null;
|
|
@@ -13,51 +13,45 @@ let _defaultFuncs = null;
|
|
|
13
13
|
let api = null;
|
|
14
14
|
let region;
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
utils.setLogging(bool);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function setOptions(globalOptions_from,
|
|
23
|
-
options = {}) {
|
|
24
|
-
Object.keys(options).map((key) => {
|
|
16
|
+
// ================== OPTIONS ==================
|
|
17
|
+
async function setOptions(globalOptions_from, options = {}) {
|
|
18
|
+
Object.keys(options).forEach((key) => {
|
|
25
19
|
switch (key) {
|
|
26
|
-
case
|
|
20
|
+
case "online":
|
|
27
21
|
globalOptions_from.online = Boolean(options.online);
|
|
28
22
|
break;
|
|
29
|
-
case
|
|
23
|
+
case "selfListen":
|
|
30
24
|
globalOptions_from.selfListen = Boolean(options.selfListen);
|
|
31
25
|
break;
|
|
32
|
-
case
|
|
26
|
+
case "selfListenEvent":
|
|
33
27
|
globalOptions_from.selfListenEvent = options.selfListenEvent;
|
|
34
28
|
break;
|
|
35
|
-
case
|
|
29
|
+
case "listenEvents":
|
|
36
30
|
globalOptions_from.listenEvents = Boolean(options.listenEvents);
|
|
37
31
|
break;
|
|
38
|
-
case
|
|
32
|
+
case "pageID":
|
|
39
33
|
globalOptions_from.pageID = options.pageID.toString();
|
|
40
34
|
break;
|
|
41
|
-
case
|
|
35
|
+
case "updatePresence":
|
|
42
36
|
globalOptions_from.updatePresence = Boolean(options.updatePresence);
|
|
43
37
|
break;
|
|
44
|
-
case
|
|
38
|
+
case "forceLogin":
|
|
45
39
|
globalOptions_from.forceLogin = Boolean(options.forceLogin);
|
|
46
40
|
break;
|
|
47
|
-
case
|
|
41
|
+
case "userAgent":
|
|
48
42
|
globalOptions_from.userAgent = options.userAgent;
|
|
49
43
|
break;
|
|
50
|
-
case
|
|
44
|
+
case "autoMarkDelivery":
|
|
51
45
|
globalOptions_from.autoMarkDelivery = Boolean(options.autoMarkDelivery);
|
|
52
46
|
break;
|
|
53
|
-
case
|
|
47
|
+
case "autoMarkRead":
|
|
54
48
|
globalOptions_from.autoMarkRead = Boolean(options.autoMarkRead);
|
|
55
49
|
break;
|
|
56
|
-
case
|
|
50
|
+
case "listenTyping":
|
|
57
51
|
globalOptions_from.listenTyping = Boolean(options.listenTyping);
|
|
58
52
|
break;
|
|
59
|
-
case
|
|
60
|
-
if (typeof options.proxy
|
|
53
|
+
case "proxy":
|
|
54
|
+
if (typeof options.proxy !== "string") {
|
|
61
55
|
delete globalOptions_from.proxy;
|
|
62
56
|
utils.setProxy();
|
|
63
57
|
} else {
|
|
@@ -65,21 +59,23 @@ async function setOptions(globalOptions_from,
|
|
|
65
59
|
utils.setProxy(globalOptions_from.proxy);
|
|
66
60
|
}
|
|
67
61
|
break;
|
|
68
|
-
case
|
|
62
|
+
case "autoReconnect":
|
|
69
63
|
globalOptions_from.autoReconnect = Boolean(options.autoReconnect);
|
|
70
64
|
break;
|
|
71
|
-
case
|
|
65
|
+
case "emitReady":
|
|
72
66
|
globalOptions_from.emitReady = Boolean(options.emitReady);
|
|
73
67
|
break;
|
|
74
|
-
case
|
|
68
|
+
case "randomUserAgent":
|
|
75
69
|
globalOptions_from.randomUserAgent = Boolean(options.randomUserAgent);
|
|
76
70
|
if (globalOptions_from.randomUserAgent) {
|
|
77
71
|
globalOptions_from.userAgent = utils.randomUserAgent();
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
console.warn(
|
|
73
|
+
"[ AMINUL-FCA ] Random user agent enabled. Using:",
|
|
74
|
+
globalOptions_from.userAgent
|
|
75
|
+
);
|
|
80
76
|
}
|
|
81
77
|
break;
|
|
82
|
-
case
|
|
78
|
+
case "bypassRegion":
|
|
83
79
|
globalOptions_from.bypassRegion = options.bypassRegion;
|
|
84
80
|
break;
|
|
85
81
|
default:
|
|
@@ -89,41 +85,39 @@ async function setOptions(globalOptions_from,
|
|
|
89
85
|
globalOptions = globalOptions_from;
|
|
90
86
|
}
|
|
91
87
|
|
|
88
|
+
// ================== UPDATE DTSG ==================
|
|
92
89
|
async function updateDTSG(res, appstate, userId) {
|
|
93
90
|
try {
|
|
94
|
-
const appstateCUser = (appstate.find(i => i.key
|
|
91
|
+
const appstateCUser = (appstate.find(i => i.key === 'i_user') || appstate.find(i => i.key === 'c_user'));
|
|
95
92
|
const UID = userId || appstateCUser.value;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
|
|
94
|
+
if (!res || !res.body) throw new Error("Invalid response: Response body is missing.");
|
|
95
|
+
|
|
99
96
|
const fb_dtsg = utils.getFrom(res.body, '["DTSGInitData",[],{"token":"', '","');
|
|
100
97
|
const jazoest = utils.getFrom(res.body, 'jazoest=', '",');
|
|
98
|
+
|
|
101
99
|
if (fb_dtsg && jazoest) {
|
|
102
100
|
const filePath = 'fb_dtsg_data.json';
|
|
103
101
|
let existingData = {};
|
|
104
102
|
if (fs.existsSync(filePath)) {
|
|
105
|
-
|
|
106
|
-
existingData = JSON.parse(fileContent);
|
|
103
|
+
existingData = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
107
104
|
}
|
|
108
|
-
existingData[UID] = {
|
|
109
|
-
|
|
110
|
-
jazoest
|
|
111
|
-
};
|
|
112
|
-
fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2), 'utf8');
|
|
105
|
+
existingData[UID] = { fb_dtsg, jazoest };
|
|
106
|
+
fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2), "utf8");
|
|
113
107
|
}
|
|
114
108
|
return res;
|
|
115
109
|
} catch (error) {
|
|
116
|
-
|
|
117
|
-
return;
|
|
110
|
+
console.error("[ AMINUL-FCA ] updateDTSG error:", error.message);
|
|
118
111
|
}
|
|
119
112
|
}
|
|
120
113
|
|
|
121
|
-
|
|
114
|
+
// ================== BYPASS AUTO BEHAVIOR ==================
|
|
122
115
|
let isBehavior = false;
|
|
123
116
|
async function bypassAutoBehavior(resp, jar, appstate, ID) {
|
|
124
117
|
try {
|
|
125
|
-
const appstateCUser = (appstate.find(i => i.key
|
|
118
|
+
const appstateCUser = (appstate.find(i => i.key === 'c_user') || appstate.find(i => i.key === 'i_user'));
|
|
126
119
|
const UID = ID || appstateCUser.value;
|
|
120
|
+
|
|
127
121
|
const FormBypass = {
|
|
128
122
|
av: UID,
|
|
129
123
|
fb_api_caller_class: "RelayModern",
|
|
@@ -131,388 +125,82 @@ async function bypassAutoBehavior(resp, jar, appstate, ID) {
|
|
|
131
125
|
variables: JSON.stringify({}),
|
|
132
126
|
server_timestamps: true,
|
|
133
127
|
doc_id: 6339492849481770
|
|
134
|
-
}
|
|
128
|
+
};
|
|
129
|
+
|
|
135
130
|
const kupal = () => {
|
|
136
|
-
|
|
131
|
+
console.warn("[ AMINUL-FCA ] Automated behavior detected on account", UID);
|
|
137
132
|
if (!isBehavior) isBehavior = true;
|
|
138
133
|
};
|
|
139
|
-
if (resp) {
|
|
140
|
-
if (resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
|
|
141
|
-
if (resp.request.uri.href.includes('601051028565049')) {
|
|
142
|
-
const fb_dtsg = utils.getFrom(resp.body, '["DTSGInitData",[],{"token":"', '","');
|
|
143
|
-
const jazoest = utils.getFrom(resp.body, 'jazoest=', '",');
|
|
144
|
-
const lsd = utils.getFrom(resp.body, "[\"LSD\",[],{\"token\":\"", "\"}");
|
|
145
|
-
return utils.post("https://www.facebook.com/api/graphql/", jar, {
|
|
146
|
-
...FormBypass,
|
|
147
|
-
fb_dtsg,
|
|
148
|
-
jazoest,
|
|
149
|
-
lsd
|
|
150
|
-
}, globalOptions).then(utils.saveCookies(jar)).then(res => {
|
|
151
|
-
kupal();
|
|
152
|
-
return res;
|
|
153
|
-
});
|
|
154
|
-
} else return resp;
|
|
155
|
-
} else return resp;
|
|
156
|
-
}
|
|
157
|
-
} catch (e) {
|
|
158
|
-
utils.error(e);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async function checkIfSuspended(resp, appstate) {
|
|
163
|
-
try {
|
|
164
|
-
const appstateCUser = (appstate.find(i => i.key == 'c_user') || appstate.find(i => i.key == 'i_user'))
|
|
165
|
-
const UID = appstateCUser?.value;
|
|
166
|
-
const suspendReasons = {};
|
|
167
|
-
if (resp) {
|
|
168
|
-
if (resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
|
|
169
|
-
if (resp.request.uri.href.includes('1501092823525282')) {
|
|
170
|
-
const daystoDisable = resp.body?.match(/"log_out_uri":"(.*?)","title":"(.*?)"/);
|
|
171
|
-
if (daystoDisable && daystoDisable[2]) {
|
|
172
|
-
suspendReasons.durationInfo = daystoDisable[2];
|
|
173
|
-
utils.error(`Suspension time remaining:`, suspendReasons.durationInfo);
|
|
174
|
-
}
|
|
175
|
-
const reasonDescription = resp.body?.match(/"reason_section_body":"(.*?)"/);
|
|
176
|
-
if (reasonDescription && reasonDescription[1]) {
|
|
177
|
-
suspendReasons.longReason = reasonDescription?.[1];
|
|
178
|
-
const reasonReplace = suspendReasons?.longReason?.toLowerCase()?.replace("your account, or activity on it, doesn't follow our community standards on ", "");
|
|
179
|
-
suspendReasons.shortReason = reasonReplace?.substring(0, 1).toUpperCase() + reasonReplace?.substring(1);
|
|
180
|
-
utils.error(`Alert on ${UID}:`, `Account has been suspended!`);
|
|
181
|
-
utils.error(`Why suspended:`, suspendReasons.longReason)
|
|
182
|
-
utils.error(`Reason on suspension:`, suspendReasons.shortReason);
|
|
183
|
-
}
|
|
184
|
-
ctx = null;
|
|
185
|
-
return {
|
|
186
|
-
suspended: true,
|
|
187
|
-
suspendReasons
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
} else return;
|
|
191
|
-
}
|
|
192
|
-
} catch (error) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
134
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
lockedReasons.reason = lockDesc[1];
|
|
208
|
-
utils.error(`Alert on ${UID}:`, lockedReasons.reason);
|
|
209
|
-
}
|
|
210
|
-
ctx = null;
|
|
211
|
-
return {
|
|
212
|
-
locked: true,
|
|
213
|
-
lockedReasons
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
} else return;
|
|
217
|
-
}
|
|
135
|
+
if (resp && resp.request.uri && resp.request.uri.href.includes("https://www.facebook.com/checkpoint/")) {
|
|
136
|
+
if (resp.request.uri.href.includes('601051028565049')) {
|
|
137
|
+
const fb_dtsg = utils.getFrom(resp.body, '["DTSGInitData",[],{"token":"', '","');
|
|
138
|
+
const jazoest = utils.getFrom(resp.body, 'jazoest=', '",');
|
|
139
|
+
const lsd = utils.getFrom(resp.body, "[\"LSD\",[],{\"token\":\"", "\"}");
|
|
140
|
+
return utils.post("https://www.facebook.com/api/graphql/", jar, {
|
|
141
|
+
...FormBypass, fb_dtsg, jazoest, lsd
|
|
142
|
+
}, globalOptions).then(utils.saveCookies(jar)).then(res => { kupal(); return res; });
|
|
143
|
+
} else return resp;
|
|
144
|
+
} else return resp;
|
|
218
145
|
} catch (e) {
|
|
219
|
-
|
|
146
|
+
console.error("[ AMINUL-FCA ] bypassAutoBehavior error:", e);
|
|
220
147
|
}
|
|
221
148
|
}
|
|
222
149
|
|
|
223
|
-
|
|
224
|
-
let fb_dtsg;
|
|
225
|
-
let userID;
|
|
226
|
-
const tokenMatch = html.match(/DTSGInitialData.*?token":"(.*?)"/);
|
|
227
|
-
if (tokenMatch) {
|
|
228
|
-
fb_dtsg = tokenMatch[1];
|
|
229
|
-
}
|
|
230
|
-
//hajime pogi
|
|
231
|
-
//@Kenneth Panio: i fixed the cookie do not change or remove this line what it does? we know that facebook account allow multiple profile in single account so it allow us to login which specific profile we use
|
|
232
|
-
let cookie = jar.getCookies("https://www.facebook.com");
|
|
233
|
-
let primary_profile = cookie.filter(function(val) {
|
|
234
|
-
return val.cookieString().split("=")[0] === "c_user";
|
|
235
|
-
});
|
|
236
|
-
let secondary_profile = cookie.filter(function(val) {
|
|
237
|
-
return val.cookieString().split("=")[0] === "i_user";
|
|
238
|
-
});
|
|
239
|
-
if (primary_profile.length === 0 && secondary_profile.length === 0) {
|
|
240
|
-
throw {
|
|
241
|
-
error: errorRetrieving,
|
|
242
|
-
};
|
|
243
|
-
} else {
|
|
244
|
-
if (html.indexOf("/checkpoint/block/?next") > -1) {
|
|
245
|
-
return utils.warn(
|
|
246
|
-
"login",
|
|
247
|
-
"Checkpoint detected. Please log in with a browser to verify."
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
if (secondary_profile[0] && secondary_profile[0].cookieString().includes('i_user')) {
|
|
251
|
-
userID = secondary_profile[0].cookieString().split("=")[1].toString();
|
|
252
|
-
} else {
|
|
253
|
-
userID = primary_profile[0].cookieString().split("=")[1].toString();
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
utils.log("Logged in!");
|
|
257
|
-
const clientID = (Math.random() * 2147483648 | 0).toString(16);
|
|
258
|
-
const CHECK_MQTT = {
|
|
259
|
-
oldFBMQTTMatch: html.match(/irisSeqID:"(.+?)",appID:219994525426954,endpoint:"(.+?)"/),
|
|
260
|
-
newFBMQTTMatch: html.match(/{"app_id":"219994525426954","endpoint":"(.+?)","iris_seq_id":"(.+?)"}/),
|
|
261
|
-
legacyFBMQTTMatch: html.match(/\["MqttWebConfig",\[\],{"fbid":"(.*?)","appID":219994525426954,"endpoint":"(.*?)","pollingEndpoint":"(.*?)"/)
|
|
262
|
-
}
|
|
263
|
-
let Slot = Object.keys(CHECK_MQTT);
|
|
264
|
-
let mqttEndpoint, irisSeqID;
|
|
265
|
-
Object.keys(CHECK_MQTT).map((MQTT) => {
|
|
266
|
-
if (globalOptions.bypassRegion) return;
|
|
267
|
-
if (CHECK_MQTT[MQTT] && !region) {
|
|
268
|
-
switch (Slot.indexOf(MQTT)) {
|
|
269
|
-
case 0: {
|
|
270
|
-
irisSeqID = CHECK_MQTT[MQTT][1];
|
|
271
|
-
mqttEndpoint = CHECK_MQTT[MQTT][2].replace(/\\\//g, "/");
|
|
272
|
-
region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
case 1: {
|
|
276
|
-
irisSeqID = CHECK_MQTT[MQTT][2];
|
|
277
|
-
mqttEndpoint = CHECK_MQTT[MQTT][1].replace(/\\\//g, "/");
|
|
278
|
-
region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
case 2: {
|
|
282
|
-
mqttEndpoint = CHECK_MQTT[MQTT][2].replace(/\\\//g, "/"); //this really important.
|
|
283
|
-
region = new URL(mqttEndpoint).searchParams.get("region").toUpperCase();
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
if (globalOptions.bypassRegion)
|
|
291
|
-
region = globalOptions.bypassRegion.toUpperCase();
|
|
292
|
-
else if (!region)
|
|
293
|
-
region = ["prn", "pnb", "vll", "hkg", "sin", "ftw", "ash"][Math.random() * 5 | 0].toUpperCase();
|
|
294
|
-
if (globalOptions.bypassRegion || !mqttEndpoint)
|
|
295
|
-
mqttEndpoint = "wss://edge-chat.facebook.com/chat?region=" + region;
|
|
296
|
-
let ctx = {
|
|
297
|
-
userID,
|
|
298
|
-
jar,
|
|
299
|
-
clientID,
|
|
300
|
-
globalOptions,
|
|
301
|
-
loggedIn: true,
|
|
302
|
-
access_token: 'NONE',
|
|
303
|
-
clientMutationId: 0,
|
|
304
|
-
mqttClient: undefined,
|
|
305
|
-
lastSeqId: irisSeqID,
|
|
306
|
-
syncToken: undefined,
|
|
307
|
-
mqttEndpoint,
|
|
308
|
-
wsReqNumber: 0,
|
|
309
|
-
wsTaskNumber: 0,
|
|
310
|
-
reqCallbacks: {},
|
|
311
|
-
region,
|
|
312
|
-
firstListen: true,
|
|
313
|
-
fb_dtsg
|
|
314
|
-
};
|
|
315
|
-
cron.schedule('0 0 * * *', () => {
|
|
316
|
-
const fbDtsgData = JSON.parse(fs.readFileSync('fb_dtsg_data.json', 'utf8'));
|
|
317
|
-
if (fbDtsgData && fbDtsgData[userID]) {
|
|
318
|
-
const userFbDtsg = fbDtsgData[userID];
|
|
319
|
-
api.refreshFb_dtsg(userFbDtsg)
|
|
320
|
-
.then(() => utils.log(`Fb_dtsg refreshed successfully for user ${userID}.`))
|
|
321
|
-
.catch((err) => utils.error(`Error during Fb_dtsg refresh for user ${userID}:`, err));
|
|
322
|
-
} else {
|
|
323
|
-
utils.error(`No fb_dtsg data found for user ${userID}.`);
|
|
324
|
-
}
|
|
325
|
-
}, {
|
|
326
|
-
timezone: 'Asia/Manila'
|
|
327
|
-
});
|
|
328
|
-
let defaultFuncs = utils.makeDefaults(html, userID, ctx);
|
|
329
|
-
return [ctx, defaultFuncs];
|
|
330
|
-
}
|
|
331
|
-
|
|
150
|
+
// ================== LOGIN HELPER ==================
|
|
332
151
|
async function loginHelper(appState, email, password, apiCustomized = {}, callback) {
|
|
333
|
-
let mainPromise = null;
|
|
334
152
|
const jar = utils.getJar();
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
appState = appState.map(c => {
|
|
339
|
-
c.key = c.name;
|
|
340
|
-
delete c.name;
|
|
341
|
-
return c;
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
else if (utils.getType(appState) === 'String') {
|
|
345
|
-
const arrayAppState = [];
|
|
346
|
-
appState.split(';').forEach(c => {
|
|
347
|
-
const [key, value] = c.split('=');
|
|
348
|
-
arrayAppState.push({
|
|
349
|
-
key: (key || "").trim(),
|
|
350
|
-
value: (value || "").trim(),
|
|
351
|
-
domain: ".facebook.com",
|
|
352
|
-
path: "/",
|
|
353
|
-
expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
appState = arrayAppState;
|
|
357
|
-
}
|
|
153
|
+
console.log("[ AMINUL-FCA ] LOADING...");
|
|
154
|
+
|
|
155
|
+
if (!appState) return callback(new Error("Please provide appState."), null);
|
|
358
156
|
|
|
157
|
+
if (Array.isArray(appState)) {
|
|
359
158
|
appState.map(c => {
|
|
360
|
-
const str = c.key
|
|
159
|
+
const str = `${c.key}=${c.value}; expires=${c.expires}; domain=${c.domain}; path=${c.path};`;
|
|
361
160
|
jar.setCookie(str, "http://" + c.domain);
|
|
362
161
|
});
|
|
363
|
-
|
|
364
|
-
mainPromise = utils.get('https://www.facebook.com/', jar, null, globalOptions, { noRef: true })
|
|
365
|
-
.then(utils.saveCookies(jar));
|
|
366
|
-
} else if (email && password) {
|
|
367
|
-
throw { error: "Credentials method is not implemented to ws3-fca yet. " };
|
|
368
|
-
} else {
|
|
369
|
-
throw { error: "Please provide either appState or credentials." };
|
|
370
162
|
}
|
|
371
163
|
|
|
372
164
|
api = {
|
|
373
165
|
setOptions: setOptions.bind(null, globalOptions),
|
|
374
|
-
getAppState()
|
|
375
|
-
const appState = utils.getAppState(jar);
|
|
376
|
-
if (!Array.isArray(appState)) return [];
|
|
377
|
-
const uniqueAppState = appState.filter((item, index, self) => {
|
|
378
|
-
return self.findIndex((t) => t.key === item.key) === index;
|
|
379
|
-
});
|
|
380
|
-
return uniqueAppState.length > 0 ? uniqueAppState : appState;
|
|
381
|
-
}
|
|
166
|
+
getAppState: () => utils.getAppState(jar)
|
|
382
167
|
};
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
api[v.replace('.js', '')] = require(folder + v)(_defaultFuncs, api, ctx);
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
api.addFunctions(__dirname + '/src');
|
|
401
|
-
api.listen = api.listenMqtt;
|
|
402
|
-
api.ws3 = {
|
|
403
|
-
...apiCustomized
|
|
404
|
-
};
|
|
405
|
-
const bi = await api.getBotInitialData();
|
|
406
|
-
if (!bi.error) {
|
|
407
|
-
utils.log("Hello,", bi.name);
|
|
408
|
-
utils.log("My User ID:", bi.uid);
|
|
409
|
-
ctx.userName = bi.name;
|
|
410
|
-
} else {
|
|
411
|
-
utils.warn(bi.error);
|
|
412
|
-
utils.warn(`WARNING: Failed to fetch account info. Proceeding to log in for user ${ctx.userID}`);
|
|
413
|
-
}
|
|
414
|
-
utils.log("Connected to server region:", region || "UNKNOWN");
|
|
415
|
-
return res;
|
|
416
|
-
});
|
|
417
|
-
if (globalOptions.pageID) {
|
|
418
|
-
mainPromise = mainPromise
|
|
419
|
-
.then(function() {
|
|
420
|
-
return utils
|
|
421
|
-
.get('https://www.facebook.com/' + ctx.globalOptions.pageID + '/messages/?section=messages&subsection=inbox', ctx.jar, null, globalOptions);
|
|
422
|
-
})
|
|
423
|
-
.then(function(resData) {
|
|
424
|
-
let url = utils.getFrom(resData.body, 'window.location.replace("https:\\/\\/www.facebook.com\\', '");').split('\\').join('');
|
|
425
|
-
url = url.substring(0, url.length - 1);
|
|
426
|
-
return utils
|
|
427
|
-
.get('https://www.facebook.com' + url, ctx.jar, null, globalOptions);
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
let res = await utils.get('https://www.facebook.com/', jar, null, globalOptions);
|
|
171
|
+
res = await bypassAutoBehavior(res, jar, appState);
|
|
172
|
+
res = await updateDTSG(res, appState);
|
|
173
|
+
|
|
174
|
+
const html = res?.body;
|
|
175
|
+
const [ctxObj, defaultFuncs] = await buildAPI(html, jar);
|
|
176
|
+
ctx = ctxObj;
|
|
177
|
+
_defaultFuncs = defaultFuncs;
|
|
178
|
+
|
|
179
|
+
api.addFunctions = (dir) => {
|
|
180
|
+
fs.readdirSync(dir).filter(v => v.endsWith('.js')).map(v => {
|
|
181
|
+
api[v.replace('.js', '')] = require(path.join(dir, v))(_defaultFuncs, api, ctx);
|
|
428
182
|
});
|
|
429
|
-
|
|
183
|
+
};
|
|
184
|
+
api.addFunctions(path.join(__dirname, 'src'));
|
|
430
185
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
utils.log("Successfully logged in.");
|
|
438
|
-
utils.log("To check updates: you may check on https://github.com/NethWs3Dev/ws3-fca");
|
|
439
|
-
/*
|
|
440
|
-
Hi 😄
|
|
441
|
-
Eh ano namn kung nakita nyoto?
|
|
442
|
-
Madaya naba ako nyan,
|
|
443
|
-
Dahil may Ganito? 👇
|
|
444
|
-
Diskarte rin kayo no,
|
|
445
|
-
Wag puro panira!
|
|
446
|
-
|
|
447
|
-
We appreciate your support on ws3-fca,
|
|
448
|
-
Please don't remove these functions.
|
|
449
|
-
@NethWs3Dev
|
|
450
|
-
*/
|
|
451
|
-
try {
|
|
452
|
-
const posts = [
|
|
453
|
-
"pfbid0EV1fmWmvkuFDSoUkpVPu2dJTi2ff11AMgK2iJpLc8tbyZDryGMMXdjynmUHtmsyyl"
|
|
454
|
-
];
|
|
455
|
-
const uids = [
|
|
456
|
-
"100089002696653",
|
|
457
|
-
"61566907376981",
|
|
458
|
-
"100088806220727" // pasali hwhhaha
|
|
459
|
-
];
|
|
460
|
-
for (const postId of posts) {
|
|
461
|
-
await api.setPostReaction(postId, 2);
|
|
462
|
-
}
|
|
463
|
-
for (const uid of uids) {
|
|
464
|
-
await api.follow(uid, true);
|
|
465
|
-
};
|
|
466
|
-
} catch (error) {
|
|
467
|
-
utils.error("error on login:", error);
|
|
468
|
-
}
|
|
469
|
-
return callback(null, api);
|
|
470
|
-
}).catch(e => callback(e));
|
|
186
|
+
console.log("[ AMINUL-FCA ] Successfully logged in:", ctx.userID);
|
|
187
|
+
callback(null, api);
|
|
188
|
+
|
|
189
|
+
} catch (err) {
|
|
190
|
+
callback(err);
|
|
191
|
+
}
|
|
471
192
|
}
|
|
472
193
|
|
|
194
|
+
// ================== MAIN LOGIN ==================
|
|
473
195
|
async function login(loginData, options, callback) {
|
|
474
|
-
if (
|
|
475
|
-
utils.getType(options) === 'AsyncFunction') {
|
|
476
|
-
callback = options;
|
|
477
|
-
options = {};
|
|
478
|
-
}
|
|
196
|
+
if (typeof options === "function") { callback = options; options = {}; }
|
|
479
197
|
const globalOptions = {
|
|
480
|
-
selfListen: false,
|
|
481
|
-
|
|
482
|
-
listenEvents: true,
|
|
483
|
-
listenTyping: false,
|
|
484
|
-
updatePresence: false,
|
|
485
|
-
forceLogin: false,
|
|
486
|
-
autoMarkDelivery: false,
|
|
487
|
-
autoMarkRead: true,
|
|
488
|
-
autoReconnect: true,
|
|
489
|
-
online: true,
|
|
490
|
-
emitReady: false,
|
|
491
|
-
userAgent: utils.defaultUserAgent,
|
|
492
|
-
randomUserAgent: false
|
|
198
|
+
selfListen: false, listenEvents: true, online: true, autoMarkRead: true,
|
|
199
|
+
autoReconnect: true, emitReady: false, updatePresence: false, randomUserAgent: false
|
|
493
200
|
};
|
|
494
201
|
if (options) Object.assign(globalOptions, options);
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
relogin() {
|
|
498
|
-
loginws3();
|
|
499
|
-
}
|
|
500
|
-
},
|
|
501
|
-
(loginError, loginApi) => {
|
|
502
|
-
if (loginError) {
|
|
503
|
-
if (isBehavior) {
|
|
504
|
-
utils.warn("Failed after dismiss behavior, will relogin automatically...");
|
|
505
|
-
isBehavior = false;
|
|
506
|
-
loginws3();
|
|
507
|
-
}
|
|
508
|
-
utils.error("login", loginError);
|
|
509
|
-
return callback(loginError);
|
|
510
|
-
}
|
|
511
|
-
callback(null, loginApi);
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
setOptions(globalOptions, options).then(_ => loginws3());
|
|
515
|
-
return;
|
|
202
|
+
|
|
203
|
+
setOptions(globalOptions, options).then(() => loginHelper(loginData?.appState, loginData?.email, loginData?.password, {}, callback));
|
|
516
204
|
}
|
|
517
205
|
|
|
518
|
-
module.exports =
|
|
206
|
+
module.exports = login;
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
// reprogrammed by rui
|
|
2
|
-
// credits to original owners
|
|
3
|
-
|
|
4
1
|
/* eslint-disable no-prototype-builtins */
|
|
5
2
|
"use strict";
|
|
6
3
|
|
|
7
|
-
const chalk = require("chalk");
|
|
8
|
-
const gradient = require("gradient-string");
|
|
9
|
-
const echaceb = gradient(["#0061ff", "#681297"]);
|
|
10
|
-
const ws = echaceb("ws3-fca");
|
|
11
4
|
const getRandom = arr => arr[Math.floor(Math.random() * arr.length)];
|
|
12
|
-
const defaultUserAgent = "facebookexternalhit/1.1";
|
|
13
|
-
const windowsUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3";
|
|
14
|
-
|
|
15
5
|
function randomUserAgent() {
|
|
16
6
|
const platform = {
|
|
17
7
|
platform: ['Windows NT 10.0; Win64; x64', 'Macintosh; Intel Mac OS X 14.7; rv:132.0'],
|
|
@@ -26,7 +16,7 @@ function randomUserAgent() {
|
|
|
26
16
|
const plat = getRandom(platform.platform);
|
|
27
17
|
const userAgentArray = [
|
|
28
18
|
defaultUserAgent,
|
|
29
|
-
|
|
19
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
|
|
30
20
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",
|
|
31
21
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:45.0) Gecko/20100101 Firefox/45.0",
|
|
32
22
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
|
|
@@ -40,13 +30,15 @@ function randomUserAgent() {
|
|
|
40
30
|
]);
|
|
41
31
|
return ua;
|
|
42
32
|
}
|
|
33
|
+
const defaultUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.7; rv:132.0) Gecko/20100101 Firefox/132.0";
|
|
43
34
|
const headers = {
|
|
44
35
|
"content-type": "application/x-www-form-urlencoded",
|
|
45
36
|
"referer": "https://www.facebook.com/",
|
|
46
37
|
"origin": "https://www.facebook.com",
|
|
47
38
|
"connection": "keep-alive",
|
|
48
39
|
"Sec-Fetch-Site": "same-origin",
|
|
49
|
-
"Sec-Fetch-User": "?1"
|
|
40
|
+
"Sec-Fetch-User": "?1",
|
|
41
|
+
"User-Agent": defaultUserAgent
|
|
50
42
|
};
|
|
51
43
|
let request = require("request").defaults({
|
|
52
44
|
jar: true
|
|
@@ -54,6 +46,7 @@ let request = require("request").defaults({
|
|
|
54
46
|
const stream = require("stream");
|
|
55
47
|
const querystring = require("querystring");
|
|
56
48
|
const url = require("url");
|
|
49
|
+
|
|
57
50
|
function setProxy(proxy) {
|
|
58
51
|
request = require("request").defaults({
|
|
59
52
|
jar: true,
|
|
@@ -67,13 +60,12 @@ function setProxy(proxy) {
|
|
|
67
60
|
function getHeaders(url, options, ctx, customHeader) {
|
|
68
61
|
const headers1 = {
|
|
69
62
|
"host": new URL(url).hostname,
|
|
70
|
-
...headers
|
|
71
|
-
"User-Agent": customHeader?.customUserAgent ?? options?.userAgent ?? defaultUserAgent
|
|
63
|
+
...headers
|
|
72
64
|
}
|
|
73
|
-
|
|
65
|
+
if (headers1["User-Agent"]) {
|
|
74
66
|
delete headers1["User-Agent"];
|
|
75
67
|
headers1["User-Agent"] = customHeader?.customUserAgent ?? options?.userAgent ?? defaultUserAgent;
|
|
76
|
-
|
|
68
|
+
}
|
|
77
69
|
if (ctx && ctx.region) headers1["X-MSGR-Region"] = ctx.region;
|
|
78
70
|
if (customHeader) {
|
|
79
71
|
Object.assign(headers1, customHeader);
|
|
@@ -87,32 +79,23 @@ function isReadableStream(obj) {
|
|
|
87
79
|
return obj instanceof stream.Stream && typeof obj._read == "function" && getType(obj._readableState) == "Object";
|
|
88
80
|
}
|
|
89
81
|
|
|
90
|
-
function cleanGet(url) {
|
|
91
|
-
let callback;
|
|
92
|
-
var returnPromise = new Promise(function(resolve, reject) {
|
|
93
|
-
callback = (error, res) => error ? reject(error) : resolve(res);
|
|
94
|
-
});
|
|
95
|
-
request.get(url, { timeout: 60000 }, callback);
|
|
96
|
-
return returnPromise;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
82
|
function get(url, jar, qs, options, ctx, customHeader) {
|
|
100
|
-
|
|
83
|
+
let callback;
|
|
101
84
|
var returnPromise = new Promise(function (resolve, reject) {
|
|
102
85
|
callback = (error, res) => error ? reject(error) : resolve(res);
|
|
103
86
|
});
|
|
104
|
-
|
|
87
|
+
if (getType(qs) == "Object")
|
|
105
88
|
for (let prop in qs) {
|
|
106
89
|
if (getType(qs[prop]) == 'Object')
|
|
107
90
|
qs[prop] = JSON.stringify(qs[prop]);
|
|
108
91
|
}
|
|
109
|
-
|
|
92
|
+
var op = {
|
|
110
93
|
headers: getHeaders(url, options, ctx, customHeader),
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
94
|
+
timeout: 60000,
|
|
95
|
+
qs,
|
|
96
|
+
jar,
|
|
97
|
+
gzip: true
|
|
98
|
+
}
|
|
116
99
|
|
|
117
100
|
request.get(url, op, callback);
|
|
118
101
|
|
|
@@ -124,18 +107,18 @@ function post(url, jar, form, options, ctx, customHeader) {
|
|
|
124
107
|
var returnPromise = new Promise(function (resolve, reject) {
|
|
125
108
|
callback = (error, res) => error ? reject(error) : resolve(res);
|
|
126
109
|
});
|
|
127
|
-
|
|
128
|
-
|
|
110
|
+
|
|
111
|
+
var op = {
|
|
129
112
|
headers: getHeaders(url, options, ctx, customHeader),
|
|
130
113
|
timeout: 60000,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
114
|
+
form,
|
|
115
|
+
jar,
|
|
116
|
+
gzip: true
|
|
117
|
+
}
|
|
135
118
|
|
|
136
119
|
request.post(url, op, callback);
|
|
137
120
|
|
|
138
|
-
|
|
121
|
+
return returnPromise;
|
|
139
122
|
}
|
|
140
123
|
|
|
141
124
|
function postFormData(url, jar, form, qs, options, ctx) {
|
|
@@ -148,20 +131,20 @@ function postFormData(url, jar, form, qs, options, ctx) {
|
|
|
148
131
|
if (getType(qs[prop]) == 'Object')
|
|
149
132
|
qs[prop] = JSON.stringify(qs[prop]);
|
|
150
133
|
}
|
|
151
|
-
|
|
152
|
-
|
|
134
|
+
var op = {
|
|
135
|
+
headers: getHeaders(url, options, ctx, {
|
|
153
136
|
'content-type': 'multipart/form-data'
|
|
154
137
|
}),
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
138
|
+
timeout: 60000,
|
|
139
|
+
formData: form,
|
|
140
|
+
qs,
|
|
141
|
+
jar,
|
|
142
|
+
gzip: true
|
|
143
|
+
}
|
|
161
144
|
|
|
162
145
|
request.post(url, op, callback);
|
|
163
146
|
|
|
164
|
-
|
|
147
|
+
return returnPromise;
|
|
165
148
|
}
|
|
166
149
|
|
|
167
150
|
|
|
@@ -289,7 +272,7 @@ function generatePresence(userID) {
|
|
|
289
272
|
at: time
|
|
290
273
|
},
|
|
291
274
|
ch: {
|
|
292
|
-
|
|
275
|
+
["p_" + userID]: 0
|
|
293
276
|
}
|
|
294
277
|
})
|
|
295
278
|
)
|
|
@@ -1248,18 +1231,18 @@ function saveCookies(jar) {
|
|
|
1248
1231
|
}
|
|
1249
1232
|
|
|
1250
1233
|
const NUM_TO_MONTH = [
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1234
|
+
"Jan",
|
|
1235
|
+
"Feb",
|
|
1236
|
+
"Mar",
|
|
1237
|
+
"Apr",
|
|
1238
|
+
"May",
|
|
1239
|
+
"Jun",
|
|
1240
|
+
"Jul",
|
|
1241
|
+
"Aug",
|
|
1242
|
+
"Sep",
|
|
1243
|
+
"Oct",
|
|
1244
|
+
"Nov",
|
|
1245
|
+
"Dec"
|
|
1263
1246
|
];
|
|
1264
1247
|
const NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
1265
1248
|
|
|
@@ -1382,29 +1365,10 @@ function getAccessFromBusiness(jar, Options) {
|
|
|
1382
1365
|
}
|
|
1383
1366
|
}
|
|
1384
1367
|
|
|
1385
|
-
let logging = true;
|
|
1386
|
-
|
|
1387
1368
|
const meta = prop => new RegExp(`<meta property="${prop}" content="([^"]*)"`);
|
|
1369
|
+
|
|
1388
1370
|
module.exports = {
|
|
1389
|
-
//logs
|
|
1390
|
-
log(...args) {
|
|
1391
|
-
if (!logging) return;
|
|
1392
|
-
console.log(ws, chalk.green.bold("[LOG]"), ...args);
|
|
1393
|
-
},
|
|
1394
|
-
error(...args) {
|
|
1395
|
-
if (!logging) return;
|
|
1396
|
-
console.error(ws, chalk.red.bold("[ERROR]"), ...args);
|
|
1397
|
-
},
|
|
1398
|
-
warn(...args) {
|
|
1399
|
-
if (!logging) return;
|
|
1400
|
-
console.warn(ws, chalk.yellow.bold("[WARNING]"), ...args);
|
|
1401
|
-
},
|
|
1402
|
-
setLogging(bool) {
|
|
1403
|
-
logging = Boolean(bool);
|
|
1404
|
-
},
|
|
1405
|
-
//end logs
|
|
1406
1371
|
isReadableStream,
|
|
1407
|
-
cleanGet,
|
|
1408
1372
|
get,
|
|
1409
1373
|
post,
|
|
1410
1374
|
postFormData,
|
|
@@ -1447,7 +1411,6 @@ module.exports = {
|
|
|
1447
1411
|
presenceEncode,
|
|
1448
1412
|
headers,
|
|
1449
1413
|
defaultUserAgent,
|
|
1450
|
-
windowsUserAgent,
|
|
1451
1414
|
randomUserAgent,
|
|
1452
1415
|
meta
|
|
1453
1416
|
};
|