hridoy-ultimate 8.0.0 → 8.0.2

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.
Files changed (264) hide show
  1. package/ANALYSIS.md +31 -0
  2. package/AUDIT_REPORT.md +57 -0
  3. package/CHANGELOG.md +40 -322
  4. package/README.md +94 -339
  5. package/advancedSystem.js +95 -0
  6. package/checkUpdate.js +47 -0
  7. package/config.json +51 -0
  8. package/e2ee.js +738 -0
  9. package/examples/basic-bot.js +122 -0
  10. package/examples/e2ee-bot.js +141 -0
  11. package/fca-config.example.json +73 -0
  12. package/index.js +824 -24
  13. package/{src/api/socket/e2ee/native/lib → lib}/index.mjs +65 -107
  14. package/package.json +22 -62
  15. package/scripts/check.js +38 -0
  16. package/src/OldMessage.js +357 -0
  17. package/src/{api/action/addExternalModule.js → addExternalModule.js} +8 -8
  18. package/src/addUserToGroup.js +117 -0
  19. package/src/changeAdminStatus.js +105 -0
  20. package/src/{api/messaging/changeArchivedStatus.js → changeArchivedStatus.js} +17 -15
  21. package/src/{api/action/changeAvatar.js → changeAvatar.js} +33 -32
  22. package/src/changeAvatarV2.js +86 -0
  23. package/src/changeAvt.js +85 -0
  24. package/src/{api/action/changeBio.js → changeBio.js} +22 -19
  25. package/src/{api/messaging/changeBlockedStatus.js → changeBlockedStatus.js} +16 -13
  26. package/src/changeBlockedStatusMqtt.js +75 -0
  27. package/src/changeCover.js +73 -0
  28. package/src/changeGroupImage.js +137 -0
  29. package/src/changeName.js +79 -0
  30. package/src/changeNickname.js +61 -0
  31. package/src/changeThreadColor.js +67 -0
  32. package/src/changeThreadEmoji.js +57 -0
  33. package/src/changeUsername.js +59 -0
  34. package/src/createCommentPost.js +232 -0
  35. package/src/{api/messaging/createNewGroup.js → createNewGroup.js} +26 -24
  36. package/src/createPoll.js +73 -0
  37. package/src/createPost.js +276 -0
  38. package/src/deleteMessage.js +58 -0
  39. package/src/{api/messaging/deleteThread.js → deleteThread.js} +16 -14
  40. package/src/editMessage.js +76 -0
  41. package/src/editMessageOld.js +62 -0
  42. package/src/follow.js +74 -0
  43. package/src/forwardAttachment.js +62 -0
  44. package/src/friendList.js +104 -0
  45. package/src/getAccess.js +112 -0
  46. package/src/getAvatarUser.js +78 -0
  47. package/src/getBotInitialData.js +42 -0
  48. package/src/getCtx.js +5 -0
  49. package/src/{api/action/getCurrentUserID.js → getCurrentUserID.js} +1 -1
  50. package/src/{api/messaging/getEmojiUrl.js → getEmojiUrl.js} +2 -2
  51. package/src/{api/messaging/getFriendsList.js → getFriendsList.js} +19 -16
  52. package/src/{api/messaging/getMessage.js → getMessage.js} +180 -160
  53. package/src/getOptions.js +5 -0
  54. package/src/getRegion.js +7 -0
  55. package/src/{api/threads/getThreadHistory.js → getThreadHistory.js} +132 -114
  56. package/src/getThreadHistoryDeprecated.js +71 -0
  57. package/src/getThreadInfo.js +232 -0
  58. package/src/getThreadInfoDeprecated.js +56 -0
  59. package/src/getThreadList.js +213 -0
  60. package/src/getThreadListDeprecated.js +46 -0
  61. package/src/getThreadPictures.js +59 -0
  62. package/src/getThreadTheme.js +81 -0
  63. package/src/getUID.js +119 -0
  64. package/src/{api/users/getUserID.js → getUserID.js} +18 -22
  65. package/src/getUserInfo.js +66 -0
  66. package/src/handleFriendRequest.js +46 -0
  67. package/src/handleMessageRequest.js +47 -0
  68. package/src/httpGet.js +49 -0
  69. package/src/httpPost.js +48 -0
  70. package/src/httpPostFormData.js +70 -0
  71. package/src/listenMqtt.js +1081 -0
  72. package/src/listenNotification.js +85 -0
  73. package/src/logout.js +18 -0
  74. package/src/markAsDelivered.js +47 -0
  75. package/src/markAsRead.js +72 -0
  76. package/src/markAsReadAll.js +40 -0
  77. package/src/markAsSeen.js +48 -0
  78. package/src/metaTheme.js +189 -0
  79. package/src/muteThread.js +45 -0
  80. package/src/note.js +228 -0
  81. package/src/pinMessage.js +54 -0
  82. package/src/refreshFb_dtsg.js +49 -0
  83. package/src/removeSuspiciousAccount.js +78 -0
  84. package/src/removeUserFromGroup.js +81 -0
  85. package/src/reply.js +442 -0
  86. package/src/{api/messaging/resolvePhotoUrl.js → resolvePhotoUrl.js} +15 -11
  87. package/src/{api/messaging/searchForThread.js → searchForThread.js} +12 -12
  88. package/src/searchFriends.js +140 -0
  89. package/src/searchStickers.js +53 -0
  90. package/src/send.js +46 -0
  91. package/src/sendButtons.js +163 -0
  92. package/src/sendComment.js +159 -0
  93. package/src/sendFriendRequest.js +112 -0
  94. package/src/sendMessage.js +441 -0
  95. package/src/sendMessageMqtt.js +323 -0
  96. package/src/sendTypingIndicator.js +68 -0
  97. package/src/sendTypingIndicatorV2.js +22 -0
  98. package/src/setActiveStatus.js +92 -0
  99. package/src/setMessageReaction.js +150 -0
  100. package/src/setMessageReactionMqtt.js +104 -0
  101. package/src/setMessageReactionSafe.js +44 -0
  102. package/src/{api/action/setPostReaction.js → setPostReaction.js} +31 -23
  103. package/src/setProfileGuard.js +44 -0
  104. package/src/setProfileLock.js +97 -0
  105. package/src/setStoryReaction.js +133 -0
  106. package/src/setStorySeen.js +108 -0
  107. package/src/setThreadTheme.js +102 -0
  108. package/src/setTitle.js +92 -0
  109. package/src/shareContact.js +110 -0
  110. package/src/shareLink.js +59 -0
  111. package/src/stopListenMqtt.js +60 -0
  112. package/src/storyManager.js +357 -0
  113. package/src/suggestFriend.js +132 -0
  114. package/src/{api/messaging/threadColors.js → threadColors.js} +5 -2
  115. package/src/{api/action/unfriend.js → unfriend.js} +14 -14
  116. package/src/unsendMessage.js +68 -0
  117. package/src/uploadAttachment.js +115 -0
  118. package/test/fixes-1_2_4.test.js +118 -0
  119. package/test/mqtt-stop.test.js +32 -0
  120. package/test/reaction-mqtt.test.js +57 -0
  121. package/utils.js +3056 -0
  122. package/DOCS.md +0 -2712
  123. package/func/checkUpdate.js +0 -7
  124. package/func/logAdapter.js +0 -33
  125. package/func/logger.js +0 -48
  126. package/index.d.ts +0 -751
  127. package/module/config.js +0 -43
  128. package/module/login.js +0 -135
  129. package/module/loginHelper.js +0 -1381
  130. package/module/options.js +0 -49
  131. package/src/api/action/dismissScrapingWarning.js +0 -50
  132. package/src/api/action/enableAutoSaveAppState.js +0 -73
  133. package/src/api/action/handleFriendRequest.js +0 -57
  134. package/src/api/action/logout.js +0 -76
  135. package/src/api/action/refreshFb_dtsg.js +0 -47
  136. package/src/api/http/httpGet.js +0 -46
  137. package/src/api/http/httpPost.js +0 -52
  138. package/src/api/http/postFormData.js +0 -47
  139. package/src/api/messaging/addUserToGroup.js +0 -68
  140. package/src/api/messaging/changeAdminStatus.js +0 -126
  141. package/src/api/messaging/changeGroupImage.js +0 -91
  142. package/src/api/messaging/changeNickname.js +0 -70
  143. package/src/api/messaging/changeThreadColor.js +0 -79
  144. package/src/api/messaging/changeThreadEmoji.js +0 -111
  145. package/src/api/messaging/createPoll.js +0 -46
  146. package/src/api/messaging/createThemeAI.js +0 -98
  147. package/src/api/messaging/deleteMessage.js +0 -136
  148. package/src/api/messaging/editMessage.js +0 -105
  149. package/src/api/messaging/forwardAttachment.js +0 -57
  150. package/src/api/messaging/forwardMessage.js +0 -134
  151. package/src/api/messaging/getThemePictures.js +0 -62
  152. package/src/api/messaging/handleMessageRequest.js +0 -65
  153. package/src/api/messaging/markAsDelivered.js +0 -69
  154. package/src/api/messaging/markAsRead.js +0 -110
  155. package/src/api/messaging/markAsReadAll.js +0 -56
  156. package/src/api/messaging/markAsSeen.js +0 -68
  157. package/src/api/messaging/muteThread.js +0 -50
  158. package/src/api/messaging/pinMessage.js +0 -115
  159. package/src/api/messaging/removeUserFromGroup.js +0 -62
  160. package/src/api/messaging/scheduler.js +0 -264
  161. package/src/api/messaging/sendBroadcast.js +0 -93
  162. package/src/api/messaging/sendMessage.js +0 -269
  163. package/src/api/messaging/sendTypingIndicator.js +0 -90
  164. package/src/api/messaging/sessionGuard.js +0 -130
  165. package/src/api/messaging/setMessageReaction.js +0 -109
  166. package/src/api/messaging/setTitle.js +0 -124
  167. package/src/api/messaging/shareContact.js +0 -98
  168. package/src/api/messaging/unsendMessage.js +0 -105
  169. package/src/api/messaging/uploadAttachment.js +0 -493
  170. package/src/api/socket/OldMessage.js +0 -199
  171. package/src/api/socket/core/connectMqtt.js +0 -277
  172. package/src/api/socket/core/emitAuth.js +0 -103
  173. package/src/api/socket/core/getSeqID.js +0 -331
  174. package/src/api/socket/core/getTaskResponseData.js +0 -25
  175. package/src/api/socket/core/parseDelta.js +0 -387
  176. package/src/api/socket/detail/buildStream.js +0 -215
  177. package/src/api/socket/detail/constants.js +0 -28
  178. package/src/api/socket/e2ee/crypto.js +0 -173
  179. package/src/api/socket/e2ee/index.js +0 -959
  180. package/src/api/socket/e2ee/localMediaServer.js +0 -59
  181. package/src/api/socket/e2ee/mediaDecode.js +0 -155
  182. package/src/api/socket/e2ee/native/NOTICE.md +0 -29
  183. package/src/api/socket/e2ee/native/nativeMediaBridge.js +0 -273
  184. package/src/api/socket/e2ee/proto/ArmadilloApplication.proto +0 -281
  185. package/src/api/socket/e2ee/proto/ArmadilloICDC.proto +0 -14
  186. package/src/api/socket/e2ee/proto/ConsumerApplication.proto +0 -232
  187. package/src/api/socket/e2ee/proto/MessageApplication.proto +0 -82
  188. package/src/api/socket/e2ee/proto/MessageTransport.proto +0 -77
  189. package/src/api/socket/e2ee/proto/WACommon.proto +0 -66
  190. package/src/api/socket/e2ee/proto/WAMediaTransport.proto +0 -176
  191. package/src/api/socket/e2ee/proto/proto-writer.ts +0 -76
  192. package/src/api/socket/e2ee/protocol.js +0 -196
  193. package/src/api/socket/e2ee/ratchet.js +0 -219
  194. package/src/api/socket/e2ee/store.js +0 -182
  195. package/src/api/socket/e2ee/vendor/fme/dist/index.cjs +0 -6477
  196. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloApplication.proto +0 -281
  197. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloICDC.proto +0 -14
  198. package/src/api/socket/e2ee/vendor/fme/proto/ConsumerApplication.proto +0 -232
  199. package/src/api/socket/e2ee/vendor/fme/proto/MessageApplication.proto +0 -82
  200. package/src/api/socket/e2ee/vendor/fme/proto/MessageTransport.proto +0 -77
  201. package/src/api/socket/e2ee/vendor/fme/proto/WACommon.proto +0 -66
  202. package/src/api/socket/e2ee/vendor/fme/proto/WAMediaTransport.proto +0 -176
  203. package/src/api/socket/listenE2EE.js +0 -85
  204. package/src/api/socket/listenMqtt.js +0 -492
  205. package/src/api/socket/middleware/index.js +0 -216
  206. package/src/api/socket/sendMessage.js +0 -331
  207. package/src/api/socket/sendMessageMqtt.js +0 -69
  208. package/src/api/threads/getThreadInfo.js +0 -329
  209. package/src/api/threads/getThreadList.js +0 -293
  210. package/src/api/threads/getThreadPictures.js +0 -78
  211. package/src/api/users/getUserInfo.js +0 -402
  212. package/src/api/users/getUserInfoV2.js +0 -134
  213. package/src/app/MessengerBot.js +0 -209
  214. package/src/app/MessengerContext.js +0 -32
  215. package/src/app/createFcaClient.js +0 -136
  216. package/src/app/threadInfoRealtimeSync.js +0 -284
  217. package/src/core/sendReqMqtt.js +0 -96
  218. package/src/database/helpers.js +0 -53
  219. package/src/database/models/index.js +0 -88
  220. package/src/database/models/thread.js +0 -50
  221. package/src/database/models/user.js +0 -46
  222. package/src/database/threadData.js +0 -94
  223. package/src/database/userData.js +0 -98
  224. package/src/remote/remoteClient.js +0 -123
  225. package/src/utils/antiSuspension.js +0 -219
  226. package/src/utils/broadcast.js +0 -51
  227. package/src/utils/client.js +0 -10
  228. package/src/utils/constants.js +0 -23
  229. package/src/utils/cookies.js +0 -85
  230. package/src/utils/fingerprint.js +0 -101
  231. package/src/utils/format/attachment.js +0 -357
  232. package/src/utils/format/cookie.js +0 -9
  233. package/src/utils/format/date.js +0 -50
  234. package/src/utils/format/decode.js +0 -44
  235. package/src/utils/format/delta.js +0 -195
  236. package/src/utils/format/ids.js +0 -64
  237. package/src/utils/format/index.js +0 -64
  238. package/src/utils/format/message.js +0 -88
  239. package/src/utils/format/presence.js +0 -132
  240. package/src/utils/format/readTyp.js +0 -44
  241. package/src/utils/format/thread.js +0 -42
  242. package/src/utils/format/utils.js +0 -141
  243. package/src/utils/headers.js +0 -125
  244. package/src/utils/humanizer.js +0 -256
  245. package/src/utils/loginParser/autoLogin.js +0 -125
  246. package/src/utils/loginParser/extractDtsg.js +0 -44
  247. package/src/utils/loginParser/helpers.js +0 -43
  248. package/src/utils/loginParser/index.js +0 -10
  249. package/src/utils/loginParser/parseAndCheckLogin.js +0 -241
  250. package/src/utils/loginParser/textUtils.js +0 -28
  251. package/src/utils/nexca-logger.js +0 -144
  252. package/src/utils/nexca-utils.js +0 -687
  253. package/src/utils/request/client.js +0 -26
  254. package/src/utils/request/config.js +0 -23
  255. package/src/utils/request/defaults.js +0 -46
  256. package/src/utils/request/helpers.js +0 -46
  257. package/src/utils/request/index.js +0 -17
  258. package/src/utils/request/methods.js +0 -163
  259. package/src/utils/request/proxy.js +0 -21
  260. package/src/utils/request/retry.js +0 -77
  261. package/src/utils/request/sanitize.js +0 -49
  262. package/src/utils/versionCheck.js +0 -47
  263. /package/{src/api/socket/e2ee/native/build → build}/messagix.dll +0 -0
  264. /package/{src/api/socket/e2ee/native/build → build}/messagix.so +0 -0
@@ -1,493 +0,0 @@
1
- "use strict";
2
-
3
- const axios = require("axios");
4
- const { wrapper } = require("axios-cookiejar-support");
5
- const { CookieJar } = require("tough-cookie");
6
- const FormData = require("form-data");
7
- const fs = require("fs");
8
- const path = require("path");
9
- const stream = require("stream");
10
- const { URL } = require("url");
11
- const log = require("../../../func/logAdapter");
12
- const { getDefaultUserAgent } = require("../../utils/fingerprint");
13
-
14
- let http = null;
15
- let cookieJar = new CookieJar();
16
- let tokenCache = null;
17
- let tokenCacheTime = 0;
18
- const TOKEN_CACHE_TTL = 5 * 60 * 1000;
19
-
20
- const DEFAULT_UA = getDefaultUserAgent();
21
-
22
- function cleanJSON(x) {
23
- if (typeof x !== "string") return x;
24
- const s = x.replace(/^for\s*\(;;\);\s*/i, "");
25
- try { return JSON.parse(s); } catch { return s; }
26
- }
27
-
28
- function pick(re, html, i = 1) {
29
- const m = html && html.match(re);
30
- return m ? m[i] : "";
31
- }
32
-
33
- function getFrom(html, a, b) {
34
- const i = html.indexOf(a);
35
- if (i < 0) return;
36
- const start = i + a.length;
37
- const j = html.indexOf(b, start);
38
- return j < 0 ? undefined : html.slice(start, j);
39
- }
40
-
41
- function respFinalUrl(res) {
42
- return (res && (res.url || res.requestUrl)) || "";
43
- }
44
-
45
- function detectCheckpoint(res) {
46
- const url = String(respFinalUrl(res) || "");
47
- const body = typeof res?.body === "string" ? res.body : "";
48
- const hit =
49
- /\/checkpoint\//i.test(url) ||
50
- /(?:href|action)\s*=\s*["']https?:\/\/[^"']*\/checkpoint\//i.test(body) ||
51
- /"checkpoint"|checkpoint_title|checkpointMain|id="checkpoint"/i.test(body) ||
52
- (/login\.php/i.test(url) && /checkpoint/i.test(body));
53
- return { hit, url: url || (body.match(/https?:\/\/[^"']*\/checkpoint\/[^"'<>]*/i)?.[0] || "") };
54
- }
55
-
56
- function checkpointError(res) {
57
- const d = detectCheckpoint(res);
58
- if (!d.hit) return null;
59
- const e = new Error("Checkpoint required");
60
- e.code = "CHECKPOINT";
61
- e.checkpoint = true;
62
- e.url = d.url || "https://www.facebook.com/checkpoint/";
63
- e.status = res?.statusCode || res?.status;
64
- return e;
65
- }
66
-
67
- async function httpGet(pageUrl, ua, headers = {}) {
68
- const host = new URL(pageUrl).hostname;
69
- const referer = `https://${host}/`;
70
- const baseHeaders = {
71
- Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
72
- "Accept-Language": "vi-VN,vi;q=0.9,en-US;q=0.8,en;q=0.7",
73
- "Accept-Encoding": "gzip, deflate, br",
74
- "Cache-Control": "max-age=0",
75
- Connection: "keep-alive",
76
- Host: host,
77
- Origin: `https://${host}`,
78
- Referer: referer,
79
- "Sec-Ch-Prefers-Color-Scheme": "dark",
80
- "Sec-Ch-Ua": '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
81
- "Sec-Ch-Ua-Full-Version-List": '"Google Chrome";v="143.0.7499.182", "Chromium";v="143.0.7499.182", "Not A(Brand";v="24.0.0.0"',
82
- "Sec-Ch-Ua-Mobile": "?0",
83
- "Sec-Ch-Ua-Model": '""',
84
- "Sec-Ch-Ua-Platform": '"Windows"',
85
- "Sec-Ch-Ua-Platform-Version": '"19.0.0"',
86
- "Sec-Fetch-Dest": "document",
87
- "Sec-Fetch-Mode": "navigate",
88
- "Sec-Fetch-Site": "same-origin",
89
- "Sec-Fetch-User": "?1",
90
- "Upgrade-Insecure-Requests": "1",
91
- "User-Agent": ua || DEFAULT_UA,
92
- "x-fb-rlafr": "0"
93
- };
94
- const res = await http.get(pageUrl, {
95
- headers: { ...baseHeaders, ...headers },
96
- timeout: 30000
97
- });
98
- const cp = checkpointError(res);
99
- if (cp) throw cp;
100
- return typeof res.data === "string" ? res.data : String(res.data || "");
101
- }
102
-
103
- async function getTokens(ua, forceRefresh = false) {
104
- const now = Date.now();
105
- if (!forceRefresh && tokenCache && (now - tokenCacheTime) < TOKEN_CACHE_TTL) {
106
- return tokenCache;
107
- }
108
- try {
109
- const html = await httpGet("https://www.facebook.com/", ua, { Referer: "https://www.facebook.com/" });
110
- const fb_dtsg = getFrom(html, '"DTSGInitData",[],{"token":"', '",') || html.match(/name="fb_dtsg"\s+value="([^"]+)"/)?.[1] || "";
111
- const jazoest = getFrom(html, 'name="jazoest" value="', '"') || getFrom(html, "jazoest=", '",') || html.match(/name="jazoest"\s+value="([^"]+)"/)?.[1] || "";
112
- const lsd = getFrom(html, '["LSD",[],{"token":"', '"}') || html.match(/name="lsd"\s+value="([^"]+)"/)?.[1] || "";
113
- const spin_r = pick(/"__spin_r":(\d+)/, html) || "";
114
- const spin_t = pick(/"__spin_t":(\d+)/, html) || "";
115
- const rev = pick(/"__rev":(\d+)/, html) || "";
116
-
117
- if (!fb_dtsg || !lsd) {
118
- // Cố gắng fallback nếu regex fail, nhưng thường là do cookie die
119
- if (!tokenCache) throw new Error("Failed to fetch fb_dtsg or LSD from Facebook");
120
- }
121
-
122
- tokenCache = { lsd, fb_dtsg, jazoest, spin_r, spin_t, rev };
123
- tokenCacheTime = now;
124
- return tokenCache;
125
- } catch (e) {
126
- if (tokenCache) {
127
- log.warn("[uploadAttachment] Token fetch failed, using cached tokens: " + (e.message || e));
128
- return tokenCache;
129
- }
130
- throw e;
131
- }
132
- }
133
-
134
- function getType(obj) { return Object.prototype.toString.call(obj).slice(8, -1); }
135
- function isReadableStream(obj) { return obj instanceof stream.Readable && (getType(obj._read) === "Function" || getType(obj._read) === "AsyncFunction") && getType(obj._readableState) === "Object"; }
136
- function fromBuffer(buf) { return stream.Readable.from(buf); }
137
- function parseDataUrl(s) { const m = /^data:([^;,]+)?(;base64)?,(.*)$/i.exec(s); if (!m) return null; const mime = m[1] || "application/octet-stream"; const isB64 = !!m[2]; const data = isB64 ? Buffer.from(m[3], "base64") : Buffer.from(decodeURIComponent(m[3]), "utf8"); return { mime, data }; }
138
-
139
- function filenameFromUrl(u, headers) {
140
- try {
141
- const urlObj = new URL(u);
142
- let filename = path.basename(urlObj.pathname) || `file-${Date.now()}`;
143
- const cd = headers && (headers["content-disposition"] || headers["Content-Disposition"]);
144
- if (cd) {
145
- const m = /filename\*?=(?:UTF-8''|")?([^";\n]+)/i.exec(cd);
146
- if (m) filename = decodeURIComponent(m[1].replace(/"/g, ""));
147
- }
148
- return filename;
149
- } catch {
150
- return `file-${Date.now()}`;
151
- }
152
- }
153
-
154
- async function normalizeOne(input, ua) {
155
- if (!input) throw new Error("Invalid input");
156
- if (Buffer.isBuffer(input)) return { stream: fromBuffer(input), filename: `file-${Date.now()}.bin`, contentType: "application/octet-stream" };
157
- if (typeof input === "string") {
158
- if (/^https?:\/\//i.test(input)) {
159
- const resp = await http.get(input, {
160
- headers: {
161
- "User-Agent": ua,
162
- Accept: "*/*",
163
- "Accept-Encoding": "gzip, deflate, br",
164
- "Cache-Control": "no-cache"
165
- },
166
- timeout: 30000,
167
- responseType: "stream"
168
- });
169
- const s = resp.data;
170
- const filename = filenameFromUrl(input, resp.headers);
171
- return { stream: s, filename };
172
- }
173
- if (input.startsWith("data:")) {
174
- const p = parseDataUrl(input);
175
- if (!p) throw new Error("Bad data URL");
176
- return { stream: fromBuffer(p.data), filename: `file-${Date.now()}`, contentType: p.mime };
177
- }
178
- if (fs.existsSync(input) && fs.statSync(input).isFile()) {
179
- return { stream: fs.createReadStream(input), filename: path.basename(input) };
180
- }
181
- throw new Error(`Unsupported string input: ${input}`);
182
- }
183
- if (isReadableStream(input)) {
184
- return { stream: input, filename: `file-${Date.now()}` };
185
- }
186
- if (typeof input === "object") {
187
- if (input.buffer && Buffer.isBuffer(input.buffer)) {
188
- const filename = input.filename || `file-${Date.now()}.bin`;
189
- const contentType = input.contentType || "application/octet-stream";
190
- return { stream: fromBuffer(input.buffer), filename, contentType };
191
- }
192
- if (input.data && Buffer.isBuffer(input.data)) {
193
- const filename = input.filename || `file-${Date.now()}.bin`;
194
- const contentType = input.contentType || "application/octet-stream";
195
- return { stream: fromBuffer(input.data), filename, contentType };
196
- }
197
- if (input.stream && isReadableStream(input.stream)) {
198
- const filename = input.filename || `file-${Date.now()}`;
199
- const contentType = input.contentType;
200
- return { stream: input.stream, filename, contentType };
201
- }
202
- if (input.url) {
203
- return normalizeOne(String(input.url), ua);
204
- }
205
- if (input.path && fs.existsSync(input.path) && fs.statSync(input.path).isFile()) {
206
- return { stream: fs.createReadStream(input.path), filename: input.filename || path.basename(input.path), contentType: input.contentType };
207
- }
208
- }
209
- throw new Error("Unrecognized input");
210
- }
211
-
212
- function mapAttachmentDetails(data) {
213
- const out = [];
214
- if (!data || typeof data !== "object") return out;
215
-
216
- const stack = [data];
217
- while (stack.length) {
218
- const cur = stack.pop();
219
- if (!cur || typeof cur !== "object") continue;
220
- const id = cur.video_id || cur.image_id || cur.audio_id || cur.file_id || cur.fbid || cur.id || cur.upload_id || cur.gif_id;
221
- const idKey =
222
- cur.video_id ? "video_id" :
223
- cur.image_id ? "image_id" :
224
- cur.audio_id ? "audio_id" :
225
- cur.file_id ? "file_id" :
226
- cur.gif_id ? "gif_id" :
227
- cur.fbid ? "fbid" :
228
- id ? "id" : null;
229
- const filename = cur.filename || cur.file_name || cur.name || cur.original_filename;
230
- const filetype = cur.filetype || cur.mime_type || cur.type || cur.content_type;
231
- let thumbnail = cur.thumbnail_src || cur.thumbnail_url || cur.preview_url || cur.thumbSrc || cur.thumb_url || cur.image_preview_url || cur.large_preview_url;
232
- if (!thumbnail) {
233
- const m = cur.media || cur.thumbnail || cur.thumb || cur.image_data || cur.video_data || cur.preview;
234
- thumbnail = m?.thumbnail_src || m?.thumbnail_url || m?.src || m?.uri || m?.url;
235
- }
236
- if (idKey) {
237
- const o = {};
238
- o[idKey] = id;
239
- if (filename) o.filename = filename;
240
- if (filetype) o.filetype = filetype;
241
- if (thumbnail) o.thumbnail_src = thumbnail;
242
- out.push(o);
243
- }
244
- if (Array.isArray(cur)) {
245
- for (const v of cur) stack.push(v);
246
- } else {
247
- for (const k of Object.keys(cur)) stack.push(cur[k]);
248
- }
249
- }
250
-
251
- if (!out.length && data.payload && Array.isArray(data.payload.metadata)) {
252
- return data.payload.metadata.slice();
253
- }
254
-
255
- return out;
256
- }
257
-
258
- function pLimit(n) {
259
- let active = 0;
260
- const queue = [];
261
- const next = () => {
262
- active--;
263
- if (queue.length) queue.shift()();
264
- };
265
- return fn => new Promise((resolve, reject) => {
266
- const run = () => {
267
- active++;
268
- fn().then(v => { resolve(v); next(); }).catch(e => { reject(e); next(); });
269
- };
270
- if (active < n) run(); else queue.push(run);
271
- });
272
- }
273
-
274
- // Hàm upload core xử lý request
275
- async function singleUpload(urlBase, file, ua, tokens, retries = 2) {
276
- const form = new FormData();
277
- // QUAN TRỌNG: Chỉ append file, KHÔNG append fb_dtsg vào body nữa
278
- form.append("farr", file.stream, { filename: file.filename, contentType: file.contentType });
279
-
280
- const headers = {
281
- ...form.getHeaders(),
282
- Accept: "*/*",
283
- "Accept-Language": "vi,en-US;q=0.9,en;q=0.8,fr-FR;q=0.7,fr;q=0.6",
284
- "Accept-Encoding": "gzip, deflate, br",
285
- "User-Agent": ua,
286
- "x-asbd-id": "359341",
287
- "x-fb-lsd": tokens.lsd || "",
288
- "x-fb-friendly-name": "MercuryUpload",
289
- "x-fb-request-analytics-tags": JSON.stringify({
290
- network_tags: {
291
- product: "256002347743983",
292
- purpose: "none",
293
- request_category: "graphql",
294
- retry_attempt: "0"
295
- },
296
- application_tags: "graphservice"
297
- }),
298
- "sec-ch-prefers-color-scheme": "dark",
299
- "sec-ch-ua": '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
300
- "sec-ch-ua-mobile": "?0",
301
- "sec-ch-ua-platform": '"Windows"',
302
- "sec-fetch-dest": "empty",
303
- "sec-fetch-mode": "cors",
304
- "sec-fetch-site": "same-origin",
305
- Origin: "https://www.facebook.com",
306
- Referer: "https://www.facebook.com/",
307
- "x-fb-rlafr": "0",
308
- Connection: "keep-alive"
309
- };
310
-
311
- // Build URL với query string tokens
312
- const finalUrl = new URL(urlBase);
313
- finalUrl.searchParams.set("fb_dtsg", tokens.fb_dtsg);
314
- finalUrl.searchParams.set("jazoest", tokens.jazoest);
315
- finalUrl.searchParams.set("lsd", tokens.lsd);
316
- finalUrl.searchParams.set("__aaid", "0");
317
- finalUrl.searchParams.set("__ccg", "EXCELLENT");
318
-
319
- for (let attempt = 0; attempt <= retries; attempt++) {
320
- try {
321
- const res = await http.post(finalUrl.toString(), form, {
322
- headers,
323
- timeout: 120000,
324
- maxContentLength: Infinity,
325
- maxBodyLength: Infinity
326
- });
327
- return res;
328
- } catch (e) {
329
- if (attempt === retries) throw e;
330
- if (e.code === "ETIMEDOUT" || e.code === "ECONNRESET" || (e.response && e.response.status >= 500)) {
331
- await new Promise(r => setTimeout(r, (attempt + 1) * 1000));
332
- continue;
333
- }
334
- throw e;
335
- }
336
- }
337
- }
338
-
339
- module.exports = function (defaultFuncs, api, ctx) {
340
- const ua = ctx?.options?.userAgent || DEFAULT_UA;
341
- cookieJar = ctx.jar instanceof CookieJar ? ctx.jar : new CookieJar();
342
-
343
- // Axios instance
344
- http = wrapper(axios.create({
345
- timeout: 60000,
346
- headers: {
347
- "User-Agent": ua,
348
- "Accept-Language": "vi-VN,vi;q=0.9,en-US;q=0.8,en;q=0.7",
349
- "Accept-Encoding": "gzip, deflate, br",
350
- Connection: "keep-alive"
351
- },
352
- maxRedirects: 5,
353
- validateStatus: () => true
354
- }));
355
- http.defaults.withCredentials = true;
356
- http.defaults.jar = cookieJar;
357
-
358
- async function uploadCore(link, opts, callback) {
359
- if (typeof opts === "function") { callback = opts; opts = undefined; }
360
- const options = {
361
- concurrency: Math.max(1, Math.min(5, Number(opts?.concurrency || 3))),
362
- mode: opts?.mode === "single" ? "single" : "parallel"
363
- };
364
-
365
- let resolveFunc = function () { };
366
- let rejectFunc = function () { };
367
- const returnPromise = new Promise(function (resolve, reject) {
368
- resolveFunc = resolve;
369
- rejectFunc = reject;
370
- });
371
- if (!callback) {
372
- callback = function (err, data) {
373
- if (err) return rejectFunc(err);
374
- resolveFunc(data);
375
- };
376
- }
377
-
378
- (async () => {
379
- try {
380
- const inputsArr = Array.isArray(link) ? link : [link];
381
- if (!inputsArr.length) {
382
- const e = new Error("No files to upload");
383
- callback(e);
384
- return;
385
- }
386
-
387
- let tokens = await getTokens(ua);
388
- const normAll = await Promise.all(inputsArr.map(x => normalizeOne(x, ua)));
389
-
390
- // Base QS setup
391
- const qs = [];
392
- const userId = (ctx && (ctx.userID || ctx.userId)) ? String(ctx.userID || ctx.userId) : "";
393
- if (userId) qs.push(`__user=${encodeURIComponent(userId)}`);
394
- qs.push("__a=1");
395
- qs.push("dpr=1");
396
- const reqId = Math.floor(Math.random() * 36 ** 2).toString(36);
397
- qs.push(`__req=${encodeURIComponent(reqId)}`);
398
- if (tokens.spin_r) qs.push(`__spin_r=${encodeURIComponent(tokens.spin_r)}`);
399
- if (tokens.spin_t) qs.push(`__spin_t=${encodeURIComponent(tokens.spin_t)}`);
400
- if (tokens.rev) qs.push(`__rev=${encodeURIComponent(tokens.rev)}`);
401
- qs.push("__spin_b=trunk");
402
- qs.push("__comet_req=15");
403
-
404
- const baseUrl = `https://www.facebook.com/ajax/mercury/upload.php?${qs.join("&")}`;
405
-
406
- if (options.mode === "single") {
407
- const f = normAll[0];
408
- const res = await singleUpload(baseUrl, f, ua, tokens);
409
-
410
- const cp = checkpointError(res);
411
- if (cp) { tokenCache = null; throw cp; }
412
-
413
- const data = cleanJSON(res.data);
414
- const ids = mapAttachmentDetails(data);
415
-
416
- if (!ids.length) {
417
- const e = new Error("UploadFb returned no metadata/ids");
418
- e.code = "NO_METADATA";
419
- e.status = res.status;
420
- e.body = typeof data === "string" ? data.slice(0, 500) : data;
421
- throw e;
422
- }
423
- log.info(`[uploadAttachment] success ${ids.length} item(s) status ${res.status}`);
424
- callback(null, { status: res.status, ids, raw: data });
425
- return;
426
- }
427
-
428
- // Parallel mode
429
- const limit = pLimit(options.concurrency);
430
- const tasks = normAll.map(f => () => singleUpload(baseUrl, f, ua, tokens));
431
- const results = await Promise.all(tasks.map(t => limit(t)));
432
-
433
- const ids = [];
434
- const errors = [];
435
- for (let i = 0; i < results.length; i++) {
436
- const res = results[i];
437
- try {
438
- const cp = checkpointError(res);
439
- if (cp) { tokenCache = null; throw cp; }
440
-
441
- const data = cleanJSON(res.data);
442
- const fileIds = mapAttachmentDetails(data);
443
- if (!fileIds.length) {
444
- log.warn(`[uploadAttachment] File ${i + 1} returned no metadata/ids`);
445
- continue;
446
- }
447
- ids.push(...fileIds);
448
- } catch (e) {
449
- errors.push({ index: i, error: e });
450
- log.error(`[uploadAttachment] Upload ${i + 1} failed: ${e.message || e}`);
451
- }
452
- }
453
-
454
- if (ids.length === 0 && errors.length > 0) {
455
- throw errors[0].error;
456
- }
457
-
458
- log.info(`[uploadAttachment] success ${ids.length}/${normAll.length} item(s)`);
459
- callback(null, { status: 200, ids, raw: null, errors: errors.length > 0 ? errors : undefined });
460
- } catch (e) {
461
- if (e.code === "CHECKPOINT" || (e.response && [401, 403].includes(e.response.status))) {
462
- tokenCache = null;
463
- try {
464
- await getTokens(ua, true);
465
- log.info("[uploadAttachment] Tokens refreshed after error");
466
- } catch (refreshErr) {
467
- log.error("[uploadAttachment] Token refresh failed: " + (refreshErr.message || refreshErr));
468
- }
469
- }
470
- log.error(`[uploadAttachment] error ${e.code || e.status || ""} ${e.message || e}`);
471
- callback(e);
472
- }
473
- })().catch(err => {
474
- log.error("[uploadAttachment] Unhandled promise rejection: " + (err.message || err));
475
- rejectFunc(err);
476
- });
477
-
478
- return returnPromise;
479
- }
480
-
481
- return function uploadAttachment(attachments, callback) {
482
- if (!attachments) throw { error: "Please pass an attachment or an array of attachments." };
483
-
484
- if (typeof callback === "function") {
485
- return uploadCore(attachments, { mode: "parallel" }, (err, result) => {
486
- if (err) return callback(err);
487
- callback(null, result && Array.isArray(result.ids) ? result.ids : []);
488
- }).then(result => (result && Array.isArray(result.ids) ? result.ids : []));
489
- }
490
-
491
- return uploadCore(attachments, { mode: "parallel" }).then(result => result && Array.isArray(result.ids) ? result.ids : []);
492
- };
493
- };
@@ -1,199 +0,0 @@
1
- "use strict";
2
-
3
- var utils = require("../../utils/nexca-utils");
4
- var logger = require("../../utils/nexca-logger");
5
- var bluebird = require("bluebird");
6
- var { globalAntiSuspension } = require("../../utils/antiSuspension");
7
-
8
- var allowedProperties = {
9
- attachment: true, url: true, sticker: true, emoji: true,
10
- emojiSize: true, body: true, mentions: true, location: true,
11
- };
12
-
13
- module.exports = function (defaultFuncs, api, ctx) {
14
-
15
- function uploadAttachment(attachments, callback) {
16
- var uploads = [];
17
- for (var i = 0; i < attachments.length; i++) {
18
- if (!utils.isReadableStream(attachments[i])) {
19
- return callback({ error: "Attachment must be a readable stream." });
20
- }
21
- uploads.push(
22
- defaultFuncs.postFormData("https://upload.facebook.com/ajax/mercury/upload.php", ctx.jar, {
23
- upload_1024: attachments[i],
24
- voice_clip: "true"
25
- })
26
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
27
- .then(resData => {
28
- if (resData.error) throw resData;
29
- return resData.payload.metadata[0];
30
- })
31
- );
32
- }
33
- bluebird.all(uploads)
34
- .then(resData => callback(null, resData))
35
- .catch(err => { globalAntiSuspension.checkAccountHealth(err); logger.error("OldMessage.upload", err); callback(err); });
36
- }
37
-
38
- function getUrl(url, callback) {
39
- defaultFuncs.post("https://www.facebook.com/message_share_attachment/fromURI/", ctx.jar, {
40
- image_height: 960, image_width: 960, uri: url
41
- })
42
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
43
- .then(resData => {
44
- if (resData.error) return callback(resData);
45
- if (!resData.payload) return callback({ error: "Invalid URL" });
46
- callback(null, resData.payload.share_data.share_params);
47
- })
48
- .catch(err => { logger.error("OldMessage.getUrl", err); callback(err); });
49
- }
50
-
51
- function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
52
- if (utils.getType(threadID) === "Array") {
53
- for (var i = 0; i < threadID.length; i++) form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
54
- form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
55
- form["client_thread_id"] = "root:" + messageAndOTID;
56
- } else {
57
- if (isSingleUser) {
58
- form["specific_to_list[0]"] = "fbid:" + threadID;
59
- form["specific_to_list[1]"] = "fbid:" + ctx.userID;
60
- form["other_user_fbid"] = threadID;
61
- } else {
62
- form["thread_fbid"] = threadID;
63
- }
64
- }
65
-
66
- if (ctx.globalOptions.pageID) {
67
- form["author"] = "fbid:" + ctx.globalOptions.pageID;
68
- form["specific_to_list[1]"] = "fbid:" + ctx.globalOptions.pageID;
69
- form["creator_info[creatorID]"] = ctx.userID;
70
- form["creator_info[creatorType]"] = "direct_admin";
71
- }
72
-
73
- defaultFuncs.post("https://www.facebook.com/messaging/send/", ctx.jar, form)
74
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
75
- .then(resData => {
76
- if (!resData.payload) {
77
- globalAntiSuspension.checkAccountHealth(resData);
78
- throw resData;
79
- }
80
- var messageID = (resData.payload.actions && resData.payload.actions[0] &&
81
- resData.payload.actions[0].message_id) || null;
82
- var threadID2 = resData.payload.thread_fbid ||
83
- (resData.payload.actions && resData.payload.actions[0] && resData.payload.actions[0].thread_fbid);
84
- callback(null, {
85
- threadID: threadID2 ? String(threadID2) : String(threadID),
86
- messageID: messageID ? String(messageID) : null,
87
- timestamp: resData.payload.timestamp
88
- });
89
- })
90
- .catch(err => {
91
- globalAntiSuspension.checkAccountHealth(err);
92
- logger.error("OldMessage.send", err);
93
- callback(err);
94
- });
95
- }
96
-
97
- function send(form, threadID, isSingleUser, callback) {
98
- var messageAndOTID = utils.generateOfflineThreadingID();
99
- form.client = "mercury";
100
- form.action_type = "ma-type:user-generated-message";
101
- form.timestamp = Date.now();
102
- form.timestamp_absolute = "Today";
103
- form.timestamp_relative = "12:00";
104
- form.timestamp_time_passed = "0";
105
- form.is_unread = false;
106
- form.is_cleared = false;
107
- form.is_forward = false;
108
- form.is_filtered_content = false;
109
- form.is_filtered_content_bec = false;
110
- form.is_filtered_content_account = false;
111
- form.is_filtered_content_quasar = false;
112
- form.is_filtered_content_invalid_app = false;
113
- form.is_not_supported = false;
114
- form.message_id = messageAndOTID;
115
- form.offline_threading_id = messageAndOTID;
116
- form.ephemeral_ttl_mode = 0;
117
- form.manual_retry_cnt = 0;
118
- form.has_attachment = false;
119
- form.signatureID = utils.getGUID().replace(/-/g, "").slice(0, 8);
120
- const doSend = () => sendContent(form, threadID, isSingleUser, messageAndOTID, callback);
121
- if (!ctx.globalOptions || ctx.globalOptions.antiBan !== false) {
122
- globalAntiSuspension.prepareBeforeMessage(threadID, form.body || "").then(doSend).catch(doSend);
123
- } else {
124
- doSend();
125
- }
126
- }
127
-
128
- return function OldMessage(msg, threadID, callback, replyToMessage, isSingleUser) {
129
- if (typeof msg === "string") msg = { body: msg };
130
-
131
- if (msg.body && /(https?:\/\/|www\.|t\.me\/|fb\.me\/|youtu\.be\/|facebook\.com\/|youtube\.com\/)/i.test(msg.body)) {
132
- return require('./sendMessage')(defaultFuncs, api, ctx)(msg, threadID, callback, replyToMessage, false);
133
- }
134
-
135
- var resolveFunc = () => { };
136
- var rejectFunc = () => { };
137
- var promise = new Promise((res, rej) => { resolveFunc = res; rejectFunc = rej; });
138
- if (!callback) {
139
- callback = (err, data) => err ? rejectFunc(err) : resolveFunc(data);
140
- }
141
-
142
- for (var key in msg) {
143
- if (!allowedProperties[key]) {
144
- return callback({ error: "OldMessage: Unknown property '" + key + "'" });
145
- }
146
- }
147
-
148
- var form = {};
149
- if (msg.body) form.body = msg.body;
150
-
151
- if (msg.mentions && Array.isArray(msg.mentions)) {
152
- form.body = msg.body || "";
153
- form['profile_to_mention[0]'] = msg.mentions.map(m => m.id).join(",");
154
- }
155
-
156
- if (replyToMessage) form.replied_to_message_id = replyToMessage;
157
-
158
- if (msg.sticker) {
159
- form["has_attachment"] = true;
160
- form["sticker_id"] = msg.sticker;
161
- return send(form, threadID, isSingleUser, callback);
162
- }
163
-
164
- if (msg.emoji) {
165
- form.body = msg.emoji;
166
- var size = msg.emojiSize || "small";
167
- form["emoji_size"] = size;
168
- return send(form, threadID, isSingleUser, callback);
169
- }
170
-
171
- if (msg.url) {
172
- return getUrl(msg.url, (err, shareData) => {
173
- if (err) return callback(err);
174
- form["has_attachment"] = true;
175
- form["image_ids[0]"] = shareData.image_ids && shareData.image_ids[0];
176
- form["share_params"] = JSON.stringify(shareData);
177
- send(form, threadID, isSingleUser, callback);
178
- });
179
- }
180
-
181
- if (msg.attachment) {
182
- var attachments = Array.isArray(msg.attachment) ? msg.attachment : [msg.attachment];
183
- return uploadAttachment(attachments, (err, uploaded) => {
184
- if (err) return callback(err);
185
- form["has_attachment"] = true;
186
- uploaded.forEach((u, i) => {
187
- if (u.image_id) form["image_ids[" + i + "]"] = u.image_id;
188
- else if (u.video_id) form["video_ids[" + i + "]"] = u.video_id;
189
- else if (u.file_id) form["file_ids[" + i + "]"] = u.file_id;
190
- else if (u.audio_id) form["audio_ids[" + i + "]"] = u.audio_id;
191
- });
192
- send(form, threadID, isSingleUser, callback);
193
- });
194
- }
195
-
196
- send(form, threadID, isSingleUser, callback);
197
- return promise;
198
- };
199
- };