nexus-fca 1.0.0
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/CHANGELOG.md +1 -0
- package/DOCS.md +2047 -0
- package/Fca_Database/database.sqlite +0 -0
- package/LICENSE-MIT +21 -0
- package/README.md +240 -0
- package/docs/README.md +9 -0
- package/docs/addExternalModule.md +15 -0
- package/docs/addUserToGroup.md +20 -0
- package/docs/changeAdminStatus.md +21 -0
- package/docs/changeArchivedStatus.md +19 -0
- package/docs/changeAvatar.md +21 -0
- package/docs/changeAvatarV2.md +18 -0
- package/docs/changeBio.md +15 -0
- package/docs/changeBlockedStatus.md +16 -0
- package/docs/changeBlockedStatusMqtt.md +16 -0
- package/docs/changeCover.md +15 -0
- package/docs/changeGroupImage.md +16 -0
- package/docs/changeName.md +18 -0
- package/docs/changeNickname.md +17 -0
- package/docs/changeThreadColor.md +16 -0
- package/docs/changeThreadEmoji.md +16 -0
- package/docs/changeUsername.md +15 -0
- package/docs/createCommentPost.md +16 -0
- package/docs/createNewGroup.md +16 -0
- package/docs/createPoll.md +17 -0
- package/docs/createPost.md +15 -0
- package/docs/deleteMessage.md +15 -0
- package/docs/deleteThread.md +15 -0
- package/docs/editMessage.md +16 -0
- package/docs/follow.md +15 -0
- package/docs/forwardAttachment.md +16 -0
- package/docs/getAccess.md +17 -0
- package/docs/getAvatarUser.md +15 -0
- package/docs/getBotInitialData.md +14 -0
- package/docs/getCtx.md +14 -0
- package/docs/getCurrentUserID.md +12 -0
- package/docs/getEmojiUrl.md +17 -0
- package/docs/getFriendsList.md +14 -0
- package/docs/getMessage.md +15 -0
- package/docs/getOptions.md +14 -0
- package/docs/getRegion.md +14 -0
- package/docs/getThreadHistory.md +17 -0
- package/docs/getThreadHistoryDeprecated.md +17 -0
- package/docs/getThreadInfo.md +15 -0
- package/docs/getThreadInfoDeprecated.md +17 -0
- package/docs/getThreadList.md +17 -0
- package/docs/getThreadListDeprecated.md +17 -0
- package/docs/getThreadPictures.md +17 -0
- package/docs/getUID.md +15 -0
- package/docs/getUserID.md +15 -0
- package/docs/getUserInfo.md +15 -0
- package/docs/handleFriendRequest.md +16 -0
- package/docs/handleMessageRequest.md +16 -0
- package/docs/httpGet.md +15 -0
- package/docs/httpPost.md +16 -0
- package/docs/httpPostFormData.md +16 -0
- package/docs/listenMqtt.md +17 -0
- package/docs/listenNotification.md +14 -0
- package/docs/logout.md +14 -0
- package/docs/markAsDelivered.md +16 -0
- package/docs/markAsRead.md +16 -0
- package/docs/markAsReadAll.md +14 -0
- package/docs/markAsSeen.md +15 -0
- package/docs/muteThread.md +16 -0
- package/docs/pinMessage.md +17 -0
- package/docs/postFormData.md +16 -0
- package/docs/refreshFb_dtsg.md +14 -0
- package/docs/removeUserFromGroup.md +16 -0
- package/docs/resolvePhotoUrl.md +15 -0
- package/docs/searchForThread.md +15 -0
- package/docs/searchStickers.md +15 -0
- package/docs/sendComment.md +16 -0
- package/docs/sendMessage.md +16 -0
- package/docs/sendMessageMqtt.md +16 -0
- package/docs/sendTypingIndicator.md +15 -0
- package/docs/setMessageReaction.md +17 -0
- package/docs/setMessageReactionMqtt.md +16 -0
- package/docs/setPostReaction.md +16 -0
- package/docs/setProfileGuard.md +15 -0
- package/docs/setStoryReaction.md +16 -0
- package/docs/setTitle.md +16 -0
- package/docs/shareContact.md +16 -0
- package/docs/shareLink.md +16 -0
- package/docs/stopListenMqtt.md +8 -0
- package/docs/threadColors.md +11 -0
- package/docs/unfriend.md +15 -0
- package/docs/unsendMessage.md +15 -0
- package/docs/uploadAttachment.md +15 -0
- package/fca-config.json +7 -0
- package/index.d.ts +618 -0
- package/index.js +361 -0
- package/lib/database/models/index.js +47 -0
- package/lib/database/models/thread.js +31 -0
- package/lib/database/threadData.js +93 -0
- package/lib/logger.js +24 -0
- package/lib/login.js +0 -0
- package/package.json +90 -0
- package/src/addExternalModule.js +19 -0
- package/src/addUserToGroup.js +113 -0
- package/src/changeAdminStatus.js +79 -0
- package/src/changeArchivedStatus.js +55 -0
- package/src/changeAvatar.js +126 -0
- package/src/changeAvatarV2.js +77 -0
- package/src/changeBio.js +77 -0
- package/src/changeBlockedStatus.js +47 -0
- package/src/changeBlockedStatusMqtt.js +71 -0
- package/src/changeCover.js +72 -0
- package/src/changeGroupImage.js +132 -0
- package/src/changeName.js +79 -0
- package/src/changeNickname.js +59 -0
- package/src/changeThreadColor.js +65 -0
- package/src/changeThreadEmoji.js +55 -0
- package/src/changeUsername.js +58 -0
- package/src/createCommentPost.js +225 -0
- package/src/createNewGroup.js +86 -0
- package/src/createPoll.js +71 -0
- package/src/createPost.js +276 -0
- package/src/deleteMessage.js +56 -0
- package/src/deleteThread.js +56 -0
- package/src/editMessage.js +57 -0
- package/src/follow.js +54 -0
- package/src/forwardAttachment.js +60 -0
- package/src/getAccess.js +67 -0
- package/src/getAvatarUser.js +56 -0
- package/src/getBotInitialData.js +37 -0
- package/src/getCtx.js +6 -0
- package/src/getCurrentUserID.js +7 -0
- package/src/getEmojiUrl.js +29 -0
- package/src/getFriendsList.js +83 -0
- package/src/getMessage.js +796 -0
- package/src/getOptions.js +6 -0
- package/src/getRegion.js +8 -0
- package/src/getThreadHistory.js +666 -0
- package/src/getThreadHistoryDeprecated.js +55 -0
- package/src/getThreadInfo.js +535 -0
- package/src/getThreadInfoDeprecated.js +49 -0
- package/src/getThreadList.js +192 -0
- package/src/getThreadListDeprecated.js +54 -0
- package/src/getThreadPictures.js +79 -0
- package/src/getUID.js +67 -0
- package/src/getUserID.js +66 -0
- package/src/getUserInfo.js +80 -0
- package/src/handleFriendRequest.js +61 -0
- package/src/handleMessageRequest.js +65 -0
- package/src/httpGet.js +57 -0
- package/src/httpPost.js +57 -0
- package/src/httpPostFormData.js +63 -0
- package/src/listenMqtt.js +1039 -0
- package/src/listenNotification.js +65 -0
- package/src/logout.js +75 -0
- package/src/markAsDelivered.js +58 -0
- package/src/markAsRead.js +80 -0
- package/src/markAsReadAll.js +50 -0
- package/src/markAsSeen.js +59 -0
- package/src/muteThread.js +52 -0
- package/src/pinMessage.js +59 -0
- package/src/postFormData.js +46 -0
- package/src/refreshFb_dtsg.js +66 -0
- package/src/removeUserFromGroup.js +79 -0
- package/src/resolvePhotoUrl.js +45 -0
- package/src/searchForThread.js +53 -0
- package/src/searchStickers.js +51 -0
- package/src/sendComment.js +63 -0
- package/src/sendMessage.js +328 -0
- package/src/sendMessageMqtt.js +316 -0
- package/src/sendTypingIndicator.js +103 -0
- package/src/setMessageReaction.js +119 -0
- package/src/setMessageReactionMqtt.js +61 -0
- package/src/setPostReaction.js +109 -0
- package/src/setProfileGuard.js +45 -0
- package/src/setStoryReaction.js +62 -0
- package/src/setTitle.js +86 -0
- package/src/shareContact.js +49 -0
- package/src/shareLink.js +59 -0
- package/src/stopListenMqtt.js +21 -0
- package/src/threadColors.js +131 -0
- package/src/unfriend.js +52 -0
- package/src/unsendMessage.js +49 -0
- package/src/uploadAttachment.js +95 -0
- package/utils.js +1432 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function addUserToGroup(userID, threadID, callback) {
|
|
8
|
+
let resolveFunc = function () { };
|
|
9
|
+
let rejectFunc = function () { };
|
|
10
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (
|
|
16
|
+
!callback &&
|
|
17
|
+
(utils.getType(threadID) === "Function" ||
|
|
18
|
+
utils.getType(threadID) === "AsyncFunction")
|
|
19
|
+
) {
|
|
20
|
+
throw new utils.CustomError({ error: "please pass a threadID as a second argument." });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!callback) {
|
|
24
|
+
callback = function (err) {
|
|
25
|
+
if (err) {
|
|
26
|
+
return rejectFunc(err);
|
|
27
|
+
}
|
|
28
|
+
resolveFunc();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
utils.getType(threadID) !== "Number" &&
|
|
34
|
+
utils.getType(threadID) !== "String"
|
|
35
|
+
) {
|
|
36
|
+
throw new utils.CustomError({
|
|
37
|
+
error:
|
|
38
|
+
"ThreadID should be of type Number or String and not " +
|
|
39
|
+
utils.getType(threadID) +
|
|
40
|
+
"."
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (utils.getType(userID) !== "Array") {
|
|
45
|
+
userID = [userID];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const messageAndOTID = utils.generateOfflineThreadingID();
|
|
49
|
+
const form = {
|
|
50
|
+
client: "mercury",
|
|
51
|
+
action_type: "ma-type:log-message",
|
|
52
|
+
author: "fbid:" + (ctx.i_userID || ctx.userID),
|
|
53
|
+
thread_id: "",
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
timestamp_absolute: "Today",
|
|
56
|
+
timestamp_relative: utils.generateTimestampRelative(),
|
|
57
|
+
timestamp_time_passed: "0",
|
|
58
|
+
is_unread: false,
|
|
59
|
+
is_cleared: false,
|
|
60
|
+
is_forward: false,
|
|
61
|
+
is_filtered_content: false,
|
|
62
|
+
is_filtered_content_bh: false,
|
|
63
|
+
is_filtered_content_account: false,
|
|
64
|
+
is_spoof_warning: false,
|
|
65
|
+
source: "source:chat:web",
|
|
66
|
+
"source_tags[0]": "source:chat",
|
|
67
|
+
log_message_type: "log:subscribe",
|
|
68
|
+
status: "0",
|
|
69
|
+
offline_threading_id: messageAndOTID,
|
|
70
|
+
message_id: messageAndOTID,
|
|
71
|
+
threading_id: utils.generateThreadingID(ctx.clientID),
|
|
72
|
+
manual_retry_cnt: "0",
|
|
73
|
+
thread_fbid: threadID
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < userID.length; i++) {
|
|
77
|
+
if (
|
|
78
|
+
utils.getType(userID[i]) !== "Number" &&
|
|
79
|
+
utils.getType(userID[i]) !== "String"
|
|
80
|
+
) {
|
|
81
|
+
throw new utils.CustomError({
|
|
82
|
+
error:
|
|
83
|
+
"Elements of userID should be of type Number or String and not " +
|
|
84
|
+
utils.getType(userID[i]) +
|
|
85
|
+
"."
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
form["log_message_data[added_participants][" + i + "]"] =
|
|
90
|
+
"fbid:" + userID[i];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
defaultFuncs
|
|
94
|
+
.post("https://www.facebook.com/messaging/send/", ctx.jar, form)
|
|
95
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
96
|
+
.then(function (resData) {
|
|
97
|
+
if (!resData) {
|
|
98
|
+
throw new utils.CustomError({ error: "Add to group failed." });
|
|
99
|
+
}
|
|
100
|
+
if (resData.error) {
|
|
101
|
+
throw new utils.CustomError(resData);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return callback();
|
|
105
|
+
})
|
|
106
|
+
.catch(function (err) {
|
|
107
|
+
log.error("addUserToGroup", err);
|
|
108
|
+
return callback(err);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return returnPromise;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeAdminStatus(threadID, adminIDs, adminStatus, callback) {
|
|
8
|
+
if (utils.getType(threadID) !== "String") {
|
|
9
|
+
throw new utils.CustomError({ error: "changeAdminStatus: threadID must be a string" });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (utils.getType(adminIDs) === "String") {
|
|
13
|
+
adminIDs = [adminIDs];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (utils.getType(adminIDs) !== "Array") {
|
|
17
|
+
throw new utils.CustomError({ error: "changeAdminStatus: adminIDs must be an array or string" });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (utils.getType(adminStatus) !== "Boolean") {
|
|
21
|
+
throw new utils.CustomError({ error: "changeAdminStatus: adminStatus must be a string" });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let resolveFunc = function () { };
|
|
25
|
+
let rejectFunc = function () { };
|
|
26
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
27
|
+
resolveFunc = resolve;
|
|
28
|
+
rejectFunc = reject;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (!callback) {
|
|
32
|
+
callback = function (err) {
|
|
33
|
+
if (err) {
|
|
34
|
+
return rejectFunc(err);
|
|
35
|
+
}
|
|
36
|
+
resolveFunc();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
|
|
41
|
+
throw new utils.CustomError({ error: "changeAdminStatus: callback is not a function" });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const form = {
|
|
45
|
+
"thread_fbid": threadID
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let i = 0;
|
|
49
|
+
for (const u of adminIDs) {
|
|
50
|
+
form[`admin_ids[${i++}]`] = u;
|
|
51
|
+
}
|
|
52
|
+
form["add"] = adminStatus;
|
|
53
|
+
|
|
54
|
+
defaultFuncs
|
|
55
|
+
.post("https://www.facebook.com/messaging/save_admins/?dpr=1", ctx.jar, form)
|
|
56
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
57
|
+
.then(function (resData) {
|
|
58
|
+
if (resData.error) {
|
|
59
|
+
switch (resData.error) {
|
|
60
|
+
case 1976004:
|
|
61
|
+
throw new utils.CustomError({ error: "Cannot alter admin status: you are not an admin.", rawResponse: resData });
|
|
62
|
+
case 1357031:
|
|
63
|
+
throw new utils.CustomError({ error: "Cannot alter admin status: this thread is not a group chat.", rawResponse: resData });
|
|
64
|
+
default:
|
|
65
|
+
throw new utils.CustomError({ error: "Cannot alter admin status: unknown error.", rawResponse: resData });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
callback();
|
|
70
|
+
})
|
|
71
|
+
.catch(function (err) {
|
|
72
|
+
log.error("changeAdminStatus", err);
|
|
73
|
+
return callback(err);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return returnPromise;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeArchivedStatus(threadOrThreads, archive, callback) {
|
|
8
|
+
let resolveFunc = function () { };
|
|
9
|
+
let rejectFunc = function () { };
|
|
10
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
callback = function (err) {
|
|
17
|
+
if (err) {
|
|
18
|
+
return rejectFunc(err);
|
|
19
|
+
}
|
|
20
|
+
resolveFunc();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const form = {};
|
|
25
|
+
|
|
26
|
+
if (utils.getType(threadOrThreads) === "Array") {
|
|
27
|
+
for (let i = 0; i < threadOrThreads.length; i++) {
|
|
28
|
+
form["ids[" + threadOrThreads[i] + "]"] = archive;
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
form["ids[" + threadOrThreads + "]"] = archive;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
defaultFuncs
|
|
35
|
+
.post(
|
|
36
|
+
"https://www.facebook.com/ajax/mercury/change_archived_status.php",
|
|
37
|
+
ctx.jar,
|
|
38
|
+
form
|
|
39
|
+
)
|
|
40
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
41
|
+
.then(function (resData) {
|
|
42
|
+
if (resData.error) {
|
|
43
|
+
throw resData;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return callback();
|
|
47
|
+
})
|
|
48
|
+
.catch(function (err) {
|
|
49
|
+
log.error("changeArchivedStatus", err);
|
|
50
|
+
return callback(err);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return returnPromise;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
function handleUpload(image, callback) {
|
|
8
|
+
const uploads = [];
|
|
9
|
+
|
|
10
|
+
const form = {
|
|
11
|
+
profile_id: ctx.i_userID || ctx.userID,
|
|
12
|
+
photo_source: 57,
|
|
13
|
+
av: ctx.i_userID || ctx.userID,
|
|
14
|
+
file: image
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
uploads.push(
|
|
18
|
+
defaultFuncs
|
|
19
|
+
.postFormData(
|
|
20
|
+
"https://www.facebook.com/profile/picture/upload/",
|
|
21
|
+
ctx.jar,
|
|
22
|
+
form,
|
|
23
|
+
{}
|
|
24
|
+
)
|
|
25
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
26
|
+
.then(function (resData) {
|
|
27
|
+
if (resData.error) {
|
|
28
|
+
throw resData;
|
|
29
|
+
}
|
|
30
|
+
return resData;
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// resolve all promises
|
|
35
|
+
Promise
|
|
36
|
+
.all(uploads)
|
|
37
|
+
.then(function (resData) {
|
|
38
|
+
callback(null, resData);
|
|
39
|
+
})
|
|
40
|
+
.catch(function (err) {
|
|
41
|
+
log.error("handleUpload", err);
|
|
42
|
+
return callback(err);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return function changeAvatar(image, caption = "", timestamp = null, callback) {
|
|
47
|
+
let resolveFunc = function () { };
|
|
48
|
+
let rejectFunc = function () { };
|
|
49
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
50
|
+
resolveFunc = resolve;
|
|
51
|
+
rejectFunc = reject;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!timestamp && utils.getType(caption) === "Number") {
|
|
55
|
+
timestamp = caption;
|
|
56
|
+
caption = "";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!timestamp && !callback && (utils.getType(caption) == "Function" || utils.getType(caption) == "AsyncFunction")) {
|
|
60
|
+
callback = caption;
|
|
61
|
+
caption = "";
|
|
62
|
+
timestamp = null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!callback) callback = function (err, data) {
|
|
66
|
+
if (err) {
|
|
67
|
+
return rejectFunc(err);
|
|
68
|
+
}
|
|
69
|
+
resolveFunc(data);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (!utils.isReadableStream(image))
|
|
73
|
+
return callback("Image is not a readable stream");
|
|
74
|
+
|
|
75
|
+
handleUpload(image, function (err, payload) {
|
|
76
|
+
if (err) {
|
|
77
|
+
return callback(err);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const form = {
|
|
81
|
+
av: ctx.i_userID || ctx.userID,
|
|
82
|
+
fb_api_req_friendly_name: "ProfileCometProfilePictureSetMutation",
|
|
83
|
+
fb_api_caller_class: "RelayModern",
|
|
84
|
+
doc_id: "5066134240065849",
|
|
85
|
+
variables: JSON.stringify({
|
|
86
|
+
input: {
|
|
87
|
+
caption,
|
|
88
|
+
existing_photo_id: payload[0].payload.fbid,
|
|
89
|
+
expiration_time: timestamp,
|
|
90
|
+
profile_id: ctx.i_userID || ctx.userID,
|
|
91
|
+
profile_pic_method: "EXISTING",
|
|
92
|
+
profile_pic_source: "TIMELINE",
|
|
93
|
+
scaled_crop_rect: {
|
|
94
|
+
height: 1,
|
|
95
|
+
width: 1,
|
|
96
|
+
x: 0,
|
|
97
|
+
y: 0
|
|
98
|
+
},
|
|
99
|
+
skip_cropping: true,
|
|
100
|
+
actor_id: ctx.i_userID || ctx.userID,
|
|
101
|
+
client_mutation_id: Math.round(Math.random() * 19).toString()
|
|
102
|
+
},
|
|
103
|
+
isPage: false,
|
|
104
|
+
isProfile: true,
|
|
105
|
+
scale: 3
|
|
106
|
+
})
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
defaultFuncs
|
|
110
|
+
.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
|
|
111
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
112
|
+
.then(function (resData) {
|
|
113
|
+
if (resData.errors) {
|
|
114
|
+
throw resData;
|
|
115
|
+
}
|
|
116
|
+
return callback(null, resData[0].data.profile_picture_set);
|
|
117
|
+
})
|
|
118
|
+
.catch(function (err) {
|
|
119
|
+
log.error("changeAvatar", err);
|
|
120
|
+
return callback(err);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return returnPromise;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Nexus-FCA: Advanced and Safe Facebook Chat API
|
|
2
|
+
// changeAvatarV2.js - Change user avatar with advanced options
|
|
3
|
+
|
|
4
|
+
const { rateLimiter, safeMode, isUserAllowed } = require('../utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Change the user's Facebook avatar with advanced safety checks.
|
|
8
|
+
* @param {Object} defaultFuncs - Default functions from Nexus-FCA context
|
|
9
|
+
* @param {Object} api - Nexus-FCA API object
|
|
10
|
+
* @param {Object} ctx - Nexus-FCA context
|
|
11
|
+
* @returns {Function}
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function changeAvatarV2(defaultFuncs, api, ctx) {
|
|
14
|
+
/**
|
|
15
|
+
* Change avatar with file stream or URL, with validation and rate limiting.
|
|
16
|
+
* @param {Object} options - { stream, url }
|
|
17
|
+
* @param {Function} callback
|
|
18
|
+
*/
|
|
19
|
+
const lastChange = { time: 0 };
|
|
20
|
+
return function(options, callback) {
|
|
21
|
+
// Extract userID from context (for rate limiting and allow/block list)
|
|
22
|
+
const userID = ctx.userID || (ctx.globalOptions && ctx.globalOptions.userID) || 'unknown';
|
|
23
|
+
|
|
24
|
+
// Safe mode disables avatar change
|
|
25
|
+
if (safeMode) {
|
|
26
|
+
return callback(new Error("Avatar change is disabled in Nexus-FCA safe mode."));
|
|
27
|
+
}
|
|
28
|
+
// Allow/block list check
|
|
29
|
+
if (!isUserAllowed(userID)) {
|
|
30
|
+
return callback(new Error("You are not allowed to change the avatar."));
|
|
31
|
+
}
|
|
32
|
+
// Rate limiting (per user)
|
|
33
|
+
if (!rateLimiter.check(userID, 'changeAvatarV2')) {
|
|
34
|
+
return callback(new Error("Rate limit exceeded. Please wait before changing avatar again."));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Safety: Only allow change every 5 minutes
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
if (now - lastChange.time < 5 * 60 * 1000) {
|
|
40
|
+
return callback(new Error("Avatar can only be changed every 5 minutes for safety."));
|
|
41
|
+
}
|
|
42
|
+
lastChange.time = now;
|
|
43
|
+
|
|
44
|
+
// Input validation
|
|
45
|
+
if (!options || (!options.stream && !options.url)) {
|
|
46
|
+
return callback(new Error("You must provide a file stream or image URL."));
|
|
47
|
+
}
|
|
48
|
+
if (options.url && !/^https?:\/\//.test(options.url)) {
|
|
49
|
+
return callback(new Error("Invalid image URL."));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Prepare form data
|
|
53
|
+
const form = {};
|
|
54
|
+
if (options.stream) {
|
|
55
|
+
form.file = options.stream;
|
|
56
|
+
} else if (options.url) {
|
|
57
|
+
form.url = options.url;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Use the existing postFormData util for upload
|
|
61
|
+
defaultFuncs.postFormData(
|
|
62
|
+
"https://www.facebook.com/profile/picture/upload/",
|
|
63
|
+
ctx.jar,
|
|
64
|
+
form
|
|
65
|
+
)
|
|
66
|
+
.then(res => {
|
|
67
|
+
if (res.statusCode === 200) {
|
|
68
|
+
callback(null, { success: true, message: "Avatar changed successfully." });
|
|
69
|
+
} else {
|
|
70
|
+
callback(new Error("Failed to change avatar. Status: " + res.statusCode));
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
.catch(err => {
|
|
74
|
+
callback(new Error("Avatar change failed: " + err.message));
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
};
|
package/src/changeBio.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeBio(bio, publish, callback) {
|
|
8
|
+
let resolveFunc = function () { };
|
|
9
|
+
let rejectFunc = function () { };
|
|
10
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
if (utils.getType(publish) == "Function" || utils.getType(publish) == "AsyncFunction") {
|
|
17
|
+
callback = publish;
|
|
18
|
+
} else {
|
|
19
|
+
callback = function (err) {
|
|
20
|
+
if (err) {
|
|
21
|
+
return rejectFunc(err);
|
|
22
|
+
}
|
|
23
|
+
resolveFunc();
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (utils.getType(publish) != "Boolean") {
|
|
29
|
+
publish = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (utils.getType(bio) != "String") {
|
|
33
|
+
bio = "";
|
|
34
|
+
publish = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const form = {
|
|
38
|
+
fb_api_caller_class: "RelayModern",
|
|
39
|
+
fb_api_req_friendly_name: "ProfileCometSetBioMutation",
|
|
40
|
+
// This doc_is is valid as of May 23, 2020
|
|
41
|
+
doc_id: "2725043627607610",
|
|
42
|
+
variables: JSON.stringify({
|
|
43
|
+
input: {
|
|
44
|
+
bio: bio,
|
|
45
|
+
publish_bio_feed_story: publish,
|
|
46
|
+
actor_id: ctx.i_userID || ctx.userID,
|
|
47
|
+
client_mutation_id: Math.round(Math.random() * 1024).toString()
|
|
48
|
+
},
|
|
49
|
+
hasProfileTileViewID: false,
|
|
50
|
+
profileTileViewID: null,
|
|
51
|
+
scale: 1
|
|
52
|
+
}),
|
|
53
|
+
av: ctx.i_userID || ctx.userID
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
defaultFuncs
|
|
57
|
+
.post(
|
|
58
|
+
"https://www.facebook.com/api/graphql/",
|
|
59
|
+
ctx.jar,
|
|
60
|
+
form
|
|
61
|
+
)
|
|
62
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
63
|
+
.then(function (resData) {
|
|
64
|
+
if (resData.errors) {
|
|
65
|
+
throw resData;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return callback();
|
|
69
|
+
})
|
|
70
|
+
.catch(function (err) {
|
|
71
|
+
log.error("changeBio", err);
|
|
72
|
+
return callback(err);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return returnPromise;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeBlockedStatus(userID, block, callback) {
|
|
8
|
+
let resolveFunc = function () { };
|
|
9
|
+
let rejectFunc = function () { };
|
|
10
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
callback = function (err) {
|
|
17
|
+
if (err) {
|
|
18
|
+
return rejectFunc(err);
|
|
19
|
+
}
|
|
20
|
+
resolveFunc();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
defaultFuncs
|
|
25
|
+
.post(
|
|
26
|
+
`https://www.facebook.com/messaging/${block ? "" : "un"}block_messages/`,
|
|
27
|
+
ctx.jar,
|
|
28
|
+
{
|
|
29
|
+
fbid: userID
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
.then(utils.saveCookies(ctx.jar))
|
|
33
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
34
|
+
.then(function (resData) {
|
|
35
|
+
if (resData.error) {
|
|
36
|
+
throw resData;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return callback();
|
|
40
|
+
})
|
|
41
|
+
.catch(function (err) {
|
|
42
|
+
log.error("changeBlockedStatus", err);
|
|
43
|
+
return callback(err);
|
|
44
|
+
});
|
|
45
|
+
return returnPromise;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Nexus-FCA: Advanced and Safe Facebook Chat API
|
|
2
|
+
// changeBlockedStatusMqtt.js - Block/unblock users via MQTT
|
|
3
|
+
|
|
4
|
+
const { generateOfflineThreadingID, getCurrentTimestamp, getGUID } = require('../utils.js');
|
|
5
|
+
|
|
6
|
+
function isCallable(func) {
|
|
7
|
+
try {
|
|
8
|
+
Reflect.apply(func, null, []);
|
|
9
|
+
return true;
|
|
10
|
+
} catch (error) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
16
|
+
return function changeBlockedStatusMqtt(userID, status, type, callback) {
|
|
17
|
+
if (!ctx.mqttClient) {
|
|
18
|
+
throw new Error('Not connected to MQTT');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
ctx.wsReqNumber += 1;
|
|
22
|
+
ctx.wsTaskNumber += 1;
|
|
23
|
+
|
|
24
|
+
const label = '334';
|
|
25
|
+
let userBlockAction = 0;
|
|
26
|
+
|
|
27
|
+
switch (type) {
|
|
28
|
+
case 'messenger':
|
|
29
|
+
userBlockAction = status ? 1 : 0;
|
|
30
|
+
break;
|
|
31
|
+
case 'facebook':
|
|
32
|
+
userBlockAction = status ? 3 : 2;
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
throw new Error('Invalid type');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const taskPayload = {
|
|
39
|
+
blockee_id: userID,
|
|
40
|
+
request_id: getGUID(),
|
|
41
|
+
user_block_action: userBlockAction,
|
|
42
|
+
};
|
|
43
|
+
const payload = JSON.stringify(taskPayload);
|
|
44
|
+
const version = '25393437286970779';
|
|
45
|
+
|
|
46
|
+
const task = {
|
|
47
|
+
failure_count: null,
|
|
48
|
+
label: label,
|
|
49
|
+
payload: payload,
|
|
50
|
+
queue_name: 'native_sync_block',
|
|
51
|
+
task_id: ctx.wsTaskNumber,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const content = {
|
|
55
|
+
app_id: '2220391788200892',
|
|
56
|
+
payload: JSON.stringify({
|
|
57
|
+
tasks: [task],
|
|
58
|
+
epoch_id: parseInt(generateOfflineThreadingID()),
|
|
59
|
+
version_id: version,
|
|
60
|
+
}),
|
|
61
|
+
request_id: ctx.wsReqNumber,
|
|
62
|
+
type: 3,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
if (isCallable(callback)) {
|
|
66
|
+
ctx.reqCallbacks[ctx.wsReqNumber] = callback;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
ctx.mqttClient.publish('/ls_req', JSON.stringify(content), { qos: 1, retain: false });
|
|
70
|
+
};
|
|
71
|
+
};
|