alicezetion 1.0.0

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