node-ainzfb-new 1.7.10-11 → 1.7.10-13

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