alicezetion 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cache/replit/__replit_disk_meta.json +1 -1
- package/.cache/replit/nix/env.json +1 -1
- package/index.js +558 -490
- package/leiamnash/addExternalModule.js +19 -0
- package/{src → leiamnash}/addUserToGroup.js +52 -16
- package/leiamnash/changeAdminStatus.js +79 -0
- package/leiamnash/changeArchivedStatus.js +55 -0
- package/{src → leiamnash}/changeBio.js +19 -6
- package/{src → leiamnash}/changeBlockedStatus.js +14 -3
- package/{src → leiamnash}/changeGroupImage.js +40 -16
- package/leiamnash/changeNickname.js +59 -0
- package/{src → leiamnash}/changeThreadColor.js +20 -10
- package/leiamnash/changeThreadEmoji.js +55 -0
- package/leiamnash/chat.js +459 -0
- package/{src → leiamnash}/createNewGroup.js +28 -12
- package/{src → leiamnash}/createPoll.js +25 -13
- package/leiamnash/deleteMessage.js +56 -0
- package/leiamnash/deleteThread.js +56 -0
- package/leiamnash/forwardAttachment.js +60 -0
- package/{src → leiamnash}/getCurrentUserID.js +1 -1
- package/{src → leiamnash}/getEmojiUrl.js +4 -2
- package/{src → leiamnash}/getFriendsList.js +21 -10
- package/{src → leiamnash}/getThreadHistory.js +166 -58
- package/{src → leiamnash}/getThreadHistoryDeprecated.js +42 -20
- package/{src → leiamnash}/getThreadInfo.js +60 -25
- package/leiamnash/getThreadInfoDeprecated.js +80 -0
- package/{src → leiamnash}/getThreadList.js +66 -41
- package/leiamnash/getThreadListDeprecated.js +75 -0
- package/leiamnash/getThreadPictures.js +79 -0
- package/{src → leiamnash}/getUserID.js +14 -9
- package/{src → leiamnash}/getUserInfo.js +1 -1
- package/leiamnash/handleFriendRequest.js +61 -0
- package/leiamnash/handleMessageRequest.js +65 -0
- package/{src → leiamnash}/httpGet.js +17 -12
- package/{src → leiamnash}/httpPost.js +17 -12
- package/leiamnash/listenMqtt.js +687 -0
- package/{src → leiamnash}/logout.js +20 -13
- package/{src → leiamnash}/markAsDelivered.js +22 -11
- package/{src → leiamnash}/markAsRead.js +21 -11
- package/{src → leiamnash}/markAsReadAll.js +20 -10
- package/{src → leiamnash}/markAsSeen.js +18 -7
- package/{src → leiamnash}/muteThread.js +18 -11
- package/leiamnash/removeUserFromGroup.js +79 -0
- package/{src → leiamnash}/resolvePhotoUrl.js +17 -8
- package/{src → leiamnash}/searchForThread.js +21 -10
- package/{src → leiamnash}/sendTypingIndicator.js +47 -14
- package/{src → leiamnash}/setMessageReaction.js +26 -12
- package/{src → leiamnash}/setPostReaction.js +26 -13
- package/{src → leiamnash}/setTitle.js +29 -13
- package/leiamnash/threadColors.js +57 -0
- package/{src → leiamnash}/unfriend.js +19 -9
- package/{src → leiamnash}/unsendMessage.js +19 -9
- package/package.json +9 -14
- package/replit.nix +0 -1
- package/utils.js +1193 -1023
- package/src/addExternalModule.js +0 -15
- package/src/changeAdminStatus.js +0 -47
- package/src/changeArchivedStatus.js +0 -41
- package/src/changeNickname.js +0 -43
- package/src/changeThreadEmoji.js +0 -41
- package/src/chat.js +0 -315
- package/src/deleteMessage.js +0 -44
- package/src/deleteThread.js +0 -42
- package/src/forwardAttachment.js +0 -47
- package/src/forwardMessage.js +0 -0
- package/src/getThreadInfoDeprecated.js +0 -56
- package/src/getThreadListDeprecated.js +0 -46
- package/src/getThreadPictures.js +0 -59
- package/src/handleFriendRequest.js +0 -46
- package/src/handleMessageRequest.js +0 -47
- package/src/listen.js +0 -553
- package/src/listenMqtt-Test.js +0 -687
- package/src/listenMqtt.js +0 -677
- package/src/removeUserFromGroup.js +0 -45
- package/src/threadColors.js +0 -41
package/utils.js
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
/*
|
2
|
-
|
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
|
-
|
16
|
-
return request = bluebird.promisify(require("request").defaults({
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
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
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
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
|
247
|
-
|
248
|
-
|
249
|
-
|
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
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
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
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
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
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
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
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
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
|
-
|
641
|
-
|
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
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
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
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
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
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
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(
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
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
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
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
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
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
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
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
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
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
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
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
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
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
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
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
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
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
|
-
|
846
|
-
|
847
|
-
|
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
|
-
|
960
|
+
return Math.floor(Math.random() * 2147483648).toString(16);
|
853
961
|
}
|
854
962
|
|
855
963
|
function generateTimestampRelative() {
|
856
|
-
|
857
|
-
|
964
|
+
var d = new Date();
|
965
|
+
return d.getHours() + ":" + padZeros(d.getMinutes());
|
858
966
|
}
|
859
967
|
|
860
968
|
function makeDefaults(html, userID, ctx) {
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
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
|
-
//
|
869
|
-
//
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
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
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
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
|
-
|
924
|
-
return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx);
|
925
|
-
}
|
1026
|
+
if (!obj) return newObj;
|
926
1027
|
|
927
|
-
|
928
|
-
|
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
|
-
|
932
|
-
|
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
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
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
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
ctx.jar
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
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
|
-
|
1003
|
-
|
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
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
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
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
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
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
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
|
-
|
1246
|
+
return (
|
1247
|
+
arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com"
|
1248
|
+
);
|
1050
1249
|
}
|
1051
1250
|
|
1052
1251
|
function formatThread(data) {
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
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
|
-
|
1288
|
+
return Object.prototype.toString.call(obj).slice(8, -1);
|
1090
1289
|
}
|
1091
1290
|
|
1092
1291
|
function formatProxyPresence(presence, userID) {
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
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
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
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
|
-
|
1114
|
-
|
1115
|
-
|
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
|
-
|
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
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
};
|
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
|
+
|