shadowx-fca 2.3.0 → 2.5.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/checkUpdate.js +1 -1
- package/index.js +345 -122
- package/package.json +1 -1
- package/src/GetBotInfo.js +57 -0
- package/src/OldMessage.js +38 -10
- package/src/comment.js +213 -0
- package/src/createThemeAI.js +129 -0
- package/src/emoji.js +124 -0
- package/src/friend.js +243 -0
- package/src/gcmember.js +122 -0
- package/src/getUserInfo.js +222 -43
- package/src/listenMqtt.js +9 -116
- package/src/nickname.js +132 -0
- package/src/postFormData.js +46 -0
- package/src/sendMessage.js +224 -235
- package/src/sendTypingIndicator.js +45 -101
- package/src/share.js +62 -0
- package/src/shareContact.js +17 -61
- package/src/stickers.js +117 -0
- package/src/story.js +181 -0
- package/src/theme.js +233 -0
- package/utils.js +24 -1311
package/src/listenMqtt.js
CHANGED
|
@@ -114,27 +114,24 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
114
114
|
|
|
115
115
|
// Display connection success message with branding and loading animation
|
|
116
116
|
const messages = [
|
|
117
|
-
'\n SHADOWX
|
|
118
|
-
|
|
117
|
+
'\n🖤 SHADOWX FCA MQTT Connected',
|
|
118
|
+
`🔰 Region: ${ctx.region || 'PNB'}`,
|
|
119
119
|
`🔄 Auto-reconnect: ${ctx.globalOptions.autoReconnect ? 'Enabled' : 'Disabled'}${ctx.globalOptions.autoReconnect ? ' (reconnects every 3s on disconnect)' : ''}`,
|
|
120
120
|
`⏱️ MQTT Restart Interval: ${ctx.globalOptions.restartListenMqtt?.enable ? `${ctx.globalOptions.restartListenMqtt.timeRestart / 1000}s` : 'Disabled'}`,
|
|
121
|
-
'
|
|
121
|
+
'✅ ShadowX FCA STARTED\n'
|
|
122
122
|
];
|
|
123
123
|
|
|
124
124
|
let index = 0;
|
|
125
125
|
const displayMessages = () => {
|
|
126
126
|
if (index < messages.length) {
|
|
127
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
128
|
-
let frameIndex = 0;
|
|
129
127
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
// loading condition - Using the extra safe method to prevent reconnect spam
|
|
129
|
+
if (index === 0 && !ctx._loadedOnce) {
|
|
130
|
+
process.stdout.write("⏳ Loading...\n");
|
|
131
|
+
ctx._loadedOnce = true;
|
|
132
|
+
}
|
|
134
133
|
|
|
135
134
|
setTimeout(() => {
|
|
136
|
-
clearInterval(loadingInterval);
|
|
137
|
-
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
138
135
|
console.log(messages[index]);
|
|
139
136
|
index++;
|
|
140
137
|
displayMessages();
|
|
@@ -677,110 +674,6 @@ function markDelivery(ctx, api, threadID, messageID) {
|
|
|
677
674
|
|
|
678
675
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
679
676
|
let globalCallback = identity;
|
|
680
|
-
// function getSeqID() {
|
|
681
|
-
// ctx.t_mqttCalled = false;
|
|
682
|
-
// async function attemptRequest(retries = 3) {
|
|
683
|
-
// try {
|
|
684
|
-
// if (!ctx.fb_dtsg) {
|
|
685
|
-
// const dtsg = await api.getFreshDtsg();
|
|
686
|
-
// if (!dtsg) {
|
|
687
|
-
// if (retries > 0) {
|
|
688
|
-
// logger.Warning("Failed to get fb_dtsg, retrying...");
|
|
689
|
-
// await utils.sleep(2000); // Longer delay for token retry
|
|
690
|
-
// return attemptRequest(retries - 1);
|
|
691
|
-
// }
|
|
692
|
-
// throw { error: "Could not obtain fb_dtsg after multiple attempts" };
|
|
693
|
-
// }
|
|
694
|
-
// ctx.fb_dtsg = dtsg;
|
|
695
|
-
// }
|
|
696
|
-
|
|
697
|
-
// const form = {
|
|
698
|
-
// av: ctx.userID,
|
|
699
|
-
// fb_dtsg: ctx.fb_dtsg,
|
|
700
|
-
// queries: JSON.stringify({
|
|
701
|
-
// o0: {
|
|
702
|
-
// doc_id: '3336396659757871',
|
|
703
|
-
// query_params: {
|
|
704
|
-
// limit: 1,
|
|
705
|
-
// before: null,
|
|
706
|
-
// tags: ['INBOX'],
|
|
707
|
-
// includeDeliveryReceipts: false,
|
|
708
|
-
// includeSeqID: true
|
|
709
|
-
// }
|
|
710
|
-
// }
|
|
711
|
-
// }),
|
|
712
|
-
// __user: ctx.userID,
|
|
713
|
-
// __a: '1',
|
|
714
|
-
// __req: '8',
|
|
715
|
-
// __hs: '19577.HYP:comet_pkg.2.1..2.1',
|
|
716
|
-
// dpr: '1',
|
|
717
|
-
// fb_api_caller_class: 'RelayModern',
|
|
718
|
-
// fb_api_req_friendly_name: 'MessengerGraphQLThreadlistFetcher'
|
|
719
|
-
// };
|
|
720
|
-
|
|
721
|
-
// const headers = {
|
|
722
|
-
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
723
|
-
// 'Referer': 'https://www.facebook.com/',
|
|
724
|
-
// 'Origin': 'https://www.facebook.com',
|
|
725
|
-
// 'sec-fetch-site': 'same-origin',
|
|
726
|
-
// 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
727
|
-
// 'Cookie': ctx.jar.getCookieString('https://www.facebook.com'),
|
|
728
|
-
// 'accept': '*/*',
|
|
729
|
-
// 'accept-encoding': 'gzip, deflate, br'
|
|
730
|
-
// };
|
|
731
|
-
|
|
732
|
-
// const resData = await defaultFuncs
|
|
733
|
-
// .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form, { headers })
|
|
734
|
-
// .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
735
|
-
|
|
736
|
-
// if (debugSeq) {
|
|
737
|
-
// console.log('GraphQL SeqID Response:', JSON.stringify(resData, null, 2));
|
|
738
|
-
// }
|
|
739
|
-
|
|
740
|
-
// if (resData.error === 1357004 || resData.error === 1357001) {
|
|
741
|
-
// if (retries > 0) {
|
|
742
|
-
// logger.Warning("Session error, refreshing token and retrying...");
|
|
743
|
-
// ctx.fb_dtsg = null; // Force new token
|
|
744
|
-
// await utils.sleep(2000);
|
|
745
|
-
// return attemptRequest(retries - 1);
|
|
746
|
-
// }
|
|
747
|
-
// throw { error: "Session refresh failed after retries" };
|
|
748
|
-
// }
|
|
749
|
-
|
|
750
|
-
// if (!Array.isArray(resData)) {
|
|
751
|
-
// throw { error: "Invalid response format", res: resData };
|
|
752
|
-
// }
|
|
753
|
-
|
|
754
|
-
// const seqID = resData[0]?.o0?.data?.viewer?.message_threads?.sync_sequence_id;
|
|
755
|
-
// if (!seqID) {
|
|
756
|
-
// throw { error: "Missing sync_sequence_id", res: resData };
|
|
757
|
-
// }
|
|
758
|
-
|
|
759
|
-
// ctx.lastSeqId = seqID;
|
|
760
|
-
// if (debugSeq) {
|
|
761
|
-
// console.log('Got SeqID:', ctx.lastSeqId);
|
|
762
|
-
// }
|
|
763
|
-
|
|
764
|
-
// return listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
|
765
|
-
|
|
766
|
-
// } catch (err) {
|
|
767
|
-
// if (retries > 0) {
|
|
768
|
-
// console.log("Request failed, retrying...");
|
|
769
|
-
|
|
770
|
-
// return attemptRequest(retries - 1);
|
|
771
|
-
// }
|
|
772
|
-
// throw err;
|
|
773
|
-
// }
|
|
774
|
-
// }
|
|
775
|
-
|
|
776
|
-
// return attemptRequest()
|
|
777
|
-
// .catch((err) => {
|
|
778
|
-
// log.error("getSeqId", err);
|
|
779
|
-
// if (utils.getType(err) == "Object" && err.error === "Not logged in") ctx.loggedIn = false;
|
|
780
|
-
// return globalCallback(err);
|
|
781
|
-
// });
|
|
782
|
-
// }
|
|
783
|
-
|
|
784
677
|
getSeqID = function getSeqID() {
|
|
785
678
|
ctx.t_mqttCalled = false;
|
|
786
679
|
defaultFuncs
|
|
@@ -867,4 +760,4 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
867
760
|
api.stopListeningAsync = msgEmitter.stopListeningAsync;
|
|
868
761
|
return msgEmitter;
|
|
869
762
|
};
|
|
870
|
-
};
|
|
763
|
+
};
|
package/src/nickname.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
6
|
+
/**
|
|
7
|
+
* Author: S4hiilAns4ri (github.com/S4hiilAns4ri)
|
|
8
|
+
* Mqtt
|
|
9
|
+
* Sets a nickname for a participant in a Facebook thread via MQTT.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} nickname The new nickname to set.
|
|
12
|
+
* @param {string} threadID The ID of the thread.
|
|
13
|
+
* @param {string} participantID The ID of the participant whose nickname will be changed. Defaults to the current user's ID if not provided or a function.
|
|
14
|
+
* @param {Function} [callback] Optional callback function to be invoked upon completion.
|
|
15
|
+
* @param {string} [initiatorID] The ID of the user who initiated the nickname change (e.g., from event.senderID).
|
|
16
|
+
* @returns {Promise<object>} A promise that resolves with a structured event object on success or rejects on error.
|
|
17
|
+
*/
|
|
18
|
+
return function setNickname(nickname, threadID, participantID, callback, initiatorID) {
|
|
19
|
+
let _callback;
|
|
20
|
+
let _initiatorID;
|
|
21
|
+
|
|
22
|
+
let _resolvePromise;
|
|
23
|
+
let _rejectPromise;
|
|
24
|
+
const returnPromise = new Promise((resolve, reject) => {
|
|
25
|
+
_resolvePromise = resolve;
|
|
26
|
+
_rejectPromise = reject;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (utils.getType(callback) === "Function" || utils.getType(callback) === "AsyncFunction") {
|
|
30
|
+
_callback = callback;
|
|
31
|
+
_initiatorID = initiatorID;
|
|
32
|
+
} else if (utils.getType(threadID) === "Function" || utils.getType(threadID) === "AsyncFunction") {
|
|
33
|
+
_callback = threadID;
|
|
34
|
+
threadID = null;
|
|
35
|
+
_initiatorID = callback;
|
|
36
|
+
} else if (utils.getType(participantID) === "Function" || utils.getType(participantID) === "AsyncFunction") {
|
|
37
|
+
_callback = participantID;
|
|
38
|
+
participantID = ctx.userID;
|
|
39
|
+
_initiatorID = callback;
|
|
40
|
+
}
|
|
41
|
+
else if (utils.getType(callback) === "string") {
|
|
42
|
+
_initiatorID = callback;
|
|
43
|
+
_callback = undefined;
|
|
44
|
+
} else {
|
|
45
|
+
_callback = undefined;
|
|
46
|
+
_initiatorID = undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!_callback) {
|
|
50
|
+
_callback = function (__err, __data) {
|
|
51
|
+
if (__err) _rejectPromise(__err);
|
|
52
|
+
else _resolvePromise(__data);
|
|
53
|
+
};
|
|
54
|
+
} else {
|
|
55
|
+
const originalCallback = _callback;
|
|
56
|
+
_callback = function(__err, __data) {
|
|
57
|
+
if (__err) {
|
|
58
|
+
originalCallback(__err);
|
|
59
|
+
_rejectPromise(__err);
|
|
60
|
+
} else {
|
|
61
|
+
originalCallback(null, __data);
|
|
62
|
+
_resolvePromise(__data);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_initiatorID = _initiatorID || ctx.userID;
|
|
68
|
+
|
|
69
|
+
threadID = threadID || ctx.threadID;
|
|
70
|
+
participantID = participantID || ctx.userID;
|
|
71
|
+
|
|
72
|
+
if (!threadID) {
|
|
73
|
+
return _callback(new Error("threadID is required to set a nickname."));
|
|
74
|
+
}
|
|
75
|
+
if (typeof nickname !== 'string') {
|
|
76
|
+
return _callback(new Error("nickname must be a string."));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!ctx.mqttClient) {
|
|
80
|
+
return _callback(new Error("Not connected to MQTT"));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ctx.wsReqNumber += 1;
|
|
84
|
+
ctx.wsTaskNumber += 1;
|
|
85
|
+
|
|
86
|
+
const queryPayload = {
|
|
87
|
+
thread_key: threadID.toString(),
|
|
88
|
+
contact_id: participantID.toString(),
|
|
89
|
+
nickname: nickname,
|
|
90
|
+
sync_group: 1,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const query = {
|
|
94
|
+
failure_count: null,
|
|
95
|
+
label: '44',
|
|
96
|
+
payload: JSON.stringify(queryPayload),
|
|
97
|
+
queue_name: 'thread_participant_nickname',
|
|
98
|
+
task_id: ctx.wsTaskNumber,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const context = {
|
|
102
|
+
app_id: ctx.appID,
|
|
103
|
+
payload: {
|
|
104
|
+
epoch_id: parseInt(utils.generateOfflineThreadingID()),
|
|
105
|
+
tasks: [query],
|
|
106
|
+
version_id: '24631415369801570',
|
|
107
|
+
},
|
|
108
|
+
request_id: ctx.wsReqNumber,
|
|
109
|
+
type: 3,
|
|
110
|
+
};
|
|
111
|
+
context.payload = JSON.stringify(context.payload);
|
|
112
|
+
|
|
113
|
+
ctx.mqttClient.publish('/ls_req', JSON.stringify(context), { qos: 1, retain: false }, (err) => {
|
|
114
|
+
if (err) {
|
|
115
|
+
return _callback(new Error(`MQTT publish failed for setNickname: ${err.message || err}`));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const nicknameChangeEvent = {
|
|
119
|
+
type: "thread_nickname_update",
|
|
120
|
+
threadID: threadID,
|
|
121
|
+
participantID: participantID,
|
|
122
|
+
newNickname: nickname,
|
|
123
|
+
senderID: _initiatorID,
|
|
124
|
+
BotID: ctx.userID,
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
};
|
|
127
|
+
_callback(null, nicknameChangeEvent);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return returnPromise;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = require("../utils");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function postFormData(url, form, callback) {
|
|
8
|
+
var resolveFunc = function () {};
|
|
9
|
+
var rejectFunc = function () {};
|
|
10
|
+
|
|
11
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
12
|
+
resolveFunc = resolve;
|
|
13
|
+
rejectFunc = reject;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (
|
|
17
|
+
!callback &&
|
|
18
|
+
(utils.getType(form) == "Function" ||
|
|
19
|
+
utils.getType(form) == "AsyncFunction")
|
|
20
|
+
) {
|
|
21
|
+
callback = form;
|
|
22
|
+
form = {};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
form = form || {};
|
|
26
|
+
|
|
27
|
+
callback =
|
|
28
|
+
callback ||
|
|
29
|
+
function (err, data) {
|
|
30
|
+
if (err) return rejectFunc(err);
|
|
31
|
+
resolveFunc(data);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
defaultFuncs
|
|
35
|
+
.postFormData(url, ctx.jar, form, {})
|
|
36
|
+
.then(function (resData) {
|
|
37
|
+
callback(null, resData.body.toString());
|
|
38
|
+
})
|
|
39
|
+
.catch(function (err) {
|
|
40
|
+
log.error("postFormData", err);
|
|
41
|
+
return callback(err);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return returnPromise;
|
|
45
|
+
};
|
|
46
|
+
};
|