@erfan_bahramali/tping 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/dist/crypto/aes-ctr.d.ts +18 -0
- package/dist/crypto/aes-ctr.d.ts.map +1 -0
- package/dist/crypto/aes-ctr.js +30 -0
- package/dist/crypto/aes-ctr.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/checker.d.ts +6 -0
- package/dist/lib/checker.d.ts.map +1 -0
- package/dist/lib/checker.js +72 -0
- package/dist/lib/checker.js.map +1 -0
- package/dist/lib/parser.d.ts +7 -0
- package/dist/lib/parser.d.ts.map +1 -0
- package/dist/lib/parser.js +96 -0
- package/dist/lib/parser.js.map +1 -0
- package/dist/lib/ping.d.ts +10 -0
- package/dist/lib/ping.d.ts.map +1 -0
- package/dist/lib/ping.js +59 -0
- package/dist/lib/ping.js.map +1 -0
- package/dist/mtproto/connection.d.ts +59 -0
- package/dist/mtproto/connection.d.ts.map +1 -0
- package/dist/mtproto/connection.js +198 -0
- package/dist/mtproto/connection.js.map +1 -0
- package/dist/mtproto/fake-tls.d.ts +56 -0
- package/dist/mtproto/fake-tls.d.ts.map +1 -0
- package/dist/mtproto/fake-tls.js +175 -0
- package/dist/mtproto/fake-tls.js.map +1 -0
- package/dist/mtproto/messages.d.ts +48 -0
- package/dist/mtproto/messages.d.ts.map +1 -0
- package/dist/mtproto/messages.js +104 -0
- package/dist/mtproto/messages.js.map +1 -0
- package/dist/mtproto/obfuscation.d.ts +26 -0
- package/dist/mtproto/obfuscation.d.ts.map +1 -0
- package/dist/mtproto/obfuscation.js +78 -0
- package/dist/mtproto/obfuscation.js.map +1 -0
- package/dist/mtproto/socks5.d.ts +36 -0
- package/dist/mtproto/socks5.d.ts.map +1 -0
- package/dist/mtproto/socks5.js +148 -0
- package/dist/mtproto/socks5.js.map +1 -0
- package/dist/types/index.d.ts +49 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/format.d.ts +22 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +131 -0
- package/dist/utils/format.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { Socket } from 'net';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { initObfuscation } from './obfuscation.js';
|
|
4
|
+
import { parseSecret, generateFakeTLSClientHello, wrapInTLSRecords, extractTlsRecords, tryVerifyFakeTLSServerHello, } from './fake-tls.js';
|
|
5
|
+
import { buildReqPqMulti, buildUnencryptedMessage, generateMessageId, parseResPQ, } from './messages.js';
|
|
6
|
+
/**
|
|
7
|
+
* MTProto proxy connection supporting both simple (dd) and fake TLS (ee) modes.
|
|
8
|
+
*
|
|
9
|
+
* A ping is a real MTProto handshake: req_pq_multi is sent and a valid ResPQ
|
|
10
|
+
* must come back from the Telegram datacenter. In fake TLS mode the proxy's
|
|
11
|
+
* ServerHello is also verified against an HMAC of the proxy secret, so a wrong
|
|
12
|
+
* secret is detected immediately.
|
|
13
|
+
*/
|
|
14
|
+
export class MTProtoConnection {
|
|
15
|
+
options;
|
|
16
|
+
socket;
|
|
17
|
+
encryptor;
|
|
18
|
+
decryptor;
|
|
19
|
+
isFakeTLS = false;
|
|
20
|
+
receiveBuffer = Buffer.alloc(0);
|
|
21
|
+
pending = null;
|
|
22
|
+
phase = 'handshake';
|
|
23
|
+
clientRandom;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
this.socket = new Socket();
|
|
27
|
+
this.socket.on('data', (data) => this.onData(data));
|
|
28
|
+
this.socket.on('error', () => { });
|
|
29
|
+
this.socket.on('close', () => this.failPending('Connection closed by proxy'));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Connect to the MTProto proxy and perform the obfuscation (+ fake TLS) handshake.
|
|
33
|
+
* Resolves only after the proxy's ServerHello is HMAC-verified (fake TLS mode).
|
|
34
|
+
*/
|
|
35
|
+
async connect() {
|
|
36
|
+
const { host, port, secret, dcId = 2, timeout = 10000 } = this.options;
|
|
37
|
+
const parsed = parseSecret(secret);
|
|
38
|
+
this.isFakeTLS = parsed.isFakeTLS;
|
|
39
|
+
const { header, encryptor, decryptor } = initObfuscation(parsed.secret, dcId);
|
|
40
|
+
this.encryptor = encryptor;
|
|
41
|
+
this.decryptor = decryptor;
|
|
42
|
+
await new Promise((resolve, reject) => {
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
this.socket.destroy();
|
|
45
|
+
reject(new Error('Connection timeout'));
|
|
46
|
+
}, timeout);
|
|
47
|
+
const onError = (err) => {
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
reject(err);
|
|
50
|
+
};
|
|
51
|
+
this.socket.once('error', onError);
|
|
52
|
+
this.socket.connect(port, host, () => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
this.socket.off('error', onError);
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
this.socket.write(header);
|
|
59
|
+
if (this.isFakeTLS && parsed.domain) {
|
|
60
|
+
const clientHello = generateFakeTLSClientHello(parsed.domain, parsed.secret);
|
|
61
|
+
this.clientRandom = clientHello.subarray(11, 43);
|
|
62
|
+
this.socket.write(clientHello);
|
|
63
|
+
// ServerHello = ServerHello + ChangeCipherSpec + one ApplicationData record.
|
|
64
|
+
const verdict = await this.awaitVerdict(parsed.secret, timeout);
|
|
65
|
+
if (verdict === 'invalid') {
|
|
66
|
+
throw new Error('FakeTLS handshake failed (bad secret or not a proxy)');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Send a real MTProto ping: req_pq_multi and wait for a valid ResPQ.
|
|
72
|
+
*
|
|
73
|
+
* @returns Round-trip time in ms
|
|
74
|
+
*/
|
|
75
|
+
async ping(timeout = 10000) {
|
|
76
|
+
if (!this.encryptor || !this.decryptor) {
|
|
77
|
+
throw new Error('Not connected');
|
|
78
|
+
}
|
|
79
|
+
const nonce = randomBytes(16);
|
|
80
|
+
const message = buildUnencryptedMessage(buildReqPqMulti(nonce), generateMessageId());
|
|
81
|
+
// Intermediate transport framing: 4-byte LE length prefix before the message.
|
|
82
|
+
const framed = Buffer.alloc(4 + message.length);
|
|
83
|
+
framed.writeUInt32LE(message.length, 0);
|
|
84
|
+
message.copy(framed, 4);
|
|
85
|
+
const payload = this.isFakeTLS
|
|
86
|
+
? wrapInTLSRecords(this.encryptor.encrypt(framed))
|
|
87
|
+
: this.encryptor.encrypt(framed);
|
|
88
|
+
const start = Date.now();
|
|
89
|
+
this.phase = 'ping';
|
|
90
|
+
this.receiveBuffer = Buffer.alloc(0);
|
|
91
|
+
const response = await new Promise((resolve, reject) => {
|
|
92
|
+
const timer = setTimeout(() => {
|
|
93
|
+
this.pending = null;
|
|
94
|
+
reject(new Error('Ping timeout'));
|
|
95
|
+
}, timeout);
|
|
96
|
+
this.pending = (data) => {
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
this.pending = null;
|
|
99
|
+
resolve(data);
|
|
100
|
+
};
|
|
101
|
+
this.socket.write(payload);
|
|
102
|
+
});
|
|
103
|
+
this.phase = 'done';
|
|
104
|
+
const parsed = parseResPQ(response);
|
|
105
|
+
if (!parsed || !parsed.nonce.equals(nonce)) {
|
|
106
|
+
throw new Error('Invalid ResPQ response');
|
|
107
|
+
}
|
|
108
|
+
return Date.now() - start;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Connect + single real ping in one call. Closes the connection afterwards.
|
|
112
|
+
*/
|
|
113
|
+
static async pingOnce(options, timeout = 10000) {
|
|
114
|
+
const conn = new MTProtoConnection(options);
|
|
115
|
+
try {
|
|
116
|
+
await conn.connect();
|
|
117
|
+
return await conn.ping(timeout);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
conn.close();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Handle incoming socket data depending on the current phase.
|
|
125
|
+
*/
|
|
126
|
+
onData(data) {
|
|
127
|
+
if (this.phase === 'handshake') {
|
|
128
|
+
this.receiveBuffer = Buffer.concat([this.receiveBuffer, data]);
|
|
129
|
+
const handler = this.pending;
|
|
130
|
+
if (handler)
|
|
131
|
+
handler(this.receiveBuffer);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (this.phase !== 'ping' || !this.decryptor) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Ping phase: decrypt, strip TLS records, feed the MTProto stream.
|
|
138
|
+
const decrypted = this.decryptor.encrypt(data);
|
|
139
|
+
const { payload } = this.isFakeTLS ? extractTlsRecords(decrypted) : { payload: decrypted };
|
|
140
|
+
this.receiveBuffer = Buffer.concat([this.receiveBuffer, payload]);
|
|
141
|
+
// Intermediate framed message: 4-byte LE length then the message.
|
|
142
|
+
// Pass the whole frame (length prefix included) so parseResPQ sees it.
|
|
143
|
+
if (this.receiveBuffer.length >= 4) {
|
|
144
|
+
const len = this.receiveBuffer.readUInt32LE(0);
|
|
145
|
+
if (this.receiveBuffer.length >= 4 + len) {
|
|
146
|
+
const handler = this.pending;
|
|
147
|
+
if (handler)
|
|
148
|
+
handler(this.receiveBuffer.subarray(0, 4 + len));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Wait until the FakeTLS ServerHello can be verified.
|
|
154
|
+
*/
|
|
155
|
+
async awaitVerdict(proxySecret, timeout) {
|
|
156
|
+
const clientRandom = this.clientRandom;
|
|
157
|
+
const started = this.receiveBuffer;
|
|
158
|
+
this.receiveBuffer = Buffer.alloc(0);
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
const timer = setTimeout(() => {
|
|
161
|
+
this.pending = null;
|
|
162
|
+
reject(new Error('FakeTLS handshake timeout'));
|
|
163
|
+
}, timeout);
|
|
164
|
+
const check = (data) => {
|
|
165
|
+
const verdict = tryVerifyFakeTLSServerHello(data, clientRandom, proxySecret);
|
|
166
|
+
if (verdict !== 'incomplete') {
|
|
167
|
+
clearTimeout(timer);
|
|
168
|
+
this.pending = null;
|
|
169
|
+
resolve(verdict);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
this.pending = check;
|
|
173
|
+
if (started.length > 0)
|
|
174
|
+
check(started);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Reject any pending waiters (socket closed mid-handshake/ping).
|
|
179
|
+
*/
|
|
180
|
+
failPending(_reason) {
|
|
181
|
+
const handler = this.pending;
|
|
182
|
+
this.pending = null;
|
|
183
|
+
if (handler) {
|
|
184
|
+
if (this.phase === 'ping') {
|
|
185
|
+
handler(Buffer.alloc(0)); // empty data -> parse fails -> error surfaces
|
|
186
|
+
}
|
|
187
|
+
// Handshake waiters resolve via their timeout; socket is gone anyway.
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Close the connection.
|
|
192
|
+
*/
|
|
193
|
+
close() {
|
|
194
|
+
this.phase = 'done';
|
|
195
|
+
this.socket.destroy();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/mtproto/connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FakeTLS layer for MTProto proxies (secret with "ee" prefix).
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Parse MTProto proxy secret and extract components.
|
|
6
|
+
*/
|
|
7
|
+
export interface ParsedSecret {
|
|
8
|
+
secret: Buffer;
|
|
9
|
+
domain?: string;
|
|
10
|
+
isFakeTLS: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse MTProto proxy secret (dd or ee prefix).
|
|
14
|
+
*
|
|
15
|
+
* @param secretHex - Hex-encoded secret (with or without dd/ee prefix)
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseSecret(secretHex: string): ParsedSecret;
|
|
18
|
+
/**
|
|
19
|
+
* TLS record content types.
|
|
20
|
+
*/
|
|
21
|
+
export declare const TLS_RECORD: {
|
|
22
|
+
readonly CHANGE_CIPHER_SPEC: 20;
|
|
23
|
+
readonly ALERT: 21;
|
|
24
|
+
readonly HANDSHAKE: 22;
|
|
25
|
+
readonly APPLICATION_DATA: 23;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Generate a FakeTLS ClientHello with a valid HMAC digest in the client random,
|
|
29
|
+
* exactly as official Telegram clients do. The proxy verifies this digest.
|
|
30
|
+
*
|
|
31
|
+
* @param domain - SNI domain from the ee secret
|
|
32
|
+
* @param secret - 16-byte proxy secret
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateFakeTLSClientHello(domain: string, secret: Buffer): Buffer;
|
|
35
|
+
/**
|
|
36
|
+
* Wrap data into TLS Application Data record(s).
|
|
37
|
+
*/
|
|
38
|
+
export declare function wrapInTLSRecords(data: Buffer): Buffer;
|
|
39
|
+
/**
|
|
40
|
+
* Extract complete TLS record payloads from a stream buffer.
|
|
41
|
+
*
|
|
42
|
+
* @returns Concatenated payload of complete records and the remaining (incomplete) buffer
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractTlsRecords(buffer: Buffer): {
|
|
45
|
+
payload: Buffer;
|
|
46
|
+
rest: Buffer;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Try to read and verify the proxy's ServerHello response.
|
|
50
|
+
* The proxy answers with exactly 3 records: ServerHello + ChangeCipherSpec + noise AppData,
|
|
51
|
+
* placing HMAC(secret, clientRandom || records-with-zeroed-digest) at RANDOM_OFFSET.
|
|
52
|
+
*
|
|
53
|
+
* @returns 'incomplete' while waiting for more bytes, 'valid' or 'invalid' when decided
|
|
54
|
+
*/
|
|
55
|
+
export declare function tryVerifyFakeTLSServerHello(buffer: Buffer, clientRandom: Buffer, secret: Buffer): 'incomplete' | 'valid' | 'invalid';
|
|
56
|
+
//# sourceMappingURL=fake-tls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-tls.d.ts","sourceRoot":"","sources":["../../src/mtproto/fake-tls.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA0B3D;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AA+BX;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAkDjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAarD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAUnF;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,YAAY,GAAG,OAAO,GAAG,SAAS,CAmBpC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createHmac, randomBytes } from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Parse MTProto proxy secret (dd or ee prefix).
|
|
4
|
+
*
|
|
5
|
+
* @param secretHex - Hex-encoded secret (with or without dd/ee prefix)
|
|
6
|
+
*/
|
|
7
|
+
export function parseSecret(secretHex) {
|
|
8
|
+
const hex = secretHex.toLowerCase().replace(/[^0-9a-f]/g, '');
|
|
9
|
+
if (hex.startsWith('dd')) {
|
|
10
|
+
const secret = Buffer.from(hex.slice(2), 'hex');
|
|
11
|
+
if (secret.length !== 16) {
|
|
12
|
+
throw new Error('dd secret must be 16 bytes');
|
|
13
|
+
}
|
|
14
|
+
return { secret, isFakeTLS: false };
|
|
15
|
+
}
|
|
16
|
+
if (hex.startsWith('ee')) {
|
|
17
|
+
const rest = hex.slice(2);
|
|
18
|
+
if (rest.length < 32) {
|
|
19
|
+
throw new Error('ee secret must have at least 16 bytes');
|
|
20
|
+
}
|
|
21
|
+
const secret = Buffer.from(rest.slice(0, 32), 'hex');
|
|
22
|
+
const domain = rest.length > 32 ? Buffer.from(rest.slice(32), 'hex').toString('ascii') : undefined;
|
|
23
|
+
return { secret, domain, isFakeTLS: true };
|
|
24
|
+
}
|
|
25
|
+
const secret = Buffer.from(hex, 'hex');
|
|
26
|
+
if (secret.length !== 16) {
|
|
27
|
+
throw new Error('Secret must be 16 bytes');
|
|
28
|
+
}
|
|
29
|
+
return { secret, isFakeTLS: false };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* TLS record content types.
|
|
33
|
+
*/
|
|
34
|
+
export const TLS_RECORD = {
|
|
35
|
+
CHANGE_CIPHER_SPEC: 0x14,
|
|
36
|
+
ALERT: 0x15,
|
|
37
|
+
HANDSHAKE: 0x16,
|
|
38
|
+
APPLICATION_DATA: 0x17,
|
|
39
|
+
};
|
|
40
|
+
/** Random field offset inside the ClientHello record:
|
|
41
|
+
* record header (5) + handshake type (1) + handshake length (3) + client version (2). */
|
|
42
|
+
const RANDOM_OFFSET = 11;
|
|
43
|
+
const RANDOM_LEN = 32;
|
|
44
|
+
const u16 = (n) => {
|
|
45
|
+
const b = Buffer.alloc(2);
|
|
46
|
+
b.writeUInt16BE(n, 0);
|
|
47
|
+
return b;
|
|
48
|
+
};
|
|
49
|
+
const u24 = (n) => {
|
|
50
|
+
const b = Buffer.alloc(3);
|
|
51
|
+
b.writeUIntBE(n, 0, 3);
|
|
52
|
+
return b;
|
|
53
|
+
};
|
|
54
|
+
const extension = (type, data) => Buffer.concat([u16(type), u16(data.length), data]);
|
|
55
|
+
/**
|
|
56
|
+
* Build the SNI (server_name) extension.
|
|
57
|
+
*/
|
|
58
|
+
const sniExtension = (domain) => {
|
|
59
|
+
const host = Buffer.from(domain, 'ascii');
|
|
60
|
+
const list = Buffer.concat([Buffer.from([0x00]), u16(host.length), host]);
|
|
61
|
+
return extension(0x0000, Buffer.concat([u16(list.length), list]));
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Generate a FakeTLS ClientHello with a valid HMAC digest in the client random,
|
|
65
|
+
* exactly as official Telegram clients do. The proxy verifies this digest.
|
|
66
|
+
*
|
|
67
|
+
* @param domain - SNI domain from the ee secret
|
|
68
|
+
* @param secret - 16-byte proxy secret
|
|
69
|
+
*/
|
|
70
|
+
export function generateFakeTLSClientHello(domain, secret) {
|
|
71
|
+
const sessionId = randomBytes(32);
|
|
72
|
+
const keyShare = randomBytes(32);
|
|
73
|
+
// Include a trailing GREASE value like real browsers do.
|
|
74
|
+
const cipherSuites = [
|
|
75
|
+
0x1301, 0x1302, 0x1303, 0x1305, 0xc02b, 0xc02f, 0xc02c, 0xc030, 0xcca9,
|
|
76
|
+
0xcca8, 0xc013, 0xc014, 0x009c, 0x009d, 0x002f, 0x0035, 0x000a, 0x0a0a,
|
|
77
|
+
];
|
|
78
|
+
const csBuf = Buffer.alloc(cipherSuites.length * 2);
|
|
79
|
+
cipherSuites.forEach((c, i) => csBuf.writeUInt16BE(c, i * 2));
|
|
80
|
+
const alpn = Buffer.concat([
|
|
81
|
+
u16(2 + 1 + 2 + 1 + 8), // protocol name list length
|
|
82
|
+
Buffer.from([2]), Buffer.from('h2', 'ascii'),
|
|
83
|
+
Buffer.from([8]), Buffer.from('http/1.1', 'ascii'),
|
|
84
|
+
]);
|
|
85
|
+
const extensions = Buffer.concat([
|
|
86
|
+
sniExtension(domain),
|
|
87
|
+
extension(0x0010, alpn), // ALPN
|
|
88
|
+
extension(0x000a, Buffer.concat([u16(4), u16(0x001d), u16(0x0017)])), // supported_groups: x25519, secp256r1
|
|
89
|
+
extension(0x000b, Buffer.concat([u16(2), Buffer.from([0x01, 0x00])])), // ec_point_formats: uncompressed
|
|
90
|
+
extension(0x000d, Buffer.concat([u16(4), u16(0x0804), u16(0x0401)])), // signature_algorithms
|
|
91
|
+
extension(0x002b, Buffer.concat([u16(4), Buffer.from([0x03, 0x04, 0x03, 0x03])])), // supported_versions: TLS1.3, TLS1.2
|
|
92
|
+
extension(0x0033, Buffer.concat([u16(2 + 2 + keyShare.length), u16(0x001d), u16(keyShare.length), keyShare])), // key_share x25519
|
|
93
|
+
extension(0x0016, Buffer.alloc(0)), // encrypt_then_mac
|
|
94
|
+
extension(0x0017, Buffer.alloc(0)), // extended_master_secret
|
|
95
|
+
]);
|
|
96
|
+
const body = Buffer.concat([
|
|
97
|
+
Buffer.from([0x03, 0x03]), // client version TLS 1.2
|
|
98
|
+
Buffer.alloc(RANDOM_LEN), // placeholder: random filled below
|
|
99
|
+
Buffer.from([sessionId.length]), sessionId,
|
|
100
|
+
u16(csBuf.length), csBuf,
|
|
101
|
+
Buffer.from([0x01, 0x00]), // compression methods: null
|
|
102
|
+
u16(extensions.length), extensions,
|
|
103
|
+
]);
|
|
104
|
+
const handshake = Buffer.concat([Buffer.from([0x01]), u24(body.length), body]); // ClientHello
|
|
105
|
+
const packet = Buffer.concat([
|
|
106
|
+
Buffer.from([TLS_RECORD.HANDSHAKE, 0x03, 0x01]), u16(handshake.length), handshake,
|
|
107
|
+
]);
|
|
108
|
+
// Client random = HMAC(secret, handshake with zeroed random); last 4 bytes = UNIX timestamp (LE).
|
|
109
|
+
const digest = createHmac('sha256', secret).update(packet).digest();
|
|
110
|
+
digest.writeUInt32LE(Math.floor(Date.now() / 1000) >>> 0, RANDOM_LEN - 4);
|
|
111
|
+
digest.copy(packet, RANDOM_OFFSET);
|
|
112
|
+
return packet;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Wrap data into TLS Application Data record(s).
|
|
116
|
+
*/
|
|
117
|
+
export function wrapInTLSRecords(data) {
|
|
118
|
+
const MAX_CHUNK_SIZE = 16384;
|
|
119
|
+
const chunks = [];
|
|
120
|
+
for (let i = 0; i < data.length; i += MAX_CHUNK_SIZE) {
|
|
121
|
+
const chunk = data.subarray(i, Math.min(i + MAX_CHUNK_SIZE, data.length));
|
|
122
|
+
const record = Buffer.alloc(5 + chunk.length);
|
|
123
|
+
record.writeUInt8(TLS_RECORD.APPLICATION_DATA, 0);
|
|
124
|
+
record.writeUInt16BE(0x0303, 1);
|
|
125
|
+
record.writeUInt16BE(chunk.length, 3);
|
|
126
|
+
chunk.copy(record, 5);
|
|
127
|
+
chunks.push(record);
|
|
128
|
+
}
|
|
129
|
+
return Buffer.concat(chunks);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Extract complete TLS record payloads from a stream buffer.
|
|
133
|
+
*
|
|
134
|
+
* @returns Concatenated payload of complete records and the remaining (incomplete) buffer
|
|
135
|
+
*/
|
|
136
|
+
export function extractTlsRecords(buffer) {
|
|
137
|
+
let offset = 0;
|
|
138
|
+
let payload = Buffer.alloc(0);
|
|
139
|
+
while (buffer.length - offset >= 5) {
|
|
140
|
+
const len = buffer.readUInt16BE(offset + 3);
|
|
141
|
+
if (buffer.length - offset < 5 + len)
|
|
142
|
+
break;
|
|
143
|
+
payload = Buffer.concat([payload, buffer.subarray(offset + 5, offset + 5 + len)]);
|
|
144
|
+
offset += 5 + len;
|
|
145
|
+
}
|
|
146
|
+
return { payload, rest: buffer.subarray(offset) };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Try to read and verify the proxy's ServerHello response.
|
|
150
|
+
* The proxy answers with exactly 3 records: ServerHello + ChangeCipherSpec + noise AppData,
|
|
151
|
+
* placing HMAC(secret, clientRandom || records-with-zeroed-digest) at RANDOM_OFFSET.
|
|
152
|
+
*
|
|
153
|
+
* @returns 'incomplete' while waiting for more bytes, 'valid' or 'invalid' when decided
|
|
154
|
+
*/
|
|
155
|
+
export function tryVerifyFakeTLSServerHello(buffer, clientRandom, secret) {
|
|
156
|
+
let offset = 0;
|
|
157
|
+
for (let i = 0; i < 3; i++) {
|
|
158
|
+
if (buffer.length - offset < 5)
|
|
159
|
+
return 'incomplete';
|
|
160
|
+
offset += 5 + buffer.readUInt16BE(offset + 3);
|
|
161
|
+
}
|
|
162
|
+
if (buffer.length < offset)
|
|
163
|
+
return 'incomplete';
|
|
164
|
+
const packet = buffer.subarray(0, offset);
|
|
165
|
+
if (packet[0] !== TLS_RECORD.HANDSHAKE)
|
|
166
|
+
return 'invalid';
|
|
167
|
+
const mac = createHmac('sha256', secret)
|
|
168
|
+
.update(clientRandom)
|
|
169
|
+
.update(packet.subarray(0, RANDOM_OFFSET))
|
|
170
|
+
.update(Buffer.alloc(RANDOM_LEN))
|
|
171
|
+
.update(packet.subarray(RANDOM_OFFSET + RANDOM_LEN))
|
|
172
|
+
.digest();
|
|
173
|
+
return mac.equals(packet.subarray(RANDOM_OFFSET, RANDOM_OFFSET + RANDOM_LEN)) ? 'valid' : 'invalid';
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=fake-tls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-tls.js","sourceRoot":"","sources":["../../src/mtproto/fake-tls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate MTProto message_id.
|
|
3
|
+
* Format: time.time() * 2^32, must be divisible by 4
|
|
4
|
+
* Client message IDs must be divisible by 4
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateMessageId(): bigint;
|
|
7
|
+
/**
|
|
8
|
+
* Build req_pq_multi message.
|
|
9
|
+
* TL Schema: req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
|
10
|
+
*
|
|
11
|
+
* @param nonce - 16-byte random nonce
|
|
12
|
+
* @returns TL-serialized message
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildReqPqMulti(nonce: Buffer): Buffer;
|
|
15
|
+
/**
|
|
16
|
+
* Build unencrypted MTProto message wrapper.
|
|
17
|
+
*
|
|
18
|
+
* Format:
|
|
19
|
+
* - auth_key_id: 8 bytes (all zeros for unencrypted)
|
|
20
|
+
* - message_id: 8 bytes
|
|
21
|
+
* - message_length: 4 bytes
|
|
22
|
+
* - message: N bytes
|
|
23
|
+
*
|
|
24
|
+
* @param tlMessage - TL-serialized message
|
|
25
|
+
* @param messageId - Message ID
|
|
26
|
+
* @returns Unencrypted message
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildUnencryptedMessage(tlMessage: Buffer, messageId: bigint): Buffer;
|
|
29
|
+
/**
|
|
30
|
+
* Add Intermediate protocol length prefix.
|
|
31
|
+
*
|
|
32
|
+
* @param payload - Message payload
|
|
33
|
+
* @returns Payload with length prefix
|
|
34
|
+
*/
|
|
35
|
+
export declare function addLengthPrefix(payload: Buffer): Buffer;
|
|
36
|
+
/**
|
|
37
|
+
* Parse ResPQ response.
|
|
38
|
+
* TL Schema: resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
|
|
39
|
+
*
|
|
40
|
+
* @param data - Decrypted response data
|
|
41
|
+
* @returns Parsed response or null if invalid
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseResPQ(data: Buffer): {
|
|
44
|
+
nonce: Buffer;
|
|
45
|
+
serverNonce: Buffer;
|
|
46
|
+
constructor: number;
|
|
47
|
+
} | null;
|
|
48
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/mtproto/messages.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAW1C;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,CAUR;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAyCpE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate MTProto message_id.
|
|
3
|
+
* Format: time.time() * 2^32, must be divisible by 4
|
|
4
|
+
* Client message IDs must be divisible by 4
|
|
5
|
+
*/
|
|
6
|
+
export function generateMessageId() {
|
|
7
|
+
// Get current time in seconds (with milliseconds as decimal)
|
|
8
|
+
const now = Date.now() / 1000; // seconds with decimal
|
|
9
|
+
// Multiply by 2^32
|
|
10
|
+
let msgId = BigInt(Math.floor(now * 2 ** 32));
|
|
11
|
+
// Must be divisible by 4 (client messages)
|
|
12
|
+
msgId = (msgId / 4n) * 4n;
|
|
13
|
+
return msgId;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build req_pq_multi message.
|
|
17
|
+
* TL Schema: req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
|
|
18
|
+
*
|
|
19
|
+
* @param nonce - 16-byte random nonce
|
|
20
|
+
* @returns TL-serialized message
|
|
21
|
+
*/
|
|
22
|
+
export function buildReqPqMulti(nonce) {
|
|
23
|
+
// Constructor ID: 0xbe7e8ef1 (little-endian)
|
|
24
|
+
const constructor = Buffer.from([0xf1, 0x8e, 0x7e, 0xbe]);
|
|
25
|
+
return Buffer.concat([constructor, nonce]);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build unencrypted MTProto message wrapper.
|
|
29
|
+
*
|
|
30
|
+
* Format:
|
|
31
|
+
* - auth_key_id: 8 bytes (all zeros for unencrypted)
|
|
32
|
+
* - message_id: 8 bytes
|
|
33
|
+
* - message_length: 4 bytes
|
|
34
|
+
* - message: N bytes
|
|
35
|
+
*
|
|
36
|
+
* @param tlMessage - TL-serialized message
|
|
37
|
+
* @param messageId - Message ID
|
|
38
|
+
* @returns Unencrypted message
|
|
39
|
+
*/
|
|
40
|
+
export function buildUnencryptedMessage(tlMessage, messageId) {
|
|
41
|
+
const authKeyId = Buffer.alloc(8, 0); // All zeros
|
|
42
|
+
const msgIdBuf = Buffer.alloc(8);
|
|
43
|
+
msgIdBuf.writeBigInt64LE(messageId, 0);
|
|
44
|
+
const msgLen = Buffer.alloc(4);
|
|
45
|
+
msgLen.writeUInt32LE(tlMessage.length, 0);
|
|
46
|
+
return Buffer.concat([authKeyId, msgIdBuf, msgLen, tlMessage]);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Add Intermediate protocol length prefix.
|
|
50
|
+
*
|
|
51
|
+
* @param payload - Message payload
|
|
52
|
+
* @returns Payload with length prefix
|
|
53
|
+
*/
|
|
54
|
+
export function addLengthPrefix(payload) {
|
|
55
|
+
const length = Buffer.alloc(4);
|
|
56
|
+
length.writeUInt32LE(payload.length, 0);
|
|
57
|
+
return Buffer.concat([length, payload]);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse ResPQ response.
|
|
61
|
+
* TL Schema: resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
|
|
62
|
+
*
|
|
63
|
+
* @param data - Decrypted response data
|
|
64
|
+
* @returns Parsed response or null if invalid
|
|
65
|
+
*/
|
|
66
|
+
export function parseResPQ(data) {
|
|
67
|
+
try {
|
|
68
|
+
let offset = 0;
|
|
69
|
+
// Intermediate frame: 4-byte LE length prefix, then the unencrypted
|
|
70
|
+
// MTProto envelope: auth_key_id(8) + message_id(8) + body_length(4) + body.
|
|
71
|
+
if (data.length < 4)
|
|
72
|
+
return null;
|
|
73
|
+
const length = data.readUInt32LE(offset);
|
|
74
|
+
offset += 4;
|
|
75
|
+
if (data.length < 4 + length)
|
|
76
|
+
return null;
|
|
77
|
+
// Parse auth_key_id (8 bytes) - should be all zeros
|
|
78
|
+
const authKeyId = data.slice(offset, offset + 8);
|
|
79
|
+
offset += 8;
|
|
80
|
+
if (!authKeyId.equals(Buffer.alloc(8, 0)))
|
|
81
|
+
return null;
|
|
82
|
+
// Parse message_id (8 bytes) - skip
|
|
83
|
+
offset += 8;
|
|
84
|
+
// Parse message_length (4 bytes) - skip
|
|
85
|
+
offset += 4;
|
|
86
|
+
// Parse constructor (4 bytes)
|
|
87
|
+
const constructor = data.readUInt32LE(offset);
|
|
88
|
+
offset += 4;
|
|
89
|
+
// Valid constructors: 0x05162463 or 0x83c95aec
|
|
90
|
+
if (constructor !== 0x05162463 && constructor !== 0x83c95aec) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// Parse nonce (16 bytes)
|
|
94
|
+
const nonce = data.slice(offset, offset + 16);
|
|
95
|
+
offset += 16;
|
|
96
|
+
// Parse server_nonce (16 bytes)
|
|
97
|
+
const serverNonce = data.slice(offset, offset + 16);
|
|
98
|
+
return { nonce, serverNonce, constructor };
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/mtproto/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AESCTR } from '../crypto/aes-ctr.js';
|
|
2
|
+
/**
|
|
3
|
+
* Protocol tags for MTProto transports.
|
|
4
|
+
*/
|
|
5
|
+
export declare const PROTO_TAG: {
|
|
6
|
+
ABRIDGED: Buffer<ArrayBuffer>;
|
|
7
|
+
INTERMEDIATE: Buffer<ArrayBuffer>;
|
|
8
|
+
SECURE: Buffer<ArrayBuffer>;
|
|
9
|
+
};
|
|
10
|
+
interface ObfuscationKeys {
|
|
11
|
+
header: Buffer;
|
|
12
|
+
encryptor: AESCTR;
|
|
13
|
+
decryptor: AESCTR;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Initialize MTProto obfuscation layer.
|
|
17
|
+
* Generates random 64-byte header and derives encryption keys.
|
|
18
|
+
*
|
|
19
|
+
* @param secret - 16-byte secret from proxy
|
|
20
|
+
* @param dcId - Telegram datacenter ID
|
|
21
|
+
* @param protocolTag - Transport protocol tag (default: INTERMEDIATE)
|
|
22
|
+
* @returns Header buffer and encryptor/decryptor ciphers
|
|
23
|
+
*/
|
|
24
|
+
export declare function initObfuscation(secret: Buffer, dcId: number, protocolTag?: Buffer): ObfuscationKeys;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=obfuscation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obfuscation.d.ts","sourceRoot":"","sources":["../../src/mtproto/obfuscation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,SAAS;;;;CAIrB,CAAC;AAYF,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,MAA+B,GAC3C,eAAe,CA+DjB"}
|