stfca 1.0.26 → 1.1.27
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 +53 -49
- package/index.js +91 -15
- package/package.json +7 -8
- package/src/listenMqtt.js +394 -393
- package/src/sendMessage.js +292 -278
- package/src/sendMessageMqtt.js +0 -1
- package/src/uploadAttachment.js +99 -77
- package/utils.js +75 -13
package/src/listenMqtt.js
CHANGED
|
@@ -3,46 +3,219 @@
|
|
|
3
3
|
var utils = require("../utils");
|
|
4
4
|
var log = require("npmlog");
|
|
5
5
|
var mqtt = require('mqtt');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var WebSocket = require('ws');
|
|
7
|
+
var Transform = require('stream').Transform;
|
|
8
8
|
const EventEmitter = require('events');
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
// ─── ANSI colour helpers ───────────────────────────────────────────────────────
|
|
11
|
+
var C = {
|
|
12
|
+
reset: '\x1b[0m',
|
|
13
|
+
bold: '\x1b[1m',
|
|
14
|
+
dim: '\x1b[2m',
|
|
15
|
+
// foregrounds
|
|
16
|
+
black: '\x1b[30m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
magenta: '\x1b[35m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
white: '\x1b[37m',
|
|
24
|
+
// bright foregrounds
|
|
25
|
+
bBlack: '\x1b[90m',
|
|
26
|
+
bRed: '\x1b[91m',
|
|
27
|
+
bGreen: '\x1b[92m',
|
|
28
|
+
bYellow: '\x1b[93m',
|
|
29
|
+
bBlue: '\x1b[94m',
|
|
30
|
+
bMagenta: '\x1b[95m',
|
|
31
|
+
bCyan: '\x1b[96m',
|
|
32
|
+
bWhite: '\x1b[97m',
|
|
33
|
+
// backgrounds
|
|
34
|
+
bgBlue: '\x1b[44m',
|
|
35
|
+
bgCyan: '\x1b[46m',
|
|
36
|
+
bgMagenta: '\x1b[45m',
|
|
37
|
+
bgGreen: '\x1b[42m',
|
|
38
|
+
bgBlack: '\x1b[40m',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ─── MQTT Spinner ──────────────────────────────────────────────────────────────
|
|
42
|
+
var _mqttSpinner = null;
|
|
43
|
+
|
|
44
|
+
function startMqttSpinner(region) {
|
|
45
|
+
var frames = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
|
|
46
|
+
var fi = 0;
|
|
47
|
+
var regionStr = region ? (' ' + C.dim + C.bCyan + '[' + region.toUpperCase() + ']' + C.reset) : '';
|
|
48
|
+
process.stdout.write('\n');
|
|
49
|
+
_mqttSpinner = setInterval(function () {
|
|
50
|
+
var frame = frames[fi++ % frames.length];
|
|
51
|
+
process.stdout.write(
|
|
52
|
+
'\r ' +
|
|
53
|
+
C.bold + C.bCyan + frame + C.reset + ' ' +
|
|
54
|
+
C.cyan + 'ST-FCA' + C.reset + ' ' +
|
|
55
|
+
C.dim + 'connecting to MQTT' + C.reset +
|
|
56
|
+
regionStr +
|
|
57
|
+
C.dim + ' ...' + C.reset +
|
|
58
|
+
' '
|
|
59
|
+
);
|
|
60
|
+
}, 80);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function stopMqttSpinner() {
|
|
64
|
+
if (_mqttSpinner) {
|
|
65
|
+
clearInterval(_mqttSpinner);
|
|
66
|
+
_mqttSpinner = null;
|
|
67
|
+
}
|
|
68
|
+
// erase the spinner line completely
|
|
69
|
+
process.stdout.write('\r\x1b[2K');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function printMqttBanner(region, autoReconnect) {
|
|
73
|
+
stopMqttSpinner();
|
|
74
|
+
|
|
75
|
+
var titleClr = C.bold + C.bGreen;
|
|
76
|
+
var labelClr = C.bold + C.bWhite;
|
|
77
|
+
var valClr = C.bYellow;
|
|
78
|
+
var accentClr = C.bold + C.bMagenta;
|
|
79
|
+
var urlClr = C.bBlue;
|
|
80
|
+
var rst = C.reset;
|
|
81
|
+
|
|
82
|
+
var regionVal = (region || '').toUpperCase();
|
|
83
|
+
var reconnTxt = autoReconnect ? 'Enabled (3s)' : 'Disabled';
|
|
84
|
+
var reconnClr = autoReconnect ? C.bGreen : C.bRed;
|
|
85
|
+
var reconnVal = reconnClr + reconnTxt + rst;
|
|
86
|
+
|
|
87
|
+
var rows = [
|
|
88
|
+
titleClr + ' ✅ ST-FCA MQTT Connected' + rst,
|
|
89
|
+
'',
|
|
90
|
+
labelClr + ' 📍 Region ' + rst + valClr + regionVal + rst,
|
|
91
|
+
labelClr + ' 🔄 Auto-reconnect ' + rst + reconnVal,
|
|
92
|
+
urlClr + ' 🌐 github.com/sheikhtamimlover/ST-BOT' + rst,
|
|
93
|
+
'',
|
|
94
|
+
accentClr + ' 💎 Author ST | Sheikh Tamim' + rst
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
process.stdout.write('\n');
|
|
98
|
+
rows.forEach(function (line) {
|
|
99
|
+
console.log(line);
|
|
100
|
+
});
|
|
101
|
+
process.stdout.write('\n');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Facebook sends non-standard MQTT packets where PUBACK/SUBACK have
|
|
106
|
+
* non-zero reserved flag bits (e.g. 0x4F instead of 0x40).
|
|
107
|
+
* mqtt-packet strictly rejects these. This transform stream patches
|
|
108
|
+
* the first byte of each MQTT frame to clear the lower nibble (flags),
|
|
109
|
+
* keeping only the packet type (upper nibble).
|
|
110
|
+
*
|
|
111
|
+
* MQTT fixed header: byte[0] = (type << 4) | flags
|
|
112
|
+
* For PUBACK (type=4): valid = 0x40, FB may send 0x4F → we clear to 0x40
|
|
113
|
+
*/
|
|
114
|
+
function createMqttPatchStream() {
|
|
115
|
+
var buf = null;
|
|
116
|
+
|
|
117
|
+
// Walk frame by frame. For types that must have flags=0 per the MQTT spec
|
|
118
|
+
// (CONNACK=2, PUBACK=4, SUBACK=9, UNSUBACK=11, PINGRESP=13), clear the
|
|
119
|
+
// lower nibble that Facebook sets to non-zero values.
|
|
120
|
+
var stream = new Transform({
|
|
121
|
+
transform: function (chunk, encoding, callback) {
|
|
122
|
+
if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, encoding);
|
|
123
|
+
|
|
124
|
+
// Prepend any leftover bytes from the previous chunk
|
|
125
|
+
var out;
|
|
126
|
+
if (buf) {
|
|
127
|
+
out = Buffer.concat([buf, chunk]);
|
|
128
|
+
buf = null;
|
|
129
|
+
} else {
|
|
130
|
+
out = Buffer.from(chunk);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var i = 0;
|
|
134
|
+
while (i < out.length) {
|
|
135
|
+
var b = out[i];
|
|
136
|
+
var type = (b >> 4) & 0x0F;
|
|
137
|
+
var flags = b & 0x0F;
|
|
138
|
+
// Types that MUST have flags=0:
|
|
139
|
+
if (flags !== 0 && (type === 4 || type === 9 || type === 11 || type === 13 || type === 2)) {
|
|
140
|
+
out[i] = (b & 0xF0); // clear lower nibble
|
|
141
|
+
}
|
|
142
|
+
// Skip past this frame: read the varint length
|
|
143
|
+
i++;
|
|
144
|
+
var multiplier = 1;
|
|
145
|
+
var frameLen = 0;
|
|
146
|
+
var lenOk = false;
|
|
147
|
+
while (i < out.length) {
|
|
148
|
+
var lb = out[i++];
|
|
149
|
+
frameLen += (lb & 0x7F) * multiplier;
|
|
150
|
+
multiplier *= 128;
|
|
151
|
+
if ((lb & 0x80) === 0) { lenOk = true; break; }
|
|
152
|
+
if (multiplier > 128 * 128 * 128) break; // malformed
|
|
153
|
+
}
|
|
154
|
+
if (!lenOk) {
|
|
155
|
+
// Incomplete frame — save remainder for next chunk
|
|
156
|
+
buf = out.slice(i - 1);
|
|
157
|
+
out = out.slice(0, i - 1);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
i += frameLen;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
callback(null, out);
|
|
164
|
+
},
|
|
165
|
+
flush: function (callback) {
|
|
166
|
+
if (buf && buf.length > 0) callback(null, buf);
|
|
167
|
+
else callback();
|
|
168
|
+
buf = null;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return stream;
|
|
172
|
+
}
|
|
173
|
+
|
|
10
174
|
var identity = function () { };
|
|
11
175
|
var form = {};
|
|
12
176
|
var getSeqID = function () { };
|
|
177
|
+
|
|
13
178
|
var topics = [
|
|
14
179
|
"/legacy_web",
|
|
15
180
|
"/webrtc",
|
|
16
181
|
"/rtc_multi",
|
|
17
182
|
"/onevc",
|
|
18
|
-
"/br_sr",
|
|
19
|
-
//Need to publish /br_sr right after this
|
|
183
|
+
"/br_sr",
|
|
20
184
|
"/sr_res",
|
|
21
185
|
"/t_ms",
|
|
22
186
|
"/thread_typing",
|
|
23
187
|
"/orca_typing_notifications",
|
|
24
188
|
"/notify_disconnect",
|
|
25
|
-
//Need to publish /messenger_sync_create_queue right after this
|
|
26
189
|
"/orca_presence",
|
|
27
|
-
//Will receive /sr_res right here.
|
|
28
|
-
|
|
29
190
|
"/inbox",
|
|
30
191
|
"/mercury",
|
|
31
192
|
"/messaging_events",
|
|
32
193
|
"/orca_message_notifications",
|
|
33
194
|
"/pp",
|
|
34
195
|
"/webrtc_response",
|
|
196
|
+
"/ls_resp"
|
|
35
197
|
];
|
|
36
198
|
|
|
199
|
+
function sanitizeHeaderValue(value) {
|
|
200
|
+
if (value === null || value === undefined) return "";
|
|
201
|
+
var str = String(value);
|
|
202
|
+
if (str.trim().startsWith("[") && str.trim().endsWith("]")) {
|
|
203
|
+
try {
|
|
204
|
+
var parsed = JSON.parse(str);
|
|
205
|
+
if (Array.isArray(parsed)) return "";
|
|
206
|
+
} catch (_) { }
|
|
207
|
+
}
|
|
208
|
+
str = str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n\[\]]/g, "").trim();
|
|
209
|
+
return str;
|
|
210
|
+
}
|
|
211
|
+
|
|
37
212
|
function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
38
|
-
//Don't really know what this does but I think it's for the active state?
|
|
39
|
-
//TODO: Move to ctx when implemented
|
|
40
213
|
var chatOn = ctx.globalOptions.online;
|
|
41
214
|
var foreground = false;
|
|
42
|
-
|
|
43
215
|
var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
|
|
44
216
|
var GUID = utils.getGUID();
|
|
45
|
-
|
|
217
|
+
|
|
218
|
+
var username = {
|
|
46
219
|
u: ctx.userID,
|
|
47
220
|
s: sessionID,
|
|
48
221
|
chat_on: chatOn,
|
|
@@ -63,86 +236,138 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
63
236
|
p: null,
|
|
64
237
|
php_override: ""
|
|
65
238
|
};
|
|
66
|
-
var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
|
|
67
239
|
|
|
240
|
+
var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
|
|
68
241
|
var host;
|
|
69
|
-
if (ctx.mqttEndpoint)
|
|
70
|
-
|
|
71
|
-
|
|
242
|
+
if (ctx.mqttEndpoint) {
|
|
243
|
+
// Ensure no duplicate sid/cid — strip any existing ones then append fresh
|
|
244
|
+
var baseEndpoint = ctx.mqttEndpoint
|
|
245
|
+
.replace(/[?&]sid=[^&]*/g, '')
|
|
246
|
+
.replace(/[?&]cid=[^&]*/g, '');
|
|
247
|
+
// Re-attach the ? if it was stripped along with the first param
|
|
248
|
+
if (baseEndpoint.indexOf('?') === -1 && ctx.mqttEndpoint.indexOf('?') !== -1) {
|
|
249
|
+
baseEndpoint = baseEndpoint.replace(/&/, '?');
|
|
250
|
+
}
|
|
251
|
+
var sep = baseEndpoint.indexOf('?') === -1 ? '?' : '&';
|
|
252
|
+
host = baseEndpoint + sep + "sid=" + sessionID + "&cid=" + GUID;
|
|
253
|
+
} else if (ctx.region) {
|
|
254
|
+
host = "wss://edge-chat.facebook.com/chat?region=" + ctx.region.toLowerCase() + "&sid=" + sessionID + "&cid=" + GUID;
|
|
255
|
+
} else {
|
|
256
|
+
host = "wss://edge-chat.facebook.com/chat?sid=" + sessionID + "&cid=" + GUID;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
var ua = ctx.globalOptions.userAgent ||
|
|
260
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15";
|
|
261
|
+
|
|
262
|
+
var wsHeaders = {
|
|
263
|
+
Cookie: sanitizeHeaderValue(cookies),
|
|
264
|
+
Origin: "https://www.facebook.com",
|
|
265
|
+
"User-Agent": sanitizeHeaderValue(ua),
|
|
266
|
+
Referer: "https://www.facebook.com/",
|
|
267
|
+
Host: "edge-chat.facebook.com",
|
|
268
|
+
Connection: "Upgrade",
|
|
269
|
+
Upgrade: "websocket",
|
|
270
|
+
"Sec-WebSocket-Version": "13",
|
|
271
|
+
"Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits",
|
|
272
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
273
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
274
|
+
"Cache-Control": "no-cache",
|
|
275
|
+
Pragma: "no-cache"
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
if (ctx.region) wsHeaders["X-MSGR-Region"] = sanitizeHeaderValue(ctx.region);
|
|
72
279
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
280
|
+
var wsOptions = {
|
|
281
|
+
headers: wsHeaders,
|
|
282
|
+
origin: "https://www.facebook.com",
|
|
283
|
+
protocolVersion: 13,
|
|
284
|
+
binaryType: "arraybuffer"
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
if (typeof ctx.globalOptions.proxy !== "undefined") {
|
|
288
|
+
var { HttpsProxyAgent } = require('https-proxy-agent');
|
|
289
|
+
wsOptions.agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
var mqttOptions = {
|
|
293
|
+
clientId: "mqttwsclient",
|
|
294
|
+
protocolId: "MQIsdp",
|
|
76
295
|
protocolVersion: 3,
|
|
77
296
|
username: JSON.stringify(username),
|
|
78
297
|
clean: true,
|
|
79
|
-
|
|
80
|
-
headers: {
|
|
81
|
-
Cookie: cookies,
|
|
82
|
-
Origin: 'https://www.facebook.com',
|
|
83
|
-
'User-Agent': ctx.globalOptions.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',
|
|
84
|
-
Referer: 'https://www.facebook.com/',
|
|
85
|
-
Host: new URL(host).hostname,
|
|
86
|
-
},
|
|
87
|
-
origin: 'https://www.facebook.com',
|
|
88
|
-
protocolVersion: 13,
|
|
89
|
-
binaryType: 'arraybuffer',
|
|
90
|
-
},
|
|
91
|
-
keepalive: 60,
|
|
298
|
+
keepalive: 30,
|
|
92
299
|
reschedulePings: true,
|
|
93
|
-
reconnectPeriod:
|
|
300
|
+
reconnectPeriod: 0,
|
|
301
|
+
connectTimeout: 12000
|
|
94
302
|
};
|
|
95
303
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
304
|
+
// Use MqttClient with a proper Duplex:
|
|
305
|
+
// Write side: mqtt → duplex.write → wsStream.write → WebSocket (send to FB)
|
|
306
|
+
// Read side: WebSocket msg → wsStream readable → patcher (fix FB header bits) → duplex.push → mqtt reads
|
|
307
|
+
function buildStream() {
|
|
308
|
+
var Duplex = require('stream').Duplex;
|
|
309
|
+
var ws = new WebSocket(host, wsOptions);
|
|
310
|
+
ws.on('error', function () { }); // suppress unhandled ws errors
|
|
311
|
+
|
|
312
|
+
var wsStream = WebSocket.createWebSocketStream(ws, { objectMode: false });
|
|
313
|
+
var patcher = createMqttPatchStream();
|
|
314
|
+
|
|
315
|
+
// Wire: wsStream readable → patcher → push into duplex
|
|
316
|
+
wsStream.pipe(patcher);
|
|
317
|
+
|
|
318
|
+
var duplex = new Duplex({
|
|
319
|
+
read: function () { },
|
|
320
|
+
write: function (chunk, enc, cb) {
|
|
321
|
+
wsStream.write(chunk, enc, cb);
|
|
322
|
+
},
|
|
323
|
+
final: function (cb) {
|
|
324
|
+
wsStream.end(cb);
|
|
325
|
+
},
|
|
326
|
+
destroy: function (err, cb) {
|
|
327
|
+
try { wsStream.destroy(err); } catch (_) { }
|
|
328
|
+
cb(err);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
patcher.on('data', function (data) {
|
|
333
|
+
if (!duplex.destroyed) duplex.push(data);
|
|
334
|
+
});
|
|
335
|
+
patcher.on('end', function () {
|
|
336
|
+
if (!duplex.destroyed) duplex.push(null);
|
|
337
|
+
});
|
|
338
|
+
patcher.on('error', function (e) {
|
|
339
|
+
if (!duplex.destroyed) duplex.destroy(e);
|
|
340
|
+
});
|
|
341
|
+
wsStream.on('error', function (e) {
|
|
342
|
+
if (!duplex.destroyed) duplex.destroy(e);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return duplex;
|
|
99
346
|
}
|
|
100
347
|
|
|
101
|
-
ctx.
|
|
348
|
+
startMqttSpinner(ctx.region);
|
|
102
349
|
|
|
350
|
+
ctx.mqttClient = new mqtt.MqttClient(buildStream, mqttOptions);
|
|
103
351
|
global.mqttClient = ctx.mqttClient;
|
|
104
352
|
|
|
353
|
+
var mqttClient = ctx.mqttClient;
|
|
354
|
+
|
|
105
355
|
mqttClient.on('error', function (err) {
|
|
356
|
+
stopMqttSpinner();
|
|
106
357
|
log.error("listenMqtt", err);
|
|
107
358
|
mqttClient.end();
|
|
108
359
|
if (ctx.globalOptions.autoReconnect) getSeqID();
|
|
109
360
|
else globalCallback({ type: "stop_listen", error: "Connection refused: Server unavailable" }, null);
|
|
110
361
|
});
|
|
111
362
|
|
|
363
|
+
mqttClient.on('close', function () { });
|
|
364
|
+
mqttClient.on('offline', function () { });
|
|
365
|
+
mqttClient.on('reconnect', function () { });
|
|
366
|
+
|
|
112
367
|
mqttClient.on('connect', function () {
|
|
113
|
-
topics.forEach(
|
|
114
|
-
|
|
115
|
-
// Display connection success message with branding and loading animation
|
|
116
|
-
const messages = [
|
|
117
|
-
'\n✅ ST-FCA MQTT Connected',
|
|
118
|
-
`📍 Region: ${ctx.region || 'PNB'}`,
|
|
119
|
-
`🔄 Auto-reconnect: ${ctx.globalOptions.autoReconnect ? 'Enabled' : 'Disabled'}${ctx.globalOptions.autoReconnect ? ' (reconnects every 3s on disconnect)' : ''}`,
|
|
120
|
-
`⏱️ MQTT Restart Interval: ${ctx.globalOptions.restartListenMqtt?.enable ? `${ctx.globalOptions.restartListenMqtt.timeRestart / 1000}s` : 'Disabled'}`,
|
|
121
|
-
'🎨 Maintained & Enhanced by ST | Sheikh Tamim\n'
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
let index = 0;
|
|
125
|
-
const displayMessages = () => {
|
|
126
|
-
if (index < messages.length) {
|
|
127
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
128
|
-
let frameIndex = 0;
|
|
129
|
-
|
|
130
|
-
const loadingInterval = setInterval(() => {
|
|
131
|
-
process.stdout.write(`\r${frames[frameIndex]} Loading...`);
|
|
132
|
-
frameIndex = (frameIndex + 1) % frames.length;
|
|
133
|
-
}, 80);
|
|
134
|
-
|
|
135
|
-
setTimeout(() => {
|
|
136
|
-
clearInterval(loadingInterval);
|
|
137
|
-
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
138
|
-
console.log(messages[index]);
|
|
139
|
-
index++;
|
|
140
|
-
displayMessages();
|
|
141
|
-
}, 500);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
368
|
+
topics.forEach(function (topic) { mqttClient.subscribe(topic); });
|
|
144
369
|
|
|
145
|
-
|
|
370
|
+
printMqttBanner(ctx.region, ctx.globalOptions.autoReconnect);
|
|
146
371
|
|
|
147
372
|
var topic;
|
|
148
373
|
var queue = {
|
|
@@ -157,8 +382,7 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
157
382
|
topic = "/messenger_sync_get_diffs";
|
|
158
383
|
queue.last_seq_id = ctx.lastSeqId;
|
|
159
384
|
queue.sync_token = ctx.syncToken;
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
385
|
+
} else {
|
|
162
386
|
topic = "/messenger_sync_create_queue";
|
|
163
387
|
queue.initial_titan_sequence_id = ctx.lastSeqId;
|
|
164
388
|
queue.device_params = null;
|
|
@@ -173,23 +397,21 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
173
397
|
|
|
174
398
|
ctx.tmsWait = function () {
|
|
175
399
|
clearTimeout(rTimeout);
|
|
176
|
-
ctx.globalOptions.emitReady
|
|
177
|
-
type: "ready",
|
|
178
|
-
error: null
|
|
179
|
-
}) : "";
|
|
400
|
+
if (ctx.globalOptions.emitReady) globalCallback({ type: "ready", error: null });
|
|
180
401
|
delete ctx.tmsWait;
|
|
181
402
|
};
|
|
182
403
|
});
|
|
183
404
|
|
|
184
|
-
mqttClient.on('message', function (topic, message
|
|
405
|
+
mqttClient.on('message', function (topic, message) {
|
|
406
|
+
var jsonMessage;
|
|
185
407
|
try {
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
catch (ex) {
|
|
408
|
+
jsonMessage = JSON.parse(message.toString());
|
|
409
|
+
} catch (ex) {
|
|
189
410
|
return log.error("listenMqtt", ex);
|
|
190
411
|
}
|
|
412
|
+
|
|
191
413
|
if (topic === "/t_ms") {
|
|
192
|
-
if (ctx.tmsWait && typeof ctx.tmsWait
|
|
414
|
+
if (ctx.tmsWait && typeof ctx.tmsWait === "function") ctx.tmsWait();
|
|
193
415
|
|
|
194
416
|
if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
|
|
195
417
|
ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
|
|
@@ -198,13 +420,11 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
198
420
|
|
|
199
421
|
if (jsonMessage.lastIssuedSeqId) ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
|
|
200
422
|
|
|
201
|
-
//If it contains more than 1 delta
|
|
202
423
|
for (var i in jsonMessage.deltas) {
|
|
203
424
|
var delta = jsonMessage.deltas[i];
|
|
204
425
|
parseDelta(defaultFuncs, api, ctx, globalCallback, { "delta": delta });
|
|
205
426
|
}
|
|
206
|
-
}
|
|
207
|
-
else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
|
|
427
|
+
} else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
|
|
208
428
|
var typ = {
|
|
209
429
|
type: "typ",
|
|
210
430
|
isTyping: !!jsonMessage.state,
|
|
@@ -212,17 +432,13 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
212
432
|
threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
|
|
213
433
|
};
|
|
214
434
|
(function () { globalCallback(null, typ); })();
|
|
215
|
-
}
|
|
216
|
-
else if (topic === "/orca_presence") {
|
|
435
|
+
} else if (topic === "/orca_presence") {
|
|
217
436
|
if (!ctx.globalOptions.updatePresence) {
|
|
218
437
|
for (var i in jsonMessage.list) {
|
|
219
438
|
var data = jsonMessage.list[i];
|
|
220
|
-
var userID = data["u"];
|
|
221
|
-
|
|
222
439
|
var presence = {
|
|
223
440
|
type: "presence",
|
|
224
|
-
userID:
|
|
225
|
-
//Convert to ms
|
|
441
|
+
userID: data["u"].toString(),
|
|
226
442
|
timestamp: data["l"] * 1000,
|
|
227
443
|
statuses: data["p"]
|
|
228
444
|
};
|
|
@@ -230,57 +446,43 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
230
446
|
}
|
|
231
447
|
}
|
|
232
448
|
}
|
|
233
|
-
|
|
234
449
|
});
|
|
235
450
|
|
|
236
451
|
mqttClient.on('close', function () { });
|
|
237
452
|
}
|
|
238
453
|
|
|
239
|
-
function
|
|
240
|
-
if (!
|
|
241
|
-
api.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
}
|
|
454
|
+
function attachImageUrlToAttachment(api, attachment) {
|
|
455
|
+
if (!attachment || attachment.type !== "photo" || !attachment.url) return;
|
|
456
|
+
if (api && api._imgUpload) {
|
|
457
|
+
api._imgUpload(attachment.url).then(function (url) {
|
|
458
|
+
if (url) attachment.imgUrl = url;
|
|
459
|
+
}).catch(function () { });
|
|
460
|
+
}
|
|
246
461
|
}
|
|
247
462
|
|
|
248
463
|
function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
249
464
|
if (v.delta.class == "NewMessage") {
|
|
250
|
-
//Not tested for pages
|
|
251
465
|
if (ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue) return;
|
|
252
466
|
|
|
253
467
|
(function resolveAttachmentUrl(i) {
|
|
254
468
|
if (i == (v.delta.attachments || []).length) {
|
|
255
|
-
|
|
469
|
+
var fmtMsg;
|
|
256
470
|
try {
|
|
257
471
|
fmtMsg = utils.formatDeltaMessage(v);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const threadFbId = v.delta.messageMetadata.threadKey.threadFbId;
|
|
261
|
-
|
|
262
|
-
// A thread is a DM if it has otherUserFbId and no threadFbId
|
|
472
|
+
var otherUserFbId = v.delta.messageMetadata.threadKey.otherUserFbId;
|
|
473
|
+
var threadFbId = v.delta.messageMetadata.threadKey.threadFbId;
|
|
263
474
|
fmtMsg.isSingleUser = !!otherUserFbId && !threadFbId;
|
|
264
475
|
fmtMsg.isGroup = !!threadFbId;
|
|
265
|
-
|
|
266
|
-
// Store thread type in context for sendMessage to use
|
|
267
476
|
if (!ctx.threadTypes) ctx.threadTypes = {};
|
|
268
477
|
ctx.threadTypes[fmtMsg.threadID] = fmtMsg.isSingleUser ? 'dm' : 'group';
|
|
269
478
|
if (fmtMsg.attachments && Array.isArray(fmtMsg.attachments)) {
|
|
270
|
-
fmtMsg.attachments.forEach(att
|
|
479
|
+
fmtMsg.attachments.forEach(function (att) { attachImageUrlToAttachment(api, att); });
|
|
271
480
|
}
|
|
272
481
|
} catch (err) {
|
|
273
|
-
return globalCallback({
|
|
274
|
-
error: "Problem parsing message object.",
|
|
275
|
-
detail: err,
|
|
276
|
-
res: v,
|
|
277
|
-
type: "parse_error"
|
|
278
|
-
});
|
|
482
|
+
return globalCallback({ error: "Problem parsing message object.", detail: err, res: v, type: "parse_error" });
|
|
279
483
|
}
|
|
280
|
-
if (fmtMsg) {
|
|
281
|
-
|
|
282
|
-
markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
|
|
283
|
-
}
|
|
484
|
+
if (fmtMsg && ctx.globalOptions.autoMarkDelivery) {
|
|
485
|
+
markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
|
|
284
486
|
}
|
|
285
487
|
return !ctx.globalOptions.selfListen &&
|
|
286
488
|
(fmtMsg.senderID === ctx.i_userID || fmtMsg.senderID === ctx.userID) ?
|
|
@@ -288,16 +490,10 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
288
490
|
(function () { globalCallback(null, fmtMsg); })();
|
|
289
491
|
} else {
|
|
290
492
|
if (v.delta.attachments[i].mercury.attach_type == "photo") {
|
|
291
|
-
api.resolvePhotoUrl(
|
|
292
|
-
v.delta.attachments[i].
|
|
293
|
-
(
|
|
294
|
-
|
|
295
|
-
v.delta.attachments[
|
|
296
|
-
i
|
|
297
|
-
].mercury.metadata.url = url;
|
|
298
|
-
return resolveAttachmentUrl(i + 1);
|
|
299
|
-
}
|
|
300
|
-
);
|
|
493
|
+
api.resolvePhotoUrl(v.delta.attachments[i].fbid, function (err, url) {
|
|
494
|
+
if (!err) v.delta.attachments[i].mercury.metadata.url = url;
|
|
495
|
+
return resolveAttachmentUrl(i + 1);
|
|
496
|
+
});
|
|
301
497
|
} else {
|
|
302
498
|
return resolveAttachmentUrl(i + 1);
|
|
303
499
|
}
|
|
@@ -321,8 +517,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
321
517
|
userID: delta.deltaMessageReaction.userId.toString()
|
|
322
518
|
});
|
|
323
519
|
})();
|
|
324
|
-
}
|
|
325
|
-
else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
|
|
520
|
+
} else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
|
|
326
521
|
(function () {
|
|
327
522
|
globalCallback(null, {
|
|
328
523
|
type: "message_unsend",
|
|
@@ -333,21 +528,17 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
333
528
|
timestamp: delta.deltaRecallMessageData.timestamp
|
|
334
529
|
});
|
|
335
530
|
})();
|
|
336
|
-
}
|
|
337
|
-
else if (delta.deltaMessageReply) {
|
|
338
|
-
//Mention block - #1
|
|
531
|
+
} else if (delta.deltaMessageReply) {
|
|
339
532
|
var mdata = delta.deltaMessageReply.message === undefined ? [] :
|
|
340
533
|
delta.deltaMessageReply.message.data === undefined ? [] :
|
|
341
534
|
delta.deltaMessageReply.message.data.prng === undefined ? [] :
|
|
342
535
|
JSON.parse(delta.deltaMessageReply.message.data.prng);
|
|
343
|
-
var m_id = mdata.map(u
|
|
344
|
-
var m_offset = mdata.map(u
|
|
345
|
-
var m_length = mdata.map(u
|
|
346
|
-
|
|
536
|
+
var m_id = mdata.map(function (u) { return u.i; });
|
|
537
|
+
var m_offset = mdata.map(function (u) { return u.o; });
|
|
538
|
+
var m_length = mdata.map(function (u) { return u.l; });
|
|
347
539
|
var mentions = {};
|
|
348
|
-
|
|
349
540
|
for (var i = 0; i < m_id.length; i++) mentions[m_id[i]] = (delta.deltaMessageReply.message.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
|
|
350
|
-
|
|
541
|
+
|
|
351
542
|
var callbackToReturn = {
|
|
352
543
|
type: "message_reply",
|
|
353
544
|
threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey.otherUserFbId).toString(),
|
|
@@ -357,16 +548,10 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
357
548
|
var mercury = JSON.parse(att.mercuryJSON);
|
|
358
549
|
Object.assign(att, mercury);
|
|
359
550
|
return att;
|
|
360
|
-
}).map(att
|
|
551
|
+
}).map(function (att) {
|
|
361
552
|
var x;
|
|
362
|
-
try {
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
catch (ex) {
|
|
366
|
-
x = att;
|
|
367
|
-
x.error = ex;
|
|
368
|
-
x.type = "unknown";
|
|
369
|
-
}
|
|
553
|
+
try { x = utils._formatAttachment(att); }
|
|
554
|
+
catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
|
|
370
555
|
return x;
|
|
371
556
|
}),
|
|
372
557
|
args: (delta.deltaMessageReply.message.body || "").trim().split(/\s+/),
|
|
@@ -374,26 +559,24 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
374
559
|
isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
|
|
375
560
|
mentions: mentions,
|
|
376
561
|
timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
|
|
377
|
-
participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e
|
|
562
|
+
participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(function (e) { return e.toString(); })
|
|
378
563
|
};
|
|
564
|
+
|
|
379
565
|
if (callbackToReturn.attachments && Array.isArray(callbackToReturn.attachments)) {
|
|
380
|
-
callbackToReturn.attachments.forEach(att
|
|
566
|
+
callbackToReturn.attachments.forEach(function (att) { attachImageUrlToAttachment(api, att); });
|
|
381
567
|
}
|
|
382
568
|
|
|
383
569
|
if (delta.deltaMessageReply.repliedToMessage) {
|
|
384
|
-
//Mention block - #2
|
|
385
570
|
mdata = delta.deltaMessageReply.repliedToMessage === undefined ? [] :
|
|
386
571
|
delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
|
|
387
572
|
delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
|
|
388
573
|
JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
|
|
389
|
-
m_id = mdata.map(u
|
|
390
|
-
m_offset = mdata.map(u
|
|
391
|
-
m_length = mdata.map(u
|
|
392
|
-
|
|
574
|
+
m_id = mdata.map(function (u) { return u.i; });
|
|
575
|
+
m_offset = mdata.map(function (u) { return u.o; });
|
|
576
|
+
m_length = mdata.map(function (u) { return u.l; });
|
|
393
577
|
var rmentions = {};
|
|
394
|
-
|
|
395
578
|
for (var i = 0; i < m_id.length; i++) rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
|
|
396
|
-
|
|
579
|
+
|
|
397
580
|
callbackToReturn.messageReply = {
|
|
398
581
|
threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.otherUserFbId).toString(),
|
|
399
582
|
messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
|
|
@@ -402,17 +585,11 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
402
585
|
var mercury = JSON.parse(att.mercuryJSON);
|
|
403
586
|
Object.assign(att, mercury);
|
|
404
587
|
return att;
|
|
405
|
-
}).map(att
|
|
588
|
+
}).map(function (att) {
|
|
406
589
|
var x;
|
|
407
|
-
try {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
catch (ex) {
|
|
411
|
-
x = att;
|
|
412
|
-
x.error = ex;
|
|
413
|
-
x.type = "unknown";
|
|
414
|
-
}
|
|
415
|
-
attachImgbbUrlToAttachment(api, x);
|
|
590
|
+
try { x = utils._formatAttachment(att); }
|
|
591
|
+
catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
|
|
592
|
+
attachImageUrlToAttachment(api, x);
|
|
416
593
|
return x;
|
|
417
594
|
}),
|
|
418
595
|
args: (delta.deltaMessageReply.repliedToMessage.body || "").trim().split(/\s+/),
|
|
@@ -421,14 +598,12 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
421
598
|
mentions: rmentions,
|
|
422
599
|
timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp
|
|
423
600
|
};
|
|
424
|
-
}
|
|
425
|
-
else if (delta.deltaMessageReply.replyToMessageId) {
|
|
601
|
+
} else if (delta.deltaMessageReply.replyToMessageId) {
|
|
426
602
|
return defaultFuncs
|
|
427
603
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
|
|
428
604
|
"av": ctx.globalOptions.pageID,
|
|
429
605
|
"queries": JSON.stringify({
|
|
430
606
|
"o0": {
|
|
431
|
-
//Using the same doc_id as forcedFetch
|
|
432
607
|
"doc_id": "2848441488556444",
|
|
433
608
|
"query_params": {
|
|
434
609
|
"thread_and_message_id": {
|
|
@@ -440,28 +615,21 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
440
615
|
})
|
|
441
616
|
})
|
|
442
617
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
443
|
-
.then((resData)
|
|
618
|
+
.then(function (resData) {
|
|
444
619
|
if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
|
|
445
620
|
if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
|
|
446
621
|
var fetchData = resData[0].o0.data.message;
|
|
447
622
|
var mobj = {};
|
|
448
623
|
for (var n in fetchData.message.ranges) mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
|
|
449
|
-
|
|
450
624
|
callbackToReturn.messageReply = {
|
|
451
625
|
threadID: callbackToReturn.threadID,
|
|
452
626
|
messageID: fetchData.message_id,
|
|
453
627
|
senderID: fetchData.message_sender.id.toString(),
|
|
454
|
-
attachments: fetchData.message.blob_attachment.map(att
|
|
628
|
+
attachments: fetchData.message.blob_attachment.map(function (att) {
|
|
455
629
|
var x;
|
|
456
|
-
try {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
catch (ex) {
|
|
460
|
-
x = att;
|
|
461
|
-
x.error = ex;
|
|
462
|
-
x.type = "unknown";
|
|
463
|
-
}
|
|
464
|
-
attachImgbbUrlToAttachment(api, x);
|
|
630
|
+
try { x = utils._formatAttachment({ blob_attachment: att }); }
|
|
631
|
+
catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
|
|
632
|
+
attachImageUrlToAttachment(api, x);
|
|
465
633
|
return x;
|
|
466
634
|
}),
|
|
467
635
|
args: (fetchData.message.text || "").trim().split(/\s+/) || [],
|
|
@@ -471,16 +639,16 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
471
639
|
timestamp: parseInt(fetchData.timestamp_precise)
|
|
472
640
|
};
|
|
473
641
|
})
|
|
474
|
-
.catch(err
|
|
642
|
+
.catch(function (err) { log.error("forcedFetch", err); })
|
|
475
643
|
.finally(function () {
|
|
476
644
|
if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
|
|
477
645
|
!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
|
|
478
646
|
});
|
|
647
|
+
} else {
|
|
648
|
+
callbackToReturn.delta = delta;
|
|
479
649
|
}
|
|
480
|
-
else callbackToReturn.delta = delta;
|
|
481
650
|
|
|
482
651
|
if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
|
|
483
|
-
|
|
484
652
|
return !ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
|
|
485
653
|
}
|
|
486
654
|
}
|
|
@@ -489,22 +657,17 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
489
657
|
}
|
|
490
658
|
|
|
491
659
|
if (v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents) return;
|
|
660
|
+
|
|
492
661
|
switch (v.delta.class) {
|
|
493
662
|
case "JoinableMode": {
|
|
494
|
-
|
|
495
|
-
try {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
return globalCallback({
|
|
499
|
-
error: "Lỗi gòi!!",
|
|
500
|
-
detail: err,
|
|
501
|
-
res: v.delta,
|
|
502
|
-
type: "parse_error"
|
|
503
|
-
});
|
|
663
|
+
var fmtMsg;
|
|
664
|
+
try { fmtMsg = utils.formatDeltaEvent(v.delta); }
|
|
665
|
+
catch (err) {
|
|
666
|
+
return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
|
|
504
667
|
}
|
|
505
668
|
return globalCallback(null, fmtMsg);
|
|
506
669
|
}
|
|
507
|
-
case "AdminTextMessage":
|
|
670
|
+
case "AdminTextMessage": {
|
|
508
671
|
switch (v.delta.type) {
|
|
509
672
|
case 'confirm_friend_request':
|
|
510
673
|
case 'shared_album_delete':
|
|
@@ -521,58 +684,44 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
521
684
|
case "magic_words":
|
|
522
685
|
case "change_thread_approval_mode":
|
|
523
686
|
case "messenger_call_log":
|
|
524
|
-
case "participant_joined_group_call":
|
|
687
|
+
case "participant_joined_group_call": {
|
|
525
688
|
var fmtMsg;
|
|
526
|
-
try {
|
|
527
|
-
fmtMsg = utils.formatDeltaEvent(v.delta);
|
|
528
|
-
}
|
|
689
|
+
try { fmtMsg = utils.formatDeltaEvent(v.delta); }
|
|
529
690
|
catch (err) {
|
|
530
|
-
return globalCallback({
|
|
531
|
-
error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
|
|
532
|
-
detail: err,
|
|
533
|
-
res: v.delta,
|
|
534
|
-
type: "parse_error"
|
|
535
|
-
});
|
|
691
|
+
return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
|
|
536
692
|
}
|
|
537
693
|
return (function () { globalCallback(null, fmtMsg); })();
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
return;
|
|
694
|
+
}
|
|
695
|
+
default: return;
|
|
541
696
|
}
|
|
542
|
-
|
|
543
|
-
case "ForcedFetch":
|
|
697
|
+
}
|
|
698
|
+
case "ForcedFetch": {
|
|
544
699
|
if (!v.delta.threadKey) return;
|
|
545
700
|
var mid = v.delta.messageId;
|
|
546
701
|
var tid = v.delta.threadKey.threadFbId;
|
|
547
702
|
if (mid && tid) {
|
|
548
|
-
|
|
703
|
+
var fetchForm = {
|
|
549
704
|
"av": ctx.globalOptions.pageID,
|
|
550
705
|
"queries": JSON.stringify({
|
|
551
706
|
"o0": {
|
|
552
|
-
//This doc_id is valid as of March 25, 2020
|
|
553
707
|
"doc_id": "2848441488556444",
|
|
554
708
|
"query_params": {
|
|
555
709
|
"thread_and_message_id": {
|
|
556
710
|
"thread_id": tid.toString(),
|
|
557
|
-
"message_id": mid
|
|
711
|
+
"message_id": mid
|
|
558
712
|
}
|
|
559
713
|
}
|
|
560
714
|
}
|
|
561
715
|
})
|
|
562
716
|
};
|
|
563
|
-
|
|
564
717
|
defaultFuncs
|
|
565
|
-
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar,
|
|
718
|
+
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, fetchForm)
|
|
566
719
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
567
|
-
.then((resData)
|
|
720
|
+
.then(function (resData) {
|
|
568
721
|
if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
|
|
569
|
-
|
|
570
722
|
if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
|
|
571
|
-
|
|
572
723
|
var fetchData = resData[0].o0.data.message;
|
|
573
|
-
|
|
574
724
|
if (utils.getType(fetchData) == "Object") {
|
|
575
|
-
log.info("forcedFetch", fetchData);
|
|
576
725
|
switch (fetchData.__typename) {
|
|
577
726
|
case "ThreadImageMessage":
|
|
578
727
|
(!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) ||
|
|
@@ -593,35 +742,6 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
593
742
|
})();
|
|
594
743
|
break;
|
|
595
744
|
case "UserMessage":
|
|
596
|
-
log.info("ff-Return", {
|
|
597
|
-
type: "message",
|
|
598
|
-
senderID: utils.formatID(fetchData.message_sender.id),
|
|
599
|
-
body: fetchData.message.text || "",
|
|
600
|
-
threadID: utils.formatID(tid.toString()),
|
|
601
|
-
messageID: fetchData.message_id,
|
|
602
|
-
attachments: [{
|
|
603
|
-
type: "share",
|
|
604
|
-
ID: fetchData.extensible_attachment.legacy_attachment_id,
|
|
605
|
-
url: fetchData.extensible_attachment.story_attachment.url,
|
|
606
|
-
|
|
607
|
-
title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
|
|
608
|
-
description: fetchData.extensible_attachment.story_attachment.description.text,
|
|
609
|
-
source: fetchData.extensible_attachment.story_attachment.source,
|
|
610
|
-
|
|
611
|
-
image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
|
|
612
|
-
width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
|
|
613
|
-
height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
|
|
614
|
-
playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
|
|
615
|
-
duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
|
|
616
|
-
|
|
617
|
-
subattachments: fetchData.extensible_attachment.subattachments,
|
|
618
|
-
properties: fetchData.extensible_attachment.story_attachment.properties,
|
|
619
|
-
}],
|
|
620
|
-
mentions: {},
|
|
621
|
-
timestamp: parseInt(fetchData.timestamp_precise),
|
|
622
|
-
participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
|
|
623
|
-
isGroup: (fetchData.message_sender.id != tid.toString())
|
|
624
|
-
});
|
|
625
745
|
globalCallback(null, {
|
|
626
746
|
type: "message",
|
|
627
747
|
senderID: utils.formatID(fetchData.message_sender.id),
|
|
@@ -632,178 +752,64 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
|
|
|
632
752
|
type: "share",
|
|
633
753
|
ID: fetchData.extensible_attachment.legacy_attachment_id,
|
|
634
754
|
url: fetchData.extensible_attachment.story_attachment.url,
|
|
635
|
-
|
|
636
755
|
title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
|
|
637
756
|
description: fetchData.extensible_attachment.story_attachment.description.text,
|
|
638
757
|
source: fetchData.extensible_attachment.story_attachment.source,
|
|
639
|
-
|
|
640
758
|
image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
|
|
641
759
|
width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
|
|
642
760
|
height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
|
|
643
761
|
playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
|
|
644
762
|
duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
|
|
645
|
-
|
|
646
763
|
subattachments: fetchData.extensible_attachment.subattachments,
|
|
647
764
|
properties: fetchData.extensible_attachment.story_attachment.properties,
|
|
648
765
|
}],
|
|
649
766
|
mentions: {},
|
|
650
767
|
timestamp: parseInt(fetchData.timestamp_precise),
|
|
651
|
-
participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
|
|
652
768
|
isGroup: (fetchData.message_sender.id != tid.toString())
|
|
653
769
|
});
|
|
770
|
+
break;
|
|
654
771
|
}
|
|
655
|
-
}
|
|
656
|
-
else log.error("forcedFetch", fetchData);
|
|
772
|
+
} else log.error("forcedFetch", fetchData);
|
|
657
773
|
})
|
|
658
|
-
.catch((err)
|
|
774
|
+
.catch(function (err) { log.error("forcedFetch", err); });
|
|
659
775
|
}
|
|
660
776
|
break;
|
|
777
|
+
}
|
|
661
778
|
case "ThreadName":
|
|
662
779
|
case "ParticipantsAddedToGroupThread":
|
|
663
|
-
case "ParticipantLeftGroupThread":
|
|
780
|
+
case "ParticipantLeftGroupThread": {
|
|
664
781
|
var formattedEvent;
|
|
665
|
-
try {
|
|
666
|
-
formattedEvent = utils.formatDeltaEvent(v.delta);
|
|
667
|
-
}
|
|
782
|
+
try { formattedEvent = utils.formatDeltaEvent(v.delta); }
|
|
668
783
|
catch (err) {
|
|
669
|
-
return globalCallback({
|
|
670
|
-
error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
|
|
671
|
-
detail: err,
|
|
672
|
-
res: v.delta,
|
|
673
|
-
type: "parse_error"
|
|
674
|
-
});
|
|
784
|
+
return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
|
|
675
785
|
}
|
|
676
786
|
return (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) || !ctx.loggedIn ? undefined : (function () { globalCallback(null, formattedEvent); })();
|
|
787
|
+
}
|
|
677
788
|
}
|
|
678
789
|
}
|
|
679
790
|
|
|
680
791
|
function markDelivery(ctx, api, threadID, messageID) {
|
|
681
792
|
if (threadID && messageID) {
|
|
682
|
-
api.markAsDelivered(threadID, messageID, (err)
|
|
793
|
+
api.markAsDelivered(threadID, messageID, function (err) {
|
|
683
794
|
if (err) log.error("markAsDelivered", err);
|
|
684
|
-
else {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
});
|
|
689
|
-
}
|
|
795
|
+
else if (ctx.globalOptions.autoMarkRead) {
|
|
796
|
+
api.markAsRead(threadID, function (err) {
|
|
797
|
+
if (err) log.error("markAsDelivered", err);
|
|
798
|
+
});
|
|
690
799
|
}
|
|
691
800
|
});
|
|
692
801
|
}
|
|
693
802
|
}
|
|
694
803
|
|
|
695
804
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
696
|
-
|
|
697
|
-
// function getSeqID() {
|
|
698
|
-
// ctx.t_mqttCalled = false;
|
|
699
|
-
// async function attemptRequest(retries = 3) {
|
|
700
|
-
// try {
|
|
701
|
-
// if (!ctx.fb_dtsg) {
|
|
702
|
-
// const dtsg = await api.getFreshDtsg();
|
|
703
|
-
// if (!dtsg) {
|
|
704
|
-
// if (retries > 0) {
|
|
705
|
-
// logger.Warning("Failed to get fb_dtsg, retrying...");
|
|
706
|
-
// await utils.sleep(2000); // Longer delay for token retry
|
|
707
|
-
// return attemptRequest(retries - 1);
|
|
708
|
-
// }
|
|
709
|
-
// throw { error: "Could not obtain fb_dtsg after multiple attempts" };
|
|
710
|
-
// }
|
|
711
|
-
// ctx.fb_dtsg = dtsg;
|
|
712
|
-
// }
|
|
713
|
-
|
|
714
|
-
// const form = {
|
|
715
|
-
// av: ctx.userID,
|
|
716
|
-
// fb_dtsg: ctx.fb_dtsg,
|
|
717
|
-
// queries: JSON.stringify({
|
|
718
|
-
// o0: {
|
|
719
|
-
// doc_id: '3336396659757871',
|
|
720
|
-
// query_params: {
|
|
721
|
-
// limit: 1,
|
|
722
|
-
// before: null,
|
|
723
|
-
// tags: ['INBOX'],
|
|
724
|
-
// includeDeliveryReceipts: false,
|
|
725
|
-
// includeSeqID: true
|
|
726
|
-
// }
|
|
727
|
-
// }
|
|
728
|
-
// }),
|
|
729
|
-
// __user: ctx.userID,
|
|
730
|
-
// __a: '1',
|
|
731
|
-
// __req: '8',
|
|
732
|
-
// __hs: '19577.HYP:comet_pkg.2.1..2.1',
|
|
733
|
-
// dpr: '1',
|
|
734
|
-
// fb_api_caller_class: 'RelayModern',
|
|
735
|
-
// fb_api_req_friendly_name: 'MessengerGraphQLThreadlistFetcher'
|
|
736
|
-
// };
|
|
737
|
-
|
|
738
|
-
// const headers = {
|
|
739
|
-
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
740
|
-
// 'Referer': 'https://www.facebook.com/',
|
|
741
|
-
// 'Origin': 'https://www.facebook.com',
|
|
742
|
-
// 'sec-fetch-site': 'same-origin',
|
|
743
|
-
// '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',
|
|
744
|
-
// 'Cookie': ctx.jar.getCookieString('https://www.facebook.com'),
|
|
745
|
-
// 'accept': '*/*',
|
|
746
|
-
// 'accept-encoding': 'gzip, deflate, br'
|
|
747
|
-
// };
|
|
748
|
-
|
|
749
|
-
// const resData = await defaultFuncs
|
|
750
|
-
// .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form, { headers })
|
|
751
|
-
// .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
752
|
-
|
|
753
|
-
// if (debugSeq) {
|
|
754
|
-
// console.log('GraphQL SeqID Response:', JSON.stringify(resData, null, 2));
|
|
755
|
-
// }
|
|
756
|
-
|
|
757
|
-
// if (resData.error === 1357004 || resData.error === 1357001) {
|
|
758
|
-
// if (retries > 0) {
|
|
759
|
-
// logger.Warning("Session error, refreshing token and retrying...");
|
|
760
|
-
// ctx.fb_dtsg = null; // Force new token
|
|
761
|
-
// await utils.sleep(2000);
|
|
762
|
-
// return attemptRequest(retries - 1);
|
|
763
|
-
// }
|
|
764
|
-
// throw { error: "Session refresh failed after retries" };
|
|
765
|
-
// }
|
|
766
|
-
|
|
767
|
-
// if (!Array.isArray(resData)) {
|
|
768
|
-
// throw { error: "Invalid response format", res: resData };
|
|
769
|
-
// }
|
|
770
|
-
|
|
771
|
-
// const seqID = resData[0]?.o0?.data?.viewer?.message_threads?.sync_sequence_id;
|
|
772
|
-
// if (!seqID) {
|
|
773
|
-
// throw { error: "Missing sync_sequence_id", res: resData };
|
|
774
|
-
// }
|
|
775
|
-
|
|
776
|
-
// ctx.lastSeqId = seqID;
|
|
777
|
-
// if (debugSeq) {
|
|
778
|
-
// console.log('Got SeqID:', ctx.lastSeqId);
|
|
779
|
-
// }
|
|
780
|
-
|
|
781
|
-
// return listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
|
782
|
-
|
|
783
|
-
// } catch (err) {
|
|
784
|
-
// if (retries > 0) {
|
|
785
|
-
// console.log("Request failed, retrying...");
|
|
786
|
-
|
|
787
|
-
// return attemptRequest(retries - 1);
|
|
788
|
-
// }
|
|
789
|
-
// throw err;
|
|
790
|
-
// }
|
|
791
|
-
// }
|
|
792
|
-
|
|
793
|
-
// return attemptRequest()
|
|
794
|
-
// .catch((err) => {
|
|
795
|
-
// log.error("getSeqId", err);
|
|
796
|
-
// if (utils.getType(err) == "Object" && err.error === "Not logged in") ctx.loggedIn = false;
|
|
797
|
-
// return globalCallback(err);
|
|
798
|
-
// });
|
|
799
|
-
// }
|
|
805
|
+
var globalCallback = identity;
|
|
800
806
|
|
|
801
807
|
getSeqID = function getSeqID() {
|
|
802
808
|
ctx.t_mqttCalled = false;
|
|
803
809
|
defaultFuncs
|
|
804
810
|
.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
|
|
805
811
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
806
|
-
.then((resData)
|
|
812
|
+
.then(function (resData) {
|
|
807
813
|
if (utils.getType(resData) != "Array") throw { error: "Not logged in", res: resData };
|
|
808
814
|
if (resData && resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
|
|
809
815
|
if (resData[resData.length - 1].successful_results === 0) throw { error: "getSeqId: there was no successful_results", res: resData };
|
|
@@ -812,7 +818,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
812
818
|
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
|
813
819
|
} else throw { error: "getSeqId: no sync_sequence_id found.", res: resData };
|
|
814
820
|
})
|
|
815
|
-
.catch((err)
|
|
821
|
+
.catch(function (err) {
|
|
816
822
|
log.error("getSeqId", err);
|
|
817
823
|
if (utils.getType(err) == "Object" && err.error === "Not logged in") ctx.loggedIn = false;
|
|
818
824
|
return globalCallback(err);
|
|
@@ -822,8 +828,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
822
828
|
return function (callback) {
|
|
823
829
|
class MessageEmitter extends EventEmitter {
|
|
824
830
|
stopListening(callback) {
|
|
825
|
-
|
|
826
|
-
callback = callback || (() => { });
|
|
831
|
+
callback = callback || (function () { });
|
|
827
832
|
globalCallback = identity;
|
|
828
833
|
if (ctx.mqttClient) {
|
|
829
834
|
ctx.mqttClient.unsubscribe("/webrtc");
|
|
@@ -838,23 +843,19 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
838
843
|
}
|
|
839
844
|
|
|
840
845
|
async stopListeningAsync() {
|
|
841
|
-
return new Promise((resolve)
|
|
846
|
+
return new Promise(function (resolve) {
|
|
842
847
|
this.stopListening(resolve);
|
|
843
|
-
});
|
|
848
|
+
}.bind(this));
|
|
844
849
|
}
|
|
845
850
|
}
|
|
846
851
|
|
|
847
|
-
|
|
852
|
+
var msgEmitter = new MessageEmitter();
|
|
848
853
|
globalCallback = (callback || function (error, message) {
|
|
849
|
-
if (error)
|
|
850
|
-
return msgEmitter.emit("error", error);
|
|
851
|
-
}
|
|
854
|
+
if (error) return msgEmitter.emit("error", error);
|
|
852
855
|
msgEmitter.emit("message", message);
|
|
853
856
|
});
|
|
854
857
|
|
|
855
|
-
|
|
856
|
-
if (!ctx.firstListen)
|
|
857
|
-
ctx.lastSeqId = null;
|
|
858
|
+
if (!ctx.firstListen) ctx.lastSeqId = null;
|
|
858
859
|
ctx.syncToken = undefined;
|
|
859
860
|
ctx.t_mqttCalled = false;
|
|
860
861
|
|
|
@@ -880,8 +881,8 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
880
881
|
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
|
881
882
|
}
|
|
882
883
|
|
|
883
|
-
api.stopListening = msgEmitter.stopListening;
|
|
884
|
-
api.stopListeningAsync = msgEmitter.stopListeningAsync;
|
|
884
|
+
api.stopListening = msgEmitter.stopListening.bind(msgEmitter);
|
|
885
|
+
api.stopListeningAsync = msgEmitter.stopListeningAsync.bind(msgEmitter);
|
|
885
886
|
return msgEmitter;
|
|
886
887
|
};
|
|
887
|
-
};
|
|
888
|
+
};
|