@eryxenx/fca 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +325 -0
  2. package/DOCS.md +2712 -0
  3. package/README.md +455 -0
  4. package/func/checkUpdate.js +7 -0
  5. package/func/logAdapter.js +33 -0
  6. package/func/logger.js +48 -0
  7. package/index.d.ts +751 -0
  8. package/index.js +22 -0
  9. package/module/config.js +40 -0
  10. package/module/login.js +133 -0
  11. package/module/loginHelper.js +1365 -0
  12. package/module/options.js +44 -0
  13. package/package.json +98 -0
  14. package/src/api/action/addExternalModule.js +25 -0
  15. package/src/api/action/changeAvatar.js +137 -0
  16. package/src/api/action/changeBio.js +75 -0
  17. package/src/api/action/enableAutoSaveAppState.js +73 -0
  18. package/src/api/action/getCurrentUserID.js +7 -0
  19. package/src/api/action/handleFriendRequest.js +57 -0
  20. package/src/api/action/logout.js +76 -0
  21. package/src/api/action/refreshFb_dtsg.js +48 -0
  22. package/src/api/action/setPostReaction.js +106 -0
  23. package/src/api/action/unfriend.js +54 -0
  24. package/src/api/http/httpGet.js +46 -0
  25. package/src/api/http/httpPost.js +52 -0
  26. package/src/api/http/postFormData.js +47 -0
  27. package/src/api/messaging/addUserToGroup.js +68 -0
  28. package/src/api/messaging/changeAdminStatus.js +126 -0
  29. package/src/api/messaging/changeArchivedStatus.js +55 -0
  30. package/src/api/messaging/changeBlockedStatus.js +48 -0
  31. package/src/api/messaging/changeGroupImage.js +91 -0
  32. package/src/api/messaging/changeNickname.js +70 -0
  33. package/src/api/messaging/changeThreadColor.js +79 -0
  34. package/src/api/messaging/changeThreadEmoji.js +111 -0
  35. package/src/api/messaging/createNewGroup.js +88 -0
  36. package/src/api/messaging/createPoll.js +46 -0
  37. package/src/api/messaging/createThemeAI.js +98 -0
  38. package/src/api/messaging/deleteMessage.js +136 -0
  39. package/src/api/messaging/deleteThread.js +56 -0
  40. package/src/api/messaging/editMessage.js +105 -0
  41. package/src/api/messaging/forwardAttachment.js +57 -0
  42. package/src/api/messaging/forwardMessage.js +134 -0
  43. package/src/api/messaging/getEmojiUrl.js +29 -0
  44. package/src/api/messaging/getFriendsList.js +82 -0
  45. package/src/api/messaging/getMessage.js +829 -0
  46. package/src/api/messaging/getThemePictures.js +62 -0
  47. package/src/api/messaging/handleMessageRequest.js +65 -0
  48. package/src/api/messaging/markAsDelivered.js +57 -0
  49. package/src/api/messaging/markAsRead.js +88 -0
  50. package/src/api/messaging/markAsReadAll.js +56 -0
  51. package/src/api/messaging/markAsSeen.js +68 -0
  52. package/src/api/messaging/muteThread.js +50 -0
  53. package/src/api/messaging/pinMessage.js +115 -0
  54. package/src/api/messaging/removeUserFromGroup.js +62 -0
  55. package/src/api/messaging/resolvePhotoUrl.js +43 -0
  56. package/src/api/messaging/scheduler.js +264 -0
  57. package/src/api/messaging/searchForThread.js +53 -0
  58. package/src/api/messaging/sendBroadcast.js +93 -0
  59. package/src/api/messaging/sendMessage.js +269 -0
  60. package/src/api/messaging/sendTypingIndicator.js +90 -0
  61. package/src/api/messaging/sessionGuard.js +130 -0
  62. package/src/api/messaging/setMessageReaction.js +109 -0
  63. package/src/api/messaging/setTitle.js +124 -0
  64. package/src/api/messaging/shareContact.js +98 -0
  65. package/src/api/messaging/threadColors.js +128 -0
  66. package/src/api/messaging/unsendMessage.js +105 -0
  67. package/src/api/messaging/uploadAttachment.js +492 -0
  68. package/src/api/socket/OldMessage.js +186 -0
  69. package/src/api/socket/core/connectMqtt.js +269 -0
  70. package/src/api/socket/core/emitAuth.js +103 -0
  71. package/src/api/socket/core/getSeqID.js +321 -0
  72. package/src/api/socket/core/getTaskResponseData.js +25 -0
  73. package/src/api/socket/core/parseDelta.js +387 -0
  74. package/src/api/socket/detail/buildStream.js +215 -0
  75. package/src/api/socket/detail/constants.js +28 -0
  76. package/src/api/socket/e2ee/crypto.js +173 -0
  77. package/src/api/socket/e2ee/index.js +925 -0
  78. package/src/api/socket/e2ee/localMediaServer.js +59 -0
  79. package/src/api/socket/e2ee/mediaDecode.js +155 -0
  80. package/src/api/socket/e2ee/native/NOTICE.md +29 -0
  81. package/src/api/socket/e2ee/native/build/messagix.dll +0 -0
  82. package/src/api/socket/e2ee/native/build/messagix.so +0 -0
  83. package/src/api/socket/e2ee/native/lib/index.mjs +1426 -0
  84. package/src/api/socket/e2ee/native/nativeMediaBridge.js +233 -0
  85. package/src/api/socket/e2ee/proto/ArmadilloApplication.proto +281 -0
  86. package/src/api/socket/e2ee/proto/ArmadilloICDC.proto +14 -0
  87. package/src/api/socket/e2ee/proto/ConsumerApplication.proto +232 -0
  88. package/src/api/socket/e2ee/proto/MessageApplication.proto +82 -0
  89. package/src/api/socket/e2ee/proto/MessageTransport.proto +77 -0
  90. package/src/api/socket/e2ee/proto/WACommon.proto +66 -0
  91. package/src/api/socket/e2ee/proto/WAMediaTransport.proto +176 -0
  92. package/src/api/socket/e2ee/proto/proto-writer.ts +76 -0
  93. package/src/api/socket/e2ee/protocol.js +196 -0
  94. package/src/api/socket/e2ee/ratchet.js +219 -0
  95. package/src/api/socket/e2ee/store.js +182 -0
  96. package/src/api/socket/e2ee/vendor/fme/dist/index.cjs +6477 -0
  97. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloApplication.proto +281 -0
  98. package/src/api/socket/e2ee/vendor/fme/proto/ArmadilloICDC.proto +14 -0
  99. package/src/api/socket/e2ee/vendor/fme/proto/ConsumerApplication.proto +232 -0
  100. package/src/api/socket/e2ee/vendor/fme/proto/MessageApplication.proto +82 -0
  101. package/src/api/socket/e2ee/vendor/fme/proto/MessageTransport.proto +77 -0
  102. package/src/api/socket/e2ee/vendor/fme/proto/WACommon.proto +66 -0
  103. package/src/api/socket/e2ee/vendor/fme/proto/WAMediaTransport.proto +176 -0
  104. package/src/api/socket/listenE2EE.js +75 -0
  105. package/src/api/socket/listenMqtt.js +436 -0
  106. package/src/api/socket/middleware/index.js +216 -0
  107. package/src/api/socket/sendMessage.js +314 -0
  108. package/src/api/socket/sendMessageMqtt.js +69 -0
  109. package/src/api/threads/getThreadHistory.js +664 -0
  110. package/src/api/threads/getThreadInfo.js +329 -0
  111. package/src/api/threads/getThreadList.js +293 -0
  112. package/src/api/threads/getThreadPictures.js +78 -0
  113. package/src/api/users/getUserID.js +65 -0
  114. package/src/api/users/getUserInfo.js +402 -0
  115. package/src/api/users/getUserInfoV2.js +134 -0
  116. package/src/app/MessengerBot.js +209 -0
  117. package/src/app/MessengerContext.js +32 -0
  118. package/src/app/createFcaClient.js +136 -0
  119. package/src/app/threadInfoRealtimeSync.js +284 -0
  120. package/src/core/sendReqMqtt.js +96 -0
  121. package/src/database/helpers.js +53 -0
  122. package/src/database/models/index.js +88 -0
  123. package/src/database/models/thread.js +50 -0
  124. package/src/database/models/user.js +46 -0
  125. package/src/database/threadData.js +94 -0
  126. package/src/database/userData.js +98 -0
  127. package/src/remote/remoteClient.js +123 -0
  128. package/src/utils/broadcast.js +51 -0
  129. package/src/utils/client.js +10 -0
  130. package/src/utils/constants.js +23 -0
  131. package/src/utils/cookies.js +68 -0
  132. package/src/utils/format/attachment.js +357 -0
  133. package/src/utils/format/cookie.js +9 -0
  134. package/src/utils/format/date.js +50 -0
  135. package/src/utils/format/decode.js +44 -0
  136. package/src/utils/format/delta.js +194 -0
  137. package/src/utils/format/ids.js +64 -0
  138. package/src/utils/format/index.js +64 -0
  139. package/src/utils/format/message.js +88 -0
  140. package/src/utils/format/presence.js +132 -0
  141. package/src/utils/format/readTyp.js +44 -0
  142. package/src/utils/format/thread.js +42 -0
  143. package/src/utils/format/utils.js +141 -0
  144. package/src/utils/headers.js +128 -0
  145. package/src/utils/loginParser/autoLogin.js +125 -0
  146. package/src/utils/loginParser/helpers.js +43 -0
  147. package/src/utils/loginParser/index.js +10 -0
  148. package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
  149. package/src/utils/loginParser/textUtils.js +28 -0
  150. package/src/utils/nexca-logger.js +144 -0
  151. package/src/utils/nexca-utils.js +686 -0
  152. package/src/utils/request/client.js +26 -0
  153. package/src/utils/request/config.js +23 -0
  154. package/src/utils/request/defaults.js +46 -0
  155. package/src/utils/request/helpers.js +46 -0
  156. package/src/utils/request/index.js +17 -0
  157. package/src/utils/request/methods.js +163 -0
  158. package/src/utils/request/proxy.js +21 -0
  159. package/src/utils/request/retry.js +77 -0
  160. package/src/utils/request/sanitize.js +49 -0
  161. package/src/utils/versionCheck.js +47 -0
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ const http = require("http");
4
+ const crypto = require("crypto");
5
+
6
+ let _server = null;
7
+ let _port = 0;
8
+ const _cache = new Map(); // token -> { buffer, mimeType, expiresAt }
9
+
10
+ const TTL_MS = 15 * 60 * 1000; // 15 min is plenty for a command to fetch it
11
+
12
+ function _cleanup() {
13
+ const now = Date.now();
14
+ for (const [token, entry] of _cache) {
15
+ if (entry.expiresAt < now) _cache.delete(token);
16
+ }
17
+ }
18
+
19
+ function ensureServer() {
20
+ if (_server) return Promise.resolve(_port);
21
+ return new Promise((resolve, reject) => {
22
+ _server = http.createServer((req, res) => {
23
+ const token = (req.url || "").replace(/^\/+/, "").split("?")[0];
24
+ const entry = _cache.get(token);
25
+ if (!entry) {
26
+ res.writeHead(404);
27
+ res.end("not found");
28
+ return;
29
+ }
30
+ res.writeHead(200, {
31
+ "Content-Type": entry.mimeType || "application/octet-stream",
32
+ "Content-Length": entry.buffer.length
33
+ });
34
+ res.end(entry.buffer);
35
+ });
36
+ _server.on("error", reject);
37
+ // 127.0.0.1 only — never expose this outside the container
38
+ _server.listen(0, "127.0.0.1", () => {
39
+ _port = _server.address().port;
40
+ setInterval(_cleanup, 60 * 1000).unref();
41
+ resolve(_port);
42
+ });
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Stores a decrypted media buffer and returns a short-lived local URL for it.
48
+ * @param {Buffer} buffer
49
+ * @param {string} mimeType
50
+ * @returns {Promise<string>} e.g. http://127.0.0.1:53211/ab12cd34
51
+ */
52
+ async function serveBuffer(buffer, mimeType) {
53
+ const port = await ensureServer();
54
+ const token = crypto.randomBytes(12).toString("hex");
55
+ _cache.set(token, { buffer, mimeType, expiresAt: Date.now() + TTL_MS });
56
+ return `http://127.0.0.1:${port}/${token}`;
57
+ }
58
+
59
+ module.exports = { serveBuffer, getCacheSize: () => _cache.size };
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+
3
+ // Generic protobuf wire-format field reader (varint / length-delimited /
4
+ // fixed32 / fixed64). Returns { fieldNumber: [values...] }.
5
+ function readVarint(buf, offset) {
6
+ let result = 0n, shift = 0n, b;
7
+ do {
8
+ b = buf[offset++];
9
+ result |= BigInt(b & 0x7f) << shift;
10
+ shift += 7n;
11
+ } while (b & 0x80);
12
+ return [result, offset];
13
+ }
14
+
15
+ function decodeFields(buf) {
16
+ const fields = {};
17
+ let offset = 0;
18
+ while (offset < buf.length) {
19
+ let tag;
20
+ try {
21
+ [tag, offset] = readVarint(buf, offset);
22
+ } catch (_) { break; }
23
+ const fieldNum = Number(tag >> 3n);
24
+ const wireType = Number(tag & 7n);
25
+ let value;
26
+ if (wireType === 0) {
27
+ [value, offset] = readVarint(buf, offset);
28
+ } else if (wireType === 2) {
29
+ let len;
30
+ [len, offset] = readVarint(buf, offset);
31
+ len = Number(len);
32
+ value = buf.slice(offset, offset + len);
33
+ offset += len;
34
+ } else if (wireType === 1) {
35
+ value = buf.readBigUInt64LE(offset); offset += 8;
36
+ } else if (wireType === 5) {
37
+ value = buf.readUInt32LE(offset); offset += 4;
38
+ } else {
39
+ break;
40
+ }
41
+ if (!fields[fieldNum]) fields[fieldNum] = [];
42
+ fields[fieldNum].push(value);
43
+ }
44
+ return fields;
45
+ }
46
+
47
+ function bytesField(fields, n) { return fields[n] ? fields[n][0] : undefined; }
48
+ function strField(fields, n) {
49
+ const b = bytesField(fields, n);
50
+ return b !== undefined ? Buffer.from(b).toString("utf8") : undefined;
51
+ }
52
+ function numField(fields, n) {
53
+ const v = fields[n] ? fields[n][0] : undefined;
54
+ return v !== undefined ? Number(v) : undefined;
55
+ }
56
+
57
+ // WACommon.SubProtocol { bytes payload = 1; int32 version = 2; }
58
+ function decodeSubProtocol(buf) {
59
+ const f = decodeFields(buf);
60
+ return { payload: bytesField(f, 1), version: numField(f, 2) };
61
+ }
62
+
63
+ // WAMediaTransport {
64
+ // Integral { bytes fileSHA256=1; bytes mediaKey=2; bytes fileEncSHA256=3; string directPath=4; int64 mediaKeyTimestamp=5; }
65
+ // Ancillary { uint64 fileLength=1; string mimetype=2; Thumbnail thumbnail=3; string objectID=4; }
66
+ // Integral integral = 1; Ancillary ancillary = 2;
67
+ // }
68
+ function decodeWAMediaTransport(buf) {
69
+ const top = decodeFields(buf);
70
+ const integralBuf = bytesField(top, 1);
71
+ const ancillaryBuf = bytesField(top, 2);
72
+ const integral = integralBuf ? decodeFields(integralBuf) : {};
73
+ const ancillary = ancillaryBuf ? decodeFields(ancillaryBuf) : {};
74
+ return {
75
+ fileSHA256: bytesField(integral, 1),
76
+ mediaKey: bytesField(integral, 2),
77
+ fileEncSHA256: bytesField(integral, 3),
78
+ directPath: strField(integral, 4),
79
+ mediaKeyTimestamp: numField(integral, 5),
80
+ fileLength: numField(ancillary, 1),
81
+ mimeType: strField(ancillary, 2),
82
+ objectId: strField(ancillary, 4)
83
+ };
84
+ }
85
+
86
+ // {Image,Video,Audio,Document}Transport {
87
+ // Integral { WAMediaTransport transport = 1; }
88
+ // Ancillary { uint32 height=1; uint32 width=2; ... } (varies per type, only
89
+ // height/width are common to image/video and are all we need)
90
+ // Integral integral = 1; Ancillary ancillary = 2;
91
+ // }
92
+ function decodeMediaTransportPayload(buf) {
93
+ const top = decodeFields(buf);
94
+ const integralWrapBuf = bytesField(top, 1);
95
+ const ancillaryBuf = bytesField(top, 2);
96
+
97
+ let transport = {};
98
+ if (integralWrapBuf) {
99
+ const integralWrap = decodeFields(integralWrapBuf);
100
+ const transportBuf = bytesField(integralWrap, 1);
101
+ if (transportBuf) transport = decodeWAMediaTransport(transportBuf);
102
+ }
103
+ let width, height;
104
+ if (ancillaryBuf) {
105
+ const anc = decodeFields(ancillaryBuf);
106
+ height = numField(anc, 1);
107
+ width = numField(anc, 2);
108
+ }
109
+ return { ...transport, width, height };
110
+ }
111
+
112
+ /**
113
+ * Decodes a Content.{image,video,audio,document}Message object (as produced
114
+ * by the vendor engine's normalizeE2EEMessage) into flat transport fields
115
+ * usable by client.downloadMedia({directPath, mediaKey, mediaSha256, ...}).
116
+ * @param {"image"|"video"|"audio"|"document"} kind
117
+ * @param {object} mediaMessage e.g. content.imageMessage
118
+ */
119
+ function decodeIncomingMedia(kind, mediaMessage) {
120
+ if (!mediaMessage) return null;
121
+ const sub = kind === "image" ? mediaMessage.image
122
+ : kind === "video" ? mediaMessage.video
123
+ : kind === "audio" ? mediaMessage.audio
124
+ : mediaMessage.document;
125
+ if (!sub) return null;
126
+
127
+ const subBuf = Buffer.isBuffer(sub) ? sub
128
+ : (sub.payload && Buffer.isBuffer(sub.payload)) ? sub.payload
129
+ : null;
130
+ if (!subBuf) return null;
131
+
132
+ let payload;
133
+ try {
134
+ const proto = decodeSubProtocol(subBuf);
135
+ payload = proto.payload ? decodeMediaTransportPayload(Buffer.from(proto.payload)) : decodeMediaTransportPayload(subBuf);
136
+ } catch (_) {
137
+ try { payload = decodeMediaTransportPayload(subBuf); } catch (__) { return null; }
138
+ }
139
+ if (!payload || !payload.directPath || !payload.mediaKey) return null;
140
+
141
+ return {
142
+ kind,
143
+ directPath: payload.directPath,
144
+ mediaKey: payload.mediaKey,
145
+ fileSHA256: payload.fileSHA256,
146
+ fileEncSHA256: payload.fileEncSHA256,
147
+ mimeType: payload.mimeType || (kind === "image" ? "image/jpeg" : kind === "video" ? "video/mp4" : kind === "audio" ? "audio/ogg" : "application/octet-stream"),
148
+ fileLength: payload.fileLength,
149
+ width: payload.width,
150
+ height: payload.height,
151
+ fileName: mediaMessage.fileName || undefined
152
+ };
153
+ }
154
+
155
+ module.exports = { decodeIncomingMedia, decodeFields, decodeSubProtocol, decodeWAMediaTransport };
@@ -0,0 +1,29 @@
1
+ # Third-Party Notice
2
+
3
+ The files in `native/build/messagix.so` and `native/build/messagix.dll`
4
+ are precompiled native binaries built from:
5
+
6
+ - **mautrix-go** — https://github.com/mautrix/go
7
+ - **mautrix-meta** — https://github.com/mautrix/meta
8
+
9
+ Copyright (c) Tulir Asokan and the mautrix-go / mautrix-meta contributors.
10
+
11
+ Both projects are licensed under the **Mozilla Public License 2.0 (MPL-2.0)**.
12
+ A copy of the license is available at:
13
+ https://www.mozilla.org/en-US/MPL/2.0/
14
+
15
+ `native/lib/index.mjs` is the Node.js FFI bridge (via `koffi`) used to call
16
+ into the compiled binary, adapted from the same upstream project's Node
17
+ bindings.
18
+
19
+ fca-eryxenx uses this native engine only for sending E2EE media attachments
20
+ (images/video/audio/documents) in end-to-end encrypted Messenger threads,
21
+ because the project's own hand-written Signal Protocol media encoder
22
+ (`../vendor/fme`) produces payloads that Facebook's servers accept but that
23
+ Messenger clients fail to render. Text messages and all non-media E2EE
24
+ functionality continue to use fca-eryxenx's original implementation.
25
+
26
+ In accordance with MPL-2.0 §3.3, this NOTICE file must be preserved and
27
+ distributed alongside these files, and any modifications to the covered
28
+ source files (if the original `.mjs`/Go source is later vendored here)
29
+ must remain under MPL-2.0 and have their source made available.