stfca 1.0.25 → 1.0.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/index.js CHANGED
@@ -6,6 +6,7 @@ var log = require("npmlog");
6
6
  var { checkForFCAUpdate } = require("./checkUpdate");
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
+ const request = require('request');
9
10
  /*var { getThemeColors } = require("../../func/utils/log.js");
10
11
  var logger = require("../../func/utils/log.js");
11
12
  var { cra, cv, cb, co } = getThemeColors();*/
@@ -279,6 +280,51 @@ function buildAPI(globalOptions, html, jar) {
279
280
  api.postFormData = function (url, body) {
280
281
  return defaultFuncs.postFormData(url, ctx.jar, body);
281
282
  };
283
+
284
+ const IMGBB_API_KEY = process.env.IMG_BB_KEY || '3e198e6ffe205d1c7968a92fd92177c9';
285
+ async function uploadImageToImgbb(image, expiration = 600) {
286
+ const formData = {};
287
+ if (Buffer.isBuffer(image)) {
288
+ formData.image = image.toString('base64');
289
+ } else if (typeof image === 'string') {
290
+ const dataUriMatch = image.match(/^data:image\/[a-zA-Z]+;base64,(.+)$/);
291
+ if (dataUriMatch) {
292
+ formData.image = dataUriMatch[1];
293
+ } else {
294
+ formData.image = image.trim();
295
+ }
296
+ } else {
297
+ throw new Error('Unsupported image type for ImgBB upload');
298
+ }
299
+
300
+ return new Promise((resolve, reject) => {
301
+ request.post(
302
+ {
303
+ url: 'https://api.imgbb.com/1/upload',
304
+ qs: {
305
+ expiration: expiration,
306
+ key: IMGBB_API_KEY
307
+ },
308
+ formData: formData,
309
+ timeout: 60000
310
+ },
311
+ function (error, response, body) {
312
+ if (error) return reject(error);
313
+ try {
314
+ const data = JSON.parse(body);
315
+ if (!data || !data.success) return reject(data || new Error('ImgBB upload failed'));
316
+ resolve(data);
317
+ } catch (err) {
318
+ reject(err);
319
+ }
320
+ }
321
+ );
322
+ });
323
+ }
324
+
325
+ api.uploadImageToImgbb = uploadImageToImgbb;
326
+ ctx.uploadImageToImgbb = uploadImageToImgbb;
327
+
282
328
  api.getFreshDtsg = async function () {
283
329
  try {
284
330
  const res = await defaultFuncs.get('https://www.facebook.com/', jar, null, globalOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stfca",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Unofficial Facebook Chat API for Node.js with Auto-Update System - Enhanced by ST | Sheikh Tamim",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -26,7 +26,27 @@
26
26
  "unofficial",
27
27
  "fca",
28
28
  "st-fca",
29
- "sheikh-tamim"
29
+ "sheikh-tamim",
30
+ "stfca",
31
+ "fbchatapi",
32
+ "fbchat",
33
+ "messenger-api",
34
+ "facebook-messenger",
35
+ "nodejs",
36
+ "javascript",
37
+ "auto-update",
38
+ "update-check",
39
+ "update-notifier",
40
+ "version-check",
41
+ "update-system",
42
+ "update-manager",
43
+ "update-handler",
44
+ "update-service",
45
+ "update-module",
46
+ "update-function",
47
+ "unofficial-facebook-chat-api",
48
+ "messengerwapper",
49
+ "e2ee"
30
50
  ],
31
51
  "author": "ST | Sheikh Tamim",
32
52
  "license": "MIT",
package/src/listenMqtt.js CHANGED
@@ -118,7 +118,10 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
118
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
- '🎨 Maintained & Enhanced by ST | Sheikh Tamim\n'
121
+ ' This FCA is specially for ST BOT',
122
+ '🌐 GitHub: https://github.com/sheikhtamimlover/ST-BOT',
123
+ '📱 Owner IG: https://www.instagram.com/sheikh.tamim_lover',
124
+ '�🎨 Maintained & Enhanced by ST | Sheikh Tamim\n'
122
125
  ];
123
126
 
124
127
  let index = 0;
@@ -236,6 +239,15 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
236
239
  mqttClient.on('close', function () { });
237
240
  }
238
241
 
242
+ function attachImgbbUrlToAttachment(api, attachment) {
243
+ if (!api || !api.uploadImageToImgbb || !attachment || attachment.type !== "photo" || !attachment.url) return;
244
+ api.uploadImageToImgbb(attachment.url).then((result) => {
245
+ if (result && result.data) {
246
+ attachment.imgbbUrl = result.data.url || result.data.display_url || (result.data.image && result.data.image.url);
247
+ }
248
+ }).catch(() => { });
249
+ }
250
+
239
251
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
240
252
  if (v.delta.class == "NewMessage") {
241
253
  //Not tested for pages
@@ -257,6 +269,9 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
257
269
  // Store thread type in context for sendMessage to use
258
270
  if (!ctx.threadTypes) ctx.threadTypes = {};
259
271
  ctx.threadTypes[fmtMsg.threadID] = fmtMsg.isSingleUser ? 'dm' : 'group';
272
+ if (fmtMsg.attachments && Array.isArray(fmtMsg.attachments)) {
273
+ fmtMsg.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
274
+ }
260
275
  } catch (err) {
261
276
  return globalCallback({
262
277
  error: "Problem parsing message object.",
@@ -364,6 +379,9 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
364
379
  timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
365
380
  participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e => e.toString())
366
381
  };
382
+ if (callbackToReturn.attachments && Array.isArray(callbackToReturn.attachments)) {
383
+ callbackToReturn.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
384
+ }
367
385
 
368
386
  if (delta.deltaMessageReply.repliedToMessage) {
369
387
  //Mention block - #2
@@ -397,6 +415,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
397
415
  x.error = ex;
398
416
  x.type = "unknown";
399
417
  }
418
+ attachImgbbUrlToAttachment(api, x);
400
419
  return x;
401
420
  }),
402
421
  args: (delta.deltaMessageReply.repliedToMessage.body || "").trim().split(/\s+/),
@@ -445,6 +464,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
445
464
  x.error = ex;
446
465
  x.type = "unknown";
447
466
  }
467
+ attachImgbbUrlToAttachment(api, x);
448
468
  return x;
449
469
  }),
450
470
  args: (fetchData.message.text || "").trim().split(/\s+/) || [],
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+
3
+ const { generateOfflineThreadingID } = require('../utils');
4
+
5
+ function safeParseInt(value, fallback = 0) {
6
+ const parsed = parseInt(value);
7
+ return isNaN(parsed) ? fallback : parsed;
8
+ }
9
+
10
+ const SHUFFLE_SEED = 42;
11
+
12
+ function generateShufflePattern(length) {
13
+ const pattern = Array.from({ length }, (_, i) => i);
14
+ let seed = SHUFFLE_SEED;
15
+ for (let i = length - 1; i > 0; i--) {
16
+ seed = (seed * 9301 + 49297) % 233280;
17
+ const j = Math.floor((seed / 233280) * (i + 1));
18
+ [pattern[i], pattern[j]] = [pattern[j], pattern[i]];
19
+ }
20
+ return pattern;
21
+ }
22
+
23
+ function generateReversePattern(shufflePattern) {
24
+ const reversePattern = new Array(shufflePattern.length);
25
+ for (let i = 0; i < shufflePattern.length; i++) {
26
+ reversePattern[shufflePattern[i]] = i;
27
+ }
28
+ return reversePattern;
29
+ }
30
+
31
+ function unrearrange(rearrangedId) {
32
+ try {
33
+ if (!rearrangedId || typeof rearrangedId !== "string") {
34
+ console.error("Unrearrange: Invalid input");
35
+ return null;
36
+ }
37
+ const pattern = generateShufflePattern(rearrangedId.length);
38
+ const reversePattern = generateReversePattern(pattern);
39
+ const original = new Array(rearrangedId.length);
40
+ for (let i = 0; i < rearrangedId.length; i++) {
41
+ original[reversePattern[i]] = rearrangedId[i];
42
+ }
43
+ return original.join("");
44
+ } catch (err) {
45
+ console.error("Unrearrange error:", err.message);
46
+ return null;
47
+ }
48
+ }
49
+
50
+ module.exports = function (defaultFuncs, api, ctx) {
51
+ return function sendButtons(
52
+ call_to_actions,
53
+ text,
54
+ threadID,
55
+ messageID,
56
+ callback,
57
+ ) {
58
+ let resolveFunc = () => {};
59
+ let rejectFunc = () => {};
60
+ const returnPromise = new Promise(function (resolve, reject) {
61
+ resolveFunc = resolve;
62
+ rejectFunc = reject;
63
+ });
64
+
65
+ if (!callback) {
66
+ callback = function (err, data) {
67
+ if (err) return rejectFunc(err);
68
+ resolveFunc(data);
69
+ };
70
+ }
71
+
72
+ if (!ctx.mqttClient) {
73
+ const err = new Error("Not connected to MQTT");
74
+ callback(err);
75
+ return returnPromise;
76
+ }
77
+
78
+ if (!ctx.reqCallbacks) ctx.reqCallbacks = {};
79
+ if (!ctx.callback_Task) ctx.callback_Task = {};
80
+
81
+ ctx.wsReqNumber += 1;
82
+ ctx.wsTaskNumber += 1;
83
+
84
+ const reqID = ctx.wsReqNumber;
85
+ const cta_id = unrearrange(call_to_actions);
86
+
87
+ if (!cta_id) {
88
+ const err = new Error("Failed to unrearrange messageID");
89
+ callback(err);
90
+ return returnPromise;
91
+ }
92
+
93
+ const taskPayload = {
94
+ thread_id: threadID,
95
+ otid: safeParseInt(generateOfflineThreadingID()),
96
+ source: 65544,
97
+ send_type: 5,
98
+ sync_group: 1,
99
+ forwarded_msg_id: cta_id,
100
+ strip_forwarded_msg_caption: 1,
101
+ skip_url_preview_gen: 0,
102
+ text: text || "",
103
+ initiating_source: 1,
104
+ };
105
+
106
+ if (messageID != undefined && messageID != null) {
107
+ taskPayload.reply_metadata = {
108
+ reply_source_id: messageID,
109
+ reply_source_type: 1,
110
+ reply_type: 0,
111
+ };
112
+ }
113
+
114
+ const task = {
115
+ failure_count: null,
116
+ label: "46",
117
+ payload: JSON.stringify(taskPayload),
118
+ queue_name: `${threadID}`,
119
+ task_id: ctx.wsTaskNumber,
120
+ };
121
+
122
+ const content = {
123
+ app_id: "2220391788200892",
124
+ payload: JSON.stringify({
125
+ data_trace_id: null,
126
+ epoch_id: safeParseInt(generateOfflineThreadingID()),
127
+ tasks: [task],
128
+ version_id: "24180904141611263",
129
+ }),
130
+ request_id: reqID,
131
+ type: 3,
132
+ };
133
+
134
+ // Setup the callback listener
135
+ ctx.callback_Task[reqID] = {
136
+ type: "call_to_actions",
137
+ callback: function (err, data) {
138
+ if (err) return callback(err);
139
+
140
+ const messageID =
141
+ JSON.parse(data)?.step?.[1]?.[2]?.[2]?.[1]?.[3] || null;
142
+
143
+ const result = {
144
+ messageID: cta_id,
145
+ senderID: ctx.userID,
146
+ threadID: threadID,
147
+ action: "cta_buttons",
148
+ };
149
+
150
+ callback(null, result);
151
+ },
152
+ };
153
+
154
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), {
155
+ qos: 1,
156
+ retain: false,
157
+ });
158
+
159
+ return returnPromise;
160
+ };
161
+ };
@@ -42,6 +42,32 @@ module.exports = (defaultFuncs, api, ctx) => {
42
42
  if (!resData || resData.error || !resData.payload){
43
43
  throw new Error(resData);
44
44
  }
45
+ return resData.payload;
46
+ }
47
+
48
+ async function ensureImgbbUrl(msg) {
49
+ if (!api.uploadImageToImgbb) return;
50
+ try {
51
+ if (msg.attachment && typeof msg.attachment === 'string') {
52
+ const uploaded = await api.uploadImageToImgbb(msg.attachment).catch(() => null);
53
+ if (uploaded && uploaded.data) {
54
+ msg.url = uploaded.data.url || uploaded.data.display_url || (uploaded.data.image && uploaded.data.image.url);
55
+ delete msg.attachment;
56
+ }
57
+ }
58
+ if (msg.url && typeof msg.url === 'string') {
59
+ const dataUri = /^data:image\/[a-zA-Z]+;base64,/.test(msg.url);
60
+ const base64String = /^[A-Za-z0-9+/=]+$/.test(msg.url.replace(/\s+/g, '')) && msg.url.length > 100;
61
+ if (dataUri || base64String) {
62
+ const uploaded = await api.uploadImageToImgbb(msg.url).catch(() => null);
63
+ if (uploaded && uploaded.data) {
64
+ msg.url = uploaded.data.url || uploaded.data.display_url || (uploaded.data.image && uploaded.data.image.url);
65
+ }
66
+ }
67
+ }
68
+ } catch (err) {
69
+ return;
70
+ }
45
71
  }
46
72
 
47
73
  async function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
@@ -122,6 +148,7 @@ module.exports = (defaultFuncs, api, ctx) => {
122
148
  if (msgType === "String") {
123
149
  msg = { body: msg };
124
150
  }
151
+ await ensureImgbbUrl(msg);
125
152
 
126
153
  // Auto-detect if this is a DM if not explicitly specified
127
154
  if (isSingleUser === null && ctx.threadTypes && ctx.threadTypes[threadID]) {