@dongdev/fca-unofficial 0.0.5 → 0.0.7
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/index.js +344 -254
- package/package.json +4 -3
- package/src/getThreadList.js +175 -224
- package/src/listenMqtt.js +230 -138
- package/src/refreshFb_dtsg.js +60 -75
- package/src/shareContact.js +49 -0
- package/utils.js +71 -41
package/src/refreshFb_dtsg.js
CHANGED
@@ -4,78 +4,63 @@ const utils = require("../utils");
|
|
4
4
|
const log = require("npmlog");
|
5
5
|
|
6
6
|
module.exports = function (defaultFuncs, api, ctx) {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
});
|
68
|
-
}
|
69
|
-
else {
|
70
|
-
Object.keys(obj).forEach(function (key) {
|
71
|
-
ctx[key] = obj[key];
|
72
|
-
});
|
73
|
-
callback(null, {
|
74
|
-
data: obj,
|
75
|
-
message: "refreshed " + Object.keys(obj).join(", ")
|
76
|
-
});
|
77
|
-
}
|
78
|
-
|
79
|
-
return returnPromise;
|
80
|
-
};
|
81
|
-
};
|
7
|
+
return function refreshFb_dtsg(obj, callback) {
|
8
|
+
let resolveFunc, rejectFunc;
|
9
|
+
const returnPromise = new Promise((resolve, reject) => {
|
10
|
+
resolveFunc = resolve;
|
11
|
+
rejectFunc = reject;
|
12
|
+
});
|
13
|
+
if (
|
14
|
+
utils.getType(obj) === "Function" ||
|
15
|
+
utils.getType(obj) === "AsyncFunction"
|
16
|
+
) {
|
17
|
+
callback = obj;
|
18
|
+
obj = {};
|
19
|
+
}
|
20
|
+
if (!obj) obj = {};
|
21
|
+
if (utils.getType(obj) !== "Object") {
|
22
|
+
throw new utils.CustomError(
|
23
|
+
"The first parameter must be an object or a callback function"
|
24
|
+
);
|
25
|
+
}
|
26
|
+
if (!callback) {
|
27
|
+
callback = (err, data) => (err ? rejectFunc(err) : resolveFunc(data));
|
28
|
+
}
|
29
|
+
if (Object.keys(obj).length === 0) {
|
30
|
+
utils
|
31
|
+
.get("https://www.facebook.com/", ctx.jar, null, ctx.globalOptions, {
|
32
|
+
noRef: true,
|
33
|
+
})
|
34
|
+
.then((resData) => {
|
35
|
+
const fb_dtsg = utils.getFrom(
|
36
|
+
resData.body,
|
37
|
+
'["DTSGInitData",[],{"token":"',
|
38
|
+
'","'
|
39
|
+
);
|
40
|
+
const jazoest = utils.getFrom(resData.body, "jazoest=", '",');
|
41
|
+
if (!fb_dtsg) {
|
42
|
+
throw new utils.CustomError(
|
43
|
+
"Could not find fb_dtsg in HTML after requesting Facebook."
|
44
|
+
);
|
45
|
+
}
|
46
|
+
ctx.fb_dtsg = fb_dtsg;
|
47
|
+
ctx.jazoest = jazoest;
|
48
|
+
callback(null, {
|
49
|
+
data: { fb_dtsg, jazoest },
|
50
|
+
message: "Refreshed fb_dtsg and jazoest",
|
51
|
+
});
|
52
|
+
})
|
53
|
+
.catch((err) => {
|
54
|
+
log.error("refreshFb_dtsg", err);
|
55
|
+
callback(err);
|
56
|
+
});
|
57
|
+
} else {
|
58
|
+
Object.assign(ctx, obj);
|
59
|
+
callback(null, {
|
60
|
+
data: obj,
|
61
|
+
message: "Refreshed " + Object.keys(obj).join(", "),
|
62
|
+
});
|
63
|
+
}
|
64
|
+
return returnPromise;
|
65
|
+
};
|
66
|
+
};
|
@@ -0,0 +1,49 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
var utils = require("../utils");
|
4
|
+
var log = require("npmlog");
|
5
|
+
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
7
|
+
return function shareContact(text, senderID, threadID, callback) {
|
8
|
+
if (!text) {
|
9
|
+
text = "";
|
10
|
+
}
|
11
|
+
var resolveFunc = function () { };
|
12
|
+
var rejectFunc = function () { };
|
13
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
14
|
+
resolveFunc = resolve;
|
15
|
+
rejectFunc = reject;
|
16
|
+
});
|
17
|
+
if (!callback) {
|
18
|
+
callback = function (err, data) {
|
19
|
+
if (err) return rejectFunc(err);
|
20
|
+
resolveFunc(data);
|
21
|
+
data
|
22
|
+
};
|
23
|
+
}
|
24
|
+
let count_req = 0
|
25
|
+
var form = JSON.stringify({
|
26
|
+
"app_id": "2220391788200892",
|
27
|
+
"payload": JSON.stringify({
|
28
|
+
tasks: [{
|
29
|
+
label: '359',
|
30
|
+
payload: JSON.stringify({
|
31
|
+
"contact_id": senderID,
|
32
|
+
"sync_group": 1,
|
33
|
+
"text": text || "",
|
34
|
+
"thread_id": threadID
|
35
|
+
}),
|
36
|
+
queue_name: 'messenger_contact_sharing',
|
37
|
+
task_id: Math.random() * 1001 << 0,
|
38
|
+
failure_count: null,
|
39
|
+
}],
|
40
|
+
epoch_id: utils.generateOfflineThreadingID(),
|
41
|
+
version_id: '7214102258676893',
|
42
|
+
}),
|
43
|
+
"request_id": ++count_req,
|
44
|
+
"type": 3
|
45
|
+
});
|
46
|
+
mqttClient.publish('/ls_req', form);
|
47
|
+
return returnPromise;
|
48
|
+
};
|
49
|
+
};
|
package/utils.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
/* eslint-disable no-prototype-builtins */
|
2
1
|
"use strict";
|
3
2
|
|
4
3
|
let request = promisifyPromise(require("request").defaults({ jar: true, proxy: process.env.FB_PROXY }));
|
@@ -1210,68 +1209,99 @@ function makeDefaults(html, userID, ctx) {
|
|
1210
1209
|
};
|
1211
1210
|
}
|
1212
1211
|
|
1213
|
-
function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
|
1214
|
-
if (
|
1212
|
+
function parseAndCheckLogin(ctx, defaultFuncs, retryCount = 0, sourceCall) {
|
1213
|
+
if (sourceCall === undefined) {
|
1214
|
+
try {
|
1215
|
+
throw new Error();
|
1216
|
+
} catch (e) {
|
1217
|
+
sourceCall = e;
|
1218
|
+
}
|
1219
|
+
}
|
1215
1220
|
return function (data) {
|
1216
|
-
return
|
1221
|
+
return tryPromise(function () {
|
1217
1222
|
log.verbose("parseAndCheckLogin", data.body);
|
1218
1223
|
if (data.statusCode >= 500 && data.statusCode < 600) {
|
1219
1224
|
if (retryCount >= 5) {
|
1220
1225
|
throw {
|
1221
|
-
|
1226
|
+
message: "Request retry failed. Check `res` and `statusCode`.",
|
1222
1227
|
statusCode: data.statusCode,
|
1223
|
-
res: data.body
|
1228
|
+
res: data.body,
|
1229
|
+
error: "Request retry failed.",
|
1230
|
+
sourceCall
|
1224
1231
|
};
|
1225
1232
|
}
|
1226
1233
|
retryCount++;
|
1227
|
-
|
1228
|
-
log.warn(
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1234
|
+
const retryTime = Math.floor(Math.random() * 5000);
|
1235
|
+
log.warn(
|
1236
|
+
"parseAndCheckLogin",
|
1237
|
+
`Got status code ${data.statusCode} - Retrying in ${retryTime}ms...`
|
1238
|
+
);
|
1239
|
+
if (!data.request) throw new Error("Invalid request object");
|
1240
|
+
const url = `${data.request.uri.protocol}//${data.request.uri.hostname}${data.request.uri.pathname}`;
|
1241
|
+
const contentType = data.request.headers?.["content-type"]?.split(";")[0];
|
1242
|
+
return delay(retryTime)
|
1243
|
+
.then(() =>
|
1244
|
+
contentType === "multipart/form-data"
|
1245
|
+
? defaultFuncs.postFormData(url, ctx.jar, data.request.formData, {})
|
1246
|
+
: defaultFuncs.post(url, ctx.jar, data.request.formData)
|
1247
|
+
)
|
1248
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
|
1232
1249
|
}
|
1233
|
-
if (data.statusCode !== 200)
|
1234
|
-
|
1235
|
-
|
1250
|
+
if (data.statusCode !== 200) {
|
1251
|
+
throw {
|
1252
|
+
message: `parseAndCheckLogin got status code: ${data.statusCode}.`,
|
1253
|
+
statusCode: data.statusCode,
|
1254
|
+
res: data.body,
|
1255
|
+
error: `parseAndCheckLogin got status code: ${data.statusCode}.`,
|
1256
|
+
sourceCall
|
1257
|
+
};
|
1258
|
+
}
|
1259
|
+
let res;
|
1236
1260
|
try {
|
1237
1261
|
res = JSON.parse(makeParsable(data.body));
|
1238
|
-
}
|
1239
|
-
|
1262
|
+
} catch (e) {
|
1263
|
+
log.error("JSON parsing failed:", data.body);
|
1240
1264
|
throw {
|
1241
|
-
|
1242
|
-
detail: e,
|
1243
|
-
res: data.body
|
1265
|
+
message: "Failed to parse JSON response.",
|
1266
|
+
detail: e.message,
|
1267
|
+
res: data.body,
|
1268
|
+
error: "JSON.parse error.",
|
1269
|
+
sourceCall
|
1244
1270
|
};
|
1245
1271
|
}
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
if (
|
1272
|
+
if (res.redirect && data.request.method === "GET") {
|
1273
|
+
return defaultFuncs
|
1274
|
+
.get(res.redirect, ctx.jar)
|
1275
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, undefined, sourceCall));
|
1276
|
+
}
|
1277
|
+
if (
|
1278
|
+
res.jsmods?.require &&
|
1279
|
+
Array.isArray(res.jsmods.require[0]) &&
|
1280
|
+
res.jsmods.require[0][0] === "Cookie"
|
1281
|
+
) {
|
1252
1282
|
res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace("_js_", "");
|
1253
|
-
|
1254
|
-
|
1283
|
+
const cookie = formatCookie(res.jsmods.require[0][3], "facebook");
|
1284
|
+
const cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
|
1255
1285
|
ctx.jar.setCookie(cookie, "https://www.facebook.com");
|
1256
1286
|
ctx.jar.setCookie(cookie2, "https://www.messenger.com");
|
1257
1287
|
}
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
for (var i in arr) {
|
1264
|
-
if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
|
1265
|
-
ctx.fb_dtsg = arr[i][3][0];
|
1266
|
-
|
1267
|
-
// Update ttstamp since that depends on fb_dtsg
|
1268
|
-
ctx.ttstamp = "2";
|
1269
|
-
for (var j = 0; j < ctx.fb_dtsg.length; j++) ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
|
1288
|
+
if (res.jsmods?.require) {
|
1289
|
+
for (const arr of res.jsmods.require) {
|
1290
|
+
if (arr[0] === "DTSG" && arr[1] === "setToken") {
|
1291
|
+
ctx.fb_dtsg = arr[3][0];
|
1292
|
+
ctx.ttstamp = "2" + ctx.fb_dtsg.split("").map(c => c.charCodeAt(0)).join("");
|
1270
1293
|
}
|
1271
1294
|
}
|
1272
1295
|
}
|
1273
|
-
|
1274
|
-
|
1296
|
+
if (res.error === 1357001) {
|
1297
|
+
throw {
|
1298
|
+
message: "Facebook blocked login. Please check your account.",
|
1299
|
+
error: "Not logged in.",
|
1300
|
+
res,
|
1301
|
+
statusCode: data.statusCode,
|
1302
|
+
sourceCall
|
1303
|
+
};
|
1304
|
+
}
|
1275
1305
|
return res;
|
1276
1306
|
});
|
1277
1307
|
};
|