@mt-tl/server 0.1.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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/auth/handshake.d.ts +35 -0
  4. package/dist/auth/handshake.d.ts.map +1 -0
  5. package/dist/auth/handshake.js +208 -0
  6. package/dist/auth/handshake.js.map +1 -0
  7. package/dist/auth/nonce-store.d.ts +22 -0
  8. package/dist/auth/nonce-store.d.ts.map +1 -0
  9. package/dist/auth/nonce-store.js +23 -0
  10. package/dist/auth/nonce-store.js.map +1 -0
  11. package/dist/bootstrap.d.ts +36 -0
  12. package/dist/bootstrap.d.ts.map +1 -0
  13. package/dist/bootstrap.js +82 -0
  14. package/dist/bootstrap.js.map +1 -0
  15. package/dist/config.d.ts +103 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +2 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/core/context.d.ts +57 -0
  20. package/dist/core/context.d.ts.map +1 -0
  21. package/dist/core/context.js +27 -0
  22. package/dist/core/context.js.map +1 -0
  23. package/dist/core/errors.d.ts +33 -0
  24. package/dist/core/errors.d.ts.map +1 -0
  25. package/dist/core/errors.js +47 -0
  26. package/dist/core/errors.js.map +1 -0
  27. package/dist/core/index.d.ts +5 -0
  28. package/dist/core/index.d.ts.map +1 -0
  29. package/dist/core/index.js +5 -0
  30. package/dist/core/index.js.map +1 -0
  31. package/dist/core/rpc.d.ts +83 -0
  32. package/dist/core/rpc.d.ts.map +1 -0
  33. package/dist/core/rpc.js +102 -0
  34. package/dist/core/rpc.js.map +1 -0
  35. package/dist/core/updates.d.ts +56 -0
  36. package/dist/core/updates.d.ts.map +1 -0
  37. package/dist/core/updates.js +34 -0
  38. package/dist/core/updates.js.map +1 -0
  39. package/dist/create-server.d.ts +89 -0
  40. package/dist/create-server.d.ts.map +1 -0
  41. package/dist/create-server.js +109 -0
  42. package/dist/create-server.js.map +1 -0
  43. package/dist/crypto/aes-ige.d.ts +3 -0
  44. package/dist/crypto/aes-ige.d.ts.map +1 -0
  45. package/dist/crypto/aes-ige.js +55 -0
  46. package/dist/crypto/aes-ige.js.map +1 -0
  47. package/dist/crypto/dh.d.ts +21 -0
  48. package/dist/crypto/dh.d.ts.map +1 -0
  49. package/dist/crypto/dh.js +99 -0
  50. package/dist/crypto/dh.js.map +1 -0
  51. package/dist/crypto/hashes.d.ts +6 -0
  52. package/dist/crypto/hashes.d.ts.map +1 -0
  53. package/dist/crypto/hashes.js +14 -0
  54. package/dist/crypto/hashes.js.map +1 -0
  55. package/dist/crypto/msg-key.d.ts +15 -0
  56. package/dist/crypto/msg-key.d.ts.map +1 -0
  57. package/dist/crypto/msg-key.js +24 -0
  58. package/dist/crypto/msg-key.js.map +1 -0
  59. package/dist/crypto/rsa.d.ts +27 -0
  60. package/dist/crypto/rsa.d.ts.map +1 -0
  61. package/dist/crypto/rsa.js +50 -0
  62. package/dist/crypto/rsa.js.map +1 -0
  63. package/dist/dispatch/dispatcher.d.ts +72 -0
  64. package/dist/dispatch/dispatcher.d.ts.map +1 -0
  65. package/dist/dispatch/dispatcher.js +503 -0
  66. package/dist/dispatch/dispatcher.js.map +1 -0
  67. package/dist/dispatch/forwarders/in-process.d.ts +12 -0
  68. package/dist/dispatch/forwarders/in-process.d.ts.map +1 -0
  69. package/dist/dispatch/forwarders/in-process.js +15 -0
  70. package/dist/dispatch/forwarders/in-process.js.map +1 -0
  71. package/dist/dispatch/forwarders/print.d.ts +14 -0
  72. package/dist/dispatch/forwarders/print.d.ts.map +1 -0
  73. package/dist/dispatch/forwarders/print.js +23 -0
  74. package/dist/dispatch/forwarders/print.js.map +1 -0
  75. package/dist/dispatch/rpc-forwarder.d.ts +14 -0
  76. package/dist/dispatch/rpc-forwarder.d.ts.map +1 -0
  77. package/dist/dispatch/rpc-forwarder.js +2 -0
  78. package/dist/dispatch/rpc-forwarder.js.map +1 -0
  79. package/dist/dispatch/types.d.ts +32 -0
  80. package/dist/dispatch/types.d.ts.map +1 -0
  81. package/dist/dispatch/types.js +23 -0
  82. package/dist/dispatch/types.js.map +1 -0
  83. package/dist/gateway.d.ts +57 -0
  84. package/dist/gateway.d.ts.map +1 -0
  85. package/dist/gateway.js +150 -0
  86. package/dist/gateway.js.map +1 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +25 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/lib.d.ts +12 -0
  92. package/dist/lib.d.ts.map +1 -0
  93. package/dist/lib.js +13 -0
  94. package/dist/lib.js.map +1 -0
  95. package/dist/server/message-pipeline.d.ts +57 -0
  96. package/dist/server/message-pipeline.d.ts.map +1 -0
  97. package/dist/server/message-pipeline.js +199 -0
  98. package/dist/server/message-pipeline.js.map +1 -0
  99. package/dist/session/inbound-tracker.d.ts +118 -0
  100. package/dist/session/inbound-tracker.d.ts.map +1 -0
  101. package/dist/session/inbound-tracker.js +170 -0
  102. package/dist/session/inbound-tracker.js.map +1 -0
  103. package/dist/session/message-id.d.ts +19 -0
  104. package/dist/session/message-id.d.ts.map +1 -0
  105. package/dist/session/message-id.js +30 -0
  106. package/dist/session/message-id.js.map +1 -0
  107. package/dist/session/salts.d.ts +51 -0
  108. package/dist/session/salts.d.ts.map +1 -0
  109. package/dist/session/salts.js +132 -0
  110. package/dist/session/salts.js.map +1 -0
  111. package/dist/session/session-manager.d.ts +18 -0
  112. package/dist/session/session-manager.d.ts.map +1 -0
  113. package/dist/session/session-manager.js +43 -0
  114. package/dist/session/session-manager.js.map +1 -0
  115. package/dist/storage/index.d.ts +14 -0
  116. package/dist/storage/index.d.ts.map +1 -0
  117. package/dist/storage/index.js +16 -0
  118. package/dist/storage/index.js.map +1 -0
  119. package/dist/storage/memory.d.ts +3 -0
  120. package/dist/storage/memory.d.ts.map +1 -0
  121. package/dist/storage/memory.js +91 -0
  122. package/dist/storage/memory.js.map +1 -0
  123. package/dist/storage/mongo.d.ts +3 -0
  124. package/dist/storage/mongo.d.ts.map +1 -0
  125. package/dist/storage/mongo.js +175 -0
  126. package/dist/storage/mongo.js.map +1 -0
  127. package/dist/storage/types.d.ts +85 -0
  128. package/dist/storage/types.d.ts.map +1 -0
  129. package/dist/storage/types.js +3 -0
  130. package/dist/storage/types.js.map +1 -0
  131. package/dist/testkit.d.ts +11 -0
  132. package/dist/testkit.d.ts.map +1 -0
  133. package/dist/testkit.js +17 -0
  134. package/dist/testkit.js.map +1 -0
  135. package/dist/tl/codec.d.ts +37 -0
  136. package/dist/tl/codec.d.ts.map +1 -0
  137. package/dist/tl/codec.js +297 -0
  138. package/dist/tl/codec.js.map +1 -0
  139. package/dist/tl/layered-registry.d.ts +29 -0
  140. package/dist/tl/layered-registry.d.ts.map +1 -0
  141. package/dist/tl/layered-registry.js +118 -0
  142. package/dist/tl/layered-registry.js.map +1 -0
  143. package/dist/tl/protocol.d.ts +126 -0
  144. package/dist/tl/protocol.d.ts.map +1 -0
  145. package/dist/tl/protocol.js +22 -0
  146. package/dist/tl/protocol.js.map +1 -0
  147. package/dist/tl/reader.d.ts +30 -0
  148. package/dist/tl/reader.d.ts.map +1 -0
  149. package/dist/tl/reader.js +87 -0
  150. package/dist/tl/reader.js.map +1 -0
  151. package/dist/tl/registry.d.ts +39 -0
  152. package/dist/tl/registry.d.ts.map +1 -0
  153. package/dist/tl/registry.js +52 -0
  154. package/dist/tl/registry.js.map +1 -0
  155. package/dist/tl/writer.d.ts +24 -0
  156. package/dist/tl/writer.d.ts.map +1 -0
  157. package/dist/tl/writer.js +95 -0
  158. package/dist/tl/writer.js.map +1 -0
  159. package/dist/transport/connection-registry.d.ts +31 -0
  160. package/dist/transport/connection-registry.d.ts.map +1 -0
  161. package/dist/transport/connection-registry.js +84 -0
  162. package/dist/transport/connection-registry.js.map +1 -0
  163. package/dist/transport/connection.d.ts +62 -0
  164. package/dist/transport/connection.d.ts.map +1 -0
  165. package/dist/transport/connection.js +77 -0
  166. package/dist/transport/connection.js.map +1 -0
  167. package/dist/transport/framing.d.ts +39 -0
  168. package/dist/transport/framing.d.ts.map +1 -0
  169. package/dist/transport/framing.js +212 -0
  170. package/dist/transport/framing.js.map +1 -0
  171. package/dist/transport/proxy-protocol.d.ts +23 -0
  172. package/dist/transport/proxy-protocol.d.ts.map +1 -0
  173. package/dist/transport/proxy-protocol.js +108 -0
  174. package/dist/transport/proxy-protocol.js.map +1 -0
  175. package/dist/transport/server-common.d.ts +27 -0
  176. package/dist/transport/server-common.d.ts.map +1 -0
  177. package/dist/transport/server-common.js +27 -0
  178. package/dist/transport/server-common.js.map +1 -0
  179. package/dist/transport/tcp-server.d.ts +26 -0
  180. package/dist/transport/tcp-server.d.ts.map +1 -0
  181. package/dist/transport/tcp-server.js +91 -0
  182. package/dist/transport/tcp-server.js.map +1 -0
  183. package/dist/transport/ws-server.d.ts +19 -0
  184. package/dist/transport/ws-server.d.ts.map +1 -0
  185. package/dist/transport/ws-server.js +78 -0
  186. package/dist/transport/ws-server.js.map +1 -0
  187. package/dist/update-publisher.d.ts +34 -0
  188. package/dist/update-publisher.d.ts.map +1 -0
  189. package/dist/update-publisher.js +29 -0
  190. package/dist/update-publisher.js.map +1 -0
  191. package/dist/updates/mongo-update-log.d.ts +13 -0
  192. package/dist/updates/mongo-update-log.d.ts.map +1 -0
  193. package/dist/updates/mongo-update-log.js +39 -0
  194. package/dist/updates/mongo-update-log.js.map +1 -0
  195. package/dist/updates/presence-binder.d.ts +29 -0
  196. package/dist/updates/presence-binder.d.ts.map +1 -0
  197. package/dist/updates/presence-binder.js +36 -0
  198. package/dist/updates/presence-binder.js.map +1 -0
  199. package/dist/updates/presence.d.ts +31 -0
  200. package/dist/updates/presence.d.ts.map +1 -0
  201. package/dist/updates/presence.js +44 -0
  202. package/dist/updates/presence.js.map +1 -0
  203. package/dist/updates/push.d.ts +25 -0
  204. package/dist/updates/push.d.ts.map +1 -0
  205. package/dist/updates/push.js +72 -0
  206. package/dist/updates/push.js.map +1 -0
  207. package/dist/updates/redis-bus.d.ts +45 -0
  208. package/dist/updates/redis-bus.d.ts.map +1 -0
  209. package/dist/updates/redis-bus.js +59 -0
  210. package/dist/updates/redis-bus.js.map +1 -0
  211. package/dist/updates/redis-presence.d.ts +43 -0
  212. package/dist/updates/redis-presence.d.ts.map +1 -0
  213. package/dist/updates/redis-presence.js +65 -0
  214. package/dist/updates/redis-presence.js.map +1 -0
  215. package/dist/updates/render.d.ts +16 -0
  216. package/dist/updates/render.d.ts.map +1 -0
  217. package/dist/updates/render.js +46 -0
  218. package/dist/updates/render.js.map +1 -0
  219. package/dist/updates/router.d.ts +27 -0
  220. package/dist/updates/router.d.ts.map +1 -0
  221. package/dist/updates/router.js +36 -0
  222. package/dist/updates/router.js.map +1 -0
  223. package/dist/updates/types.d.ts +23 -0
  224. package/dist/updates/types.d.ts.map +1 -0
  225. package/dist/updates/types.js +2 -0
  226. package/dist/updates/types.js.map +1 -0
  227. package/dist/updates/update-bus.d.ts +29 -0
  228. package/dist/updates/update-bus.d.ts.map +1 -0
  229. package/dist/updates/update-bus.js +24 -0
  230. package/dist/updates/update-bus.js.map +1 -0
  231. package/dist/util/bytes.d.ts +12 -0
  232. package/dist/util/bytes.d.ts.map +1 -0
  233. package/dist/util/bytes.js +46 -0
  234. package/dist/util/bytes.js.map +1 -0
  235. package/package.json +84 -0
  236. package/src/auth/handshake.ts +262 -0
  237. package/src/auth/nonce-store.ts +39 -0
  238. package/src/bootstrap.ts +114 -0
  239. package/src/config.ts +103 -0
  240. package/src/core/context.ts +94 -0
  241. package/src/core/errors.ts +52 -0
  242. package/src/core/index.ts +4 -0
  243. package/src/core/rpc.ts +165 -0
  244. package/src/core/updates.ts +69 -0
  245. package/src/create-server.ts +181 -0
  246. package/src/crypto/aes-ige.ts +57 -0
  247. package/src/crypto/dh.ts +101 -0
  248. package/src/crypto/hashes.ts +17 -0
  249. package/src/crypto/msg-key.ts +29 -0
  250. package/src/crypto/rsa.ts +70 -0
  251. package/src/dispatch/dispatcher.ts +586 -0
  252. package/src/dispatch/forwarders/in-process.ts +14 -0
  253. package/src/dispatch/forwarders/print.ts +22 -0
  254. package/src/dispatch/rpc-forwarder.ts +15 -0
  255. package/src/dispatch/types.ts +60 -0
  256. package/src/gateway.ts +214 -0
  257. package/src/index.ts +53 -0
  258. package/src/lib.ts +24 -0
  259. package/src/server/message-pipeline.ts +256 -0
  260. package/src/session/inbound-tracker.ts +221 -0
  261. package/src/session/message-id.ts +43 -0
  262. package/src/session/salts.ts +162 -0
  263. package/src/session/session-manager.ts +66 -0
  264. package/src/storage/index.ts +26 -0
  265. package/src/storage/memory.ts +101 -0
  266. package/src/storage/mongo.ts +215 -0
  267. package/src/storage/types.ts +92 -0
  268. package/src/testkit.ts +19 -0
  269. package/src/tl/codec.ts +292 -0
  270. package/src/tl/layered-registry.ts +132 -0
  271. package/src/tl/protocol.ts +146 -0
  272. package/src/tl/reader.ts +99 -0
  273. package/src/tl/registry.ts +78 -0
  274. package/src/tl/writer.ts +104 -0
  275. package/src/transport/connection-registry.ts +91 -0
  276. package/src/transport/connection.ts +113 -0
  277. package/src/transport/framing.ts +223 -0
  278. package/src/transport/proxy-protocol.ts +109 -0
  279. package/src/transport/server-common.ts +49 -0
  280. package/src/transport/tcp-server.ts +102 -0
  281. package/src/transport/ws-server.ts +94 -0
  282. package/src/update-publisher.ts +47 -0
  283. package/src/updates/mongo-update-log.ts +49 -0
  284. package/src/updates/presence-binder.ts +51 -0
  285. package/src/updates/presence.ts +61 -0
  286. package/src/updates/push.ts +90 -0
  287. package/src/updates/redis-bus.ts +86 -0
  288. package/src/updates/redis-presence.ts +87 -0
  289. package/src/updates/render.ts +53 -0
  290. package/src/updates/router.ts +52 -0
  291. package/src/updates/types.ts +24 -0
  292. package/src/updates/update-bus.ts +49 -0
  293. package/src/util/bytes.ts +49 -0
@@ -0,0 +1,32 @@
1
+ import type { Connection } from '../transport/connection.js';
2
+ import type { TlObject } from '@mt-tl/tl';
3
+ import type { AcceptResult } from '../session/inbound-tracker.js';
4
+ /** Per-message context extracted from the encrypted envelope. */
5
+ export interface MessageContext {
6
+ msgId: bigint;
7
+ seqNo: number;
8
+ sessionId: bigint;
9
+ authKeyId: bigint;
10
+ salt: bigint;
11
+ }
12
+ export interface SendOptions {
13
+ /** Notification (msg_id ends in 3), not a direct response. */
14
+ isNotification?: boolean;
15
+ /** Consumes a seqno slot and gets an odd seqno (default true). */
16
+ contentRelated?: boolean;
17
+ }
18
+ /** Sends an encrypted message back to a connected client. */
19
+ export interface Responder {
20
+ sendEncrypted(conn: Connection, body: TlObject, opts?: SendOptions): void;
21
+ }
22
+ /**
23
+ * Reply to a rejected inbound message (the non-`ok` result of
24
+ * `InboundTracker.accept`): `bad_msg_notification` for a coded violation,
25
+ * `msg_detailed_info` for a duplicate whose answer is cached, or nothing for a
26
+ * benign silent drop. Shared by the pipeline (outer envelope) and the dispatcher
27
+ * (container-inner messages).
28
+ */
29
+ export declare function replyToBadAccept(responder: Responder, conn: Connection, result: Exclude<AcceptResult, {
30
+ ok: true;
31
+ }>, msgId: bigint, seqNo: number): void;
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dispatch/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAEjE,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IACxB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,6DAA6D;AAC7D,MAAM,WAAW,SAAS;IACtB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;CAC5E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,EAC3C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACd,IAAI,CAqBN"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Reply to a rejected inbound message (the non-`ok` result of
3
+ * `InboundTracker.accept`): `bad_msg_notification` for a coded violation,
4
+ * `msg_detailed_info` for a duplicate whose answer is cached, or nothing for a
5
+ * benign silent drop. Shared by the pipeline (outer envelope) and the dispatcher
6
+ * (container-inner messages).
7
+ */
8
+ export function replyToBadAccept(responder, conn, result, msgId, seqNo) {
9
+ if ('code' in result) {
10
+ responder.sendEncrypted(conn, { _: 'bad_msg_notification', bad_msg_id: msgId, bad_msg_seqno: seqNo, error_code: result.code }, { contentRelated: false });
11
+ }
12
+ else if ('detailed' in result) {
13
+ responder.sendEncrypted(conn, {
14
+ _: 'msg_detailed_info',
15
+ msg_id: msgId,
16
+ answer_msg_id: result.detailed.answerMsgId,
17
+ bytes: result.detailed.bytes,
18
+ status: 0,
19
+ }, { contentRelated: false });
20
+ }
21
+ // { drop: true } → no reply.
22
+ }
23
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/dispatch/types.ts"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC5B,SAAoB,EACpB,IAAgB,EAChB,MAA2C,EAC3C,KAAa,EACb,KAAa;IAEb,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,aAAa,CACnB,IAAI,EACJ,EAAE,CAAC,EAAE,sBAAsB,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,EAC/F,EAAE,cAAc,EAAE,KAAK,EAAE,CAC5B,CAAA;IACL,CAAC;SAAM,IAAI,UAAU,IAAI,MAAM,EAAE,CAAC;QAC9B,SAAS,CAAC,aAAa,CACnB,IAAI,EACJ;YACI,CAAC,EAAE,mBAAmB;YACtB,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW;YAC1C,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;YAC5B,MAAM,EAAE,CAAC;SACZ,EACD,EAAE,cAAc,EAAE,KAAK,EAAE,CAC5B,CAAA;IACL,CAAC;IACD,6BAA6B;AACjC,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { type Storage } from './storage/index.js';
2
+ import type { RpcForwarder } from './dispatch/rpc-forwarder.js';
3
+ import { MessagePipeline } from './server/message-pipeline.js';
4
+ import { MtprotoWsServer } from './transport/ws-server.js';
5
+ import { MtprotoTcpServer } from './transport/tcp-server.js';
6
+ import { ConnectionRegistry } from './transport/connection-registry.js';
7
+ import type { Presence } from './updates/presence.js';
8
+ import type { UpdateBus } from './updates/update-bus.js';
9
+ import type { UpdateLog } from './core/updates.js';
10
+ import type { MTProtoConfig } from './config.js';
11
+ import { type Logger } from '@mt-tl/tl';
12
+ import type { MigrationRegistry } from '@mt-tl/tl';
13
+ import type { KeyObject } from 'node:crypto';
14
+ export interface Gateway {
15
+ /** Present when `config.wsPort` is set. */
16
+ wsServer?: MtprotoWsServer;
17
+ /** Present when `config.tcpPort` is set. */
18
+ tcpServer?: MtprotoTcpServer;
19
+ pipeline: MessagePipeline;
20
+ storage: Storage;
21
+ registry: ConnectionRegistry;
22
+ nodeId: string;
23
+ fingerprint: bigint;
24
+ /** Gateway's RSA public key (clients encrypt pq_inner_data with it). */
25
+ publicKey: KeyObject;
26
+ stats: {
27
+ constructors: number;
28
+ methods: number;
29
+ crcMismatches: number;
30
+ layers: number[];
31
+ };
32
+ /** Start every configured carrier. */
33
+ listen(): Promise<void>;
34
+ close(): Promise<void>;
35
+ }
36
+ export interface BuildOptions {
37
+ forwarder?: RpcForwarder;
38
+ /** Structured logger for observability; defaults to env-configured. */
39
+ logger?: Logger;
40
+ /** Enables server-push: presence map (Redis in prod, in-memory for tests). */
41
+ presence?: Presence;
42
+ /** Update bus this node consumes routed deliveries from (Redis pub/sub in prod). */
43
+ bus?: UpdateBus;
44
+ /** Per-predicate migration ladders (input up / output down). */
45
+ migrations?: MigrationRegistry;
46
+ /** Durable pts log read by the engine to answer getState/getDifference when managed. */
47
+ updateLog?: UpdateLog;
48
+ /** When true, the engine answers `updates.getState`/`getDifference` from `updateLog`. */
49
+ managedUpdates?: boolean;
50
+ }
51
+ /**
52
+ * Wires the gateway from config: load schema -> codec, RSA key, storage,
53
+ * handshake, dispatcher, pipeline, and the WS carrier. Returns the assembled
54
+ * gateway; call `wsServer.listen()` to start accepting clients.
55
+ */
56
+ export declare function buildGateway(config: MTProtoConfig, opts?: BuildOptions): Promise<Gateway>;
57
+ //# sourceMappingURL=gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAMhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AAGvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,WAAW,OAAO;IACpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,QAAQ,EAAE,eAAe,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,wEAAwE;IACxE,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IACzF,sCAAsC;IACtC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,oFAAoF;IACpF,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,gEAAgE;IAChE,UAAU,CAAC,EAAE,iBAAiB,CAAA;IAC9B,wFAAwF;IACxF,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,yFAAyF;IACzF,cAAc,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmJnG"}
@@ -0,0 +1,150 @@
1
+ import { protocolSchemaDir } from '@mt-tl/tl';
2
+ import { loadSchema } from './tl/registry.js';
3
+ import { TlCodec } from './tl/codec.js';
4
+ import { loadLayeredRegistry } from './tl/layered-registry.js';
5
+ import { loadRsaKeyPair } from './crypto/rsa.js';
6
+ import { createStorage } from './storage/index.js';
7
+ import { NonceStore } from './auth/nonce-store.js';
8
+ import { Handshake } from './auth/handshake.js';
9
+ import { SaltService } from './session/salts.js';
10
+ import { Dispatcher } from './dispatch/dispatcher.js';
11
+ import { PrintForwarder } from './dispatch/forwarders/print.js';
12
+ import { MessagePipeline } from './server/message-pipeline.js';
13
+ import { MtprotoWsServer } from './transport/ws-server.js';
14
+ import { MtprotoTcpServer } from './transport/tcp-server.js';
15
+ import { ConnectionRegistry } from './transport/connection-registry.js';
16
+ import { NodePresenceBinder, NoopPresenceBinder } from './updates/presence-binder.js';
17
+ import { PushService } from './updates/push.js';
18
+ import { createLogger } from '@mt-tl/tl';
19
+ /**
20
+ * Wires the gateway from config: load schema -> codec, RSA key, storage,
21
+ * handshake, dispatcher, pipeline, and the WS carrier. Returns the assembled
22
+ * gateway; call `wsServer.listen()` to start accepting clients.
23
+ */
24
+ export async function buildGateway(config, opts = {}) {
25
+ const logger = opts.logger ?? createLogger({ name: config.nodeId });
26
+ // Merge the framework's protocol schema with the app's business schema — the
27
+ // consumer ships only business `.tl`; the protocol layer lives in @mt-tl/tl.
28
+ const { registry, constructors, methods, crcMismatches } = loadSchema([
29
+ protocolSchemaDir,
30
+ config.schemaDir,
31
+ ]);
32
+ const layeredAll = loadLayeredRegistry(config.schemaLayersDir);
33
+ const layered = layeredAll.hasLayers() ? layeredAll : undefined;
34
+ // Decode-union: register every layer's constructor ids so older-layer clients
35
+ // decode by id (the name index keeps the newest, so encode is unaffected).
36
+ for (const def of layeredAll.allDefs())
37
+ registry.register(def);
38
+ const codec = new TlCodec(registry, layered);
39
+ const rsa = loadRsaKeyPair(config.rsaKeyPath);
40
+ const storage = await createStorage(config.storage);
41
+ const saltService = new SaltService(storage.salts);
42
+ const nonceStore = new NonceStore();
43
+ const handshake = new Handshake({
44
+ codec,
45
+ rsa,
46
+ storage,
47
+ saltService,
48
+ nonceStore,
49
+ defaultLayer: config.defaultLayer,
50
+ logger: logger.child({ scope: 'handshake' }),
51
+ });
52
+ const forwarder = opts.forwarder ?? new PrintForwarder(logger.child({ scope: 'rpc' }));
53
+ // Presence / server-push wiring (no-op unless a presence map is supplied).
54
+ const connRegistry = new ConnectionRegistry();
55
+ const binder = opts.presence
56
+ ? new NodePresenceBinder(config.nodeId, connRegistry, opts.presence)
57
+ : new NoopPresenceBinder();
58
+ const migrations = opts.migrations;
59
+ const pipeline = new MessagePipeline({
60
+ codec,
61
+ storage,
62
+ handshake,
63
+ saltService,
64
+ defaultLayer: config.defaultLayer,
65
+ binder,
66
+ disableMsgKeyCheck: config.disableMsgKeyCheck,
67
+ disableSeqNoCheck: config.disableSeqNoCheck,
68
+ logger: logger.child({ scope: 'mtproto' }),
69
+ });
70
+ pipeline.dispatcher = new Dispatcher({
71
+ codec,
72
+ registry,
73
+ storage,
74
+ saltService,
75
+ responder: pipeline,
76
+ forwarder,
77
+ binder,
78
+ migrations,
79
+ logger: logger.child({ scope: 'rpc' }),
80
+ disableSeqNoCheck: config.disableSeqNoCheck,
81
+ updateLog: opts.updateLog,
82
+ managedUpdates: opts.managedUpdates,
83
+ allowedApiIds: config.allowedApiIds,
84
+ });
85
+ // Consume routed updates addressed to this node and push to local sockets.
86
+ if (opts.bus && opts.presence) {
87
+ const push = new PushService(connRegistry, pipeline, layered, migrations, logger.child({ scope: 'push' }));
88
+ opts.bus.subscribeNode(config.nodeId, msg => {
89
+ if (msg.authKeyId !== undefined)
90
+ push.deliverToAuthKey(msg.authKeyId, msg.update);
91
+ else if (msg.subject !== undefined)
92
+ push.deliver(msg.subject, msg.update);
93
+ });
94
+ }
95
+ // Refresh presence TTL for locally-connected users + auth keys (heartbeat).
96
+ let heartbeat;
97
+ if (opts.presence) {
98
+ const presence = opts.presence;
99
+ heartbeat = setInterval(() => {
100
+ for (const subject of connRegistry.subjects())
101
+ void presence.add(subject, config.nodeId).catch(() => { });
102
+ for (const authKeyId of connRegistry.authKeys())
103
+ void presence.addAuthKey(authKeyId, config.nodeId).catch(() => { });
104
+ }, Math.max(5_000, Math.floor(config.updates.presenceTtlMs / 3)));
105
+ if (typeof heartbeat.unref === 'function')
106
+ heartbeat.unref();
107
+ }
108
+ const handlers = {
109
+ onPacket: (packet, conn) => pipeline.handlePacket(packet, conn),
110
+ onClose: (conn) => binder.unbind(conn),
111
+ };
112
+ const wsServer = config.wsPort !== undefined
113
+ ? new MtprotoWsServer({
114
+ port: config.wsPort,
115
+ defaultLayer: config.defaultLayer,
116
+ trustProxy: config.trustProxy,
117
+ logger,
118
+ }, handlers)
119
+ : undefined;
120
+ const tcpServer = config.tcpPort !== undefined
121
+ ? new MtprotoTcpServer({
122
+ port: config.tcpPort,
123
+ defaultLayer: config.defaultLayer,
124
+ trustProxy: config.trustProxy,
125
+ logger,
126
+ }, handlers)
127
+ : undefined;
128
+ return {
129
+ wsServer,
130
+ tcpServer,
131
+ pipeline,
132
+ storage,
133
+ registry: connRegistry,
134
+ nodeId: config.nodeId,
135
+ fingerprint: rsa.fingerprint,
136
+ publicKey: rsa.publicKey,
137
+ stats: { constructors, methods, crcMismatches, layers: layeredAll.layerNumbers() },
138
+ async listen() {
139
+ await Promise.all([wsServer?.listen(), tcpServer?.listen()]);
140
+ },
141
+ async close() {
142
+ if (heartbeat)
143
+ clearInterval(heartbeat);
144
+ wsServer?.close();
145
+ tcpServer?.close();
146
+ await storage.close();
147
+ },
148
+ };
149
+ }
150
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway.js","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export * from './create-server.js';
2
+ export * from './update-publisher.js';
3
+ export { AppError, BadRequestError, AuthRequiredError, NotFoundError, FloodWaitError, InternalError, defineHook, type Hook, RpcRegistry, dispatchRpc, type DispatchDeps, type HandlerCtx, type RpcMethodSpec, type RpcMethodMap, type RpcModule, type UpdateEmitter, } from './core/index.js';
4
+ export type { MTProtoConfig } from './lib.js';
5
+ export { createLogger, noopLogger, type Logger, type LogLevel, type LoggerOptions, type Fields, } from './lib.js';
6
+ export { MigrationRegistry, type MigrationRung } from '@mt-tl/tl';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AAGrC,OAAO,EAEH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,aAAa,EAEb,UAAU,EACV,KAAK,IAAI,EAET,WAAW,EACX,WAAW,EACX,KAAK,YAAY,EAEjB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,aAAa,GACrB,MAAM,iBAAiB,CAAA;AAGxB,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAM7C,OAAO,EACH,YAAY,EACZ,UAAU,EACV,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,MAAM,GACd,MAAM,UAAU,CAAA;AAIjB,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ // @mt-tl/server — the consumer-facing framework facade. Install this (plus
2
+ // @mt-tl/tl for codegen) to build an MTProto server: define routes, listen.
3
+ // The protocol engine (transport/crypto/session/dispatch) and the handler layer
4
+ // (registry/dispatch/hooks/context/errors, under ./core) live in this same
5
+ // package; this file re-exports just the consumer surface — not the internal
6
+ // event/job/runner machinery.
7
+ export * from './create-server.js'; // createServer, definePlugin, MtprotoServer, Plugin, MethodOpts/Handler
8
+ export * from './update-publisher.js'; // createUpdatePublisher
9
+ // Handler surface (curated from ./core).
10
+ export {
11
+ // errors → rpc_error
12
+ AppError, BadRequestError, AuthRequiredError, NotFoundError, FloodWaitError, InternalError,
13
+ // hooks
14
+ defineHook,
15
+ // dispatch + registry (for tests / advanced wiring)
16
+ RpcRegistry, dispatchRpc, } from './core/index.js';
17
+ // Structured logger (re-exported from @mt-tl/tl) — build one with createLogger
18
+ // and pass it to createServer, or use the same factory in your app code for a
19
+ // unified log style. Handlers get a per-request child via `ctx.log`; the server
20
+ // exposes its root logger as `app.log`. See docs/guide/observability.md.
21
+ export { createLogger, noopLogger, } from './lib.js';
22
+ // Schema-version migration ladders (input `up` / output `down`) — pass via
23
+ // createServer(config, { migrations }). See docs/guide/releasing-a-version.md.
24
+ export { MigrationRegistry } from '@mt-tl/tl';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,gFAAgF;AAChF,2EAA2E;AAC3E,6EAA6E;AAC7E,8BAA8B;AAE9B,cAAc,oBAAoB,CAAA,CAAC,wEAAwE;AAC3G,cAAc,uBAAuB,CAAA,CAAC,wBAAwB;AAE9D,yCAAyC;AACzC,OAAO;AACH,qBAAqB;AACrB,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,aAAa;AACb,QAAQ;AACR,UAAU;AAEV,oDAAoD;AACpD,WAAW,EACX,WAAW,GAQd,MAAM,iBAAiB,CAAA;AAKxB,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,yEAAyE;AACzE,OAAO,EACH,YAAY,EACZ,UAAU,GAKb,MAAM,UAAU,CAAA;AAEjB,2EAA2E;AAC3E,+EAA+E;AAC/E,OAAO,EAAE,iBAAiB,EAAsB,MAAM,WAAW,CAAA"}
package/dist/lib.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export { bootstrap, type BootstrapOptions, type ForwardHandler, type UpdatePublish } from './bootstrap.js';
2
+ export { buildGateway, type Gateway, type BuildOptions } from './gateway.js';
3
+ export { type MTProtoConfig } from './config.js';
4
+ export { InProcessForwarder } from './dispatch/forwarders/in-process.js';
5
+ export { createLogger, noopLogger, type Logger, type LogLevel, type LoggerOptions, type Fields, } from '@mt-tl/tl';
6
+ export type { RpcForwarder } from './dispatch/rpc-forwarder.js';
7
+ export type { RpcContext, RpcRequest, RpcResponse, SessionEffect } from '@mt-tl/tl';
8
+ export type { UpdateMessage, NodeDelivery } from './updates/types.js';
9
+ export { createRedisPresence, type RedisPresenceHandle } from './updates/redis-presence.js';
10
+ export { createRedisUpdateBus, type RedisBusHandle } from './updates/redis-bus.js';
11
+ export { UpdateRouter, type RouterOptions } from './updates/router.js';
12
+ //# sourceMappingURL=lib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAA;AACxE,OAAO,EACH,YAAY,EACZ,UAAU,EACV,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,MAAM,GACd,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/D,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACnF,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAIrE,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
package/dist/lib.js ADDED
@@ -0,0 +1,13 @@
1
+ // The protocol ENGINE's internal API (transport/crypto/session/dispatch wiring).
2
+ // Consumers don't import this directly; they use `createServer()` (./create-server),
3
+ // which wraps it. Env-free and side-effect-free: the caller builds an MTProtoConfig.
4
+ export { bootstrap } from './bootstrap.js';
5
+ export { buildGateway } from './gateway.js';
6
+ export { InProcessForwarder } from './dispatch/forwarders/in-process.js';
7
+ export { createLogger, noopLogger, } from '@mt-tl/tl';
8
+ // Update-delivery adapters — the Redis pub/sub bus + presence behind the
9
+ // in-process push loop (multi-instance), and the router that fans updates to nodes.
10
+ export { createRedisPresence } from './updates/redis-presence.js';
11
+ export { createRedisUpdateBus } from './updates/redis-bus.js';
12
+ export { UpdateRouter } from './updates/router.js';
13
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,qFAAqF;AACrF,qFAAqF;AACrF,OAAO,EAAE,SAAS,EAAkE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAmC,MAAM,cAAc,CAAA;AAE5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAA;AACxE,OAAO,EACH,YAAY,EACZ,UAAU,GAKb,MAAM,WAAW,CAAA;AAKlB,yEAAyE;AACzE,oFAAoF;AACpF,OAAO,EAAE,mBAAmB,EAA4B,MAAM,6BAA6B,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAuB,MAAM,wBAAwB,CAAA;AAClF,OAAO,EAAE,YAAY,EAAsB,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,57 @@
1
+ import { type Logger } from '@mt-tl/tl';
2
+ import type { TlCodec } from '../tl/codec.js';
3
+ import type { TlObject } from '@mt-tl/tl';
4
+ import type { Connection } from '../transport/connection.js';
5
+ import type { Storage } from '../storage/index.js';
6
+ import type { SaltService } from '../session/salts.js';
7
+ import { Handshake } from '../auth/handshake.js';
8
+ import { Dispatcher } from '../dispatch/dispatcher.js';
9
+ import { type Responder, type SendOptions } from '../dispatch/types.js';
10
+ import type { PresenceBinder } from '../updates/presence-binder.js';
11
+ export interface PipelineDeps {
12
+ codec: TlCodec;
13
+ storage: Storage;
14
+ handshake: Handshake;
15
+ saltService: SaltService;
16
+ defaultLayer: number;
17
+ /** Presence/registry binder; defaults to a no-op (push disabled). */
18
+ binder?: PresenceBinder;
19
+ /**
20
+ * Disable the inbound MTProto 2.0 `msg_key` integrity check.
21
+ *
22
+ * ⚠️ INSECURE — leave this `false` (the default). When `false`, every inbound
23
+ * encrypted message must carry a `msg_key` equal to the 2.0 recompute
24
+ * `SHA256(authKey[88:120] ‖ plaintext)[8:24]`, which authenticates the
25
+ * ciphertext (integrity + binding to the auth key). Setting it `true` makes the
26
+ * gateway accept any ciphertext that merely decrypts to a well-formed message,
27
+ * dropping that authentication — only enable it as a temporary interop shim for
28
+ * non-compliant clients (e.g. ones still on the MTProto 1.0 msg_key scheme; see
29
+ * docs/internals/msgkey-v1-quirk.md).
30
+ */
31
+ disableMsgKeyCheck?: boolean;
32
+ /** Disable inbound seqno validation (bad_msg codes 32/34/35); default enforced.
33
+ * Interop shim for clients that don't set seqno to spec. */
34
+ disableSeqNoCheck?: boolean;
35
+ /** Observability sink; defaults to a no-op logger. */
36
+ logger?: Logger;
37
+ }
38
+ /**
39
+ * Central message pipeline. Routes plaintext (handshake) vs encrypted packets,
40
+ * performs MTProto 2.0 decrypt/encrypt, ensures the session, and hands decoded
41
+ * payloads to the dispatcher. Implements {@link Responder} so the dispatcher and
42
+ * session manager can send encrypted replies.
43
+ */
44
+ export declare class MessagePipeline implements Responder {
45
+ private readonly deps;
46
+ /** Set once after construction (the dispatcher needs this pipeline as its Responder). */
47
+ dispatcher: Dispatcher;
48
+ private readonly binder;
49
+ private readonly log;
50
+ constructor(deps: PipelineDeps);
51
+ handlePacket(packet: Buffer, conn: Connection): Promise<void>;
52
+ private handlePlaintext;
53
+ private sendPlain;
54
+ private handleEncrypted;
55
+ sendEncrypted(conn: Connection, body: TlObject, opts?: SendOptions): void;
56
+ }
57
+ //# sourceMappingURL=message-pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-pipeline.d.ts","sourceRoot":"","sources":["../../src/server/message-pipeline.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AAGnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACtD,OAAO,EAAyC,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAM9G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAGnE,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB;;;;;;;;;;;OAWG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;iEAC6D;IAC7D,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAMjC,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,yFAAyF;IACzF,UAAU,EAAG,UAAU,CAAA;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;gBAEC,IAAI,EAAE,YAAY;IAYzC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAcrD,eAAe;IAmB7B,OAAO,CAAC,SAAS;YAYH,eAAe;IA2G7B,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,WAAgB,GAAG,IAAI;CA+BhF"}
@@ -0,0 +1,199 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { noopLogger } from '@mt-tl/tl';
3
+ import { TlReader } from '../tl/reader.js';
4
+ import { TlWriter } from '../tl/writer.js';
5
+ import { Handshake } from '../auth/handshake.js';
6
+ import { replyToBadAccept } from '../dispatch/types.js';
7
+ import { ensureSession } from '../session/session-manager.js';
8
+ import { messageClass } from '../session/inbound-tracker.js';
9
+ import { igeDecrypt, igeEncrypt } from '../crypto/aes-ige.js';
10
+ import { generateMessageKey, computeMsgKey } from '../crypto/msg-key.js';
11
+ import { toBigIntLE, toBufferLE } from '../util/bytes.js';
12
+ import { NoopPresenceBinder } from '../updates/presence-binder.js';
13
+ /**
14
+ * Central message pipeline. Routes plaintext (handshake) vs encrypted packets,
15
+ * performs MTProto 2.0 decrypt/encrypt, ensures the session, and hands decoded
16
+ * payloads to the dispatcher. Implements {@link Responder} so the dispatcher and
17
+ * session manager can send encrypted replies.
18
+ */
19
+ export class MessagePipeline {
20
+ deps;
21
+ /** Set once after construction (the dispatcher needs this pipeline as its Responder). */
22
+ dispatcher;
23
+ binder;
24
+ log;
25
+ constructor(deps) {
26
+ this.deps = deps;
27
+ this.binder = deps.binder ?? new NoopPresenceBinder();
28
+ this.log = deps.logger ?? noopLogger;
29
+ // Surface the insecure interop shim ONCE at startup, not per message.
30
+ if (deps.disableMsgKeyCheck) {
31
+ this.log.warn('enc.msgkey.disabled', {
32
+ insecure: true,
33
+ hint: 'inbound ciphertext integrity not verified; see docs/internals/msgkey-v1-quirk.md',
34
+ });
35
+ }
36
+ }
37
+ async handlePacket(packet, conn) {
38
+ if (packet.length < 8) {
39
+ conn.close();
40
+ return;
41
+ }
42
+ // Any inbound traffic resets a pending ping_delay_disconnect idle timer.
43
+ conn.resetDisconnect();
44
+ const isPlaintext = packet.readUInt32LE(0) === 0 && packet.readUInt32LE(4) === 0;
45
+ if (isPlaintext)
46
+ return this.handlePlaintext(packet, conn);
47
+ return this.handleEncrypted(packet, conn);
48
+ }
49
+ // --- plaintext (handshake) ---------------------------------------------
50
+ async handlePlaintext(packet, conn) {
51
+ // [auth_key_id=0 (8)][msg_id (8)][len (4)][body]
52
+ if (packet.length < 20)
53
+ return conn.close();
54
+ const len = packet.readUInt32LE(16);
55
+ if (len < 4 || packet.length < 20 + len)
56
+ return conn.close();
57
+ const reader = new TlReader(packet.subarray(20, 20 + len));
58
+ const id = reader.readUInt32();
59
+ if (!Handshake.isHandshakeId(id))
60
+ return;
61
+ const res = await this.deps.handshake.handle(id, reader);
62
+ if (!res)
63
+ return;
64
+ if ('raw' in res) {
65
+ conn.send(res.raw);
66
+ return;
67
+ }
68
+ this.sendPlain(conn, res.reply);
69
+ }
70
+ sendPlain(conn, body) {
71
+ const bodyBuf = this.deps.codec.encode(body);
72
+ const w = new TlWriter(bodyBuf.length + 24);
73
+ w.writeLong(0n); // auth_key_id
74
+ w.writeLong(conn.nextMessageId());
75
+ w.writeUInt32(bodyBuf.length);
76
+ w.writeRaw(bodyBuf);
77
+ conn.send(w.toBuffer());
78
+ }
79
+ // --- encrypted ----------------------------------------------------------
80
+ async handleEncrypted(packet, conn) {
81
+ if (packet.length < 24)
82
+ return conn.close();
83
+ const authKeyId = toBigIntLE(packet.subarray(0, 8));
84
+ const msgKey = packet.subarray(8, 24);
85
+ const ciphertext = packet.subarray(24);
86
+ if (ciphertext.length % 16 !== 0 || ciphertext.length === 0) {
87
+ this.log.debug('enc.badlen', { authKeyId, len: ciphertext.length });
88
+ return conn.close();
89
+ }
90
+ const rec = await this.deps.storage.authKeys.getById(authKeyId);
91
+ this.log.debug('enc.key', { authKeyId, found: !!rec, blocked: rec?.isBlocked });
92
+ if (!rec || rec.isBlocked)
93
+ return conn.close();
94
+ const { aesKey, aesIv } = generateMessageKey(rec.key, msgKey, false);
95
+ const plain = igeDecrypt(ciphertext, aesKey, aesIv);
96
+ // Inbound msg_key integrity (MTProto 2.0): the packet's msg_key must equal
97
+ // SHA256(authKey[88:120] ‖ plaintext)[8:24]. This authenticates the ciphertext
98
+ // and binds it to the auth key. Disabling the check (deps.disableMsgKeyCheck)
99
+ // is insecure and only intended as a temporary interop shim for non-compliant
100
+ // clients — see docs/internals/msgkey-v1-quirk.md.
101
+ if (!this.deps.disableMsgKeyCheck) {
102
+ if (!computeMsgKey(rec.key, plain, false).equals(msgKey)) {
103
+ // Ciphertext failed integrity/binding — a forged or non-2.0 client.
104
+ this.log.warn('enc.msgkey.reject', { authKeyId });
105
+ return conn.close();
106
+ }
107
+ }
108
+ const r = new TlReader(plain);
109
+ const salt = r.readLong();
110
+ const sessionId = r.readLong();
111
+ const msgId = r.readLong();
112
+ const seqNo = r.readUInt32();
113
+ const len = r.readUInt32();
114
+ this.log.trace('enc.ok', { authKeyId, len });
115
+ if (len < 4 || len > plain.length)
116
+ return conn.close();
117
+ const payload = r.read(len);
118
+ // Bind auth/session state to the connection.
119
+ conn.ctx.authKeyId = authKeyId;
120
+ conn.ctx.authKey = rec.key;
121
+ conn.ctx.sessionId = sessionId;
122
+ if (rec.meta?.apiLayer && conn.ctx.apiLayer === this.deps.defaultLayer) {
123
+ conn.ctx.apiLayer = rec.meta.apiLayer;
124
+ }
125
+ // Server-salt schedule: advertise the current salt and validate the one the
126
+ // client encrypted with. A wrong/expired salt earns a `bad_server_salt`
127
+ // carrying the current salt — the client re-sends with it — and we drop this
128
+ // message. See docs/internals/protocol-compliance.md.
129
+ const { current, valid } = await this.deps.saltService.resolve(authKeyId, salt);
130
+ conn.ctx.serverSalt = current;
131
+ if (!valid) {
132
+ this.log.debug('salt.bad', { authKeyId });
133
+ this.sendEncrypted(conn, {
134
+ _: 'bad_server_salt',
135
+ bad_msg_id: msgId,
136
+ bad_msg_seqno: seqNo,
137
+ error_code: 48,
138
+ new_server_salt: current,
139
+ }, { contentRelated: false });
140
+ return;
141
+ }
142
+ // Inbound msg_id / seqno validation (https://core.telegram.org/mtproto/description):
143
+ // a wrong/duplicate/out-of-window msg_id (or bad seqno) earns a
144
+ // `bad_msg_notification` and the message is dropped (not dispatched, no session
145
+ // touched). Runs after the salt gate so a salt re-send keeps its original
146
+ // msg_id. Content-relatedness is read from the payload's constructor id. See
147
+ // docs/internals/protocol-compliance.md.
148
+ const seqCheck = !this.deps.disableSeqNoCheck;
149
+ const check = conn.tracker.accept(msgId, seqNo, {
150
+ ...messageClass(payload),
151
+ checkSeqNo: seqCheck,
152
+ checkOrder: seqCheck,
153
+ });
154
+ if (!check.ok) {
155
+ this.log.debug('msg.rejected', { authKeyId, result: check });
156
+ replyToBadAccept(this, conn, check, msgId, seqNo);
157
+ return;
158
+ }
159
+ await ensureSession(this.deps.storage, this, conn, { sessionId, authKeyId, firstMsgId: msgId, subject: rec.subject ?? undefined }, this.log);
160
+ // Register presence: by auth key (any connection — enables anonymous push)
161
+ // and, for already-authorized keys, by subject.
162
+ this.binder.bindAuthKey(conn, authKeyId.toString());
163
+ if (conn.ctx.subject !== undefined)
164
+ this.binder.bind(conn, conn.ctx.subject);
165
+ const ctx = { msgId, seqNo, sessionId, authKeyId, salt };
166
+ await this.dispatcher.dispatchPayload(payload, ctx, conn);
167
+ }
168
+ // --- Responder ----------------------------------------------------------
169
+ sendEncrypted(conn, body, opts = {}) {
170
+ const authKey = conn.ctx.authKey;
171
+ const authKeyId = conn.ctx.authKeyId;
172
+ if (!authKey || authKeyId === undefined)
173
+ return;
174
+ const bodyBuf = this.deps.codec.encode(body, conn.ctx.apiLayer);
175
+ const outMsgId = conn.nextMessageId(opts.isNotification);
176
+ // Cache the answer to a request so a later duplicate of it gets a
177
+ // `msg_detailed_info` (the request id is the `rpc_result.req_msg_id`).
178
+ if (body._ === 'rpc_result' && typeof body.req_msg_id === 'bigint') {
179
+ conn.tracker.recordAnswer(body.req_msg_id, outMsgId, bodyBuf.length);
180
+ }
181
+ const w = new TlWriter(bodyBuf.length + 32);
182
+ w.writeLong(conn.ctx.serverSalt ?? 0n);
183
+ w.writeLong(conn.ctx.sessionId ?? 0n);
184
+ w.writeLong(outMsgId);
185
+ w.writeUInt32(conn.nextSeqNo(opts.contentRelated ?? true));
186
+ w.writeUInt32(bodyBuf.length);
187
+ w.writeRaw(bodyBuf);
188
+ let plain = w.toBuffer();
189
+ // MTProto 2.0 padding: 12..1024 random bytes, total length divisible by 16.
190
+ const minPad = 12;
191
+ const pad = minPad + ((16 - ((plain.length + minPad) % 16)) % 16);
192
+ plain = Buffer.concat([plain, randomBytes(pad)]);
193
+ const msgKey = computeMsgKey(authKey, plain, true);
194
+ const { aesKey, aesIv } = generateMessageKey(authKey, msgKey, true);
195
+ const ciphertext = igeEncrypt(plain, aesKey, aesIv);
196
+ conn.send(Buffer.concat([toBufferLE(authKeyId, 8), msgKey, ciphertext]));
197
+ }
198
+ }
199
+ //# sourceMappingURL=message-pipeline.js.map