alicezetion 1.8.8 → 1.9.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.
- package/index.js +69 -288
- package/leiamnash/listenMqtt.js +2 -3
- package/package.json +1 -2
- package/utils.js +1382 -1334
package/utils.js
CHANGED
@@ -1,1497 +1,1545 @@
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
1
2
|
"use strict";
|
2
3
|
|
3
|
-
|
4
|
-
let request = bluebird.promisify(require("request").defaults({ jar: true, proxy: process.env.FB_PROXY }));
|
4
|
+
let request = promisifyPromise(require("request").defaults({ jar: true, proxy: process.env.FB_PROXY }));
|
5
5
|
const stream = require("stream");
|
6
6
|
const log = require("npmlog");
|
7
7
|
const querystring = require("querystring");
|
8
8
|
const url = require("url");
|
9
9
|
|
10
10
|
class CustomError extends Error {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
constructor(obj) {
|
12
|
+
if (typeof obj === 'string')
|
13
|
+
obj = { message: obj };
|
14
|
+
if (typeof obj !== 'object' || obj === null)
|
15
|
+
throw new TypeError('Object required');
|
16
|
+
obj.message ? super(obj.message) : super();
|
17
|
+
Object.assign(this, obj);
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
function callbackToPromise(func) {
|
22
|
+
return function (...args) {
|
23
|
+
return new Promise((resolve, reject) => {
|
24
|
+
func(...args, (err, data) => {
|
25
|
+
if (err)
|
26
|
+
reject(err);
|
27
|
+
else
|
28
|
+
resolve(data);
|
29
|
+
});
|
30
|
+
});
|
31
|
+
};
|
32
|
+
}
|
33
|
+
|
34
|
+
function isHasCallback(func) {
|
35
|
+
if (typeof func !== "function")
|
36
|
+
return false;
|
37
|
+
return func.toString().split("\n")[0].match(/(callback|cb)\s*\)/) !== null;
|
38
|
+
}
|
39
|
+
|
40
|
+
// replace for bluebird.promisify (but this only applies best to the `request` package)
|
41
|
+
function promisifyPromise(promise) {
|
42
|
+
const keys = Object.keys(promise);
|
43
|
+
let promise_;
|
44
|
+
if (
|
45
|
+
typeof promise === "function"
|
46
|
+
&& isHasCallback(promise)
|
47
|
+
)
|
48
|
+
promise_ = callbackToPromise(promise);
|
49
|
+
else
|
50
|
+
promise_ = promise;
|
51
|
+
|
52
|
+
for (const key of keys) {
|
53
|
+
if (!promise[key]?.toString)
|
54
|
+
continue;
|
55
|
+
|
56
|
+
if (
|
57
|
+
typeof promise[key] === "function"
|
58
|
+
&& isHasCallback(promise[key])
|
59
|
+
) {
|
60
|
+
promise_[key] = callbackToPromise(promise[key]);
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
promise_[key] = promise[key];
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
return promise_;
|
68
|
+
}
|
69
|
+
|
70
|
+
// replace for bluebird.delay
|
71
|
+
function delay(ms) {
|
72
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
73
|
+
}
|
74
|
+
|
75
|
+
// replace for bluebird.try
|
76
|
+
function tryPromise(tryFunc) {
|
77
|
+
return new Promise((resolve, reject) => {
|
78
|
+
try {
|
79
|
+
resolve(tryFunc());
|
80
|
+
} catch (error) {
|
81
|
+
reject(error);
|
82
|
+
}
|
83
|
+
});
|
19
84
|
}
|
20
85
|
|
21
86
|
function setProxy(url) {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
87
|
+
if (typeof url == "undefined")
|
88
|
+
return request = promisifyPromise(require("request").defaults({
|
89
|
+
jar: true
|
90
|
+
}));
|
91
|
+
return request = promisifyPromise(require("request").defaults({
|
92
|
+
jar: true,
|
93
|
+
proxy: url
|
94
|
+
}));
|
30
95
|
}
|
31
96
|
|
32
97
|
function getHeaders(url, options, ctx, customHeader) {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
98
|
+
const headers = {
|
99
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
100
|
+
Referer: "https://www.facebook.com/",
|
101
|
+
Host: url.replace("https://", "").split("/")[0],
|
102
|
+
Origin: "https://www.facebook.com",
|
103
|
+
"User-Agent": options.userAgent,
|
104
|
+
Connection: "keep-alive",
|
105
|
+
"sec-fetch-site": "same-origin"
|
106
|
+
};
|
107
|
+
if (customHeader) {
|
108
|
+
Object.assign(headers, customHeader);
|
109
|
+
}
|
110
|
+
if (ctx && ctx.region) {
|
111
|
+
headers["X-MSGR-Region"] = ctx.region;
|
112
|
+
}
|
113
|
+
|
114
|
+
return headers;
|
50
115
|
}
|
51
116
|
|
52
117
|
function isReadableStream(obj) {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
118
|
+
return (
|
119
|
+
obj instanceof stream.Stream &&
|
120
|
+
(getType(obj._read) === "Function" ||
|
121
|
+
getType(obj._read) === "AsyncFunction") &&
|
122
|
+
getType(obj._readableState) === "Object"
|
123
|
+
);
|
59
124
|
}
|
60
125
|
|
61
126
|
function get(url, jar, qs, options, ctx) {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
127
|
+
// I'm still confused about this
|
128
|
+
if (getType(qs) === "Object") {
|
129
|
+
for (const prop in qs) {
|
130
|
+
if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") {
|
131
|
+
qs[prop] = JSON.stringify(qs[prop]);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
const op = {
|
136
|
+
headers: getHeaders(url, options, ctx),
|
137
|
+
timeout: 60000,
|
138
|
+
qs: qs,
|
139
|
+
url: url,
|
140
|
+
method: "GET",
|
141
|
+
jar: jar,
|
142
|
+
gzip: true
|
143
|
+
};
|
144
|
+
|
145
|
+
return request(op).then(function (res) {
|
146
|
+
return Array.isArray(res) ? res[0] : res;
|
147
|
+
});
|
83
148
|
}
|
84
149
|
|
85
150
|
function post(url, jar, form, options, ctx, customHeader) {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
151
|
+
const op = {
|
152
|
+
headers: getHeaders(url, options, ctx, customHeader),
|
153
|
+
timeout: 60000,
|
154
|
+
url: url,
|
155
|
+
method: "POST",
|
156
|
+
form: form,
|
157
|
+
jar: jar,
|
158
|
+
gzip: true
|
159
|
+
};
|
160
|
+
|
161
|
+
return request(op).then(function (res) {
|
162
|
+
return Array.isArray(res) ? res[0] : res;
|
163
|
+
});
|
99
164
|
}
|
100
165
|
|
101
166
|
function postFormData(url, jar, form, qs, options, ctx) {
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
167
|
+
const headers = getHeaders(url, options, ctx);
|
168
|
+
headers["Content-Type"] = "multipart/form-data";
|
169
|
+
const op = {
|
170
|
+
headers: headers,
|
171
|
+
timeout: 60000,
|
172
|
+
url: url,
|
173
|
+
method: "POST",
|
174
|
+
formData: form,
|
175
|
+
qs: qs,
|
176
|
+
jar: jar,
|
177
|
+
gzip: true
|
178
|
+
};
|
179
|
+
|
180
|
+
return request(op).then(function (res) {
|
181
|
+
return Array.isArray(res) ? res[0] : res;
|
182
|
+
});
|
118
183
|
}
|
119
184
|
|
120
185
|
function padZeros(val, len) {
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
186
|
+
val = String(val);
|
187
|
+
len = len || 2;
|
188
|
+
while (val.length < len) val = "0" + val;
|
189
|
+
return val;
|
125
190
|
}
|
126
191
|
|
127
192
|
function generateThreadingID(clientID) {
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
193
|
+
const k = Date.now();
|
194
|
+
const l = Math.floor(Math.random() * 4294967295);
|
195
|
+
const m = clientID;
|
196
|
+
return "<" + k + ":" + l + "-" + m + "@mail.projektitan.com>";
|
132
197
|
}
|
133
198
|
|
134
199
|
function binaryToDecimal(data) {
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
200
|
+
let ret = "";
|
201
|
+
while (data !== "0") {
|
202
|
+
let end = 0;
|
203
|
+
let fullName = "";
|
204
|
+
let i = 0;
|
205
|
+
for (; i < data.length; i++) {
|
206
|
+
end = 2 * end + parseInt(data[i], 10);
|
207
|
+
if (end >= 10) {
|
208
|
+
fullName += "1";
|
209
|
+
end -= 10;
|
210
|
+
}
|
211
|
+
else {
|
212
|
+
fullName += "0";
|
213
|
+
}
|
214
|
+
}
|
215
|
+
ret = end.toString() + ret;
|
216
|
+
data = fullName.slice(fullName.indexOf("1"));
|
217
|
+
}
|
218
|
+
return ret;
|
154
219
|
}
|
155
220
|
|
156
221
|
function generateOfflineThreadingID() {
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
222
|
+
const ret = Date.now();
|
223
|
+
const value = Math.floor(Math.random() * 4294967295);
|
224
|
+
const str = ("0000000000000000000000" + value.toString(2)).slice(-22);
|
225
|
+
const msgs = ret.toString(2) + str;
|
226
|
+
return binaryToDecimal(msgs);
|
162
227
|
}
|
163
228
|
|
164
229
|
let h;
|
165
230
|
const i = {};
|
166
231
|
const j = {
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
232
|
+
_: "%",
|
233
|
+
A: "%2",
|
234
|
+
B: "000",
|
235
|
+
C: "%7d",
|
236
|
+
D: "%7b%22",
|
237
|
+
E: "%2c%22",
|
238
|
+
F: "%22%3a",
|
239
|
+
G: "%2c%22ut%22%3a1",
|
240
|
+
H: "%2c%22bls%22%3a",
|
241
|
+
I: "%2c%22n%22%3a%22%",
|
242
|
+
J: "%22%3a%7b%22i%22%3a0%7d",
|
243
|
+
K: "%2c%22pt%22%3a0%2c%22vis%22%3a",
|
244
|
+
L: "%2c%22ch%22%3a%7b%22h%22%3a%22",
|
245
|
+
M: "%7b%22v%22%3a2%2c%22time%22%3a1",
|
246
|
+
N: ".channel%22%2c%22sub%22%3a%5b",
|
247
|
+
O: "%2c%22sb%22%3a1%2c%22t%22%3a%5b",
|
248
|
+
P: "%2c%22ud%22%3a100%2c%22lc%22%3a0",
|
249
|
+
Q: "%5d%2c%22f%22%3anull%2c%22uct%22%3a",
|
250
|
+
R: ".channel%22%2c%22sub%22%3a%5b1%5d",
|
251
|
+
S: "%22%2c%22m%22%3a0%7d%2c%7b%22i%22%3a",
|
252
|
+
T: "%2c%22blc%22%3a1%2c%22snd%22%3a1%2c%22ct%22%3a",
|
253
|
+
U: "%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
|
254
|
+
V: "%2c%22blc%22%3a0%2c%22snd%22%3a0%2c%22ct%22%3a",
|
255
|
+
W: "%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a",
|
256
|
+
X: "%2c%22ri%22%3a0%7d%2c%22state%22%3a%7b%22p%22%3a0%2c%22ut%22%3a1",
|
257
|
+
Y:
|
258
|
+
"%2c%22pt%22%3a0%2c%22vis%22%3a1%2c%22bls%22%3a0%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
|
259
|
+
Z:
|
260
|
+
"%2c%22sb%22%3a1%2c%22t%22%3a%5b%5d%2c%22f%22%3anull%2c%22uct%22%3a0%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a"
|
196
261
|
};
|
197
262
|
(function () {
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
263
|
+
const l = [];
|
264
|
+
for (const m in j) {
|
265
|
+
i[j[m]] = m;
|
266
|
+
l.push(j[m]);
|
267
|
+
}
|
268
|
+
l.reverse();
|
269
|
+
h = new RegExp(l.join("|"), "g");
|
205
270
|
})();
|
206
271
|
|
207
272
|
function presenceEncode(str) {
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
273
|
+
return encodeURIComponent(str)
|
274
|
+
.replace(/([_A-Z])|%../g, function (m, n) {
|
275
|
+
return n ? "%" + n.charCodeAt(0).toString(16) : m;
|
276
|
+
})
|
277
|
+
.toLowerCase()
|
278
|
+
.replace(h, function (m) {
|
279
|
+
return i[m];
|
280
|
+
});
|
216
281
|
}
|
217
282
|
|
218
283
|
// eslint-disable-next-line no-unused-vars
|
219
284
|
function presenceDecode(str) {
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
285
|
+
return decodeURIComponent(
|
286
|
+
str.replace(/[_A-Z]/g, function (m) {
|
287
|
+
return j[m];
|
288
|
+
})
|
289
|
+
);
|
225
290
|
}
|
226
291
|
|
227
292
|
function generatePresence(userID) {
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
293
|
+
const time = Date.now();
|
294
|
+
return (
|
295
|
+
"E" +
|
296
|
+
presenceEncode(
|
297
|
+
JSON.stringify({
|
298
|
+
v: 3,
|
299
|
+
time: parseInt(time / 1000, 10),
|
300
|
+
user: userID,
|
301
|
+
state: {
|
302
|
+
ut: 0,
|
303
|
+
t2: [],
|
304
|
+
lm2: null,
|
305
|
+
uct2: time,
|
306
|
+
tr: null,
|
307
|
+
tw: Math.floor(Math.random() * 4294967295) + 1,
|
308
|
+
at: time
|
309
|
+
},
|
310
|
+
ch: {
|
311
|
+
["p_" + userID]: 0
|
312
|
+
}
|
313
|
+
})
|
314
|
+
)
|
315
|
+
);
|
251
316
|
}
|
252
317
|
|
253
318
|
function generateAccessiblityCookie() {
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
319
|
+
const time = Date.now();
|
320
|
+
return encodeURIComponent(
|
321
|
+
JSON.stringify({
|
322
|
+
sr: 0,
|
323
|
+
"sr-ts": time,
|
324
|
+
jk: 0,
|
325
|
+
"jk-ts": time,
|
326
|
+
kb: 0,
|
327
|
+
"kb-ts": time,
|
328
|
+
hcm: 0,
|
329
|
+
"hcm-ts": time
|
330
|
+
})
|
331
|
+
);
|
267
332
|
}
|
268
333
|
|
269
334
|
function getGUID() {
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
335
|
+
/** @type {number} */
|
336
|
+
let sectionLength = Date.now();
|
337
|
+
/** @type {string} */
|
338
|
+
const id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
339
|
+
/** @type {number} */
|
340
|
+
const r = Math.floor((sectionLength + Math.random() * 16) % 16);
|
341
|
+
/** @type {number} */
|
342
|
+
sectionLength = Math.floor(sectionLength / 16);
|
343
|
+
/** @type {string} */
|
344
|
+
const _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
|
345
|
+
return _guid;
|
346
|
+
});
|
347
|
+
return id;
|
283
348
|
}
|
284
349
|
|
285
350
|
function getExtension(original_extension, fullFileName = "") {
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
351
|
+
if (original_extension) {
|
352
|
+
return original_extension;
|
353
|
+
}
|
354
|
+
else {
|
355
|
+
const extension = fullFileName.split(".").pop();
|
356
|
+
if (extension === fullFileName) {
|
357
|
+
return "";
|
358
|
+
}
|
359
|
+
else {
|
360
|
+
return extension;
|
361
|
+
}
|
362
|
+
}
|
298
363
|
}
|
299
364
|
|
300
365
|
function _formatAttachment(attachment1, attachment2) {
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
366
|
+
// TODO: THIS IS REALLY BAD
|
367
|
+
// This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
|
368
|
+
// two attachment objects, but sometimes only one. They each contain part of the
|
369
|
+
// data that you'd want so we merge them for convenience.
|
370
|
+
// Instead of having a bunch of if statements guarding every access to image_data,
|
371
|
+
// we set it to empty object and use the fact that it'll return undefined.
|
372
|
+
const fullFileName = attachment1.filename;
|
373
|
+
const fileSize = Number(attachment1.fileSize || 0);
|
374
|
+
const durationVideo = attachment1.genericMetadata ? Number(attachment1.genericMetadata.videoLength) : undefined;
|
375
|
+
const durationAudio = attachment1.genericMetadata ? Number(attachment1.genericMetadata.duration) : undefined;
|
376
|
+
const mimeType = attachment1.mimeType;
|
377
|
+
|
378
|
+
attachment2 = attachment2 || { id: "", image_data: {} };
|
379
|
+
attachment1 = attachment1.mercury || attachment1;
|
380
|
+
let blob = attachment1.blob_attachment || attachment1.sticker_attachment;
|
381
|
+
let type =
|
382
|
+
blob && blob.__typename ? blob.__typename : attachment1.attach_type;
|
383
|
+
if (!type && attachment1.sticker_attachment) {
|
384
|
+
type = "StickerAttachment";
|
385
|
+
blob = attachment1.sticker_attachment;
|
386
|
+
}
|
387
|
+
else if (!type && attachment1.extensible_attachment) {
|
388
|
+
if (
|
389
|
+
attachment1.extensible_attachment.story_attachment &&
|
390
|
+
attachment1.extensible_attachment.story_attachment.target &&
|
391
|
+
attachment1.extensible_attachment.story_attachment.target.__typename &&
|
392
|
+
attachment1.extensible_attachment.story_attachment.target.__typename === "MessageLocation"
|
393
|
+
) {
|
394
|
+
type = "MessageLocation";
|
395
|
+
}
|
396
|
+
else {
|
397
|
+
type = "ExtensibleAttachment";
|
398
|
+
}
|
399
|
+
|
400
|
+
blob = attachment1.extensible_attachment;
|
401
|
+
}
|
402
|
+
// TODO: Determine whether "sticker", "photo", "file" etc are still used
|
403
|
+
// KEEP IN SYNC WITH getThreadHistory
|
404
|
+
switch (type) {
|
405
|
+
case "sticker":
|
406
|
+
return {
|
407
|
+
type: "sticker",
|
408
|
+
ID: attachment1.metadata.stickerID.toString(),
|
409
|
+
url: attachment1.url,
|
410
|
+
|
411
|
+
packID: attachment1.metadata.packID.toString(),
|
412
|
+
spriteUrl: attachment1.metadata.spriteURI,
|
413
|
+
spriteUrl2x: attachment1.metadata.spriteURI2x,
|
414
|
+
width: attachment1.metadata.width,
|
415
|
+
height: attachment1.metadata.height,
|
416
|
+
|
417
|
+
caption: attachment2.caption,
|
418
|
+
description: attachment2.description,
|
419
|
+
|
420
|
+
frameCount: attachment1.metadata.frameCount,
|
421
|
+
frameRate: attachment1.metadata.frameRate,
|
422
|
+
framesPerRow: attachment1.metadata.framesPerRow,
|
423
|
+
framesPerCol: attachment1.metadata.framesPerCol,
|
424
|
+
|
425
|
+
stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
|
426
|
+
spriteURI: attachment1.metadata.spriteURI, // @Legacy
|
427
|
+
spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
|
428
|
+
};
|
429
|
+
case "file":
|
430
|
+
return {
|
431
|
+
type: "file",
|
432
|
+
ID: attachment2.id.toString(),
|
433
|
+
fullFileName: fullFileName,
|
434
|
+
filename: attachment1.name,
|
435
|
+
fileSize: fileSize,
|
436
|
+
original_extension: getExtension(attachment1.original_extension, fullFileName),
|
437
|
+
mimeType: mimeType,
|
438
|
+
url: attachment1.url,
|
439
|
+
|
440
|
+
isMalicious: attachment2.is_malicious,
|
441
|
+
contentType: attachment2.mime_type,
|
442
|
+
|
443
|
+
name: attachment1.name // @Legacy
|
444
|
+
};
|
445
|
+
case "photo":
|
446
|
+
return {
|
447
|
+
type: "photo",
|
448
|
+
ID: attachment1.metadata.fbid.toString(),
|
449
|
+
filename: attachment1.fileName,
|
450
|
+
fullFileName: fullFileName,
|
451
|
+
fileSize: fileSize,
|
452
|
+
original_extension: getExtension(attachment1.original_extension, fullFileName),
|
453
|
+
mimeType: mimeType,
|
454
|
+
thumbnailUrl: attachment1.thumbnail_url,
|
455
|
+
|
456
|
+
previewUrl: attachment1.preview_url,
|
457
|
+
previewWidth: attachment1.preview_width,
|
458
|
+
previewHeight: attachment1.preview_height,
|
459
|
+
|
460
|
+
largePreviewUrl: attachment1.large_preview_url,
|
461
|
+
largePreviewWidth: attachment1.large_preview_width,
|
462
|
+
largePreviewHeight: attachment1.large_preview_height,
|
463
|
+
|
464
|
+
url: attachment1.metadata.url, // @Legacy
|
465
|
+
width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
|
466
|
+
height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
|
467
|
+
name: fullFileName // @Legacy
|
468
|
+
};
|
469
|
+
case "animated_image":
|
470
|
+
return {
|
471
|
+
type: "animated_image",
|
472
|
+
ID: attachment2.id.toString(),
|
473
|
+
filename: attachment2.filename,
|
474
|
+
fullFileName: fullFileName,
|
475
|
+
original_extension: getExtension(attachment2.original_extension, fullFileName),
|
476
|
+
mimeType: mimeType,
|
477
|
+
|
478
|
+
previewUrl: attachment1.preview_url,
|
479
|
+
previewWidth: attachment1.preview_width,
|
480
|
+
previewHeight: attachment1.preview_height,
|
481
|
+
|
482
|
+
url: attachment2.image_data.url,
|
483
|
+
width: attachment2.image_data.width,
|
484
|
+
height: attachment2.image_data.height,
|
485
|
+
|
486
|
+
name: attachment1.name, // @Legacy
|
487
|
+
facebookUrl: attachment1.url, // @Legacy
|
488
|
+
thumbnailUrl: attachment1.thumbnail_url, // @Legacy
|
489
|
+
rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
|
490
|
+
rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
|
491
|
+
animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
|
492
|
+
animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
|
493
|
+
animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
|
494
|
+
animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
|
495
|
+
};
|
496
|
+
case "share":
|
497
|
+
return {
|
498
|
+
type: "share",
|
499
|
+
ID: attachment1.share.share_id.toString(),
|
500
|
+
url: attachment2.href,
|
501
|
+
|
502
|
+
title: attachment1.share.title,
|
503
|
+
description: attachment1.share.description,
|
504
|
+
source: attachment1.share.source,
|
505
|
+
|
506
|
+
image: attachment1.share.media.image,
|
507
|
+
width: attachment1.share.media.image_size.width,
|
508
|
+
height: attachment1.share.media.image_size.height,
|
509
|
+
playable: attachment1.share.media.playable,
|
510
|
+
duration: attachment1.share.media.duration,
|
511
|
+
|
512
|
+
subattachments: attachment1.share.subattachments,
|
513
|
+
properties: {},
|
514
|
+
|
515
|
+
animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
|
516
|
+
facebookUrl: attachment1.share.uri, // @Legacy
|
517
|
+
target: attachment1.share.target, // @Legacy
|
518
|
+
styleList: attachment1.share.style_list // @Legacy
|
519
|
+
};
|
520
|
+
case "video":
|
521
|
+
return {
|
522
|
+
type: "video",
|
523
|
+
ID: attachment1.metadata.fbid.toString(),
|
524
|
+
filename: attachment1.name,
|
525
|
+
fullFileName: fullFileName,
|
526
|
+
original_extension: getExtension(attachment1.original_extension, fullFileName),
|
527
|
+
mimeType: mimeType,
|
528
|
+
duration: durationVideo,
|
529
|
+
|
530
|
+
previewUrl: attachment1.preview_url,
|
531
|
+
previewWidth: attachment1.preview_width,
|
532
|
+
previewHeight: attachment1.preview_height,
|
533
|
+
|
534
|
+
url: attachment1.url,
|
535
|
+
width: attachment1.metadata.dimensions.width,
|
536
|
+
height: attachment1.metadata.dimensions.height,
|
537
|
+
|
538
|
+
videoType: "unknown",
|
539
|
+
|
540
|
+
thumbnailUrl: attachment1.thumbnail_url // @Legacy
|
541
|
+
};
|
542
|
+
case "error":
|
543
|
+
return {
|
544
|
+
type: "error",
|
545
|
+
|
546
|
+
// Save error attachments because we're unsure of their format,
|
547
|
+
// and whether there are cases they contain something useful for debugging.
|
548
|
+
attachment1: attachment1,
|
549
|
+
attachment2: attachment2
|
550
|
+
};
|
551
|
+
case "MessageImage":
|
552
|
+
return {
|
553
|
+
type: "photo",
|
554
|
+
ID: blob.legacy_attachment_id,
|
555
|
+
filename: blob.filename,
|
556
|
+
fullFileName: fullFileName,
|
557
|
+
fileSize: fileSize,
|
558
|
+
original_extension: getExtension(blob.original_extension, fullFileName),
|
559
|
+
mimeType: mimeType,
|
560
|
+
thumbnailUrl: blob.thumbnail.uri,
|
561
|
+
|
562
|
+
previewUrl: blob.preview.uri,
|
563
|
+
previewWidth: blob.preview.width,
|
564
|
+
previewHeight: blob.preview.height,
|
565
|
+
|
566
|
+
largePreviewUrl: blob.large_preview.uri,
|
567
|
+
largePreviewWidth: blob.large_preview.width,
|
568
|
+
largePreviewHeight: blob.large_preview.height,
|
569
|
+
|
570
|
+
url: blob.large_preview.uri, // @Legacy
|
571
|
+
width: blob.original_dimensions.x, // @Legacy
|
572
|
+
height: blob.original_dimensions.y, // @Legacy
|
573
|
+
name: blob.filename // @Legacy
|
574
|
+
};
|
575
|
+
case "MessageAnimatedImage":
|
576
|
+
return {
|
577
|
+
type: "animated_image",
|
578
|
+
ID: blob.legacy_attachment_id,
|
579
|
+
filename: blob.filename,
|
580
|
+
fullFileName: fullFileName,
|
581
|
+
original_extension: getExtension(blob.original_extension, fullFileName),
|
582
|
+
mimeType: mimeType,
|
583
|
+
|
584
|
+
previewUrl: blob.preview_image.uri,
|
585
|
+
previewWidth: blob.preview_image.width,
|
586
|
+
previewHeight: blob.preview_image.height,
|
587
|
+
|
588
|
+
url: blob.animated_image.uri,
|
589
|
+
width: blob.animated_image.width,
|
590
|
+
height: blob.animated_image.height,
|
591
|
+
|
592
|
+
thumbnailUrl: blob.preview_image.uri, // @Legacy
|
593
|
+
name: blob.filename, // @Legacy
|
594
|
+
facebookUrl: blob.animated_image.uri, // @Legacy
|
595
|
+
rawGifImage: blob.animated_image.uri, // @Legacy
|
596
|
+
animatedGifUrl: blob.animated_image.uri, // @Legacy
|
597
|
+
animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
|
598
|
+
animatedWebpUrl: blob.animated_image.uri, // @Legacy
|
599
|
+
animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
|
600
|
+
};
|
601
|
+
case "MessageVideo":
|
602
|
+
return {
|
603
|
+
type: "video",
|
604
|
+
ID: blob.legacy_attachment_id,
|
605
|
+
filename: blob.filename,
|
606
|
+
fullFileName: fullFileName,
|
607
|
+
original_extension: getExtension(blob.original_extension, fullFileName),
|
608
|
+
fileSize: fileSize,
|
609
|
+
duration: durationVideo,
|
610
|
+
mimeType: mimeType,
|
611
|
+
|
612
|
+
previewUrl: blob.large_image.uri,
|
613
|
+
previewWidth: blob.large_image.width,
|
614
|
+
previewHeight: blob.large_image.height,
|
615
|
+
|
616
|
+
url: blob.playable_url,
|
617
|
+
width: blob.original_dimensions.x,
|
618
|
+
height: blob.original_dimensions.y,
|
619
|
+
|
620
|
+
videoType: blob.video_type.toLowerCase(),
|
621
|
+
|
622
|
+
thumbnailUrl: blob.large_image.uri // @Legacy
|
623
|
+
};
|
624
|
+
case "MessageAudio":
|
625
|
+
return {
|
626
|
+
type: "audio",
|
627
|
+
ID: blob.url_shimhash,
|
628
|
+
filename: blob.filename,
|
629
|
+
fullFileName: fullFileName,
|
630
|
+
fileSize: fileSize,
|
631
|
+
duration: durationAudio,
|
632
|
+
original_extension: getExtension(blob.original_extension, fullFileName),
|
633
|
+
mimeType: mimeType,
|
634
|
+
|
635
|
+
audioType: blob.audio_type,
|
636
|
+
url: blob.playable_url,
|
637
|
+
|
638
|
+
isVoiceMail: blob.is_voicemail
|
639
|
+
};
|
640
|
+
case "StickerAttachment":
|
641
|
+
case "Sticker":
|
642
|
+
return {
|
643
|
+
type: "sticker",
|
644
|
+
ID: blob.id,
|
645
|
+
url: blob.url,
|
646
|
+
|
647
|
+
packID: blob.pack ? blob.pack.id : null,
|
648
|
+
spriteUrl: blob.sprite_image,
|
649
|
+
spriteUrl2x: blob.sprite_image_2x,
|
650
|
+
width: blob.width,
|
651
|
+
height: blob.height,
|
652
|
+
|
653
|
+
caption: blob.label,
|
654
|
+
description: blob.label,
|
655
|
+
|
656
|
+
frameCount: blob.frame_count,
|
657
|
+
frameRate: blob.frame_rate,
|
658
|
+
framesPerRow: blob.frames_per_row,
|
659
|
+
framesPerCol: blob.frames_per_column,
|
660
|
+
|
661
|
+
stickerID: blob.id, // @Legacy
|
662
|
+
spriteURI: blob.sprite_image, // @Legacy
|
663
|
+
spriteURI2x: blob.sprite_image_2x // @Legacy
|
664
|
+
};
|
665
|
+
case "MessageLocation":
|
666
|
+
var urlAttach = blob.story_attachment.url;
|
667
|
+
var mediaAttach = blob.story_attachment.media;
|
668
|
+
|
669
|
+
var u = querystring.parse(url.parse(urlAttach).query).u;
|
670
|
+
var where1 = querystring.parse(url.parse(u).query).where1;
|
671
|
+
var address = where1.split(", ");
|
672
|
+
|
673
|
+
var latitude;
|
674
|
+
var longitude;
|
675
|
+
|
676
|
+
try {
|
677
|
+
latitude = Number.parseFloat(address[0]);
|
678
|
+
longitude = Number.parseFloat(address[1]);
|
679
|
+
} catch (err) {
|
680
|
+
/* empty */
|
681
|
+
}
|
682
|
+
|
683
|
+
var imageUrl;
|
684
|
+
var width;
|
685
|
+
var height;
|
686
|
+
|
687
|
+
if (mediaAttach && mediaAttach.image) {
|
688
|
+
imageUrl = mediaAttach.image.uri;
|
689
|
+
width = mediaAttach.image.width;
|
690
|
+
height = mediaAttach.image.height;
|
691
|
+
}
|
692
|
+
|
693
|
+
return {
|
694
|
+
type: "location",
|
695
|
+
ID: blob.legacy_attachment_id,
|
696
|
+
latitude: latitude,
|
697
|
+
longitude: longitude,
|
698
|
+
image: imageUrl,
|
699
|
+
width: width,
|
700
|
+
height: height,
|
701
|
+
url: u || urlAttach,
|
702
|
+
address: where1,
|
703
|
+
|
704
|
+
facebookUrl: blob.story_attachment.url, // @Legacy
|
705
|
+
target: blob.story_attachment.target, // @Legacy
|
706
|
+
styleList: blob.story_attachment.style_list // @Legacy
|
707
|
+
};
|
708
|
+
case "ExtensibleAttachment":
|
709
|
+
return {
|
710
|
+
type: "share",
|
711
|
+
ID: blob.legacy_attachment_id,
|
712
|
+
url: blob.story_attachment.url,
|
713
|
+
|
714
|
+
title: blob.story_attachment.title_with_entities.text,
|
715
|
+
description:
|
716
|
+
blob.story_attachment.description &&
|
717
|
+
blob.story_attachment.description.text,
|
718
|
+
source: blob.story_attachment.source
|
719
|
+
? blob.story_attachment.source.text
|
720
|
+
: null,
|
721
|
+
|
722
|
+
image:
|
723
|
+
blob.story_attachment.media &&
|
724
|
+
blob.story_attachment.media.image &&
|
725
|
+
blob.story_attachment.media.image.uri,
|
726
|
+
width:
|
727
|
+
blob.story_attachment.media &&
|
728
|
+
blob.story_attachment.media.image &&
|
729
|
+
blob.story_attachment.media.image.width,
|
730
|
+
height:
|
731
|
+
blob.story_attachment.media &&
|
732
|
+
blob.story_attachment.media.image &&
|
733
|
+
blob.story_attachment.media.image.height,
|
734
|
+
playable:
|
735
|
+
blob.story_attachment.media &&
|
736
|
+
blob.story_attachment.media.is_playable,
|
737
|
+
duration:
|
738
|
+
blob.story_attachment.media &&
|
739
|
+
blob.story_attachment.media.playable_duration_in_ms,
|
740
|
+
playableUrl:
|
741
|
+
blob.story_attachment.media == null
|
742
|
+
? null
|
743
|
+
: blob.story_attachment.media.playable_url,
|
744
|
+
|
745
|
+
subattachments: blob.story_attachment.subattachments,
|
746
|
+
properties: blob.story_attachment.properties.reduce(function (obj, cur) {
|
747
|
+
obj[cur.key] = cur.value.text;
|
748
|
+
return obj;
|
749
|
+
}, {}),
|
750
|
+
|
751
|
+
facebookUrl: blob.story_attachment.url, // @Legacy
|
752
|
+
target: blob.story_attachment.target, // @Legacy
|
753
|
+
styleList: blob.story_attachment.style_list // @Legacy
|
754
|
+
};
|
755
|
+
case "MessageFile":
|
756
|
+
return {
|
757
|
+
type: "file",
|
758
|
+
ID: blob.message_file_fbid,
|
759
|
+
fullFileName: fullFileName,
|
760
|
+
filename: blob.filename,
|
761
|
+
fileSize: fileSize,
|
762
|
+
mimeType: blob.mimetype,
|
763
|
+
original_extension: blob.original_extension || fullFileName.split(".").pop(),
|
764
|
+
|
765
|
+
url: blob.url,
|
766
|
+
isMalicious: blob.is_malicious,
|
767
|
+
contentType: blob.content_type,
|
768
|
+
|
769
|
+
name: blob.filename
|
770
|
+
};
|
771
|
+
default:
|
772
|
+
throw new Error(
|
773
|
+
"unrecognized attach_file of type " +
|
774
|
+
type +
|
775
|
+
"`" +
|
776
|
+
JSON.stringify(attachment1, null, 4) +
|
777
|
+
" attachment2: " +
|
778
|
+
JSON.stringify(attachment2, null, 4) +
|
779
|
+
"`"
|
780
|
+
);
|
781
|
+
}
|
717
782
|
}
|
718
783
|
|
719
784
|
function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
785
|
+
attachmentMap = shareMap || attachmentMap;
|
786
|
+
return attachments
|
787
|
+
? attachments.map(function (val, i) {
|
788
|
+
if (
|
789
|
+
!attachmentMap ||
|
790
|
+
!attachmentIds ||
|
791
|
+
!attachmentMap[attachmentIds[i]]
|
792
|
+
) {
|
793
|
+
return _formatAttachment(val);
|
794
|
+
}
|
795
|
+
return _formatAttachment(val, attachmentMap[attachmentIds[i]]);
|
796
|
+
})
|
797
|
+
: [];
|
733
798
|
}
|
734
799
|
|
735
800
|
function formatDeltaMessage(m) {
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
801
|
+
const md = m.delta.messageMetadata;
|
802
|
+
|
803
|
+
const mdata =
|
804
|
+
m.delta.data === undefined
|
805
|
+
? []
|
806
|
+
: m.delta.data.prng === undefined
|
807
|
+
? []
|
808
|
+
: JSON.parse(m.delta.data.prng);
|
809
|
+
const m_id = mdata.map(u => u.i);
|
810
|
+
const m_offset = mdata.map(u => u.o);
|
811
|
+
const m_length = mdata.map(u => u.l);
|
812
|
+
const mentions = {};
|
813
|
+
for (let i = 0; i < m_id.length; i++) {
|
814
|
+
mentions[m_id[i]] = m.delta.body.substring(
|
815
|
+
m_offset[i],
|
816
|
+
m_offset[i] + m_length[i]
|
817
|
+
);
|
818
|
+
}
|
819
|
+
return {
|
820
|
+
type: "message",
|
821
|
+
senderID: formatID(md.actorFbId.toString()),
|
822
|
+
body: m.delta.body || "",
|
823
|
+
threadID: formatID(
|
824
|
+
(md.threadKey.threadFbId || md.threadKey.otherUserFbId).toString()
|
825
|
+
),
|
826
|
+
messageID: md.messageId,
|
827
|
+
attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
|
828
|
+
mentions: mentions,
|
829
|
+
timestamp: md.timestamp,
|
830
|
+
isGroup: !!md.threadKey.threadFbId,
|
831
|
+
participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || []
|
832
|
+
};
|
768
833
|
}
|
769
834
|
|
770
835
|
function formatID(id) {
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
836
|
+
if (id != undefined && id != null) {
|
837
|
+
return id.replace(/(fb)?id[:.]/, "");
|
838
|
+
}
|
839
|
+
else {
|
840
|
+
return id;
|
841
|
+
}
|
777
842
|
}
|
778
843
|
|
779
844
|
function formatMessage(m) {
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
845
|
+
const originalMessage = m.message ? m.message : m;
|
846
|
+
const obj = {
|
847
|
+
type: "message",
|
848
|
+
senderName: originalMessage.sender_name,
|
849
|
+
senderID: formatID(originalMessage.sender_fbid.toString()),
|
850
|
+
participantNames: originalMessage.group_thread_info
|
851
|
+
? originalMessage.group_thread_info.participant_names
|
852
|
+
: [originalMessage.sender_name.split(" ")[0]],
|
853
|
+
participantIDs: originalMessage.group_thread_info
|
854
|
+
? originalMessage.group_thread_info.participant_ids.map(function (v) {
|
855
|
+
return formatID(v.toString());
|
856
|
+
})
|
857
|
+
: [formatID(originalMessage.sender_fbid)],
|
858
|
+
body: originalMessage.body || "",
|
859
|
+
threadID: formatID(
|
860
|
+
(
|
861
|
+
originalMessage.thread_fbid || originalMessage.other_user_fbid
|
862
|
+
).toString()
|
863
|
+
),
|
864
|
+
threadName: originalMessage.group_thread_info
|
865
|
+
? originalMessage.group_thread_info.name
|
866
|
+
: originalMessage.sender_name,
|
867
|
+
location: originalMessage.coordinates ? originalMessage.coordinates : null,
|
868
|
+
messageID: originalMessage.mid
|
869
|
+
? originalMessage.mid.toString()
|
870
|
+
: originalMessage.message_id,
|
871
|
+
attachments: formatAttachment(
|
872
|
+
originalMessage.attachments,
|
873
|
+
originalMessage.attachmentIds,
|
874
|
+
originalMessage.attachment_map,
|
875
|
+
originalMessage.share_map
|
876
|
+
),
|
877
|
+
timestamp: originalMessage.timestamp,
|
878
|
+
timestampAbsolute: originalMessage.timestamp_absolute,
|
879
|
+
timestampRelative: originalMessage.timestamp_relative,
|
880
|
+
timestampDatetime: originalMessage.timestamp_datetime,
|
881
|
+
tags: originalMessage.tags,
|
882
|
+
reactions: originalMessage.reactions ? originalMessage.reactions : [],
|
883
|
+
isUnread: originalMessage.is_unread
|
884
|
+
};
|
885
|
+
|
886
|
+
if (m.type === "pages_messaging")
|
887
|
+
obj.pageID = m.realtime_viewer_fbid.toString();
|
888
|
+
obj.isGroup = obj.participantIDs.length > 2;
|
889
|
+
|
890
|
+
return obj;
|
826
891
|
}
|
827
892
|
|
828
893
|
function formatEvent(m) {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
894
|
+
const originalMessage = m.message ? m.message : m;
|
895
|
+
let logMessageType = originalMessage.log_message_type;
|
896
|
+
let logMessageData;
|
897
|
+
if (logMessageType === "log:generic-admin-text") {
|
898
|
+
logMessageData = originalMessage.log_message_data.untypedData;
|
899
|
+
logMessageType = getAdminTextMessageType(
|
900
|
+
originalMessage.log_message_data.message_type
|
901
|
+
);
|
902
|
+
}
|
903
|
+
else {
|
904
|
+
logMessageData = originalMessage.log_message_data;
|
905
|
+
}
|
906
|
+
|
907
|
+
return Object.assign(formatMessage(originalMessage), {
|
908
|
+
type: "event",
|
909
|
+
logMessageType: logMessageType,
|
910
|
+
logMessageData: logMessageData,
|
911
|
+
logMessageBody: originalMessage.log_message_body
|
912
|
+
});
|
848
913
|
}
|
849
914
|
|
850
915
|
function formatHistoryMessage(m) {
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
916
|
+
switch (m.action_type) {
|
917
|
+
case "ma-type:log-message":
|
918
|
+
return formatEvent(m);
|
919
|
+
default:
|
920
|
+
return formatMessage(m);
|
921
|
+
}
|
857
922
|
}
|
858
923
|
|
859
924
|
// Get a more readable message type for AdminTextMessages
|
860
925
|
function getAdminTextMessageType(type) {
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
926
|
+
switch (type) {
|
927
|
+
case "change_thread_theme":
|
928
|
+
return "log:thread-color";
|
929
|
+
case "change_thread_icon":
|
930
|
+
case "change_thread_quick_reaction":
|
931
|
+
return "log:thread-icon";
|
932
|
+
case "change_thread_nickname":
|
933
|
+
return "log:user-nickname";
|
934
|
+
case "change_thread_admins":
|
935
|
+
return "log:thread-admins";
|
936
|
+
case "group_poll":
|
937
|
+
return "log:thread-poll";
|
938
|
+
case "change_thread_approval_mode":
|
939
|
+
return "log:thread-approval-mode";
|
940
|
+
case "messenger_call_log":
|
941
|
+
case "participant_joined_group_call":
|
942
|
+
return "log:thread-call";
|
943
|
+
default:
|
944
|
+
return type;
|
945
|
+
}
|
880
946
|
}
|
881
947
|
|
882
948
|
function formatDeltaEvent(m) {
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
949
|
+
let logMessageType;
|
950
|
+
let logMessageData;
|
951
|
+
|
952
|
+
// log:thread-color => {theme_color}
|
953
|
+
// log:user-nickname => {participant_id, nickname}
|
954
|
+
// log:thread-icon => {thread_icon}
|
955
|
+
// log:thread-name => {name}
|
956
|
+
// log:subscribe => {addedParticipants - [Array]}
|
957
|
+
// log:unsubscribe => {leftParticipantFbId}
|
958
|
+
|
959
|
+
switch (m.class) {
|
960
|
+
case "AdminTextMessage":
|
961
|
+
logMessageData = m.untypedData;
|
962
|
+
logMessageType = getAdminTextMessageType(m.type);
|
963
|
+
break;
|
964
|
+
case "ThreadName":
|
965
|
+
logMessageType = "log:thread-name";
|
966
|
+
logMessageData = { name: m.name };
|
967
|
+
break;
|
968
|
+
case "ParticipantsAddedToGroupThread":
|
969
|
+
logMessageType = "log:subscribe";
|
970
|
+
logMessageData = { addedParticipants: m.addedParticipants };
|
971
|
+
break;
|
972
|
+
case "ParticipantLeftGroupThread":
|
973
|
+
logMessageType = "log:unsubscribe";
|
974
|
+
logMessageData = { leftParticipantFbId: m.leftParticipantFbId };
|
975
|
+
break;
|
976
|
+
case "ApprovalQueue":
|
977
|
+
logMessageType = "log:approval-queue";
|
978
|
+
logMessageData = {
|
979
|
+
approvalQueue: {
|
980
|
+
action: m.action,
|
981
|
+
recipientFbId: m.recipientFbId,
|
982
|
+
requestSource: m.requestSource,
|
983
|
+
...m.messageMetadata
|
984
|
+
}
|
985
|
+
};
|
986
|
+
}
|
987
|
+
|
988
|
+
return {
|
989
|
+
type: "event",
|
990
|
+
threadID: formatID(
|
991
|
+
(
|
992
|
+
m.messageMetadata.threadKey.threadFbId ||
|
993
|
+
m.messageMetadata.threadKey.otherUserFbId
|
994
|
+
).toString()
|
995
|
+
),
|
996
|
+
messageID: m.messageMetadata.messageId.toString(),
|
997
|
+
logMessageType: logMessageType,
|
998
|
+
logMessageData: logMessageData,
|
999
|
+
logMessageBody: m.messageMetadata.adminText,
|
1000
|
+
timestamp: m.messageMetadata.timestamp,
|
1001
|
+
author: m.messageMetadata.actorFbId,
|
1002
|
+
participantIDs: (m.participants || []).map(p => p.toString())
|
1003
|
+
};
|
938
1004
|
}
|
939
1005
|
|
940
1006
|
function formatTyp(event) {
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
1007
|
+
return {
|
1008
|
+
isTyping: !!event.st,
|
1009
|
+
from: event.from.toString(),
|
1010
|
+
threadID: formatID(
|
1011
|
+
(event.to || event.thread_fbid || event.from).toString()
|
1012
|
+
),
|
1013
|
+
// When receiving typ indication from mobile, `from_mobile` isn't set.
|
1014
|
+
// If it is, we just use that value.
|
1015
|
+
fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
|
1016
|
+
userID: (event.realtime_viewer_fbid || event.from).toString(),
|
1017
|
+
type: "typ"
|
1018
|
+
};
|
953
1019
|
}
|
954
1020
|
|
955
1021
|
function formatDeltaReadReceipt(delta) {
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
1022
|
+
// otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
|
1023
|
+
// In a group chat actorFbId is used for the reader and threadFbId for the thread.
|
1024
|
+
return {
|
1025
|
+
reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
|
1026
|
+
time: delta.actionTimestampMs,
|
1027
|
+
threadID: formatID(
|
1028
|
+
(delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()
|
1029
|
+
),
|
1030
|
+
type: "read_receipt"
|
1031
|
+
};
|
966
1032
|
}
|
967
1033
|
|
968
1034
|
function formatReadReceipt(event) {
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
1035
|
+
return {
|
1036
|
+
reader: event.reader.toString(),
|
1037
|
+
time: event.time,
|
1038
|
+
threadID: formatID((event.thread_fbid || event.reader).toString()),
|
1039
|
+
type: "read_receipt"
|
1040
|
+
};
|
975
1041
|
}
|
976
1042
|
|
977
1043
|
function formatRead(event) {
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
1044
|
+
return {
|
1045
|
+
threadID: formatID(
|
1046
|
+
(
|
1047
|
+
(event.chat_ids && event.chat_ids[0]) ||
|
1048
|
+
(event.thread_fbids && event.thread_fbids[0])
|
1049
|
+
).toString()
|
1050
|
+
),
|
1051
|
+
time: event.timestamp,
|
1052
|
+
type: "read"
|
1053
|
+
};
|
988
1054
|
}
|
989
1055
|
|
990
1056
|
function getFrom(str, startToken, endToken) {
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1057
|
+
const start = str.indexOf(startToken) + startToken.length;
|
1058
|
+
if (start < startToken.length) return "";
|
1059
|
+
|
1060
|
+
const lastHalf = str.substring(start);
|
1061
|
+
const end = lastHalf.indexOf(endToken);
|
1062
|
+
if (end === -1) {
|
1063
|
+
throw new Error(
|
1064
|
+
"Could not find endTime `" + endToken + "` in the given string."
|
1065
|
+
);
|
1066
|
+
}
|
1067
|
+
return lastHalf.substring(0, end);
|
1002
1068
|
}
|
1003
1069
|
|
1004
1070
|
function makeParsable(html) {
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1071
|
+
const withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, "");
|
1072
|
+
|
1073
|
+
// (What the fuck FB, why windows style newlines?)
|
1074
|
+
// So sometimes FB will send us base multiple objects in the same response.
|
1075
|
+
// They're all valid JSON, one after the other, at the top level. We detect
|
1076
|
+
// that and make it parse-able by JSON.parse.
|
1077
|
+
// Ben - July 15th 2017
|
1078
|
+
//
|
1079
|
+
// It turns out that Facebook may insert random number of spaces before
|
1080
|
+
// next object begins (issue #616)
|
1081
|
+
// rav_kr - 2018-03-19
|
1082
|
+
const maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
|
1083
|
+
if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
|
1084
|
+
|
1085
|
+
return "[" + maybeMultipleObjects.join("},{") + "]";
|
1020
1086
|
}
|
1021
1087
|
|
1022
1088
|
function arrToForm(form) {
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1089
|
+
return arrayToObject(
|
1090
|
+
form,
|
1091
|
+
function (v) {
|
1092
|
+
return v.name;
|
1093
|
+
},
|
1094
|
+
function (v) {
|
1095
|
+
return v.val;
|
1096
|
+
}
|
1097
|
+
);
|
1032
1098
|
}
|
1033
1099
|
|
1034
1100
|
function arrayToObject(arr, getKey, getValue) {
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1101
|
+
return arr.reduce(function (acc, val) {
|
1102
|
+
acc[getKey(val)] = getValue(val);
|
1103
|
+
return acc;
|
1104
|
+
}, {});
|
1039
1105
|
}
|
1040
1106
|
|
1041
1107
|
function getSignatureID() {
|
1042
|
-
|
1108
|
+
return Math.floor(Math.random() * 2147483648).toString(16);
|
1043
1109
|
}
|
1044
1110
|
|
1045
1111
|
function generateTimestampRelative() {
|
1046
|
-
|
1047
|
-
|
1112
|
+
const d = new Date();
|
1113
|
+
return d.getHours() + ":" + padZeros(d.getMinutes());
|
1048
1114
|
}
|
1049
1115
|
|
1050
1116
|
function makeDefaults(html, userID, ctx) {
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1117
|
+
let reqCounter = 1;
|
1118
|
+
const fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
|
1119
|
+
|
1120
|
+
// @Hack Ok we've done hacky things, this is definitely on top 5.
|
1121
|
+
// We totally assume the object is flat and try parsing until a }.
|
1122
|
+
// If it works though it's cool because we get a bunch of extra data things.
|
1123
|
+
//
|
1124
|
+
// Update: we don't need this. Leaving it in in case we ever do.
|
1125
|
+
// Ben - July 15th 2017
|
1126
|
+
|
1127
|
+
// var siteData = getFrom(html, "[\"SiteData\",[],", "},");
|
1128
|
+
// try {
|
1129
|
+
// siteData = JSON.parse(siteData + "}");
|
1130
|
+
// } catch(e) {
|
1131
|
+
// log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
|
1132
|
+
// siteData = {};
|
1133
|
+
// }
|
1134
|
+
|
1135
|
+
let ttstamp = "2";
|
1136
|
+
for (let i = 0; i < fb_dtsg.length; i++) {
|
1137
|
+
ttstamp += fb_dtsg.charCodeAt(i);
|
1138
|
+
}
|
1139
|
+
const revision = getFrom(html, 'revision":', ",");
|
1140
|
+
|
1141
|
+
function mergeWithDefaults(obj) {
|
1142
|
+
// @TODO This is missing a key called __dyn.
|
1143
|
+
// After some investigation it seems like __dyn is some sort of set that FB
|
1144
|
+
// calls BitMap. It seems like certain responses have a "define" key in the
|
1145
|
+
// res.jsmods arrays. I think the code iterates over those and calls `set`
|
1146
|
+
// on the bitmap for each of those keys. Then it calls
|
1147
|
+
// bitmap.toCompressedString() which returns what __dyn is.
|
1148
|
+
//
|
1149
|
+
// So far the API has been working without this.
|
1150
|
+
//
|
1151
|
+
// Ben - July 15th 2017
|
1152
|
+
const newObj = {
|
1153
|
+
__user: userID,
|
1154
|
+
__req: (reqCounter++).toString(36),
|
1155
|
+
__rev: revision,
|
1156
|
+
__a: 1,
|
1157
|
+
// __af: siteData.features,
|
1158
|
+
fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
|
1159
|
+
jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
|
1160
|
+
// __spin_r: siteData.__spin_r,
|
1161
|
+
// __spin_b: siteData.__spin_b,
|
1162
|
+
// __spin_t: siteData.__spin_t,
|
1163
|
+
};
|
1164
|
+
|
1165
|
+
// @TODO this is probably not needed.
|
1166
|
+
// Ben - July 15th 2017
|
1167
|
+
// if (siteData.be_key) {
|
1168
|
+
// newObj[siteData.be_key] = siteData.be_mode;
|
1169
|
+
// }
|
1170
|
+
// if (siteData.pkg_cohort_key) {
|
1171
|
+
// newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
|
1172
|
+
// }
|
1173
|
+
|
1174
|
+
if (!obj) return newObj;
|
1175
|
+
|
1176
|
+
for (const prop in obj) {
|
1177
|
+
if (obj.hasOwnProperty(prop)) {
|
1178
|
+
if (!newObj[prop]) {
|
1179
|
+
newObj[prop] = obj[prop];
|
1180
|
+
}
|
1181
|
+
}
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
return newObj;
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
function postWithDefaults(url, jar, form, ctxx, customHeader = {}) {
|
1188
|
+
return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader);
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
function getWithDefaults(url, jar, qs, ctxx, customHeader = {}) {
|
1192
|
+
return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx, customHeader);
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
function postFormDataWithDefault(url, jar, form, qs, ctxx) {
|
1196
|
+
return postFormData(
|
1197
|
+
url,
|
1198
|
+
jar,
|
1199
|
+
mergeWithDefaults(form),
|
1200
|
+
mergeWithDefaults(qs),
|
1201
|
+
ctx.globalOptions,
|
1202
|
+
ctxx || ctx
|
1203
|
+
);
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
return {
|
1207
|
+
get: getWithDefaults,
|
1208
|
+
post: postWithDefaults,
|
1209
|
+
postFormData: postFormDataWithDefault
|
1210
|
+
};
|
1145
1211
|
}
|
1146
1212
|
|
1147
1213
|
function parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall) {
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
});
|
1288
|
-
};
|
1214
|
+
if (retryCount == undefined) {
|
1215
|
+
retryCount = 0;
|
1216
|
+
}
|
1217
|
+
if (sourceCall == undefined) {
|
1218
|
+
try {
|
1219
|
+
throw new Error();
|
1220
|
+
}
|
1221
|
+
catch (e) {
|
1222
|
+
sourceCall = e;
|
1223
|
+
}
|
1224
|
+
}
|
1225
|
+
return function (data) {
|
1226
|
+
return tryPromise(function () {
|
1227
|
+
log.verbose("parseAndCheckLogin", data.body);
|
1228
|
+
if (data.statusCode >= 500 && data.statusCode < 600) {
|
1229
|
+
if (retryCount >= 5) {
|
1230
|
+
throw new CustomError({
|
1231
|
+
message: "Request retry failed. Check the `res` and `statusCode` property on this error.",
|
1232
|
+
statusCode: data.statusCode,
|
1233
|
+
res: data.body,
|
1234
|
+
error: "Request retry failed. Check the `res` and `statusCode` property on this error.",
|
1235
|
+
sourceCall: sourceCall
|
1236
|
+
});
|
1237
|
+
}
|
1238
|
+
retryCount++;
|
1239
|
+
const retryTime = Math.floor(Math.random() * 5000);
|
1240
|
+
log.warn(
|
1241
|
+
"parseAndCheckLogin",
|
1242
|
+
"Got status code " +
|
1243
|
+
data.statusCode +
|
1244
|
+
" - " +
|
1245
|
+
retryCount +
|
1246
|
+
". attempt to retry in " +
|
1247
|
+
retryTime +
|
1248
|
+
" milliseconds..."
|
1249
|
+
);
|
1250
|
+
const url =
|
1251
|
+
data.request.uri.protocol +
|
1252
|
+
"//" +
|
1253
|
+
data.request.uri.hostname +
|
1254
|
+
data.request.uri.pathname;
|
1255
|
+
if (
|
1256
|
+
data.request.headers["Content-Type"].split(";")[0] ===
|
1257
|
+
"multipart/form-data"
|
1258
|
+
) {
|
1259
|
+
return delay(retryTime)
|
1260
|
+
.then(function () {
|
1261
|
+
return defaultFuncs.postFormData(
|
1262
|
+
url,
|
1263
|
+
ctx.jar,
|
1264
|
+
data.request.formData,
|
1265
|
+
{}
|
1266
|
+
);
|
1267
|
+
})
|
1268
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
|
1269
|
+
}
|
1270
|
+
else {
|
1271
|
+
return delay(retryTime)
|
1272
|
+
.then(function () {
|
1273
|
+
return defaultFuncs.post(url, ctx.jar, data.request.formData);
|
1274
|
+
})
|
1275
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
|
1276
|
+
}
|
1277
|
+
}
|
1278
|
+
if (data.statusCode !== 200)
|
1279
|
+
throw new CustomError({
|
1280
|
+
message: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
|
1281
|
+
statusCode: data.statusCode,
|
1282
|
+
res: data.body,
|
1283
|
+
error: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
|
1284
|
+
sourceCall: sourceCall
|
1285
|
+
});
|
1286
|
+
|
1287
|
+
let res = null;
|
1288
|
+
try {
|
1289
|
+
res = JSON.parse(makeParsable(data.body));
|
1290
|
+
} catch (e) {
|
1291
|
+
throw new CustomError({
|
1292
|
+
message: "JSON.parse error. Check the `detail` property on this error.",
|
1293
|
+
detail: e,
|
1294
|
+
res: data.body,
|
1295
|
+
error: "JSON.parse error. Check the `detail` property on this error.",
|
1296
|
+
sourceCall: sourceCall
|
1297
|
+
});
|
1298
|
+
}
|
1299
|
+
|
1300
|
+
// In some cases the response contains only a redirect URL which should be followed
|
1301
|
+
if (res.redirect && data.request.method === "GET") {
|
1302
|
+
return defaultFuncs
|
1303
|
+
.get(res.redirect, ctx.jar)
|
1304
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, undefined, sourceCall));
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
// TODO: handle multiple cookies?
|
1308
|
+
if (
|
1309
|
+
res.jsmods &&
|
1310
|
+
res.jsmods.require &&
|
1311
|
+
Array.isArray(res.jsmods.require[0]) &&
|
1312
|
+
res.jsmods.require[0][0] === "Cookie"
|
1313
|
+
) {
|
1314
|
+
res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace(
|
1315
|
+
"_js_",
|
1316
|
+
""
|
1317
|
+
);
|
1318
|
+
const cookie = formatCookie(res.jsmods.require[0][3], "facebook");
|
1319
|
+
const cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
|
1320
|
+
ctx.jar.setCookie(cookie, "https://www.facebook.com");
|
1321
|
+
ctx.jar.setCookie(cookie2, "https://www.messenger.com");
|
1322
|
+
}
|
1323
|
+
|
1324
|
+
// On every request we check if we got a DTSG and we mutate the context so that we use the latest
|
1325
|
+
// one for the next requests.
|
1326
|
+
if (res.jsmods && Array.isArray(res.jsmods.require)) {
|
1327
|
+
const arr = res.jsmods.require;
|
1328
|
+
for (const i in arr) {
|
1329
|
+
if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
|
1330
|
+
ctx.fb_dtsg = arr[i][3][0];
|
1331
|
+
|
1332
|
+
// Update ttstamp since that depends on fb_dtsg
|
1333
|
+
ctx.ttstamp = "2";
|
1334
|
+
for (let j = 0; j < ctx.fb_dtsg.length; j++) {
|
1335
|
+
ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
|
1336
|
+
}
|
1337
|
+
}
|
1338
|
+
}
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
if (res.error === 1357001) {
|
1342
|
+
throw new CustomError({
|
1343
|
+
message: "Facebook blocked login. Please visit https://facebook.com and check your account.",
|
1344
|
+
error: "Not logged in.",
|
1345
|
+
res: res,
|
1346
|
+
statusCode: data.statusCode,
|
1347
|
+
sourceCall: sourceCall
|
1348
|
+
});
|
1349
|
+
}
|
1350
|
+
return res;
|
1351
|
+
});
|
1352
|
+
};
|
1289
1353
|
}
|
1290
1354
|
|
1291
1355
|
function checkLiveCookie(ctx, defaultFuncs) {
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1356
|
+
return defaultFuncs
|
1357
|
+
.get("https://m.facebook.com/me", ctx.jar)
|
1358
|
+
.then(function (res) {
|
1359
|
+
if (res.body.indexOf(ctx.i_userID || ctx.userID) === -1) {
|
1360
|
+
throw new CustomError({
|
1361
|
+
message: "Not logged in.",
|
1362
|
+
error: "Not logged in."
|
1363
|
+
});
|
1364
|
+
}
|
1365
|
+
return true;
|
1366
|
+
});
|
1303
1367
|
}
|
1304
1368
|
|
1305
1369
|
function saveCookies(jar) {
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1370
|
+
return function (res) {
|
1371
|
+
const cookies = res.headers["set-cookie"] || [];
|
1372
|
+
cookies.forEach(function (c) {
|
1373
|
+
if (c.indexOf(".facebook.com") > -1) {
|
1374
|
+
jar.setCookie(c, "https://www.facebook.com");
|
1375
|
+
}
|
1376
|
+
const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
|
1377
|
+
jar.setCookie(c2, "https://www.messenger.com");
|
1378
|
+
});
|
1379
|
+
return res;
|
1380
|
+
};
|
1317
1381
|
}
|
1318
1382
|
|
1319
1383
|
const NUM_TO_MONTH = [
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1384
|
+
"Jan",
|
1385
|
+
"Feb",
|
1386
|
+
"Mar",
|
1387
|
+
"Apr",
|
1388
|
+
"May",
|
1389
|
+
"Jun",
|
1390
|
+
"Jul",
|
1391
|
+
"Aug",
|
1392
|
+
"Sep",
|
1393
|
+
"Oct",
|
1394
|
+
"Nov",
|
1395
|
+
"Dec"
|
1332
1396
|
];
|
1333
1397
|
const NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
1334
1398
|
function formatDate(date) {
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1399
|
+
let d = date.getUTCDate();
|
1400
|
+
d = d >= 10 ? d : "0" + d;
|
1401
|
+
let h = date.getUTCHours();
|
1402
|
+
h = h >= 10 ? h : "0" + h;
|
1403
|
+
let m = date.getUTCMinutes();
|
1404
|
+
m = m >= 10 ? m : "0" + m;
|
1405
|
+
let s = date.getUTCSeconds();
|
1406
|
+
s = s >= 10 ? s : "0" + s;
|
1407
|
+
return (
|
1408
|
+
NUM_TO_DAY[date.getUTCDay()] +
|
1409
|
+
", " +
|
1410
|
+
d +
|
1411
|
+
" " +
|
1412
|
+
NUM_TO_MONTH[date.getUTCMonth()] +
|
1413
|
+
" " +
|
1414
|
+
date.getUTCFullYear() +
|
1415
|
+
" " +
|
1416
|
+
h +
|
1417
|
+
":" +
|
1418
|
+
m +
|
1419
|
+
":" +
|
1420
|
+
s +
|
1421
|
+
" GMT"
|
1422
|
+
);
|
1359
1423
|
}
|
1360
1424
|
|
1361
1425
|
function formatCookie(arr, url) {
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1426
|
+
return (
|
1427
|
+
arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com"
|
1428
|
+
);
|
1365
1429
|
}
|
1366
1430
|
|
1367
1431
|
function formatThread(data) {
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1432
|
+
return {
|
1433
|
+
threadID: formatID(data.thread_fbid.toString()),
|
1434
|
+
participants: data.participants.map(formatID),
|
1435
|
+
participantIDs: data.participants.map(formatID),
|
1436
|
+
name: data.name,
|
1437
|
+
nicknames: data.custom_nickname,
|
1438
|
+
snippet: data.snippet,
|
1439
|
+
snippetAttachments: data.snippet_attachments,
|
1440
|
+
snippetSender: formatID((data.snippet_sender || "").toString()),
|
1441
|
+
unreadCount: data.unread_count,
|
1442
|
+
messageCount: data.message_count,
|
1443
|
+
imageSrc: data.image_src,
|
1444
|
+
timestamp: data.timestamp,
|
1445
|
+
serverTimestamp: data.server_timestamp, // what is this?
|
1446
|
+
muteUntil: data.mute_until,
|
1447
|
+
isCanonicalUser: data.is_canonical_user,
|
1448
|
+
isCanonical: data.is_canonical,
|
1449
|
+
isSubscribed: data.is_subscribed,
|
1450
|
+
folder: data.folder,
|
1451
|
+
isArchived: data.is_archived,
|
1452
|
+
recipientsLoadable: data.recipients_loadable,
|
1453
|
+
hasEmailParticipant: data.has_email_participant,
|
1454
|
+
readOnly: data.read_only,
|
1455
|
+
canReply: data.can_reply,
|
1456
|
+
cannotReplyReason: data.cannot_reply_reason,
|
1457
|
+
lastMessageTimestamp: data.last_message_timestamp,
|
1458
|
+
lastReadTimestamp: data.last_read_timestamp,
|
1459
|
+
lastMessageType: data.last_message_type,
|
1460
|
+
emoji: data.custom_like_icon,
|
1461
|
+
color: data.custom_color,
|
1462
|
+
adminIDs: data.admin_ids,
|
1463
|
+
threadType: data.thread_type
|
1464
|
+
};
|
1401
1465
|
}
|
1402
1466
|
|
1403
1467
|
function getType(obj) {
|
1404
|
-
|
1468
|
+
return Object.prototype.toString.call(obj).slice(8, -1);
|
1405
1469
|
}
|
1406
1470
|
|
1407
1471
|
function formatProxyPresence(presence, userID) {
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1472
|
+
if (presence.lat === undefined || presence.p === undefined) return null;
|
1473
|
+
return {
|
1474
|
+
type: "presence",
|
1475
|
+
timestamp: presence.lat * 1000,
|
1476
|
+
userID: userID,
|
1477
|
+
statuses: presence.p
|
1478
|
+
};
|
1415
1479
|
}
|
1416
1480
|
|
1417
1481
|
function formatPresence(presence, userID) {
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1482
|
+
return {
|
1483
|
+
type: "presence",
|
1484
|
+
timestamp: presence.la * 1000,
|
1485
|
+
userID: userID,
|
1486
|
+
statuses: presence.a
|
1487
|
+
};
|
1424
1488
|
}
|
1425
1489
|
|
1426
1490
|
function decodeClientPayload(payload) {
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1491
|
+
/*
|
1492
|
+
Special function which Client using to "encode" clients JSON payload
|
1493
|
+
*/
|
1494
|
+
return JSON.parse(String.fromCharCode.apply(null, payload));
|
1431
1495
|
}
|
1432
1496
|
|
1433
1497
|
function getAppState(jar) {
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
}
|
1439
|
-
|
1440
|
-
function createAccess_token(jar, globalOptions) {
|
1441
|
-
return function (res) {
|
1442
|
-
return get('https://business.facebook.com/business_locations', jar, null, globalOptions)
|
1443
|
-
.then(function (resp) {
|
1444
|
-
var accessToken = /"],\["(\S+)","436761779744620",{/g.exec(resp.body);
|
1445
|
-
if (accessToken) accessToken = accessToken[1].split('"],["').pop();
|
1446
|
-
else accessToken = 'NONE';
|
1447
|
-
return [(res || resp.body), accessToken];
|
1448
|
-
})
|
1449
|
-
.catch(() => {
|
1450
|
-
return [(res || null), 'NONE'];
|
1451
|
-
})
|
1452
|
-
}
|
1498
|
+
return jar
|
1499
|
+
.getCookies("https://www.facebook.com")
|
1500
|
+
.concat(jar.getCookies("https://facebook.com"))
|
1501
|
+
.concat(jar.getCookies("https://www.messenger.com"));
|
1453
1502
|
}
|
1454
|
-
|
1455
1503
|
module.exports = {
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1504
|
+
CustomError,
|
1505
|
+
isReadableStream,
|
1506
|
+
get,
|
1507
|
+
post,
|
1508
|
+
postFormData,
|
1509
|
+
generateThreadingID,
|
1510
|
+
generateOfflineThreadingID,
|
1511
|
+
getGUID,
|
1512
|
+
getFrom,
|
1513
|
+
makeParsable,
|
1514
|
+
arrToForm,
|
1515
|
+
getSignatureID,
|
1516
|
+
getJar: request.jar,
|
1517
|
+
generateTimestampRelative,
|
1518
|
+
makeDefaults,
|
1519
|
+
parseAndCheckLogin,
|
1520
|
+
saveCookies,
|
1521
|
+
getType,
|
1522
|
+
_formatAttachment,
|
1523
|
+
formatHistoryMessage,
|
1524
|
+
formatID,
|
1525
|
+
formatMessage,
|
1526
|
+
formatDeltaEvent,
|
1527
|
+
formatDeltaMessage,
|
1528
|
+
formatProxyPresence,
|
1529
|
+
formatPresence,
|
1530
|
+
formatTyp,
|
1531
|
+
formatDeltaReadReceipt,
|
1532
|
+
formatCookie,
|
1533
|
+
formatThread,
|
1534
|
+
formatReadReceipt,
|
1535
|
+
formatRead,
|
1536
|
+
generatePresence,
|
1537
|
+
generateAccessiblityCookie,
|
1538
|
+
formatDate,
|
1539
|
+
decodeClientPayload,
|
1540
|
+
getAppState,
|
1541
|
+
getAdminTextMessageType,
|
1542
|
+
setProxy,
|
1543
|
+
checkLiveCookie
|
1544
|
+
};
|
1545
|
+
|