@vangbanlanhat/fca-unofficial 1.4.2
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/.gitattributes +2 -0
- package/.github/workflows/nodejs.yml +26 -0
- package/.github/workflows/npmpublish.yml +30 -0
- package/.travis.yml +6 -0
- package/CHANGELOG.md +2 -0
- package/DOCS.md +1932 -0
- package/LICENSE-MIT +21 -0
- package/README.md +198 -0
- package/jest.config.js +10 -0
- package/package.json +86 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/actions/addExternalModule.js +34 -0
- package/src/actions/addUserToGroup.js +113 -0
- package/src/actions/changeAdminStatus.js +79 -0
- package/src/actions/changeArchivedStatus.js +55 -0
- package/src/actions/changeBio.js +77 -0
- package/src/actions/changeBlockedStatus.js +47 -0
- package/src/actions/changeGroupImage.js +129 -0
- package/src/actions/changeNickname.js +59 -0
- package/src/actions/changeThreadColor.js +71 -0
- package/src/actions/changeThreadEmoji.js +55 -0
- package/src/actions/createNewGroup.js +86 -0
- package/src/actions/createPoll.js +71 -0
- package/src/actions/deleteMessage.js +56 -0
- package/src/actions/deleteThread.js +56 -0
- package/src/actions/editMessage.js +81 -0
- package/src/actions/forwardAttachment.js +60 -0
- package/src/actions/getAvatarUser.js +77 -0
- package/src/actions/getCurrentUserID.js +11 -0
- package/src/actions/getEmojiUrl.js +37 -0
- package/src/actions/getFriendsList.js +84 -0
- package/src/actions/getMessage.js +833 -0
- package/src/actions/getRegion.js +11 -0
- package/src/actions/getThreadHistory.js +702 -0
- package/src/actions/getThreadHistoryDeprecated.js +93 -0
- package/src/actions/getThreadInfo.js +265 -0
- package/src/actions/getThreadInfoDeprecated.js +80 -0
- package/src/actions/getThreadList.js +274 -0
- package/src/actions/getThreadListDeprecated.js +91 -0
- package/src/actions/getThreadPictures.js +79 -0
- package/src/actions/getUserID.js +66 -0
- package/src/actions/getUserInfo.js +92 -0
- package/src/actions/handleFriendRequest.js +61 -0
- package/src/actions/handleMessageRequest.js +65 -0
- package/src/actions/httpGet.js +70 -0
- package/src/actions/httpPost.js +70 -0
- package/src/actions/index.js +69 -0
- package/src/actions/listenMqtt.js +818 -0
- package/src/actions/logout.js +136 -0
- package/src/actions/markAsDelivered.js +58 -0
- package/src/actions/markAsRead.js +92 -0
- package/src/actions/markAsReadAll.js +50 -0
- package/src/actions/markAsSeen.js +59 -0
- package/src/actions/muteThread.js +52 -0
- package/src/actions/pinMessage.js +86 -0
- package/src/actions/refreshFb_dtsg.js +89 -0
- package/src/actions/removeUserFromGroup.js +79 -0
- package/src/actions/resolvePhotoUrl.js +45 -0
- package/src/actions/searchForThread.js +53 -0
- package/src/actions/searchStickers.js +53 -0
- package/src/actions/sendMessage.js +490 -0
- package/src/actions/sendMessageMqtt.js +235 -0
- package/src/actions/sendTypingIndicator.js +59 -0
- package/src/actions/setMessageReaction.js +140 -0
- package/src/actions/setMessageReactionMqtt.js +72 -0
- package/src/actions/setPostReaction.js +76 -0
- package/src/actions/setTitle.js +86 -0
- package/src/actions/stopListenMqtt.js +63 -0
- package/src/actions/threadColors.js +57 -0
- package/src/actions/unfriend.js +52 -0
- package/src/actions/unsendMessage.js +61 -0
- package/src/index.js +659 -0
- package/src/service/uploadAttachment.js +318 -0
- package/src/utils/base-parts/auth.js +286 -0
- package/src/utils/base-parts/formatters.js +751 -0
- package/src/utils/base-parts/identity.js +169 -0
- package/src/utils/base-parts/network.js +159 -0
- package/src/utils/base-parts/parsing.js +53 -0
- package/src/utils/base-parts/type.js +9 -0
- package/src/utils/base.js +18 -0
- package/src/utils/defaults.js +10 -0
- package/src/utils/format-attachments.js +7 -0
- package/src/utils/format-core.js +8 -0
- package/src/utils/format-events.js +11 -0
- package/src/utils/format-messages.js +10 -0
- package/src/utils/format-presence.js +9 -0
- package/src/utils/format-threads.js +8 -0
- package/src/utils/formatters.js +18 -0
- package/src/utils/identity.js +12 -0
- package/src/utils/index.js +15 -0
- package/src/utils/network.js +12 -0
- package/src/utils/parsing.js +11 -0
- package/src/utils.js +3 -0
- package/test/config.env.example +30 -0
- package/test/data/shareAttach.js +146 -0
- package/test/data/something.mov +0 -0
- package/test/data/test.png +0 -0
- package/test/data/test.txt +7 -0
- package/test/example-appstate.txt +11 -0
- package/test/integration/actions.appstate.integration.test.js +233 -0
- package/test/integration/api.integration.test.js +387 -0
- package/test/integration/env-test-config.js +46 -0
- package/test/integration/login.appstate.integration.test.js +47 -0
- package/test/integration/page.integration.test.js +139 -0
- package/test/jest.setup.js +54 -0
- package/test/unit/actions/actions.basic.test.js +116 -0
- package/test/unit/actions/actions.registry.test.js +36 -0
- package/test/unit/index/index.test.js +109 -0
- package/test/unit/utils/base-parts/auth.test.js +92 -0
- package/test/unit/utils/base-parts/formatters.test.js +53 -0
- package/test/unit/utils/base-parts/identity.test.js +43 -0
- package/test/unit/utils/base-parts/parsing.test.js +38 -0
- package/test/unit/utils/base-parts/type.test.js +23 -0
- package/test/unit/utils/base.test.js +35 -0
- package/vangbanlanhat-fca-unofficial-1.4.2.tgz +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var fs = require("fs");
|
|
4
|
+
var bluebird = require("bluebird");
|
|
5
|
+
var utils = require("../utils");
|
|
6
|
+
|
|
7
|
+
function stringifyUploadResponse(resData) {
|
|
8
|
+
if (resData instanceof Error) {
|
|
9
|
+
var errInfo = {
|
|
10
|
+
name: resData.name,
|
|
11
|
+
message: resData.message
|
|
12
|
+
};
|
|
13
|
+
if (resData.code !== undefined) errInfo.code = resData.code;
|
|
14
|
+
if (resData.statusCode !== undefined) errInfo.statusCode = resData.statusCode;
|
|
15
|
+
try {
|
|
16
|
+
return JSON.stringify(errInfo);
|
|
17
|
+
} catch (_) {
|
|
18
|
+
return String(resData.message || resData);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (resData && typeof resData === "object") {
|
|
23
|
+
var commonErr = {
|
|
24
|
+
message: resData.message,
|
|
25
|
+
error: resData.error,
|
|
26
|
+
code: resData.code,
|
|
27
|
+
statusCode: resData.statusCode
|
|
28
|
+
};
|
|
29
|
+
if (
|
|
30
|
+
commonErr.message !== undefined ||
|
|
31
|
+
commonErr.error !== undefined ||
|
|
32
|
+
commonErr.code !== undefined ||
|
|
33
|
+
commonErr.statusCode !== undefined
|
|
34
|
+
) {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.stringify(commonErr);
|
|
37
|
+
} catch (_) {
|
|
38
|
+
return String(resData);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
return JSON.stringify(resData);
|
|
45
|
+
} catch (_) {
|
|
46
|
+
return String(resData);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function pickUploadRequestDebug(rawRes) {
|
|
51
|
+
var req = rawRes && rawRes.request ? rawRes.request : null;
|
|
52
|
+
var headers = req && req.headers ? req.headers : {};
|
|
53
|
+
var query = req && req.uri && req.uri.query && typeof req.uri.query === "object"
|
|
54
|
+
? req.uri.query
|
|
55
|
+
: {};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
method: req && req.method ? req.method : undefined,
|
|
59
|
+
host: headers.host || headers.Host,
|
|
60
|
+
origin: headers.origin || headers.Origin,
|
|
61
|
+
referer: headers.referer || headers.Referer,
|
|
62
|
+
userAgent: headers["user-agent"] || headers["User-Agent"],
|
|
63
|
+
contentType: headers["content-type"] || headers["Content-Type"],
|
|
64
|
+
xFbLsd: headers["x-fb-lsd"] || headers["X-FB-LSD"],
|
|
65
|
+
xAsbdId: headers["x-asbd-id"] || headers["X-ASBD-ID"],
|
|
66
|
+
secFetchSite: headers["sec-fetch-site"] || headers["Sec-Fetch-Site"],
|
|
67
|
+
secFetchMode: headers["sec-fetch-mode"] || headers["Sec-Fetch-Mode"],
|
|
68
|
+
secFetchDest: headers["sec-fetch-dest"] || headers["Sec-Fetch-Dest"],
|
|
69
|
+
hasCookie: !!(headers.cookie || headers.Cookie),
|
|
70
|
+
queryKeys: Object.keys(query)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function extractUploadMetadata(resData) {
|
|
75
|
+
var rawMetadata =
|
|
76
|
+
resData &&
|
|
77
|
+
resData.payload
|
|
78
|
+
? resData.payload.metadata
|
|
79
|
+
: null;
|
|
80
|
+
|
|
81
|
+
if (Array.isArray(rawMetadata)) {
|
|
82
|
+
return rawMetadata;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (rawMetadata && typeof rawMetadata === "object") {
|
|
86
|
+
return Object.keys(rawMetadata)
|
|
87
|
+
.sort(function (a, b) {
|
|
88
|
+
return Number(a) - Number(b);
|
|
89
|
+
})
|
|
90
|
+
.map(function (key) {
|
|
91
|
+
return rawMetadata[key];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function extractStatusCode(err) {
|
|
99
|
+
if (!err) return null;
|
|
100
|
+
if (typeof err.statusCode === "number") return err.statusCode;
|
|
101
|
+
|
|
102
|
+
var message = "";
|
|
103
|
+
if (typeof err === "string") message += err;
|
|
104
|
+
if (err && typeof err.message === "string") message += " " + err.message;
|
|
105
|
+
if (err && typeof err.error === "string") message += " " + err.error;
|
|
106
|
+
|
|
107
|
+
var match = message.match(/status code:\s*(\d{3})/i);
|
|
108
|
+
return match ? Number(match[1]) : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function shouldTryLegacyHostFallback(err) {
|
|
112
|
+
var statusCode = extractStatusCode(err);
|
|
113
|
+
if (statusCode === 408 || statusCode === 429) return true;
|
|
114
|
+
if (typeof statusCode === "number" && statusCode >= 500 && statusCode < 600) return true;
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = function createUploadAttachment(defaultFuncs, ctx, logger) {
|
|
119
|
+
function writeError(message) {
|
|
120
|
+
if (logger && typeof logger.error === "function") {
|
|
121
|
+
logger.error("uploadAttachment", message);
|
|
122
|
+
}
|
|
123
|
+
console.error("uploadAttachment", message);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return function uploadAttachment(attachments, callback) {
|
|
127
|
+
var uploads = [];
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
130
|
+
let attachment = attachments[i];
|
|
131
|
+
let attachmentPath =
|
|
132
|
+
attachment && typeof attachment.path === "string"
|
|
133
|
+
? attachment.path
|
|
134
|
+
: null;
|
|
135
|
+
|
|
136
|
+
if (!utils.isReadableStream(attachment)) {
|
|
137
|
+
throw {
|
|
138
|
+
error:
|
|
139
|
+
"Attachment should be a readable stream and not " +
|
|
140
|
+
utils.getType(attachment) +
|
|
141
|
+
"."
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const form = {
|
|
146
|
+
farr: attachment,
|
|
147
|
+
voice_clip: "true"
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
uploads.push(
|
|
151
|
+
bluebird.resolve()
|
|
152
|
+
.then(function () {
|
|
153
|
+
return defaultFuncs.postFormData(
|
|
154
|
+
"https://www.facebook.com/ajax/mercury/upload.php",
|
|
155
|
+
ctx.jar,
|
|
156
|
+
form,
|
|
157
|
+
{}
|
|
158
|
+
);
|
|
159
|
+
})
|
|
160
|
+
.then(function (rawRes) {
|
|
161
|
+
return {
|
|
162
|
+
rawRes: rawRes,
|
|
163
|
+
uploadReqDebug: pickUploadRequestDebug(rawRes)
|
|
164
|
+
};
|
|
165
|
+
})
|
|
166
|
+
.then(function (bundle) {
|
|
167
|
+
return utils.parseAndCheckLogin(ctx, defaultFuncs)(bundle.rawRes)
|
|
168
|
+
.then(function (resData) {
|
|
169
|
+
return {
|
|
170
|
+
resData: resData,
|
|
171
|
+
uploadReqDebug: bundle.uploadReqDebug
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
})
|
|
175
|
+
.then(function (bundle) {
|
|
176
|
+
var resData = bundle.resData;
|
|
177
|
+
var uploadReqDebug = bundle.uploadReqDebug;
|
|
178
|
+
|
|
179
|
+
if (resData.error) {
|
|
180
|
+
throw resData;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var metadata = extractUploadMetadata(resData);
|
|
184
|
+
if (metadata.length) {
|
|
185
|
+
return metadata[0];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
writeError("Raw upload response (empty metadata): " + stringifyUploadResponse(resData));
|
|
189
|
+
writeError("Upload request debug: " + stringifyUploadResponse(uploadReqDebug));
|
|
190
|
+
|
|
191
|
+
if (!attachmentPath) {
|
|
192
|
+
throw {
|
|
193
|
+
error: "Upload succeeded but did not return attachment metadata.",
|
|
194
|
+
res: resData
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
var fallbackForm = {
|
|
199
|
+
upload_1024: fs.createReadStream(attachmentPath),
|
|
200
|
+
voice_clip: "true"
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return defaultFuncs
|
|
204
|
+
.postFormData(
|
|
205
|
+
"https://upload.facebook.com/ajax/mercury/upload.php",
|
|
206
|
+
ctx.jar,
|
|
207
|
+
fallbackForm,
|
|
208
|
+
{}
|
|
209
|
+
)
|
|
210
|
+
.then(function (fallbackRawRes) {
|
|
211
|
+
return {
|
|
212
|
+
fallbackRawRes: fallbackRawRes,
|
|
213
|
+
fallbackReqDebug: pickUploadRequestDebug(fallbackRawRes)
|
|
214
|
+
};
|
|
215
|
+
})
|
|
216
|
+
.then(function (fallbackBundle) {
|
|
217
|
+
return utils.parseAndCheckLogin(ctx, defaultFuncs)(fallbackBundle.fallbackRawRes)
|
|
218
|
+
.then(function (fallbackData) {
|
|
219
|
+
return {
|
|
220
|
+
fallbackData: fallbackData,
|
|
221
|
+
fallbackReqDebug: fallbackBundle.fallbackReqDebug
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
})
|
|
225
|
+
.then(function (fallbackBundle) {
|
|
226
|
+
var fallbackData = fallbackBundle.fallbackData;
|
|
227
|
+
var fallbackReqDebug = fallbackBundle.fallbackReqDebug;
|
|
228
|
+
|
|
229
|
+
if (fallbackData.error) {
|
|
230
|
+
throw fallbackData;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
var fallbackMetadata = extractUploadMetadata(fallbackData);
|
|
234
|
+
if (fallbackMetadata.length) {
|
|
235
|
+
return fallbackMetadata[0];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
writeError("Raw upload response (legacy fallback empty metadata): " + stringifyUploadResponse(fallbackData));
|
|
239
|
+
writeError("Legacy upload request debug: " + stringifyUploadResponse(fallbackReqDebug));
|
|
240
|
+
|
|
241
|
+
throw {
|
|
242
|
+
error: "Upload succeeded but did not return attachment metadata.",
|
|
243
|
+
res: fallbackData,
|
|
244
|
+
firstRes: resData
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
})
|
|
248
|
+
.catch(function (primaryErr) {
|
|
249
|
+
if (!attachmentPath || !shouldTryLegacyHostFallback(primaryErr)) {
|
|
250
|
+
throw primaryErr;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
var fallbackForm = {
|
|
254
|
+
upload_1024: fs.createReadStream(attachmentPath),
|
|
255
|
+
voice_clip: "true"
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
return defaultFuncs
|
|
259
|
+
.postFormData(
|
|
260
|
+
"https://upload.facebook.com/ajax/mercury/upload.php",
|
|
261
|
+
ctx.jar,
|
|
262
|
+
fallbackForm,
|
|
263
|
+
{}
|
|
264
|
+
)
|
|
265
|
+
.then(function (fallbackRawRes) {
|
|
266
|
+
return {
|
|
267
|
+
fallbackRawRes: fallbackRawRes,
|
|
268
|
+
fallbackReqDebug: pickUploadRequestDebug(fallbackRawRes)
|
|
269
|
+
};
|
|
270
|
+
})
|
|
271
|
+
.then(function (fallbackBundle) {
|
|
272
|
+
return utils.parseAndCheckLogin(ctx, defaultFuncs)(fallbackBundle.fallbackRawRes)
|
|
273
|
+
.then(function (fallbackData) {
|
|
274
|
+
return {
|
|
275
|
+
fallbackData: fallbackData,
|
|
276
|
+
fallbackReqDebug: fallbackBundle.fallbackReqDebug
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
})
|
|
280
|
+
.then(function (fallbackBundle) {
|
|
281
|
+
var fallbackData = fallbackBundle.fallbackData;
|
|
282
|
+
var fallbackReqDebug = fallbackBundle.fallbackReqDebug;
|
|
283
|
+
|
|
284
|
+
if (fallbackData.error) {
|
|
285
|
+
throw fallbackData;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
var fallbackMetadata = extractUploadMetadata(fallbackData);
|
|
289
|
+
if (fallbackMetadata.length) {
|
|
290
|
+
return fallbackMetadata[0];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
writeError("Raw upload response (legacy host fallback empty metadata): " + stringifyUploadResponse(fallbackData));
|
|
294
|
+
writeError("Legacy host request debug: " + stringifyUploadResponse(fallbackReqDebug));
|
|
295
|
+
|
|
296
|
+
throw {
|
|
297
|
+
error: "Upload succeeded but did not return attachment metadata.",
|
|
298
|
+
res: fallbackData,
|
|
299
|
+
firstErr: primaryErr
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
})
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
bluebird
|
|
307
|
+
.all(uploads)
|
|
308
|
+
.then(function (resData) {
|
|
309
|
+
callback(null, resData);
|
|
310
|
+
})
|
|
311
|
+
.catch(function (err) {
|
|
312
|
+
if (logger && typeof logger.error === "function") {
|
|
313
|
+
logger.error("uploadAttachment", err);
|
|
314
|
+
}
|
|
315
|
+
callback(err);
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
};
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var bluebird = require("bluebird");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
var network = require("./network");
|
|
7
|
+
var parsing = require("./parsing");
|
|
8
|
+
|
|
9
|
+
function formatCookie(arr, url) {
|
|
10
|
+
return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function makeDefaults(html, userID, ctx) {
|
|
14
|
+
var reqCounter = 1;
|
|
15
|
+
var fb_dtsg = parsing.getFrom(html, 'name="fb_dtsg" value="', '"');
|
|
16
|
+
var lsd = parsing.getFrom(html, '["LSD",[],{"token":"', '"');
|
|
17
|
+
if (!lsd) {
|
|
18
|
+
lsd = parsing.getFrom(html, 'name="lsd" value="', '"');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var ttstamp = "2";
|
|
22
|
+
for (var i = 0; i < fb_dtsg.length; i++) {
|
|
23
|
+
ttstamp += fb_dtsg.charCodeAt(i);
|
|
24
|
+
}
|
|
25
|
+
var revision = parsing.getFrom(html, 'revision":', ",");
|
|
26
|
+
|
|
27
|
+
function mergeWithDefaults(obj) {
|
|
28
|
+
var newObj = {
|
|
29
|
+
av: userID,
|
|
30
|
+
__user: userID,
|
|
31
|
+
__req: (reqCounter++).toString(36),
|
|
32
|
+
__rev: revision,
|
|
33
|
+
__a: 1,
|
|
34
|
+
fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
|
|
35
|
+
jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp,
|
|
36
|
+
lsd: ctx.lsd ? ctx.lsd : lsd
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (!obj) return newObj;
|
|
40
|
+
|
|
41
|
+
for (var prop in obj) {
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
43
|
+
if (!newObj[prop]) {
|
|
44
|
+
newObj[prop] = obj[prop];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return newObj;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function resolveCtx(ctxx) {
|
|
53
|
+
if (ctxx && (ctxx.jar || ctxx.userID || ctxx.globalOptions || ctxx.region)) {
|
|
54
|
+
return ctxx;
|
|
55
|
+
}
|
|
56
|
+
return ctx;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function postWithDefaults(url, jar, form, ctxx, customHeader) {
|
|
60
|
+
return network.post(
|
|
61
|
+
url,
|
|
62
|
+
jar,
|
|
63
|
+
mergeWithDefaults(form),
|
|
64
|
+
ctx.globalOptions,
|
|
65
|
+
resolveCtx(ctxx),
|
|
66
|
+
customHeader
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getWithDefaults(url, jar, qs, ctxx, customHeader) {
|
|
71
|
+
return network.get(
|
|
72
|
+
url,
|
|
73
|
+
jar,
|
|
74
|
+
mergeWithDefaults(qs),
|
|
75
|
+
ctx.globalOptions,
|
|
76
|
+
resolveCtx(ctxx),
|
|
77
|
+
customHeader
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function postFormDataWithDefault(url, jar, form, qs, ctxx) {
|
|
82
|
+
return network.postFormData(
|
|
83
|
+
url,
|
|
84
|
+
jar,
|
|
85
|
+
mergeWithDefaults(form),
|
|
86
|
+
mergeWithDefaults(qs),
|
|
87
|
+
ctx.globalOptions,
|
|
88
|
+
ctxx || ctx
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
get: getWithDefaults,
|
|
94
|
+
post: postWithDefaults,
|
|
95
|
+
postFormData: postFormDataWithDefault
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
|
|
100
|
+
if (retryCount == undefined) {
|
|
101
|
+
retryCount = 0;
|
|
102
|
+
}
|
|
103
|
+
return function (data) {
|
|
104
|
+
return bluebird.try(function () {
|
|
105
|
+
log.verbose("parseAndCheckLogin", data.body);
|
|
106
|
+
|
|
107
|
+
function isMercuryUploadRequest() {
|
|
108
|
+
var pathname = data && data.request && data.request.uri
|
|
109
|
+
? data.request.uri.pathname
|
|
110
|
+
: "";
|
|
111
|
+
return typeof pathname === "string" && pathname.indexOf("/ajax/mercury/upload.php") !== -1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function hasUploadMetadata(parsed) {
|
|
115
|
+
var metadata = parsed && parsed.payload ? parsed.payload.metadata : null;
|
|
116
|
+
if (Array.isArray(metadata)) return metadata.length > 0;
|
|
117
|
+
return !!(metadata && typeof metadata === "object" && Object.keys(metadata).length);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function tryParseUploadPayloadFromNon200() {
|
|
121
|
+
if (!isMercuryUploadRequest()) return null;
|
|
122
|
+
if (!data || typeof data.body !== "string" || data.body.trim() === "") return null;
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
var parsedUpload = JSON.parse(parsing.makeParsable(data.body));
|
|
126
|
+
if (parsedUpload && !parsedUpload.error && hasUploadMetadata(parsedUpload)) {
|
|
127
|
+
return parsedUpload;
|
|
128
|
+
}
|
|
129
|
+
} catch (_) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (data.statusCode >= 500 && data.statusCode < 600) {
|
|
137
|
+
if (retryCount >= 5) {
|
|
138
|
+
throw {
|
|
139
|
+
error:
|
|
140
|
+
"Request retry failed. Check the `res` and `statusCode` property on this error.",
|
|
141
|
+
statusCode: data.statusCode,
|
|
142
|
+
res: data.body
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
retryCount++;
|
|
146
|
+
var retryTime = Math.floor(Math.random() * 5000);
|
|
147
|
+
log.warn(
|
|
148
|
+
"parseAndCheckLogin",
|
|
149
|
+
"Got status code " +
|
|
150
|
+
data.statusCode +
|
|
151
|
+
" - " +
|
|
152
|
+
retryCount +
|
|
153
|
+
". attempt to retry in " +
|
|
154
|
+
retryTime +
|
|
155
|
+
" milliseconds..."
|
|
156
|
+
);
|
|
157
|
+
var url =
|
|
158
|
+
data.request.uri.protocol +
|
|
159
|
+
"//" +
|
|
160
|
+
data.request.uri.hostname +
|
|
161
|
+
data.request.uri.pathname;
|
|
162
|
+
var reqHeaders = data.request && data.request.headers ? data.request.headers : {};
|
|
163
|
+
var reqContentType = reqHeaders["content-type"] || reqHeaders["Content-Type"] || "";
|
|
164
|
+
if (
|
|
165
|
+
String(reqContentType).split(";")[0] ===
|
|
166
|
+
"multipart/form-data"
|
|
167
|
+
) {
|
|
168
|
+
return bluebird
|
|
169
|
+
.delay(retryTime)
|
|
170
|
+
.then(function () {
|
|
171
|
+
return defaultFuncs.postFormData(
|
|
172
|
+
url,
|
|
173
|
+
ctx.jar,
|
|
174
|
+
data.request.formData,
|
|
175
|
+
{}
|
|
176
|
+
);
|
|
177
|
+
})
|
|
178
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
|
|
179
|
+
} else {
|
|
180
|
+
return bluebird
|
|
181
|
+
.delay(retryTime)
|
|
182
|
+
.then(function () {
|
|
183
|
+
return defaultFuncs.post(url, ctx.jar, data.request.formData);
|
|
184
|
+
})
|
|
185
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (data.statusCode !== 200) {
|
|
189
|
+
var parsedUploadFromNon200 = tryParseUploadPayloadFromNon200();
|
|
190
|
+
if (parsedUploadFromNon200) {
|
|
191
|
+
log.warn(
|
|
192
|
+
"parseAndCheckLogin",
|
|
193
|
+
"Parsed mercury upload payload from non-200 status " + data.statusCode
|
|
194
|
+
);
|
|
195
|
+
return parsedUploadFromNon200;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
throw new Error(
|
|
199
|
+
"parseAndCheckLogin got status code: " +
|
|
200
|
+
data.statusCode +
|
|
201
|
+
". Bailing out of trying to parse response."
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
var res = null;
|
|
206
|
+
try {
|
|
207
|
+
res = JSON.parse(parsing.makeParsable(data.body));
|
|
208
|
+
} catch (e) {
|
|
209
|
+
throw {
|
|
210
|
+
error: "JSON.parse error. Check the `detail` property on this error.",
|
|
211
|
+
detail: e,
|
|
212
|
+
res: data.body
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (res.redirect && data.request.method === "GET") {
|
|
217
|
+
return defaultFuncs
|
|
218
|
+
.get(res.redirect, ctx.jar)
|
|
219
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (
|
|
223
|
+
res.jsmods &&
|
|
224
|
+
res.jsmods.require &&
|
|
225
|
+
Array.isArray(res.jsmods.require[0]) &&
|
|
226
|
+
res.jsmods.require[0][0] === "Cookie"
|
|
227
|
+
) {
|
|
228
|
+
res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace(
|
|
229
|
+
"_js_",
|
|
230
|
+
""
|
|
231
|
+
);
|
|
232
|
+
var cookie = formatCookie(res.jsmods.require[0][3], "facebook");
|
|
233
|
+
var cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
|
|
234
|
+
ctx.jar.setCookie(cookie, "https://www.facebook.com");
|
|
235
|
+
ctx.jar.setCookie(cookie2, "https://www.messenger.com");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (res.jsmods && Array.isArray(res.jsmods.require)) {
|
|
239
|
+
var arr = res.jsmods.require;
|
|
240
|
+
for (var idx in arr) {
|
|
241
|
+
if (arr[idx][0] === "DTSG" && arr[idx][1] === "setToken") {
|
|
242
|
+
ctx.fb_dtsg = arr[idx][3][0];
|
|
243
|
+
ctx.ttstamp = "2";
|
|
244
|
+
for (var j = 0; j < ctx.fb_dtsg.length; j++) {
|
|
245
|
+
ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (res.error === 1357001) {
|
|
252
|
+
throw { error: "Not logged in." };
|
|
253
|
+
}
|
|
254
|
+
return res;
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function saveCookies(jar) {
|
|
260
|
+
return function (res) {
|
|
261
|
+
var cookies = res.headers["set-cookie"] || [];
|
|
262
|
+
cookies.forEach(function (c) {
|
|
263
|
+
if (c.indexOf(".facebook.com") > -1) {
|
|
264
|
+
jar.setCookie(c, "https://www.facebook.com");
|
|
265
|
+
}
|
|
266
|
+
var c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
|
|
267
|
+
jar.setCookie(c2, "https://www.messenger.com");
|
|
268
|
+
});
|
|
269
|
+
return res;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function getAppState(jar) {
|
|
274
|
+
return jar
|
|
275
|
+
.getCookies("https://www.facebook.com")
|
|
276
|
+
.concat(jar.getCookies("https://facebook.com"))
|
|
277
|
+
.concat(jar.getCookies("https://www.messenger.com"));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = {
|
|
281
|
+
makeDefaults,
|
|
282
|
+
parseAndCheckLogin,
|
|
283
|
+
saveCookies,
|
|
284
|
+
getAppState,
|
|
285
|
+
formatCookie
|
|
286
|
+
};
|