@dongdev/fca-unofficial 3.0.11 → 3.0.15
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 +6 -0
- package/module/loginHelper.js +59 -18
- package/package.json +2 -3
- package/src/api/socket/core/parseDelta.js +97 -66
package/CHANGELOG.md
CHANGED
package/module/loginHelper.js
CHANGED
|
@@ -284,14 +284,31 @@ async function setJarCookies(j, appstate) {
|
|
|
284
284
|
const cookieName = c.name || c.key;
|
|
285
285
|
const cookieValue = c.value;
|
|
286
286
|
if (!cookieName || cookieValue === undefined) continue;
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
287
|
+
|
|
288
|
+
const cookieDomain = c.domain || ".facebook.com";
|
|
289
|
+
const cookiePath = c.path || "/";
|
|
290
|
+
const dom = cookieDomain.replace(/^\./, "");
|
|
291
|
+
|
|
292
|
+
// Format expires if provided
|
|
293
|
+
let expiresStr = "";
|
|
294
|
+
if (c.expires) {
|
|
295
|
+
const expiresDate = typeof c.expires === "number" ? new Date(c.expires) : new Date(c.expires);
|
|
296
|
+
expiresStr = `; expires=${expiresDate.toUTCString()}`;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Build cookie string
|
|
300
|
+
const str = `${cookieName}=${cookieValue}${expiresStr}; Domain=${cookieDomain}; Path=${cookiePath};`;
|
|
301
|
+
|
|
302
|
+
// Set cookie for both http and https, with and without www
|
|
303
|
+
const base1 = `http://${dom}${cookiePath}`;
|
|
304
|
+
const base2 = `https://${dom}${cookiePath}`;
|
|
305
|
+
const base3 = `http://www.${dom}${cookiePath}`;
|
|
306
|
+
const base4 = `https://www.${dom}${cookiePath}`;
|
|
307
|
+
|
|
308
|
+
tasks.push(j.setCookie(str, base1).catch(() => { }));
|
|
309
|
+
tasks.push(j.setCookie(str, base2).catch(() => { }));
|
|
310
|
+
tasks.push(j.setCookie(str, base3).catch(() => { }));
|
|
311
|
+
tasks.push(j.setCookie(str, base4).catch(() => { }));
|
|
295
312
|
}
|
|
296
313
|
await Promise.all(tasks);
|
|
297
314
|
}
|
|
@@ -577,23 +594,47 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
|
|
|
577
594
|
(async () => {
|
|
578
595
|
try {
|
|
579
596
|
if (appState) {
|
|
580
|
-
|
|
597
|
+
// Check and convert cookie to appState format
|
|
598
|
+
if (Array.isArray(appState) && appState.some(c => c.name)) {
|
|
599
|
+
// Convert name to key if needed
|
|
600
|
+
appState = appState.map(c => {
|
|
601
|
+
if (c.name && !c.key) {
|
|
602
|
+
c.key = c.name;
|
|
603
|
+
delete c.name;
|
|
604
|
+
}
|
|
605
|
+
return c;
|
|
606
|
+
});
|
|
607
|
+
} else if (typeof appState === "string") {
|
|
608
|
+
// Try to parse as JSON first
|
|
581
609
|
let parsed = appState;
|
|
582
610
|
try {
|
|
583
611
|
parsed = JSON.parse(appState);
|
|
584
612
|
} catch { }
|
|
613
|
+
|
|
585
614
|
if (Array.isArray(parsed)) {
|
|
586
|
-
//
|
|
587
|
-
|
|
588
|
-
} else if (typeof parsed === "string") {
|
|
589
|
-
const pairs = normalizeCookieHeaderString(parsed);
|
|
590
|
-
if (!pairs.length) throw new Error("Empty appState cookie header");
|
|
591
|
-
setJarFromPairs(jar, pairs, domain);
|
|
615
|
+
// Already parsed as array, use it
|
|
616
|
+
appState = parsed;
|
|
592
617
|
} else {
|
|
593
|
-
|
|
618
|
+
// Parse string cookie format (key=value; key2=value2)
|
|
619
|
+
const arrayAppState = [];
|
|
620
|
+
appState.split(';').forEach(c => {
|
|
621
|
+
const [key, value] = c.split('=');
|
|
622
|
+
if (key && value) {
|
|
623
|
+
arrayAppState.push({
|
|
624
|
+
key: key.trim(),
|
|
625
|
+
value: value.trim(),
|
|
626
|
+
domain: ".facebook.com",
|
|
627
|
+
path: "/",
|
|
628
|
+
expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
appState = arrayAppState;
|
|
594
633
|
}
|
|
595
|
-
}
|
|
596
|
-
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Set cookies into jar with individual domain/path
|
|
637
|
+
if (Array.isArray(appState)) {
|
|
597
638
|
await setJarCookies(jar, appState);
|
|
598
639
|
} else {
|
|
599
640
|
throw new Error("Invalid appState format");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dongdev/fca-unofficial",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.15",
|
|
4
4
|
"description": "Unofficial Facebook Chat API for Node.js - Interact with Facebook Messenger programmatically",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"test": "mocha",
|
|
16
|
-
"lint": "eslint ."
|
|
17
|
-
"prepublishOnly": "npm test"
|
|
16
|
+
"lint": "eslint ."
|
|
18
17
|
},
|
|
19
18
|
"repository": {
|
|
20
19
|
"type": "git",
|
|
@@ -60,61 +60,34 @@ module.exports = function createParseDelta(deps) {
|
|
|
60
60
|
};
|
|
61
61
|
globalCallback(null, messageUnsend);
|
|
62
62
|
} else if (d.deltaMessageReply) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
mentions[m_id[i]] = (d.deltaMessageReply.message.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
|
|
70
|
-
}
|
|
71
|
-
const callbackToReturn = {
|
|
72
|
-
type: "message_reply",
|
|
73
|
-
threadID: (d.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? d.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : d.deltaMessageReply.message.messageMetadata.threadKey.otherUserFbId).toString(),
|
|
74
|
-
messageID: d.deltaMessageReply.message.messageMetadata.messageId,
|
|
75
|
-
senderID: d.deltaMessageReply.message.messageMetadata.actorFbId.toString(),
|
|
76
|
-
attachments: (d.deltaMessageReply.message.attachments || []).map(att => {
|
|
77
|
-
const mercury = JSON.parse(att.mercuryJSON);
|
|
78
|
-
Object.assign(att, mercury);
|
|
79
|
-
return att;
|
|
80
|
-
}).map(att => {
|
|
81
|
-
let x;
|
|
82
|
-
try {
|
|
83
|
-
x = _formatAttachment(att);
|
|
84
|
-
} catch (ex) {
|
|
85
|
-
x = att;
|
|
86
|
-
x.error = ex;
|
|
87
|
-
x.type = "unknown";
|
|
88
|
-
}
|
|
89
|
-
return x;
|
|
90
|
-
}),
|
|
91
|
-
args: (d.deltaMessageReply.message.body || "").trim().split(/\s+/),
|
|
92
|
-
body: d.deltaMessageReply.message.body || "",
|
|
93
|
-
isGroup: !!d.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
|
|
94
|
-
mentions,
|
|
95
|
-
timestamp: parseInt(d.deltaMessageReply.message.messageMetadata.timestamp),
|
|
96
|
-
participantIDs: (d.deltaMessageReply.message.participants || []).map(e => e.toString())
|
|
97
|
-
};
|
|
98
|
-
if (d.deltaMessageReply.repliedToMessage) {
|
|
99
|
-
const mdata2 = d.deltaMessageReply.repliedToMessage === undefined ? [] : d.deltaMessageReply.repliedToMessage.data === undefined ? [] : d.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] : JSON.parse(d.deltaMessageReply.repliedToMessage.data.prng);
|
|
100
|
-
const m_id2 = mdata2.map(u => u.i);
|
|
101
|
-
const m_offset2 = mdata2.map(u => u.o);
|
|
102
|
-
const m_length2 = mdata2.map(u => u.l);
|
|
103
|
-
const rmentions = {};
|
|
104
|
-
for (let i = 0; i < m_id2.length; i++) {
|
|
105
|
-
rmentions[m_id2[i]] = (d.deltaMessageReply.repliedToMessage.body || "").substring(m_offset2[i], m_offset2[i] + m_length2[i]);
|
|
63
|
+
let callbackToReturn;
|
|
64
|
+
try {
|
|
65
|
+
const msg = d.deltaMessageReply.message;
|
|
66
|
+
if (!msg || !msg.messageMetadata) {
|
|
67
|
+
logger("parseDelta: deltaMessageReply.message or messageMetadata is missing", "warn");
|
|
68
|
+
return;
|
|
106
69
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
70
|
+
const mdata = msg === undefined ? [] : msg.data === undefined ? [] : msg.data.prng === undefined ? [] : JSON.parse(msg.data.prng);
|
|
71
|
+
const m_id = mdata.map(u => u.i);
|
|
72
|
+
const m_offset = mdata.map(u => u.o);
|
|
73
|
+
const m_length = mdata.map(u => u.l);
|
|
74
|
+
const mentions = {};
|
|
75
|
+
for (let i = 0; i < m_id.length; i++) {
|
|
76
|
+
mentions[m_id[i]] = (msg.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
|
|
77
|
+
}
|
|
78
|
+
const msgMetadata = msg.messageMetadata;
|
|
79
|
+
const threadKey = msgMetadata.threadKey || {};
|
|
80
|
+
callbackToReturn = {
|
|
81
|
+
type: "message_reply",
|
|
82
|
+
threadID: (threadKey.threadFbId ? threadKey.threadFbId : threadKey.otherUserFbId || "").toString(),
|
|
83
|
+
messageID: msgMetadata.messageId || "",
|
|
84
|
+
senderID: (msgMetadata.actorFbId || "").toString(),
|
|
85
|
+
attachments: (msg.attachments || []).map(att => {
|
|
113
86
|
try {
|
|
114
|
-
mercury = JSON.parse(att.mercuryJSON);
|
|
87
|
+
const mercury = JSON.parse(att.mercuryJSON);
|
|
115
88
|
Object.assign(att, mercury);
|
|
116
89
|
} catch (ex) {
|
|
117
|
-
|
|
90
|
+
// Ignore parsing errors
|
|
118
91
|
}
|
|
119
92
|
return att;
|
|
120
93
|
}).map(att => {
|
|
@@ -128,13 +101,62 @@ module.exports = function createParseDelta(deps) {
|
|
|
128
101
|
}
|
|
129
102
|
return x;
|
|
130
103
|
}),
|
|
131
|
-
args: (
|
|
132
|
-
body:
|
|
133
|
-
isGroup: !!
|
|
134
|
-
mentions
|
|
135
|
-
timestamp: parseInt(
|
|
136
|
-
participantIDs: (
|
|
104
|
+
args: (msg.body || "").trim().split(/\s+/),
|
|
105
|
+
body: msg.body || "",
|
|
106
|
+
isGroup: !!threadKey.threadFbId,
|
|
107
|
+
mentions,
|
|
108
|
+
timestamp: parseInt(msgMetadata.timestamp || 0),
|
|
109
|
+
participantIDs: (msg.participants || []).map(e => e.toString())
|
|
137
110
|
};
|
|
111
|
+
if (d.deltaMessageReply.repliedToMessage) {
|
|
112
|
+
try {
|
|
113
|
+
const repliedTo = d.deltaMessageReply.repliedToMessage;
|
|
114
|
+
const mdata2 = repliedTo === undefined ? [] : repliedTo.data === undefined ? [] : repliedTo.data.prng === undefined ? [] : JSON.parse(repliedTo.data.prng);
|
|
115
|
+
const m_id2 = mdata2.map(u => u.i);
|
|
116
|
+
const m_offset2 = mdata2.map(u => u.o);
|
|
117
|
+
const m_length2 = mdata2.map(u => u.l);
|
|
118
|
+
const rmentions = {};
|
|
119
|
+
for (let i = 0; i < m_id2.length; i++) {
|
|
120
|
+
rmentions[m_id2[i]] = (repliedTo.body || "").substring(m_offset2[i], m_offset2[i] + m_length2[i]);
|
|
121
|
+
}
|
|
122
|
+
const msgMetadata = repliedTo.messageMetadata;
|
|
123
|
+
if (msgMetadata && msgMetadata.threadKey) {
|
|
124
|
+
callbackToReturn.messageReply = {
|
|
125
|
+
threadID: (msgMetadata.threadKey.threadFbId ? msgMetadata.threadKey.threadFbId : msgMetadata.threadKey.otherUserFbId || "").toString(),
|
|
126
|
+
messageID: msgMetadata.messageId || "",
|
|
127
|
+
senderID: (msgMetadata.actorFbId || "").toString(),
|
|
128
|
+
attachments: (repliedTo.attachments || []).map(att => {
|
|
129
|
+
let mercury;
|
|
130
|
+
try {
|
|
131
|
+
mercury = JSON.parse(att.mercuryJSON);
|
|
132
|
+
Object.assign(att, mercury);
|
|
133
|
+
} catch (ex) {
|
|
134
|
+
mercury = {};
|
|
135
|
+
}
|
|
136
|
+
return att;
|
|
137
|
+
}).map(att => {
|
|
138
|
+
let x;
|
|
139
|
+
try {
|
|
140
|
+
x = _formatAttachment(att);
|
|
141
|
+
} catch (ex) {
|
|
142
|
+
x = att;
|
|
143
|
+
x.error = ex;
|
|
144
|
+
x.type = "unknown";
|
|
145
|
+
}
|
|
146
|
+
return x;
|
|
147
|
+
}),
|
|
148
|
+
args: (repliedTo.body || "").trim().split(/\s+/),
|
|
149
|
+
body: repliedTo.body || "",
|
|
150
|
+
isGroup: !!msgMetadata.threadKey.threadFbId,
|
|
151
|
+
mentions: rmentions,
|
|
152
|
+
timestamp: parseInt(msgMetadata.timestamp || 0),
|
|
153
|
+
participantIDs: (repliedTo.participants || []).map(e => e.toString())
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
} catch (err) {
|
|
157
|
+
const errMsg = err && err.message ? err.message : String(err || "Unknown error");
|
|
158
|
+
logger(`parseDelta message_reply repliedToMessage error: ${errMsg}`, "warn");
|
|
159
|
+
}
|
|
138
160
|
} else if (d.deltaMessageReply.replyToMessageId) {
|
|
139
161
|
return defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
|
|
140
162
|
av: ctx.globalOptions.pageID,
|
|
@@ -173,20 +195,29 @@ module.exports = function createParseDelta(deps) {
|
|
|
173
195
|
const errMsg = err && err.message ? err.message : String(err || "Unknown error");
|
|
174
196
|
logger(`parseDelta message_reply fetch error: ${errMsg}`, "warn");
|
|
175
197
|
}).finally(() => {
|
|
176
|
-
if (
|
|
177
|
-
|
|
198
|
+
if (callbackToReturn) {
|
|
199
|
+
if (ctx.globalOptions.autoMarkDelivery) {
|
|
200
|
+
markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
|
|
201
|
+
}
|
|
202
|
+
if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
|
|
203
|
+
globalCallback(null, callbackToReturn);
|
|
178
204
|
}
|
|
179
|
-
if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
|
|
180
|
-
globalCallback(null, callbackToReturn);
|
|
181
205
|
});
|
|
182
206
|
} else {
|
|
183
|
-
callbackToReturn.delta = d;
|
|
207
|
+
if (callbackToReturn) callbackToReturn.delta = d;
|
|
184
208
|
}
|
|
185
|
-
|
|
186
|
-
|
|
209
|
+
} catch (err) {
|
|
210
|
+
const errMsg = err && err.message ? err.message : String(err || "Unknown error");
|
|
211
|
+
logger(`parseDelta message_reply error: ${errMsg}`, "warn");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (callbackToReturn) {
|
|
215
|
+
if (ctx.globalOptions.autoMarkDelivery) {
|
|
216
|
+
markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
|
|
217
|
+
}
|
|
218
|
+
if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
|
|
219
|
+
globalCallback(null, callbackToReturn);
|
|
187
220
|
}
|
|
188
|
-
if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
|
|
189
|
-
globalCallback(null, callbackToReturn);
|
|
190
221
|
}
|
|
191
222
|
}
|
|
192
223
|
return;
|