@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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/auth/handshake.d.ts +35 -0
- package/dist/auth/handshake.d.ts.map +1 -0
- package/dist/auth/handshake.js +208 -0
- package/dist/auth/handshake.js.map +1 -0
- package/dist/auth/nonce-store.d.ts +22 -0
- package/dist/auth/nonce-store.d.ts.map +1 -0
- package/dist/auth/nonce-store.js +23 -0
- package/dist/auth/nonce-store.js.map +1 -0
- package/dist/bootstrap.d.ts +36 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +82 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -0
- package/dist/core/context.d.ts +57 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +27 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/errors.d.ts +33 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +47 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/rpc.d.ts +83 -0
- package/dist/core/rpc.d.ts.map +1 -0
- package/dist/core/rpc.js +102 -0
- package/dist/core/rpc.js.map +1 -0
- package/dist/core/updates.d.ts +56 -0
- package/dist/core/updates.d.ts.map +1 -0
- package/dist/core/updates.js +34 -0
- package/dist/core/updates.js.map +1 -0
- package/dist/create-server.d.ts +89 -0
- package/dist/create-server.d.ts.map +1 -0
- package/dist/create-server.js +109 -0
- package/dist/create-server.js.map +1 -0
- package/dist/crypto/aes-ige.d.ts +3 -0
- package/dist/crypto/aes-ige.d.ts.map +1 -0
- package/dist/crypto/aes-ige.js +55 -0
- package/dist/crypto/aes-ige.js.map +1 -0
- package/dist/crypto/dh.d.ts +21 -0
- package/dist/crypto/dh.d.ts.map +1 -0
- package/dist/crypto/dh.js +99 -0
- package/dist/crypto/dh.js.map +1 -0
- package/dist/crypto/hashes.d.ts +6 -0
- package/dist/crypto/hashes.d.ts.map +1 -0
- package/dist/crypto/hashes.js +14 -0
- package/dist/crypto/hashes.js.map +1 -0
- package/dist/crypto/msg-key.d.ts +15 -0
- package/dist/crypto/msg-key.d.ts.map +1 -0
- package/dist/crypto/msg-key.js +24 -0
- package/dist/crypto/msg-key.js.map +1 -0
- package/dist/crypto/rsa.d.ts +27 -0
- package/dist/crypto/rsa.d.ts.map +1 -0
- package/dist/crypto/rsa.js +50 -0
- package/dist/crypto/rsa.js.map +1 -0
- package/dist/dispatch/dispatcher.d.ts +72 -0
- package/dist/dispatch/dispatcher.d.ts.map +1 -0
- package/dist/dispatch/dispatcher.js +503 -0
- package/dist/dispatch/dispatcher.js.map +1 -0
- package/dist/dispatch/forwarders/in-process.d.ts +12 -0
- package/dist/dispatch/forwarders/in-process.d.ts.map +1 -0
- package/dist/dispatch/forwarders/in-process.js +15 -0
- package/dist/dispatch/forwarders/in-process.js.map +1 -0
- package/dist/dispatch/forwarders/print.d.ts +14 -0
- package/dist/dispatch/forwarders/print.d.ts.map +1 -0
- package/dist/dispatch/forwarders/print.js +23 -0
- package/dist/dispatch/forwarders/print.js.map +1 -0
- package/dist/dispatch/rpc-forwarder.d.ts +14 -0
- package/dist/dispatch/rpc-forwarder.d.ts.map +1 -0
- package/dist/dispatch/rpc-forwarder.js +2 -0
- package/dist/dispatch/rpc-forwarder.js.map +1 -0
- package/dist/dispatch/types.d.ts +32 -0
- package/dist/dispatch/types.d.ts.map +1 -0
- package/dist/dispatch/types.js +23 -0
- package/dist/dispatch/types.js.map +1 -0
- package/dist/gateway.d.ts +57 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +150 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +12 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +13 -0
- package/dist/lib.js.map +1 -0
- package/dist/server/message-pipeline.d.ts +57 -0
- package/dist/server/message-pipeline.d.ts.map +1 -0
- package/dist/server/message-pipeline.js +199 -0
- package/dist/server/message-pipeline.js.map +1 -0
- package/dist/session/inbound-tracker.d.ts +118 -0
- package/dist/session/inbound-tracker.d.ts.map +1 -0
- package/dist/session/inbound-tracker.js +170 -0
- package/dist/session/inbound-tracker.js.map +1 -0
- package/dist/session/message-id.d.ts +19 -0
- package/dist/session/message-id.d.ts.map +1 -0
- package/dist/session/message-id.js +30 -0
- package/dist/session/message-id.js.map +1 -0
- package/dist/session/salts.d.ts +51 -0
- package/dist/session/salts.d.ts.map +1 -0
- package/dist/session/salts.js +132 -0
- package/dist/session/salts.js.map +1 -0
- package/dist/session/session-manager.d.ts +18 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +43 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +16 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/memory.d.ts +3 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +91 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/mongo.d.ts +3 -0
- package/dist/storage/mongo.d.ts.map +1 -0
- package/dist/storage/mongo.js +175 -0
- package/dist/storage/mongo.js.map +1 -0
- package/dist/storage/types.d.ts +85 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +3 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/testkit.d.ts +11 -0
- package/dist/testkit.d.ts.map +1 -0
- package/dist/testkit.js +17 -0
- package/dist/testkit.js.map +1 -0
- package/dist/tl/codec.d.ts +37 -0
- package/dist/tl/codec.d.ts.map +1 -0
- package/dist/tl/codec.js +297 -0
- package/dist/tl/codec.js.map +1 -0
- package/dist/tl/layered-registry.d.ts +29 -0
- package/dist/tl/layered-registry.d.ts.map +1 -0
- package/dist/tl/layered-registry.js +118 -0
- package/dist/tl/layered-registry.js.map +1 -0
- package/dist/tl/protocol.d.ts +126 -0
- package/dist/tl/protocol.d.ts.map +1 -0
- package/dist/tl/protocol.js +22 -0
- package/dist/tl/protocol.js.map +1 -0
- package/dist/tl/reader.d.ts +30 -0
- package/dist/tl/reader.d.ts.map +1 -0
- package/dist/tl/reader.js +87 -0
- package/dist/tl/reader.js.map +1 -0
- package/dist/tl/registry.d.ts +39 -0
- package/dist/tl/registry.d.ts.map +1 -0
- package/dist/tl/registry.js +52 -0
- package/dist/tl/registry.js.map +1 -0
- package/dist/tl/writer.d.ts +24 -0
- package/dist/tl/writer.d.ts.map +1 -0
- package/dist/tl/writer.js +95 -0
- package/dist/tl/writer.js.map +1 -0
- package/dist/transport/connection-registry.d.ts +31 -0
- package/dist/transport/connection-registry.d.ts.map +1 -0
- package/dist/transport/connection-registry.js +84 -0
- package/dist/transport/connection-registry.js.map +1 -0
- package/dist/transport/connection.d.ts +62 -0
- package/dist/transport/connection.d.ts.map +1 -0
- package/dist/transport/connection.js +77 -0
- package/dist/transport/connection.js.map +1 -0
- package/dist/transport/framing.d.ts +39 -0
- package/dist/transport/framing.d.ts.map +1 -0
- package/dist/transport/framing.js +212 -0
- package/dist/transport/framing.js.map +1 -0
- package/dist/transport/proxy-protocol.d.ts +23 -0
- package/dist/transport/proxy-protocol.d.ts.map +1 -0
- package/dist/transport/proxy-protocol.js +108 -0
- package/dist/transport/proxy-protocol.js.map +1 -0
- package/dist/transport/server-common.d.ts +27 -0
- package/dist/transport/server-common.d.ts.map +1 -0
- package/dist/transport/server-common.js +27 -0
- package/dist/transport/server-common.js.map +1 -0
- package/dist/transport/tcp-server.d.ts +26 -0
- package/dist/transport/tcp-server.d.ts.map +1 -0
- package/dist/transport/tcp-server.js +91 -0
- package/dist/transport/tcp-server.js.map +1 -0
- package/dist/transport/ws-server.d.ts +19 -0
- package/dist/transport/ws-server.d.ts.map +1 -0
- package/dist/transport/ws-server.js +78 -0
- package/dist/transport/ws-server.js.map +1 -0
- package/dist/update-publisher.d.ts +34 -0
- package/dist/update-publisher.d.ts.map +1 -0
- package/dist/update-publisher.js +29 -0
- package/dist/update-publisher.js.map +1 -0
- package/dist/updates/mongo-update-log.d.ts +13 -0
- package/dist/updates/mongo-update-log.d.ts.map +1 -0
- package/dist/updates/mongo-update-log.js +39 -0
- package/dist/updates/mongo-update-log.js.map +1 -0
- package/dist/updates/presence-binder.d.ts +29 -0
- package/dist/updates/presence-binder.d.ts.map +1 -0
- package/dist/updates/presence-binder.js +36 -0
- package/dist/updates/presence-binder.js.map +1 -0
- package/dist/updates/presence.d.ts +31 -0
- package/dist/updates/presence.d.ts.map +1 -0
- package/dist/updates/presence.js +44 -0
- package/dist/updates/presence.js.map +1 -0
- package/dist/updates/push.d.ts +25 -0
- package/dist/updates/push.d.ts.map +1 -0
- package/dist/updates/push.js +72 -0
- package/dist/updates/push.js.map +1 -0
- package/dist/updates/redis-bus.d.ts +45 -0
- package/dist/updates/redis-bus.d.ts.map +1 -0
- package/dist/updates/redis-bus.js +59 -0
- package/dist/updates/redis-bus.js.map +1 -0
- package/dist/updates/redis-presence.d.ts +43 -0
- package/dist/updates/redis-presence.d.ts.map +1 -0
- package/dist/updates/redis-presence.js +65 -0
- package/dist/updates/redis-presence.js.map +1 -0
- package/dist/updates/render.d.ts +16 -0
- package/dist/updates/render.d.ts.map +1 -0
- package/dist/updates/render.js +46 -0
- package/dist/updates/render.js.map +1 -0
- package/dist/updates/router.d.ts +27 -0
- package/dist/updates/router.d.ts.map +1 -0
- package/dist/updates/router.js +36 -0
- package/dist/updates/router.js.map +1 -0
- package/dist/updates/types.d.ts +23 -0
- package/dist/updates/types.d.ts.map +1 -0
- package/dist/updates/types.js +2 -0
- package/dist/updates/types.js.map +1 -0
- package/dist/updates/update-bus.d.ts +29 -0
- package/dist/updates/update-bus.d.ts.map +1 -0
- package/dist/updates/update-bus.js +24 -0
- package/dist/updates/update-bus.js.map +1 -0
- package/dist/util/bytes.d.ts +12 -0
- package/dist/util/bytes.d.ts.map +1 -0
- package/dist/util/bytes.js +46 -0
- package/dist/util/bytes.js.map +1 -0
- package/package.json +84 -0
- package/src/auth/handshake.ts +262 -0
- package/src/auth/nonce-store.ts +39 -0
- package/src/bootstrap.ts +114 -0
- package/src/config.ts +103 -0
- package/src/core/context.ts +94 -0
- package/src/core/errors.ts +52 -0
- package/src/core/index.ts +4 -0
- package/src/core/rpc.ts +165 -0
- package/src/core/updates.ts +69 -0
- package/src/create-server.ts +181 -0
- package/src/crypto/aes-ige.ts +57 -0
- package/src/crypto/dh.ts +101 -0
- package/src/crypto/hashes.ts +17 -0
- package/src/crypto/msg-key.ts +29 -0
- package/src/crypto/rsa.ts +70 -0
- package/src/dispatch/dispatcher.ts +586 -0
- package/src/dispatch/forwarders/in-process.ts +14 -0
- package/src/dispatch/forwarders/print.ts +22 -0
- package/src/dispatch/rpc-forwarder.ts +15 -0
- package/src/dispatch/types.ts +60 -0
- package/src/gateway.ts +214 -0
- package/src/index.ts +53 -0
- package/src/lib.ts +24 -0
- package/src/server/message-pipeline.ts +256 -0
- package/src/session/inbound-tracker.ts +221 -0
- package/src/session/message-id.ts +43 -0
- package/src/session/salts.ts +162 -0
- package/src/session/session-manager.ts +66 -0
- package/src/storage/index.ts +26 -0
- package/src/storage/memory.ts +101 -0
- package/src/storage/mongo.ts +215 -0
- package/src/storage/types.ts +92 -0
- package/src/testkit.ts +19 -0
- package/src/tl/codec.ts +292 -0
- package/src/tl/layered-registry.ts +132 -0
- package/src/tl/protocol.ts +146 -0
- package/src/tl/reader.ts +99 -0
- package/src/tl/registry.ts +78 -0
- package/src/tl/writer.ts +104 -0
- package/src/transport/connection-registry.ts +91 -0
- package/src/transport/connection.ts +113 -0
- package/src/transport/framing.ts +223 -0
- package/src/transport/proxy-protocol.ts +109 -0
- package/src/transport/server-common.ts +49 -0
- package/src/transport/tcp-server.ts +102 -0
- package/src/transport/ws-server.ts +94 -0
- package/src/update-publisher.ts +47 -0
- package/src/updates/mongo-update-log.ts +49 -0
- package/src/updates/presence-binder.ts +51 -0
- package/src/updates/presence.ts +61 -0
- package/src/updates/push.ts +90 -0
- package/src/updates/redis-bus.ts +86 -0
- package/src/updates/redis-presence.ts +87 -0
- package/src/updates/render.ts +53 -0
- package/src/updates/router.ts +52 -0
- package/src/updates/types.ts +24 -0
- package/src/updates/update-bus.ts +49 -0
- package/src/util/bytes.ts +49 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { createDecipheriv } from 'node:crypto';
|
|
2
|
+
import CRC32 from 'crc-32';
|
|
3
|
+
import { noopLogger } from '@mt-tl/tl';
|
|
4
|
+
import { calculatePadding } from '../crypto/dh.js';
|
|
5
|
+
function looksLikeTcpFullStreamStart(buf) {
|
|
6
|
+
const len = buf.readUInt32LE(0);
|
|
7
|
+
if (len > 65536 || buf.length < len)
|
|
8
|
+
return false;
|
|
9
|
+
return buf.readUInt32LE(len - 8) === 0;
|
|
10
|
+
}
|
|
11
|
+
export class Framing {
|
|
12
|
+
log;
|
|
13
|
+
mode;
|
|
14
|
+
inner;
|
|
15
|
+
/** Plaintext queue from which inner packets are read. */
|
|
16
|
+
queue = Buffer.alloc(0);
|
|
17
|
+
/** Pre-detection accumulation. */
|
|
18
|
+
detectBuf = Buffer.alloc(0);
|
|
19
|
+
sequenceIn = 0;
|
|
20
|
+
sequenceOut = 0;
|
|
21
|
+
decryptor;
|
|
22
|
+
encryptor;
|
|
23
|
+
constructor(log = noopLogger) {
|
|
24
|
+
this.log = log;
|
|
25
|
+
}
|
|
26
|
+
/** Feed received bytes; returns any complete packets that became available. */
|
|
27
|
+
feed(chunk) {
|
|
28
|
+
if (this.mode === undefined) {
|
|
29
|
+
this.detectBuf = Buffer.concat([this.detectBuf, chunk]);
|
|
30
|
+
if (!this.detect())
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
else if (this.mode === 'obfuscated') {
|
|
34
|
+
this.queue = Buffer.concat([this.queue, this.decryptor.update(chunk)]);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.queue = Buffer.concat([this.queue, chunk]);
|
|
38
|
+
}
|
|
39
|
+
return this.drain();
|
|
40
|
+
}
|
|
41
|
+
/** Frame an outgoing packet for the negotiated mode. */
|
|
42
|
+
frame(packet) {
|
|
43
|
+
const eff = this.effectiveMode();
|
|
44
|
+
const framed = this.frameInner(eff, packet);
|
|
45
|
+
return this.mode === 'obfuscated' ? this.encryptor.update(framed) : framed;
|
|
46
|
+
}
|
|
47
|
+
effectiveMode() {
|
|
48
|
+
if (this.mode === 'obfuscated')
|
|
49
|
+
return this.inner;
|
|
50
|
+
return this.mode;
|
|
51
|
+
}
|
|
52
|
+
detect() {
|
|
53
|
+
const buf = this.detectBuf;
|
|
54
|
+
if (buf.length < 4)
|
|
55
|
+
return false;
|
|
56
|
+
if (buf.readUInt8(0) === 0xef) {
|
|
57
|
+
this.mode = 'abridged';
|
|
58
|
+
this.queue = Buffer.from(buf.subarray(1));
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (buf.readUInt32LE(0) === 0xeeeeeeee) {
|
|
62
|
+
this.mode = 'intermediate';
|
|
63
|
+
this.queue = Buffer.from(buf.subarray(4));
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (buf.length < 8)
|
|
67
|
+
return false;
|
|
68
|
+
if (buf.readUInt32LE(4) === 0 || looksLikeTcpFullStreamStart(buf)) {
|
|
69
|
+
this.mode = 'full';
|
|
70
|
+
this.queue = Buffer.from(buf);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (buf.length < 64)
|
|
74
|
+
return false;
|
|
75
|
+
// Obfuscated: 64-byte header sets up AES-CTR streams.
|
|
76
|
+
const header = Buffer.from(buf.subarray(0, 64));
|
|
77
|
+
const rev = Buffer.from(header).reverse();
|
|
78
|
+
this.decryptor = createDecipheriv('aes-256-ctr', header.subarray(8, 40), header.subarray(40, 56));
|
|
79
|
+
this.encryptor = createDecipheriv('aes-256-ctr', rev.subarray(8, 40), rev.subarray(40, 56));
|
|
80
|
+
const decHeader = this.decryptor.update(header);
|
|
81
|
+
if (this.log.isLevelEnabled('trace')) {
|
|
82
|
+
this.log.trace('framing.obfuscated', {
|
|
83
|
+
tag: decHeader.subarray(56, 60).toString('hex'),
|
|
84
|
+
rawHead: header.subarray(0, 16).toString('hex'),
|
|
85
|
+
decHead: decHeader.subarray(0, 16).toString('hex'),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
switch (decHeader[56]) {
|
|
89
|
+
case 0xdd:
|
|
90
|
+
case 0xee:
|
|
91
|
+
this.inner = 'intermediate';
|
|
92
|
+
break;
|
|
93
|
+
case 0xef:
|
|
94
|
+
this.inner = 'abridged';
|
|
95
|
+
break;
|
|
96
|
+
default:
|
|
97
|
+
throw new Error(`obfuscated: cannot determine inner mode (tag ${decHeader.subarray(56, 60).toString('hex')})`);
|
|
98
|
+
}
|
|
99
|
+
this.mode = 'obfuscated';
|
|
100
|
+
this.queue = this.decryptor.update(Buffer.from(buf.subarray(64)));
|
|
101
|
+
if (this.log.isLevelEnabled('trace')) {
|
|
102
|
+
this.log.trace('framing.detected', {
|
|
103
|
+
mode: this.mode,
|
|
104
|
+
inner: this.inner,
|
|
105
|
+
queued: this.queue.length,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
drain() {
|
|
111
|
+
const out = [];
|
|
112
|
+
for (;;) {
|
|
113
|
+
const p = this.readOne();
|
|
114
|
+
if (p === undefined)
|
|
115
|
+
break;
|
|
116
|
+
out.push(p);
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
readOne() {
|
|
121
|
+
switch (this.effectiveMode()) {
|
|
122
|
+
case 'abridged':
|
|
123
|
+
return this.readAbridged();
|
|
124
|
+
case 'intermediate':
|
|
125
|
+
return this.readIntermediate();
|
|
126
|
+
case 'full':
|
|
127
|
+
return this.readFull();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
readAbridged() {
|
|
131
|
+
const q = this.queue;
|
|
132
|
+
if (q.length < 1)
|
|
133
|
+
return undefined;
|
|
134
|
+
let len = q.readUInt8(0);
|
|
135
|
+
let shift = 1;
|
|
136
|
+
if (len === 0x7f) {
|
|
137
|
+
if (q.length < 4)
|
|
138
|
+
return undefined;
|
|
139
|
+
len = (q.readUInt8(1) | (q.readUInt8(2) << 8) | (q.readUInt8(3) << 16)) << 2;
|
|
140
|
+
shift = 4;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
len <<= 2;
|
|
144
|
+
}
|
|
145
|
+
if (q.length < len + shift)
|
|
146
|
+
return undefined;
|
|
147
|
+
const packet = Buffer.from(q.subarray(shift, shift + len));
|
|
148
|
+
this.queue = q.subarray(shift + len);
|
|
149
|
+
return packet;
|
|
150
|
+
}
|
|
151
|
+
readIntermediate() {
|
|
152
|
+
const q = this.queue;
|
|
153
|
+
if (q.length < 4)
|
|
154
|
+
return undefined;
|
|
155
|
+
const len = q.readUInt32LE(0);
|
|
156
|
+
if (q.length < len + 4)
|
|
157
|
+
return undefined;
|
|
158
|
+
const packet = Buffer.from(q.subarray(4, 4 + len));
|
|
159
|
+
this.queue = q.subarray(4 + len);
|
|
160
|
+
return packet;
|
|
161
|
+
}
|
|
162
|
+
readFull() {
|
|
163
|
+
// Standard tcp_full layout: [len(4)][seq(4)][payload][crc(4)], len = payload + 12.
|
|
164
|
+
const q = this.queue;
|
|
165
|
+
if (q.length < 4)
|
|
166
|
+
return undefined;
|
|
167
|
+
const len = q.readUInt32LE(0);
|
|
168
|
+
if (len < 12 || q.length < len)
|
|
169
|
+
return undefined;
|
|
170
|
+
const seqNo = q.readUInt32LE(4);
|
|
171
|
+
if (seqNo !== this.sequenceIn) {
|
|
172
|
+
throw new Error(`tcp_full: wrong sequence ${seqNo}, expected ${this.sequenceIn}`);
|
|
173
|
+
}
|
|
174
|
+
this.sequenceIn++;
|
|
175
|
+
const packet = Buffer.from(q.subarray(8, len - 4));
|
|
176
|
+
this.queue = q.subarray(len);
|
|
177
|
+
return packet;
|
|
178
|
+
}
|
|
179
|
+
frameInner(mode, packet) {
|
|
180
|
+
switch (mode) {
|
|
181
|
+
case 'abridged': {
|
|
182
|
+
const pad = Buffer.alloc(calculatePadding(packet.length, 4));
|
|
183
|
+
const lenValue = (packet.length + pad.length) / 4;
|
|
184
|
+
const lenB = lenValue < 127
|
|
185
|
+
? Buffer.from([lenValue])
|
|
186
|
+
: Buffer.from([
|
|
187
|
+
0x7f,
|
|
188
|
+
lenValue & 0xff,
|
|
189
|
+
(lenValue >> 8) & 0xff,
|
|
190
|
+
(lenValue >> 16) & 0xff,
|
|
191
|
+
]);
|
|
192
|
+
return Buffer.concat([lenB, packet, pad]);
|
|
193
|
+
}
|
|
194
|
+
case 'intermediate': {
|
|
195
|
+
const lenB = Buffer.alloc(4);
|
|
196
|
+
lenB.writeUInt32LE(packet.length, 0);
|
|
197
|
+
return Buffer.concat([lenB, packet]);
|
|
198
|
+
}
|
|
199
|
+
case 'full': {
|
|
200
|
+
const lenB = Buffer.alloc(4);
|
|
201
|
+
lenB.writeUInt32LE(packet.length + 12, 0);
|
|
202
|
+
const seqB = Buffer.alloc(4);
|
|
203
|
+
seqB.writeUInt32LE(this.sequenceOut++, 0);
|
|
204
|
+
const body = Buffer.concat([lenB, seqB, packet]);
|
|
205
|
+
const crc = Buffer.alloc(4);
|
|
206
|
+
crc.writeUInt32LE(CRC32.buf(body) >>> 0, 0);
|
|
207
|
+
return Buffer.concat([body, crc]);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=framing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framing.js","sourceRoot":"","sources":["../../src/transport/framing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,MAAM,QAAQ,CAAA;AAC1B,OAAO,EAAE,UAAU,EAAe,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAgBlD,SAAS,2BAA2B,CAAC,GAAW;IAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAC/B,IAAI,GAAG,GAAG,KAAK,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA;IACjD,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,OAAO,OAAO;IAYa;IAX7B,IAAI,CAAO;IACH,KAAK,CAAY;IACzB,yDAAyD;IACjD,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC/B,kCAAkC;IAC1B,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC3B,UAAU,GAAG,CAAC,CAAA;IACd,WAAW,GAAG,CAAC,CAAA;IACf,SAAS,CAAW;IACpB,SAAS,CAAW;IAE5B,YAA6B,MAAc,UAAU;QAAxB,QAAG,GAAH,GAAG,CAAqB;IAAG,CAAC;IAEzD,+EAA+E;IAC/E,IAAI,CAAC,KAAa;QACd,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,OAAO,EAAE,CAAA;QACjC,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC3E,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,EAAE,CAAA;IACvB,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,MAAc;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC3C,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,SAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;IAC/E,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;YAAE,OAAO,IAAI,CAAC,KAAM,CAAA;QAClD,OAAO,IAAI,CAAC,IAAiB,CAAA;IACjC,CAAC;IAEO,MAAM;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAA;QAC1B,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QAEhC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;YACtB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QACf,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;YAC1B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QACf,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QAChC,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,2BAA2B,CAAC,GAAG,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAA;YAClB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC7B,OAAO,IAAI,CAAA;QACf,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO,KAAK,CAAA;QAEjC,sDAAsD;QACtD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAA;QACzC,IAAI,CAAC,SAAS,GAAG,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;QACjG,IAAI,CAAC,SAAS,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;QAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC/C,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE;gBACjC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC/C,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC/C,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;aACrD,CAAC,CAAA;QACN,CAAC;QACD,QAAQ,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;YACpB,KAAK,IAAI,CAAC;YACV,KAAK,IAAI;gBACL,IAAI,CAAC,KAAK,GAAG,cAAc,CAAA;gBAC3B,MAAK;YACT,KAAK,IAAI;gBACL,IAAI,CAAC,KAAK,GAAG,UAAU,CAAA;gBACvB,MAAK;YACT;gBACI,MAAM,IAAI,KAAK,CACX,gDAAgD,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAChG,CAAA;QACT,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAA;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACjE,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE;gBAC/B,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;aAC5B,CAAC,CAAA;QACN,CAAC;QACD,OAAO,IAAI,CAAA;IACf,CAAC;IAEO,KAAK;QACT,MAAM,GAAG,GAAa,EAAE,CAAA;QACxB,SAAS,CAAC;YACN,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YACxB,IAAI,CAAC,KAAK,SAAS;gBAAE,MAAK;YAC1B,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACf,CAAC;QACD,OAAO,GAAG,CAAA;IACd,CAAC;IAEO,OAAO;QACX,QAAQ,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YAC3B,KAAK,UAAU;gBACX,OAAO,IAAI,CAAC,YAAY,EAAE,CAAA;YAC9B,KAAK,cAAc;gBACf,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAA;YAClC,KAAK,MAAM;gBACP,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC9B,CAAC;IACL,CAAC;IAEO,YAAY;QAChB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;QACpB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QAClC,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;QACxB,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAA;YAClC,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;YAC5E,KAAK,GAAG,CAAC,CAAA;QACb,CAAC;aAAM,CAAC;YACJ,GAAG,KAAK,CAAC,CAAA;QACb,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,KAAK;YAAE,OAAO,SAAS,CAAA;QAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC,CAAA;QAC1D,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,CAAA;QACpC,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,gBAAgB;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;QACpB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QAClC,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAChC,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,QAAQ;QACZ,mFAAmF;QACnF,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;QACpB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;QAClC,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG;YAAE,OAAO,SAAS,CAAA;QAChD,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC/B,IAAI,KAAK,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,cAAc,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,CAAA;QACjB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC5B,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,UAAU,CAAC,IAAe,EAAE,MAAc;QAC9C,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,UAAU,CAAC,CAAC,CAAC;gBACd,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;gBAC5D,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBACjD,MAAM,IAAI,GACN,QAAQ,GAAG,GAAG;oBACV,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;oBACzB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;wBACR,IAAI;wBACJ,QAAQ,GAAG,IAAI;wBACf,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI;wBACtB,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG,IAAI;qBAC1B,CAAC,CAAA;gBACZ,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;YAC7C,CAAC;YACD,KAAK,cAAc,CAAC,CAAC,CAAC;gBAClB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC5B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;gBACpC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;YACxC,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACV,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC5B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;gBACzC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAA;gBACzC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;gBAChD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC3B,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;gBAC3C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YACrC,CAAC;QACL,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ProxyParse =
|
|
2
|
+
/** A complete header. `sourceIp` is undefined for UNKNOWN/LOCAL/UNSPEC (use the socket address). */
|
|
3
|
+
{
|
|
4
|
+
status: 'done';
|
|
5
|
+
sourceIp?: string;
|
|
6
|
+
consumed: number;
|
|
7
|
+
}
|
|
8
|
+
/** Need more bytes — the buffer is a valid prefix of a header so far. */
|
|
9
|
+
| {
|
|
10
|
+
status: 'incomplete';
|
|
11
|
+
}
|
|
12
|
+
/** No PROXY header — treat the bytes as the start of the MTProto stream. */
|
|
13
|
+
| {
|
|
14
|
+
status: 'absent';
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Inspects the start of a freshly-accepted TCP stream for a PROXY-protocol
|
|
18
|
+
* header. Returns `done` (with the parsed source IP and how many bytes the header
|
|
19
|
+
* occupied), `incomplete` (call again with more bytes), or `absent` (no header —
|
|
20
|
+
* the bytes are the MTProto stream itself).
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseProxyHeader(buf: Buffer): ProxyParse;
|
|
23
|
+
//# sourceMappingURL=proxy-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-protocol.d.ts","sourceRoot":"","sources":["../../src/transport/proxy-protocol.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,UAAU;AAClB,oGAAoG;AAClG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACzD,yEAAyE;GACvE;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE;AAC1B,4EAA4E;GAC1E;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE1B;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAyBxD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// PROXY protocol (HAProxy) header parsing for the raw-TCP carrier. When a TCP
|
|
2
|
+
// load balancer / proxy sits in front, it prepends a small header announcing the
|
|
3
|
+
// real client address before the MTProto byte stream. We parse it (v1 text and
|
|
4
|
+
// v2 binary) so `RpcContext.ip` reflects the client, not the proxy. Only used
|
|
5
|
+
// when `trustProxy` is set — the spec assumes a trusted proxy always prepends it.
|
|
6
|
+
// Ref: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
|
7
|
+
/** 12-byte v2 signature: `\r\n\r\n\0\r\nQUIT\n`. */
|
|
8
|
+
const V2_SIG = Buffer.from([0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a]);
|
|
9
|
+
/** v1 lines start with `PROXY ` and are at most 107 bytes incl. CRLF. */
|
|
10
|
+
const V1_PREFIX = Buffer.from('PROXY ');
|
|
11
|
+
const V1_MAX = 107;
|
|
12
|
+
/** Cap buffered bytes while a header is still incomplete (guards a slow/malicious peer). */
|
|
13
|
+
const MAX_HEADER = 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Inspects the start of a freshly-accepted TCP stream for a PROXY-protocol
|
|
16
|
+
* header. Returns `done` (with the parsed source IP and how many bytes the header
|
|
17
|
+
* occupied), `incomplete` (call again with more bytes), or `absent` (no header —
|
|
18
|
+
* the bytes are the MTProto stream itself).
|
|
19
|
+
*/
|
|
20
|
+
export function parseProxyHeader(buf) {
|
|
21
|
+
if (buf.length === 0)
|
|
22
|
+
return { status: 'incomplete' };
|
|
23
|
+
const b0 = buf[0];
|
|
24
|
+
// v2 — binary, begins with 0x0D.
|
|
25
|
+
if (b0 === 0x0d) {
|
|
26
|
+
const n = Math.min(buf.length, V2_SIG.length);
|
|
27
|
+
for (let i = 0; i < n; i++)
|
|
28
|
+
if (buf[i] !== V2_SIG[i])
|
|
29
|
+
return { status: 'absent' };
|
|
30
|
+
if (buf.length < 16)
|
|
31
|
+
return buf.length > MAX_HEADER ? { status: 'absent' } : { status: 'incomplete' };
|
|
32
|
+
return parseV2(buf);
|
|
33
|
+
}
|
|
34
|
+
// v1 — text, begins with 'P' (0x50) of "PROXY ".
|
|
35
|
+
if (b0 === 0x50) {
|
|
36
|
+
const crlf = buf.indexOf('\r\n');
|
|
37
|
+
if (crlf === -1) {
|
|
38
|
+
if (buf.length > V1_MAX)
|
|
39
|
+
return { status: 'absent' };
|
|
40
|
+
const n = Math.min(buf.length, V1_PREFIX.length);
|
|
41
|
+
for (let i = 0; i < n; i++)
|
|
42
|
+
if (buf[i] !== V1_PREFIX[i])
|
|
43
|
+
return { status: 'absent' };
|
|
44
|
+
return { status: 'incomplete' };
|
|
45
|
+
}
|
|
46
|
+
return parseV1(buf.toString('latin1', 0, crlf), crlf + 2);
|
|
47
|
+
}
|
|
48
|
+
return { status: 'absent' };
|
|
49
|
+
}
|
|
50
|
+
function parseV1(line, consumed) {
|
|
51
|
+
// "PROXY TCP4 <src> <dst> <srcPort> <dstPort>" | "PROXY UNKNOWN ..."
|
|
52
|
+
const parts = line.split(' ');
|
|
53
|
+
if (parts[0] !== 'PROXY')
|
|
54
|
+
return { status: 'absent' };
|
|
55
|
+
if (parts[1] === 'TCP4' || parts[1] === 'TCP6')
|
|
56
|
+
return { status: 'done', sourceIp: parts[2], consumed };
|
|
57
|
+
return { status: 'done', consumed }; // UNKNOWN — no announced address
|
|
58
|
+
}
|
|
59
|
+
function parseV2(buf) {
|
|
60
|
+
const cmd = buf[12] & 0x0f; // 0 = LOCAL (health check), 1 = PROXY
|
|
61
|
+
const family = buf[13] >> 4; // 1 = AF_INET, 2 = AF_INET6
|
|
62
|
+
const addrLen = buf.readUInt16BE(14);
|
|
63
|
+
const total = 16 + addrLen;
|
|
64
|
+
if (buf.length < total)
|
|
65
|
+
return total > MAX_HEADER ? { status: 'absent' } : { status: 'incomplete' };
|
|
66
|
+
let sourceIp;
|
|
67
|
+
if (cmd === 0x1) {
|
|
68
|
+
if (family === 0x1 && addrLen >= 12) {
|
|
69
|
+
sourceIp = `${buf[16]}.${buf[17]}.${buf[18]}.${buf[19]}`;
|
|
70
|
+
}
|
|
71
|
+
else if (family === 0x2 && addrLen >= 36) {
|
|
72
|
+
sourceIp = formatIpv6(buf.subarray(16, 32));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { status: 'done', sourceIp, consumed: total };
|
|
76
|
+
}
|
|
77
|
+
/** 16 bytes → a compressed IPv6 string (longest run of zero groups → `::`). */
|
|
78
|
+
function formatIpv6(b) {
|
|
79
|
+
const groups = [];
|
|
80
|
+
for (let i = 0; i < 16; i += 2)
|
|
81
|
+
groups.push((b[i] << 8) | b[i + 1]);
|
|
82
|
+
// Find the longest run of zero groups to compress.
|
|
83
|
+
let bestStart = -1;
|
|
84
|
+
let bestLen = 0;
|
|
85
|
+
let curStart = -1;
|
|
86
|
+
let curLen = 0;
|
|
87
|
+
for (let i = 0; i < 8; i++) {
|
|
88
|
+
if (groups[i] === 0) {
|
|
89
|
+
if (curStart === -1)
|
|
90
|
+
curStart = i;
|
|
91
|
+
curLen++;
|
|
92
|
+
if (curLen > bestLen) {
|
|
93
|
+
bestLen = curLen;
|
|
94
|
+
bestStart = curStart;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
curStart = -1;
|
|
99
|
+
curLen = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (bestLen < 2)
|
|
103
|
+
return groups.map(g => g.toString(16)).join(':');
|
|
104
|
+
const head = groups.slice(0, bestStart).map(g => g.toString(16));
|
|
105
|
+
const tail = groups.slice(bestStart + bestLen).map(g => g.toString(16));
|
|
106
|
+
return `${head.join(':')}::${tail.join(':')}`;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=proxy-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-protocol.js","sourceRoot":"","sources":["../../src/transport/proxy-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Logger } from '@mt-tl/tl';
|
|
2
|
+
import type { Connection } from './connection.js';
|
|
3
|
+
export type PacketHandler = (packet: Buffer, conn: Connection) => void | Promise<void>;
|
|
4
|
+
export interface TransportHandlers {
|
|
5
|
+
onPacket: PacketHandler;
|
|
6
|
+
onConnect?: (conn: Connection) => void;
|
|
7
|
+
onClose?: (conn: Connection) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface TransportOptions {
|
|
10
|
+
port: number;
|
|
11
|
+
defaultLayer: number;
|
|
12
|
+
/**
|
|
13
|
+
* Trust an upstream proxy for the client address: parse the PROXY-protocol
|
|
14
|
+
* header on raw TCP, and trust `X-Forwarded-For` on WebSocket. Leave off
|
|
15
|
+
* (default) when clients connect directly — the headers are spoofable.
|
|
16
|
+
*/
|
|
17
|
+
trustProxy?: boolean;
|
|
18
|
+
/** Structured logger; the carrier derives a per-connection child from it. */
|
|
19
|
+
logger?: Logger;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Feed a received byte chunk into a connection's framing and enqueue any
|
|
23
|
+
* complete packets. Shared by the WebSocket and raw-TCP carriers — both deliver
|
|
24
|
+
* bytes (WS as binary frames, TCP as a stream) to the same stateful framer.
|
|
25
|
+
*/
|
|
26
|
+
export declare function pump(conn: Connection, chunk: Buffer, handlers: TransportHandlers): void;
|
|
27
|
+
//# sourceMappingURL=server-common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-common.d.ts","sourceRoot":"","sources":["../../src/transport/server-common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAEtF,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,EAAE,aAAa,CAAA;IACvB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAA;IACtC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAA;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAmBvF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feed a received byte chunk into a connection's framing and enqueue any
|
|
3
|
+
* complete packets. Shared by the WebSocket and raw-TCP carriers — both deliver
|
|
4
|
+
* bytes (WS as binary frames, TCP as a stream) to the same stateful framer.
|
|
5
|
+
*/
|
|
6
|
+
export function pump(conn, chunk, handlers) {
|
|
7
|
+
let packets;
|
|
8
|
+
try {
|
|
9
|
+
packets = conn.framing.feed(chunk);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
// Unframable bytes = a broken/hostile client; drop the connection. Expected
|
|
13
|
+
// enough to be a warn, not an error (no server fault).
|
|
14
|
+
conn.log.warn('framing.error', { err: String(err) });
|
|
15
|
+
conn.close();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (packets.length && conn.log.isLevelEnabled('trace')) {
|
|
19
|
+
conn.log.trace('framing.packets', {
|
|
20
|
+
packets: packets.map(p => ({ bytes: p.length, head: p.subarray(0, 8).toString('hex') })),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
for (const packet of packets) {
|
|
24
|
+
conn.enqueue(() => handlers.onPacket(packet, conn));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=server-common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-common.js","sourceRoot":"","sources":["../../src/transport/server-common.ts"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,IAAgB,EAAE,KAAa,EAAE,QAA2B;IAC7E,IAAI,OAAiB,CAAA;IACrB,IAAI,CAAC;QACD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,4EAA4E;QAC5E,uDAAuD;QACvD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACpD,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,OAAM;IACV,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE;YAC9B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;SAC3F,CAAC,CAAA;IACN,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IACvD,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type TransportHandlers, type TransportOptions } from './server-common.js';
|
|
2
|
+
/**
|
|
3
|
+
* Raw TCP carrier for MTProto, for legacy clients that connect over a plain
|
|
4
|
+
* socket rather than WebSocket. The byte stream is fed into the same framing as
|
|
5
|
+
* WS (the framer already reassembles packets across `data` events), so abridged
|
|
6
|
+
* / intermediate / full / obfuscated transports all work identically here.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MtprotoTcpServer {
|
|
9
|
+
private readonly options;
|
|
10
|
+
private readonly handlers;
|
|
11
|
+
private server?;
|
|
12
|
+
private lastId;
|
|
13
|
+
constructor(options: TransportOptions, handlers: TransportHandlers);
|
|
14
|
+
listen(): Promise<void>;
|
|
15
|
+
get port(): number;
|
|
16
|
+
private onConnection;
|
|
17
|
+
/**
|
|
18
|
+
* Data handler that strips a leading PROXY-protocol header (when present)
|
|
19
|
+
* before the byte stream reaches framing, recording the announced client IP
|
|
20
|
+
* on the connection. Once the header is consumed (or shown absent), all
|
|
21
|
+
* further bytes pass straight to `pump`.
|
|
22
|
+
*/
|
|
23
|
+
private proxyAware;
|
|
24
|
+
close(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=tcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-server.d.ts","sourceRoot":"","sources":["../../src/transport/tcp-server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAQ,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGxF;;;;;GAKG;AACH,qBAAa,gBAAgB;IAKrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL7B,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAI;gBAGG,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB;IAGhD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAQvB,IAAI,IAAI,IAAI,MAAM,CAGjB;IAED,OAAO,CAAC,YAAY;IAsCpB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAoBlB,KAAK,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createServer } from 'node:net';
|
|
2
|
+
import { noopLogger } from '@mt-tl/tl';
|
|
3
|
+
import { Connection } from './connection.js';
|
|
4
|
+
import { pump } from './server-common.js';
|
|
5
|
+
import { parseProxyHeader } from './proxy-protocol.js';
|
|
6
|
+
/**
|
|
7
|
+
* Raw TCP carrier for MTProto, for legacy clients that connect over a plain
|
|
8
|
+
* socket rather than WebSocket. The byte stream is fed into the same framing as
|
|
9
|
+
* WS (the framer already reassembles packets across `data` events), so abridged
|
|
10
|
+
* / intermediate / full / obfuscated transports all work identically here.
|
|
11
|
+
*/
|
|
12
|
+
export class MtprotoTcpServer {
|
|
13
|
+
options;
|
|
14
|
+
handlers;
|
|
15
|
+
server;
|
|
16
|
+
lastId = 0;
|
|
17
|
+
constructor(options, handlers) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
this.handlers = handlers;
|
|
20
|
+
}
|
|
21
|
+
listen() {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
this.server = createServer({ allowHalfOpen: false }, socket => this.onConnection(socket));
|
|
24
|
+
this.server.once('error', reject);
|
|
25
|
+
this.server.listen(this.options.port, () => resolve());
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
get port() {
|
|
29
|
+
const addr = this.server?.address();
|
|
30
|
+
return addr && typeof addr === 'object' ? addr.port : this.options.port;
|
|
31
|
+
}
|
|
32
|
+
onConnection(socket) {
|
|
33
|
+
socket.setNoDelay(true);
|
|
34
|
+
const id = ++this.lastId;
|
|
35
|
+
const log = (this.options.logger ?? noopLogger).child({ scope: 'tcp', conn: id });
|
|
36
|
+
log.info('conn.open', { remote: socket.remoteAddress });
|
|
37
|
+
const conn = new Connection(id, bytes => {
|
|
38
|
+
try {
|
|
39
|
+
socket.write(bytes);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
conn.close();
|
|
43
|
+
}
|
|
44
|
+
}, () => socket.destroy(), socket.remoteAddress, this.options.defaultLayer, log);
|
|
45
|
+
this.handlers.onConnect?.(conn);
|
|
46
|
+
socket.on('data', this.options.trustProxy ? this.proxyAware(conn) : chunk => pump(conn, chunk, this.handlers));
|
|
47
|
+
socket.on('close', () => {
|
|
48
|
+
log.info('conn.close');
|
|
49
|
+
conn.closed = true;
|
|
50
|
+
this.handlers.onClose?.(conn);
|
|
51
|
+
});
|
|
52
|
+
socket.on('error', err => {
|
|
53
|
+
log.warn('tcp.error', { err: String(err) });
|
|
54
|
+
conn.close();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Data handler that strips a leading PROXY-protocol header (when present)
|
|
59
|
+
* before the byte stream reaches framing, recording the announced client IP
|
|
60
|
+
* on the connection. Once the header is consumed (or shown absent), all
|
|
61
|
+
* further bytes pass straight to `pump`.
|
|
62
|
+
*/
|
|
63
|
+
proxyAware(conn) {
|
|
64
|
+
let header = Buffer.alloc(0);
|
|
65
|
+
return (chunk) => {
|
|
66
|
+
if (header === null)
|
|
67
|
+
return pump(conn, chunk, this.handlers);
|
|
68
|
+
header = header.length ? Buffer.concat([header, chunk]) : chunk;
|
|
69
|
+
const res = parseProxyHeader(header);
|
|
70
|
+
if (res.status === 'incomplete')
|
|
71
|
+
return;
|
|
72
|
+
const buffered = header;
|
|
73
|
+
header = null; // done parsing; subsequent chunks bypass this path
|
|
74
|
+
if (res.status === 'done') {
|
|
75
|
+
if (res.sourceIp)
|
|
76
|
+
conn.ctx.remoteAddress = res.sourceIp;
|
|
77
|
+
const rest = buffered.subarray(res.consumed);
|
|
78
|
+
if (rest.length)
|
|
79
|
+
pump(conn, rest, this.handlers);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// No PROXY header — the bytes are the MTProto stream itself.
|
|
83
|
+
pump(conn, buffered, this.handlers);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
close() {
|
|
88
|
+
this.server?.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=tcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-server.js","sourceRoot":"","sources":["../../src/transport/tcp-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type TransportHandlers, type TransportOptions } from './server-common.js';
|
|
2
|
+
export type { PacketHandler, TransportHandlers } from './server-common.js';
|
|
3
|
+
/**
|
|
4
|
+
* WebSocket carrier for MTProto. Each binary frame is fed into the connection's
|
|
5
|
+
* transport framing; complete packets are handed to `onPacket` in arrival order.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MtprotoWsServer {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private readonly handlers;
|
|
10
|
+
private wss?;
|
|
11
|
+
private lastId;
|
|
12
|
+
constructor(options: TransportOptions, handlers: TransportHandlers);
|
|
13
|
+
listen(): Promise<void>;
|
|
14
|
+
/** Bound TCP port (useful when listening on port 0 in tests). */
|
|
15
|
+
get port(): number;
|
|
16
|
+
private onConnection;
|
|
17
|
+
close(): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ws-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../../src/transport/ws-server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAQ,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAExF,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAQ1E;;;GAGG;AACH,qBAAa,eAAe;IAKpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL7B,OAAO,CAAC,GAAG,CAAC,CAAiB;IAC7B,OAAO,CAAC,MAAM,CAAI;gBAGG,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB;IAGhD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAQvB,iEAAiE;IACjE,IAAI,IAAI,IAAI,MAAM,CAGjB;IAED,OAAO,CAAC,YAAY;IAgDpB,KAAK,IAAI,IAAI;CAGhB"}
|