@lazyneoaz/testfca 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 +229 -0
- package/COOKIE_LOGIN.md +208 -0
- package/LICENSE +3 -0
- package/README.md +492 -0
- package/index.js +2 -0
- package/package.json +120 -0
- package/scripts/build-go.mjs +54 -0
- package/scripts/detect-platform.mjs +36 -0
- package/scripts/download-prebuilt.mjs +119 -0
- package/scripts/package.mjs +6 -0
- package/scripts/postinstall.mjs +113 -0
- package/src/apis/addExternalModule.js +24 -0
- package/src/apis/addUserToGroup.js +108 -0
- package/src/apis/changeAdminStatus.js +148 -0
- package/src/apis/changeArchivedStatus.js +61 -0
- package/src/apis/changeAvatar.js +103 -0
- package/src/apis/changeBio.js +69 -0
- package/src/apis/changeBlockedStatus.js +54 -0
- package/src/apis/changeGroupImage.js +136 -0
- package/src/apis/changeThreadColor.js +116 -0
- package/src/apis/changeThreadEmoji.js +53 -0
- package/src/apis/comment.js +207 -0
- package/src/apis/createAITheme.js +129 -0
- package/src/apis/createNewGroup.js +79 -0
- package/src/apis/createPoll.js +73 -0
- package/src/apis/deleteMessage.js +52 -0
- package/src/apis/deleteThread.js +52 -0
- package/src/apis/e2ee.js +170 -0
- package/src/apis/editMessage.js +78 -0
- package/src/apis/emoji.js +124 -0
- package/src/apis/fetchThemeData.js +82 -0
- package/src/apis/follow.js +81 -0
- package/src/apis/forwardMessage.js +52 -0
- package/src/apis/friend.js +243 -0
- package/src/apis/gcmember.js +122 -0
- package/src/apis/gcname.js +123 -0
- package/src/apis/gcrule.js +119 -0
- package/src/apis/getAccess.js +111 -0
- package/src/apis/getBotInfo.js +88 -0
- package/src/apis/getBotInitialData.js +43 -0
- package/src/apis/getFriendsList.js +79 -0
- package/src/apis/getMessage.js +423 -0
- package/src/apis/getTheme.js +95 -0
- package/src/apis/getThemeInfo.js +116 -0
- package/src/apis/getThreadHistory.js +239 -0
- package/src/apis/getThreadInfo.js +267 -0
- package/src/apis/getThreadList.js +232 -0
- package/src/apis/getThreadPictures.js +58 -0
- package/src/apis/getUserID.js +117 -0
- package/src/apis/getUserInfo.js +513 -0
- package/src/apis/getUserInfoV2.js +146 -0
- package/src/apis/handleMessageRequest.js +50 -0
- package/src/apis/httpGet.js +63 -0
- package/src/apis/httpPost.js +89 -0
- package/src/apis/httpPostFormData.js +69 -0
- package/src/apis/listenMqtt.js +1236 -0
- package/src/apis/listenSpeed.js +179 -0
- package/src/apis/logout.js +93 -0
- package/src/apis/markAsDelivered.js +47 -0
- package/src/apis/markAsRead.js +115 -0
- package/src/apis/markAsReadAll.js +40 -0
- package/src/apis/markAsSeen.js +70 -0
- package/src/apis/mqttDeltaValue.js +250 -0
- package/src/apis/muteThread.js +45 -0
- package/src/apis/nickname.js +132 -0
- package/src/apis/notes.js +163 -0
- package/src/apis/pinMessage.js +150 -0
- package/src/apis/produceMetaTheme.js +180 -0
- package/src/apis/realtime.js +182 -0
- package/src/apis/removeUserFromGroup.js +117 -0
- package/src/apis/resolvePhotoUrl.js +58 -0
- package/src/apis/searchForThread.js +154 -0
- package/src/apis/sendMessage.js +346 -0
- package/src/apis/sendMessageMqtt.js +248 -0
- package/src/apis/sendTypingIndicator.js +105 -0
- package/src/apis/setMessageReaction.js +38 -0
- package/src/apis/setMessageReactionMqtt.js +61 -0
- package/src/apis/setThreadTheme.js +260 -0
- package/src/apis/setThreadThemeMqtt.js +94 -0
- package/src/apis/share.js +107 -0
- package/src/apis/shareContact.js +66 -0
- package/src/apis/stickers.js +257 -0
- package/src/apis/story.js +181 -0
- package/src/apis/theme.js +233 -0
- package/src/apis/unfriend.js +47 -0
- package/src/apis/unsendMessage.js +25 -0
- package/src/database/appStateBackup.js +298 -0
- package/src/database/models/index.js +56 -0
- package/src/database/models/thread.js +31 -0
- package/src/database/models/user.js +32 -0
- package/src/database/threadData.js +101 -0
- package/src/database/userData.js +90 -0
- package/src/e2ee/bridge.js +275 -0
- package/src/e2ee/index.js +60 -0
- package/src/engine/client.js +95 -0
- package/src/engine/models/buildAPI.js +152 -0
- package/src/engine/models/loginHelper.js +574 -0
- package/src/engine/models/setOptions.js +88 -0
- package/src/types/index.d.ts +574 -0
- package/src/utils/antiSuspension.js +529 -0
- package/src/utils/auth-helpers.js +149 -0
- package/src/utils/autoReLogin.js +336 -0
- package/src/utils/axios.js +436 -0
- package/src/utils/cache.js +54 -0
- package/src/utils/clients.js +282 -0
- package/src/utils/constants.js +410 -0
- package/src/utils/formatters/data/formatAttachment.js +370 -0
- package/src/utils/formatters/data/formatDelta.js +109 -0
- package/src/utils/formatters/index.js +159 -0
- package/src/utils/formatters/value/formatCookie.js +91 -0
- package/src/utils/formatters/value/formatDate.js +36 -0
- package/src/utils/formatters/value/formatID.js +16 -0
- package/src/utils/formatters.js +1373 -0
- package/src/utils/headers.js +235 -0
- package/src/utils/index.js +153 -0
- package/src/utils/monitoring.js +333 -0
- package/src/utils/rateLimiter.js +319 -0
- package/src/utils/tokenRefresh.js +680 -0
- package/src/utils/user-agents.js +238 -0
- package/src/utils/validation.js +157 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
const mqtt = require('mqtt');
|
|
5
|
+
const websocket = require('websocket-stream');
|
|
6
|
+
const HttpsProxyAgent = require('https-proxy-agent');
|
|
7
|
+
const EventEmitter = require('events');
|
|
8
|
+
|
|
9
|
+
function connectLightspeed(ctx, globalCallback) {
|
|
10
|
+
let client;
|
|
11
|
+
let isStopped = false;
|
|
12
|
+
const guard = (label, fn) => (...args) => {
|
|
13
|
+
try {
|
|
14
|
+
return fn(...args);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
utils.error(`[Lightspeed] ${label} handler error:`, err && err.message ? err.message : err);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function startConnection(retryCount = 0) {
|
|
21
|
+
if (isStopped) return;
|
|
22
|
+
|
|
23
|
+
const chatOn = ctx.globalOptions.online;
|
|
24
|
+
const foreground = false;
|
|
25
|
+
const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
|
|
26
|
+
const cookies = ctx.jar.getCookiesSync('https://www.facebook.com').join('; ');
|
|
27
|
+
const cid = ctx.clientID;
|
|
28
|
+
|
|
29
|
+
const username = {
|
|
30
|
+
u: ctx.userID,
|
|
31
|
+
s: sessionID,
|
|
32
|
+
chat_on: chatOn,
|
|
33
|
+
fg: foreground,
|
|
34
|
+
d: cid,
|
|
35
|
+
ct: 'websocket',
|
|
36
|
+
aid: '2220391788200892',
|
|
37
|
+
mqtt_sid: '',
|
|
38
|
+
cp: 3,
|
|
39
|
+
ecp: 10,
|
|
40
|
+
st: [],
|
|
41
|
+
pm: [],
|
|
42
|
+
dc: '',
|
|
43
|
+
no_auto_fg: true,
|
|
44
|
+
gas: null,
|
|
45
|
+
pack: [],
|
|
46
|
+
a: ctx.globalOptions.userAgent,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const queryParams = new URLSearchParams({
|
|
50
|
+
'x-dgw-appid': '2220391788200892',
|
|
51
|
+
'x-dgw-appversion': '0',
|
|
52
|
+
'x-dgw-authtype': '1:0',
|
|
53
|
+
'x-dgw-version': '5',
|
|
54
|
+
'x-dgw-uuid': ctx.userID,
|
|
55
|
+
'x-dgw-tier': 'prod',
|
|
56
|
+
'x-dgw-loggingid': utils.getGUID(),
|
|
57
|
+
'x-dgw-regionhint': ctx.region || 'PRN',
|
|
58
|
+
'x-dgw-deviceid': ctx.clientID
|
|
59
|
+
});
|
|
60
|
+
const host = `wss://gateway.facebook.com/ws/lightspeed?${queryParams.toString()}`;
|
|
61
|
+
|
|
62
|
+
// Generate a unique clientId per session, just like a real browser would
|
|
63
|
+
const lsClientId = 'mqttwsclient_' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36);
|
|
64
|
+
const options = {
|
|
65
|
+
clientId: lsClientId,
|
|
66
|
+
protocolId: 'MQIsdp',
|
|
67
|
+
protocolVersion: 3,
|
|
68
|
+
username: JSON.stringify(username),
|
|
69
|
+
clean: true,
|
|
70
|
+
wsOptions: {
|
|
71
|
+
headers: {
|
|
72
|
+
'Cookie': cookies,
|
|
73
|
+
'Origin': 'https://www.facebook.com',
|
|
74
|
+
'User-Agent': username.a,
|
|
75
|
+
'Referer': 'https://www.facebook.com/',
|
|
76
|
+
'Host': new URL(host).hostname
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
keepalive: 60, // 60s is standard; 10s was too aggressive (sent PING every 10 seconds)
|
|
80
|
+
reconnectPeriod: 0
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (ctx.globalOptions.proxy) {
|
|
84
|
+
options.wsOptions.agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
client = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
|
|
89
|
+
utils.log("[Lightspeed] Attempting MQTT connection...");
|
|
90
|
+
} catch (err) {
|
|
91
|
+
utils.error("[Lightspeed] MQTT Client creation failed:", err.message);
|
|
92
|
+
reconnect(retryCount + 1);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
client.on('connect', guard("connect", () => {
|
|
97
|
+
utils.log("[Lightspeed] MQTT client connected. Attempting to subscribe to topics...");
|
|
98
|
+
retryCount = 0;
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
const topicsToSubscribe = [
|
|
102
|
+
"/t_ms", // Para sa mga messages at deltas
|
|
103
|
+
"/orca_presence", // Para sa online status
|
|
104
|
+
"/messaging_events" // Para sa ibang events
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
topicsToSubscribe.forEach(topic => {
|
|
108
|
+
client.subscribe(topic, (err) => {
|
|
109
|
+
if (err) {
|
|
110
|
+
utils.error(`[Lightspeed] Failed to subscribe to topic ${topic}:`, err.message);
|
|
111
|
+
} else {
|
|
112
|
+
utils.log(`[Lightspeed] Subscribed to topic: ${topic}`);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
client.on('message', guard("message", (topic, payload) => {
|
|
120
|
+
utils.log(`[Lightspeed] Payload Received on topic ${topic}:`);
|
|
121
|
+
globalCallback(null, { type: 'lightspeed_message', topic: topic.toString(), payload: payload });
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
client.on('close', guard("close", () => {
|
|
125
|
+
utils.warn(`[Lightspeed] Connection closed.`);
|
|
126
|
+
if (!isStopped) {
|
|
127
|
+
reconnect(retryCount + 1);
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
client.on('error', guard("error", (err) => {
|
|
132
|
+
utils.error("[Lightspeed] MQTT Connection Error:", err.message);
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function reconnect(retryCount) {
|
|
137
|
+
const delay = Math.min(3000 * Math.pow(2, retryCount), 60000);
|
|
138
|
+
utils.log(`[Lightspeed] Reconnecting in ${delay / 1000} seconds...`);
|
|
139
|
+
setTimeout(() => startConnection(retryCount), delay);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
startConnection();
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
stop: () => {
|
|
146
|
+
isStopped = true;
|
|
147
|
+
if (client) client.end(true);
|
|
148
|
+
utils.log("[Lightspeed] Listener has been manually stopped.");
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
154
|
+
return (callback) => {
|
|
155
|
+
class MessageEmitter extends EventEmitter {
|
|
156
|
+
constructor() {
|
|
157
|
+
super();
|
|
158
|
+
this.listener = null;
|
|
159
|
+
}
|
|
160
|
+
stop() {
|
|
161
|
+
if (this.listener) {
|
|
162
|
+
this.listener.stop();
|
|
163
|
+
}
|
|
164
|
+
this.emit('stop');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const msgEmitter = new MessageEmitter();
|
|
168
|
+
const globalCallback = (error, message) => {
|
|
169
|
+
if (error) return msgEmitter.emit("error", error);
|
|
170
|
+
msgEmitter.emit("message", message);
|
|
171
|
+
};
|
|
172
|
+
if (typeof callback === 'function') {
|
|
173
|
+
msgEmitter.listener = connectLightspeed(ctx, callback);
|
|
174
|
+
} else {
|
|
175
|
+
msgEmitter.listener = connectLightspeed(ctx, globalCallback);
|
|
176
|
+
}
|
|
177
|
+
return msgEmitter;
|
|
178
|
+
};
|
|
179
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} defaultFuncs
|
|
7
|
+
* @param {Object} api
|
|
8
|
+
* @param {Object} ctx
|
|
9
|
+
* @returns {function(): Promise<void>}
|
|
10
|
+
*/
|
|
11
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
12
|
+
/**
|
|
13
|
+
* Logs the current user out of Facebook.
|
|
14
|
+
* @returns {Promise<void>} A promise that resolves when logout is successful or rejects on error.
|
|
15
|
+
*/
|
|
16
|
+
return async function logout() {
|
|
17
|
+
const form = {
|
|
18
|
+
pmid: "0",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const resData = await defaultFuncs
|
|
23
|
+
.post(
|
|
24
|
+
"https://www.facebook.com/bluebar/modern_settings_menu/?help_type=364455653583099&show_contextual_help=1",
|
|
25
|
+
ctx.jar,
|
|
26
|
+
form,
|
|
27
|
+
)
|
|
28
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
29
|
+
|
|
30
|
+
const elem = resData.jsmods.instances[0][2][0].find(v => v.value === "logout");
|
|
31
|
+
if (!elem) {
|
|
32
|
+
throw { error: "Could not find logout form element." };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const html = resData.jsmods.markup.find(v => v[0] === elem.markup.__m)[1].__html;
|
|
36
|
+
|
|
37
|
+
const logoutForm = {
|
|
38
|
+
fb_dtsg: utils.getFrom(html, '"fb_dtsg" value="', '"'),
|
|
39
|
+
ref: utils.getFrom(html, '"ref" value="', '"'),
|
|
40
|
+
h: utils.getFrom(html, '"h" value="', '"'),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const logoutRes = await defaultFuncs
|
|
44
|
+
.post("https://www.facebook.com/logout.php", ctx.jar, logoutForm)
|
|
45
|
+
.then(utils.saveCookies(ctx.jar));
|
|
46
|
+
|
|
47
|
+
if (!logoutRes.headers || !logoutRes.headers.location) {
|
|
48
|
+
throw { error: "An error occurred when logging out." };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await defaultFuncs
|
|
52
|
+
.get(logoutRes.headers.location, ctx.jar)
|
|
53
|
+
.then(utils.saveCookies(ctx.jar));
|
|
54
|
+
|
|
55
|
+
ctx.loggedIn = false;
|
|
56
|
+
|
|
57
|
+
// Clear sensitive session tokens so stale credentials cannot be reused
|
|
58
|
+
// if this ctx object is accidentally referenced again after logout.
|
|
59
|
+
ctx.fb_dtsg = undefined;
|
|
60
|
+
ctx.fb_dtsg_ag = undefined;
|
|
61
|
+
ctx.lsd = undefined;
|
|
62
|
+
ctx.access_token = undefined;
|
|
63
|
+
|
|
64
|
+
// Stop background timers that are owned by this session, if present.
|
|
65
|
+
if (typeof ctx._stopTokenRefresh === 'function') {
|
|
66
|
+
try { ctx._stopTokenRefresh(); } catch (_) {}
|
|
67
|
+
}
|
|
68
|
+
if (typeof ctx._stopAutoReLogin === 'function') {
|
|
69
|
+
try { ctx._stopAutoReLogin(); } catch (_) {}
|
|
70
|
+
}
|
|
71
|
+
if (typeof ctx._stopCookieBackup === 'function') {
|
|
72
|
+
try { ctx._stopCookieBackup(); } catch (_) {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Stop auto backup
|
|
76
|
+
try {
|
|
77
|
+
const { stopAutoBackup } = require('../database/appStateBackup');
|
|
78
|
+
stopAutoBackup();
|
|
79
|
+
} catch (_) {}
|
|
80
|
+
|
|
81
|
+
// Invalidate the response cache so nothing stale is served after logout.
|
|
82
|
+
if (ctx.cache && typeof ctx.cache.clear === 'function') {
|
|
83
|
+
ctx.cache.clear();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
utils.log("logout", "Logged out successfully.");
|
|
87
|
+
|
|
88
|
+
} catch (err) {
|
|
89
|
+
utils.error("logout", err);
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const utils = require('../utils');
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} defaultFuncs
|
|
7
|
+
* @param {Object} api
|
|
8
|
+
* @param {Object} ctx
|
|
9
|
+
* @returns {function(threadID: string, messageID: string): Promise<void>}
|
|
10
|
+
*/
|
|
11
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
12
|
+
/**
|
|
13
|
+
* Marks a message as delivered.
|
|
14
|
+
* @param {string} threadID - The ID of the thread.
|
|
15
|
+
* @param {string} messageID - The ID of the message to mark as delivered.
|
|
16
|
+
* @returns {Promise<void>} A promise that resolves on success or rejects on error.
|
|
17
|
+
*/
|
|
18
|
+
return async function markAsDelivered(threadID, messageID) {
|
|
19
|
+
if (!threadID || !messageID) {
|
|
20
|
+
const err = "Error: messageID or threadID is not defined";
|
|
21
|
+
utils.error("markAsDelivered", err);
|
|
22
|
+
throw new Error(err);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const form = {};
|
|
26
|
+
form["message_ids[0]"] = messageID;
|
|
27
|
+
form["thread_ids[" + threadID + "][0]"] = messageID;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const resData = await defaultFuncs
|
|
31
|
+
.post(
|
|
32
|
+
"https://www.facebook.com/ajax/mercury/delivery_receipts.php",
|
|
33
|
+
ctx.jar,
|
|
34
|
+
form,
|
|
35
|
+
)
|
|
36
|
+
.then(utils.saveCookies(ctx.jar))
|
|
37
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
38
|
+
|
|
39
|
+
if (resData.error) {
|
|
40
|
+
throw resData;
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
utils.error("markAsDelivered", err);
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} defaultFuncs
|
|
7
|
+
* @param {Object} api
|
|
8
|
+
* @param {Object} ctx
|
|
9
|
+
*/
|
|
10
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
11
|
+
/**
|
|
12
|
+
* Marks a thread as read.
|
|
13
|
+
* @param {string} threadID - The ID of the thread to mark as read.
|
|
14
|
+
* @param {boolean} [read=true] - Whether to mark as read (true) or unread (false). Defaults to true.
|
|
15
|
+
* @param {Function} [callback] - The callback function.
|
|
16
|
+
* @returns {Promise<null|Error>} A Promise that resolves with null on success, or rejects with an Error.
|
|
17
|
+
*/
|
|
18
|
+
return async function markAsRead(threadID, read, callback) {
|
|
19
|
+
if (
|
|
20
|
+
utils.getType(read) === "Function" ||
|
|
21
|
+
utils.getType(read) === "AsyncFunction"
|
|
22
|
+
) {
|
|
23
|
+
callback = read;
|
|
24
|
+
read = true;
|
|
25
|
+
}
|
|
26
|
+
if (read == undefined) {
|
|
27
|
+
read = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!callback) {
|
|
31
|
+
callback = () => {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// E2EE routing: if threadID is a JID (e.g. '61234@msgr')
|
|
35
|
+
const threadStr = threadID ? threadID.toString() : '';
|
|
36
|
+
if (threadStr.includes('@msgr') || threadStr.includes('@facebook')) {
|
|
37
|
+
if (api.e2ee && api.e2ee.isAvailable() && api.e2ee.isConnected().e2eeConnected) {
|
|
38
|
+
try {
|
|
39
|
+
await api.e2ee.markRead(threadStr, Date.now());
|
|
40
|
+
callback();
|
|
41
|
+
} catch (err) {
|
|
42
|
+
callback(err);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
callback(new Error("E2EE not connected. Call api.e2ee.connect() and api.e2ee.connectE2EE() first."));
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const form = {};
|
|
51
|
+
|
|
52
|
+
if (typeof ctx.globalOptions.pageID !== "undefined") {
|
|
53
|
+
form["source"] = "PagesManagerMessagesInterface";
|
|
54
|
+
form["request_user_id"] = ctx.globalOptions.pageID;
|
|
55
|
+
form["ids[" + threadID + "]"] = read;
|
|
56
|
+
form["watermarkTimestamp"] = new Date().getTime();
|
|
57
|
+
form["shouldSendReadReceipt"] = true;
|
|
58
|
+
form["commerce_last_message_type"] = "";
|
|
59
|
+
|
|
60
|
+
let resData;
|
|
61
|
+
try {
|
|
62
|
+
resData = await defaultFuncs
|
|
63
|
+
.post(
|
|
64
|
+
"https://www.facebook.com/ajax/mercury/change_read_status.php",
|
|
65
|
+
ctx.jar,
|
|
66
|
+
form,
|
|
67
|
+
)
|
|
68
|
+
.then(utils.saveCookies(ctx.jar))
|
|
69
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
70
|
+
} catch (e) {
|
|
71
|
+
callback(e);
|
|
72
|
+
return e;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (resData.error) {
|
|
76
|
+
const err = resData.error;
|
|
77
|
+
utils.error("markAsRead", err);
|
|
78
|
+
callback(err);
|
|
79
|
+
return err;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
callback();
|
|
83
|
+
return null;
|
|
84
|
+
} else {
|
|
85
|
+
try {
|
|
86
|
+
if (ctx.mqttClient) {
|
|
87
|
+
await new Promise((resolve, reject) => {
|
|
88
|
+
// Guard against a disconnected MQTT client hanging forever.
|
|
89
|
+
const timer = setTimeout(
|
|
90
|
+
() => reject(new Error("markAsRead: MQTT publish timed out after 8s")),
|
|
91
|
+
8000
|
|
92
|
+
);
|
|
93
|
+
ctx.mqttClient.publish(
|
|
94
|
+
"/mark_thread",
|
|
95
|
+
JSON.stringify({ threadID, mark: "read", state: read }),
|
|
96
|
+
{ qos: 1, retain: false },
|
|
97
|
+
(err, _packet) => {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
if (err) reject(err);
|
|
100
|
+
else resolve();
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
throw {
|
|
106
|
+
error: "You can only use this function after you start listening.",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
} catch (e) {
|
|
110
|
+
callback(e);
|
|
111
|
+
return e;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} defaultFuncs
|
|
8
|
+
* @param {Object} api
|
|
9
|
+
* @param {Object} ctx
|
|
10
|
+
* @returns {function(): Promise<void>}
|
|
11
|
+
*/
|
|
12
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
13
|
+
/**
|
|
14
|
+
* @returns {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
return async function markAsReadAll() {
|
|
17
|
+
const form = {
|
|
18
|
+
folder: "inbox",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const parsedData = await defaultFuncs
|
|
23
|
+
.post(
|
|
24
|
+
"https://www.facebook.com/ajax/mercury/mark_folder_as_read.php",
|
|
25
|
+
ctx.jar,
|
|
26
|
+
form
|
|
27
|
+
)
|
|
28
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
29
|
+
|
|
30
|
+
if (parsedData.error) {
|
|
31
|
+
throw parsedData;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return;
|
|
35
|
+
} catch (err) {
|
|
36
|
+
utils.error("markAsReadAll", err);
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} defaultFuncs
|
|
7
|
+
* @param {Object} api
|
|
8
|
+
* @param {Object} ctx
|
|
9
|
+
*/
|
|
10
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
11
|
+
/**
|
|
12
|
+
* Marks all messages as "seen" up to a specific timestamp.
|
|
13
|
+
* @param {number} [seen_timestamp=Date.now()] - The timestamp (in milliseconds) up to which messages should be marked as seen. If a function is provided, it's treated as the callback and the timestamp defaults to the current time.
|
|
14
|
+
* @param {Function} [callback] - The callback function.
|
|
15
|
+
* @returns {Promise<void>} A Promise that resolves on success or rejects with an error.
|
|
16
|
+
*/
|
|
17
|
+
return async function markAsSeen(seen_timestamp, callback) {
|
|
18
|
+
let resolveFunc = function () {};
|
|
19
|
+
let rejectFunc = function () {};
|
|
20
|
+
const returnPromise = new Promise(function (resolve, reject) {
|
|
21
|
+
resolveFunc = resolve;
|
|
22
|
+
rejectFunc = reject;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (utils.getType(seen_timestamp) == "Function" || utils.getType(seen_timestamp) == "AsyncFunction") {
|
|
26
|
+
callback = seen_timestamp;
|
|
27
|
+
seen_timestamp = Date.now();
|
|
28
|
+
} else if (seen_timestamp === undefined) {
|
|
29
|
+
seen_timestamp = Date.now();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!callback) {
|
|
33
|
+
callback = function (err, friendList) {
|
|
34
|
+
if (err) {
|
|
35
|
+
return rejectFunc(err);
|
|
36
|
+
}
|
|
37
|
+
resolveFunc(friendList);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const form = {
|
|
42
|
+
seen_timestamp: seen_timestamp,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const resData = await defaultFuncs
|
|
47
|
+
.post(
|
|
48
|
+
"https://www.facebook.com/ajax/mercury/mark_seen.php",
|
|
49
|
+
ctx.jar,
|
|
50
|
+
form,
|
|
51
|
+
)
|
|
52
|
+
.then(utils.saveCookies(ctx.jar))
|
|
53
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
54
|
+
|
|
55
|
+
if (resData.error) {
|
|
56
|
+
throw resData;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return callback();
|
|
60
|
+
} catch (err) {
|
|
61
|
+
utils.error("markAsSeen", err);
|
|
62
|
+
if (utils.getType(err) == "Object" && err.error === "Not logged in.") {
|
|
63
|
+
ctx.loggedIn = false;
|
|
64
|
+
}
|
|
65
|
+
return callback(err);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return returnPromise;
|
|
69
|
+
};
|
|
70
|
+
};
|