@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.
@@ -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
- * Refreshes the fb_dtsg and jazoest values.
9
- * @param {Function} callback
10
- * @returns {Promise}
11
- * @description if you don't update the value of fb_dtsg and jazoest for a long time an error "Please try closing and re-opening your browser window" will appear
12
- * @description you should refresh it every 48h or less
13
- */
14
- return function refreshFb_dtsg(obj, callback) {
15
- let resolveFunc = function () { };
16
- let rejectFunc = function () { };
17
- const returnPromise = new Promise(function (resolve, reject) {
18
- resolveFunc = resolve;
19
- rejectFunc = reject;
20
- });
21
-
22
- if (utils.getType(obj) === "Function" || utils.getType(obj) === "AsyncFunction") {
23
- callback = obj;
24
- obj = {};
25
- }
26
-
27
- if (!obj) {
28
- obj = {};
29
- }
30
-
31
- if (utils.getType(obj) !== "Object") {
32
- throw new utils.CustomError("the first parameter must be an object or a callback function");
33
- }
34
-
35
- if (!callback) {
36
- callback = function (err, friendList) {
37
- if (err) {
38
- return rejectFunc(err);
39
- }
40
- resolveFunc(friendList);
41
- };
42
- }
43
-
44
- if (Object.keys(obj).length == 0) {
45
- utils
46
- .get('https://m.facebook.com/', ctx.jar, null, ctx.globalOptions, { noRef: true })
47
- .then(function (resData) {
48
- const html = resData.body;
49
- const fb_dtsg = utils.getFrom(html, 'name="fb_dtsg" value="', '"');
50
- const jazoest = utils.getFrom(html, 'name="jazoest" value="', '"');
51
- if (!fb_dtsg) {
52
- throw new utils.CustomError("Could not find fb_dtsg in HTML after requesting https://www.facebook.com/");
53
- }
54
- ctx.fb_dtsg = fb_dtsg;
55
- ctx.jazoest = jazoest;
56
- callback(null, {
57
- data: {
58
- fb_dtsg: fb_dtsg,
59
- jazoest: jazoest
60
- },
61
- message: "refreshed fb_dtsg and jazoest"
62
- });
63
- })
64
- .catch(function (err) {
65
- log.error("refreshFb_dtsg", err);
66
- return callback(err);
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 (retryCount == undefined) retryCount = 0;
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 bluebird.try(function () {
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
- error: "Request retry failed. Check the `res` and `statusCode` property on this error.",
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
- var retryTime = Math.floor(Math.random() * 5000);
1228
- log.warn("parseAndCheckLogin", "Got status code " + data.statusCode + " - " + retryCount + ". attempt to retry in " + retryTime + " milliseconds...");
1229
- var url = data.request.uri.protocol + "//" + data.request.uri.hostname + data.request.uri.pathname;
1230
- if (data.request.headers["Content-Type"].split(";")[0] === "multipart/form-data") return bluebird.delay(retryTime).then(() => defaultFuncs.postFormData(url, ctx.jar, data.request.formData, {})).then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
1231
- else return bluebird.delay(retryTime).then(() => defaultFuncs.post(url, ctx.jar, data.request.formData)).then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
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) throw new Error("parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.");
1234
-
1235
- var res = null;
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
- catch (e) {
1262
+ } catch (e) {
1263
+ log.error("JSON parsing failed:", data.body);
1240
1264
  throw {
1241
- error: "JSON.parse error. Check the `detail` property on this error.",
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
- // In some cases the response contains only a redirect URL which should be followed
1248
- if (res.redirect && data.request.method === "GET") return defaultFuncs.get(res.redirect, ctx.jar).then(parseAndCheckLogin(ctx, defaultFuncs));
1249
-
1250
- // TODO: handle multiple cookies?
1251
- if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
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
- var cookie = formatCookie(res.jsmods.require[0][3], "facebook");
1254
- var cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
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
- // On every request we check if we got a DTSG and we mutate the context so that we use the latest
1260
- // one for the next requests.
1261
- if (res.jsmods && Array.isArray(res.jsmods.require)) {
1262
- var arr = res.jsmods.require;
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
- if (res.error === 1357001) throw { error: "Not logged in." };
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
  };