stfca 1.0.27 → 1.1.27
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/checkUpdate.js +53 -49
- package/index.js +91 -15
- package/package.json +7 -8
- package/src/listenMqtt.js +394 -396
- package/src/sendMessage.js +292 -278
- package/src/sendMessageMqtt.js +0 -1
- package/src/uploadAttachment.js +99 -77
- package/utils.js +75 -13
package/src/uploadAttachment.js
CHANGED
|
@@ -1,93 +1,115 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const log = require("npmlog");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const mime = require("mime");
|
|
6
|
+
const { parseAndCheckLogin, isReadableStream, getType } = require("../utils");
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
const UPLOAD_URL = "https://www.facebook.com/ajax/mercury/upload.php";
|
|
9
|
+
|
|
10
|
+
function _filenameFromStream(stream, fallback) {
|
|
11
|
+
try {
|
|
12
|
+
if (stream && typeof stream.path === "string" && stream.path.length) {
|
|
13
|
+
return path.basename(stream.path);
|
|
14
|
+
}
|
|
15
|
+
if (stream && stream.path && typeof stream.path.toString === "function") {
|
|
16
|
+
return path.basename(stream.path.toString());
|
|
17
|
+
}
|
|
18
|
+
} catch (_) { }
|
|
19
|
+
return fallback || "upload.bin";
|
|
20
|
+
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
function _contentTypeFor(filename, stream) {
|
|
23
|
+
try {
|
|
24
|
+
if (stream && typeof stream._contentType === "string" && stream._contentType.length) {
|
|
25
|
+
return stream._contentType;
|
|
26
|
+
}
|
|
27
|
+
if (stream && stream.headers && typeof stream.headers["content-type"] === "string") {
|
|
28
|
+
return stream.headers["content-type"];
|
|
29
|
+
}
|
|
30
|
+
} catch (_) { }
|
|
31
|
+
const t = mime.getType(filename);
|
|
32
|
+
return t || "application/octet-stream";
|
|
33
|
+
}
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
36
|
+
function uploadOne(stream) {
|
|
37
|
+
if (!isReadableStream(stream)) {
|
|
38
|
+
return Promise.reject({
|
|
39
|
+
error: "Attachment should be a readable stream and not " + getType(stream) + "."
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const filename = _filenameFromStream(stream);
|
|
44
|
+
const contentType = _contentTypeFor(filename, stream);
|
|
45
|
+
|
|
46
|
+
const form = {
|
|
47
|
+
farr: {
|
|
48
|
+
value: stream,
|
|
49
|
+
options: {
|
|
50
|
+
filename: filename,
|
|
51
|
+
contentType: contentType
|
|
52
|
+
}
|
|
36
53
|
}
|
|
54
|
+
};
|
|
37
55
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
return defaultFuncs
|
|
57
|
+
.postFormData(UPLOAD_URL, ctx.jar, form, {})
|
|
58
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs))
|
|
59
|
+
.then(function (resData) {
|
|
60
|
+
if (resData.error) throw resData;
|
|
61
|
+
if (!resData.payload || !resData.payload.metadata) {
|
|
62
|
+
throw { error: "Mercury upload returned no metadata", res: resData };
|
|
63
|
+
}
|
|
64
|
+
const md = resData.payload.metadata[0] || resData.payload.metadata["0"];
|
|
65
|
+
if (!md) {
|
|
66
|
+
throw { error: "Mercury upload metadata[0] missing", res: resData };
|
|
67
|
+
}
|
|
68
|
+
return md;
|
|
69
|
+
});
|
|
43
70
|
}
|
|
44
71
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
72
|
+
function upload(attachments, callback) {
|
|
73
|
+
callback = callback || function () { };
|
|
74
|
+
Promise.all(attachments.map(uploadOne))
|
|
75
|
+
.then(function (resData) { callback(null, resData); })
|
|
76
|
+
.catch(function (err) {
|
|
77
|
+
log.error("uploadAttachment", err);
|
|
78
|
+
return callback(err);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
82
|
+
return function uploadAttachment(attachments, callback) {
|
|
83
|
+
if (
|
|
84
|
+
!attachments &&
|
|
85
|
+
!isReadableStream(attachments) &&
|
|
86
|
+
!getType(attachments) === "Array" &&
|
|
87
|
+
getType(attachments) === "Array" && !attachments.length
|
|
88
|
+
) {
|
|
89
|
+
throw { error: "Please pass an attachment or an array of attachments." };
|
|
90
|
+
}
|
|
65
91
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
let resolveFunc = function () { };
|
|
93
|
+
let rejectFunc = function () { };
|
|
94
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
95
|
+
resolveFunc = resolve;
|
|
96
|
+
rejectFunc = reject;
|
|
97
|
+
});
|
|
72
98
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
99
|
+
if (!callback) {
|
|
100
|
+
callback = function (err, info) {
|
|
101
|
+
if (err) return rejectFunc(err);
|
|
102
|
+
resolveFunc(info);
|
|
103
|
+
};
|
|
77
104
|
}
|
|
78
|
-
resolveFunc(info);
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
105
|
|
|
82
|
-
|
|
106
|
+
if (getType(attachments) !== "Array") attachments = [attachments];
|
|
83
107
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
callback(null, info);
|
|
89
|
-
});
|
|
108
|
+
upload(attachments, (err, info) => {
|
|
109
|
+
if (err) return callback(err);
|
|
110
|
+
callback(null, info);
|
|
111
|
+
});
|
|
90
112
|
|
|
91
|
-
|
|
92
|
-
|
|
113
|
+
return returnPromise;
|
|
114
|
+
};
|
|
93
115
|
};
|
package/utils.js
CHANGED
|
@@ -27,21 +27,83 @@ function setProxy(url) {
|
|
|
27
27
|
* @param {undefined} [customHeader]
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
+
function sanitizeHeaderValue(value) {
|
|
31
|
+
if (value === null || value === undefined) return "";
|
|
32
|
+
var str = String(value);
|
|
33
|
+
if (str.trim().startsWith("[") && str.trim().endsWith("]")) {
|
|
34
|
+
try {
|
|
35
|
+
var parsed = JSON.parse(str);
|
|
36
|
+
if (Array.isArray(parsed)) return "";
|
|
37
|
+
} catch (_) { }
|
|
38
|
+
}
|
|
39
|
+
str = str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n\[\]]/g, "").trim();
|
|
40
|
+
return str;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sanitizeHeaderName(name) {
|
|
44
|
+
if (!name || typeof name !== "string") return "";
|
|
45
|
+
return name.replace(/[^\x21-\x7E]/g, "").trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
function getHeaders(url, options, ctx, customHeader) {
|
|
49
|
+
options = options || {};
|
|
50
|
+
var host;
|
|
51
|
+
try { host = new URL(url).host; } catch (_) { host = url.replace("https://", "").split("/")[0]; }
|
|
52
|
+
var ua = options.userAgent ||
|
|
53
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15";
|
|
54
|
+
var referer = options.referer || "https://www.facebook.com/";
|
|
55
|
+
var origin = referer.replace(/\/+$/, "");
|
|
56
|
+
var contentType = options.contentType || "application/x-www-form-urlencoded";
|
|
57
|
+
var acceptLang = options.acceptLanguage || "en-US,en;q=0.9";
|
|
58
|
+
|
|
31
59
|
var headers = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
Host: sanitizeHeaderValue(host),
|
|
61
|
+
Origin: sanitizeHeaderValue(origin),
|
|
62
|
+
Referer: sanitizeHeaderValue(referer),
|
|
63
|
+
"User-Agent": sanitizeHeaderValue(ua),
|
|
64
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,application/json;q=0.8,*/*;q=0.7",
|
|
65
|
+
"Accept-Language": sanitizeHeaderValue(acceptLang),
|
|
66
|
+
"Accept-Encoding": "gzip, deflate",
|
|
67
|
+
"Content-Type": sanitizeHeaderValue(contentType),
|
|
37
68
|
Connection: "keep-alive",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
69
|
+
DNT: "1",
|
|
70
|
+
"Upgrade-Insecure-Requests": "1",
|
|
71
|
+
"sec-ch-ua": "\"Safari\";v=\"18\", \"Not;A=Brand\";v=\"24\"",
|
|
72
|
+
"sec-ch-ua-mobile": "?0",
|
|
73
|
+
"sec-ch-ua-platform": "\"macOS\"",
|
|
74
|
+
"Sec-Fetch-Site": "same-origin",
|
|
75
|
+
"Sec-Fetch-Mode": "cors",
|
|
76
|
+
"Sec-Fetch-Dest": "empty",
|
|
77
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
78
|
+
Pragma: "no-cache",
|
|
79
|
+
"Cache-Control": "no-cache"
|
|
40
80
|
};
|
|
41
|
-
if (customHeader) Object.assign(headers, customHeader);
|
|
42
|
-
if (ctx && ctx.region) headers["X-MSGR-Region"] = ctx.region;
|
|
43
81
|
|
|
44
|
-
|
|
82
|
+
if (ctx && ctx.region) {
|
|
83
|
+
var regionVal = sanitizeHeaderValue(ctx.region);
|
|
84
|
+
if (regionVal) headers["X-MSGR-Region"] = regionVal;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (customHeader && typeof customHeader === "object") {
|
|
88
|
+
for (var key in customHeader) {
|
|
89
|
+
if (!Object.prototype.hasOwnProperty.call(customHeader, key)) continue;
|
|
90
|
+
var val = customHeader[key];
|
|
91
|
+
if (val === null || val === undefined || typeof val === "function") continue;
|
|
92
|
+
if (typeof val === "object") continue;
|
|
93
|
+
var sk = sanitizeHeaderName(key);
|
|
94
|
+
var sv = sanitizeHeaderValue(val);
|
|
95
|
+
if (sk && sv !== "") headers[sk] = sv;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var sanitized = {};
|
|
100
|
+
for (var k in headers) {
|
|
101
|
+
if (!Object.prototype.hasOwnProperty.call(headers, k)) continue;
|
|
102
|
+
var sk2 = sanitizeHeaderName(k);
|
|
103
|
+
var sv2 = sanitizeHeaderValue(headers[k]);
|
|
104
|
+
if (sk2 && sv2 !== "") sanitized[sk2] = sv2;
|
|
105
|
+
}
|
|
106
|
+
return sanitized;
|
|
45
107
|
}
|
|
46
108
|
|
|
47
109
|
/**
|
|
@@ -2603,9 +2665,9 @@ function saveCookies(jar) {
|
|
|
2603
2665
|
return function (/** @type {{ headers: { [x: string]: any[]; }; }} */res) {
|
|
2604
2666
|
var cookies = res.headers["set-cookie"] || [];
|
|
2605
2667
|
cookies.forEach(function (/** @type {string} */c) {
|
|
2606
|
-
if (c.indexOf(".facebook.com") > -1) {
|
|
2607
|
-
jar.setCookie(c, "https://www.facebook.com");
|
|
2608
|
-
jar.setCookie(c.replace(/domain=\.facebook\.com/, "domain=.messenger.com"), "https://www.messenger.com");
|
|
2668
|
+
if (c.indexOf(".facebook.com") > -1) {
|
|
2669
|
+
try { jar.setCookie(c, "https://www.facebook.com"); } catch (_) { }
|
|
2670
|
+
try { jar.setCookie(c.replace(/domain=\.facebook\.com/, "domain=.messenger.com"), "https://www.messenger.com"); } catch (_) { }
|
|
2609
2671
|
}
|
|
2610
2672
|
});
|
|
2611
2673
|
return res;
|