meta-fca 2.5.9 → 2.6.0

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