alicezetion 1.0.9 → 1.1.1

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