@erfan_bahramali/tping 1.0.0 → 1.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/README.md +76 -55
- package/dist/crypto/x25519.d.ts +10 -0
- package/dist/crypto/x25519.d.ts.map +1 -0
- package/dist/crypto/x25519.js +51 -0
- package/dist/crypto/x25519.js.map +1 -0
- package/dist/index.js +82 -39
- package/dist/index.js.map +1 -1
- package/dist/lib/attempt.d.ts +31 -0
- package/dist/lib/attempt.d.ts.map +1 -0
- package/dist/lib/attempt.js +94 -0
- package/dist/lib/attempt.js.map +1 -0
- package/dist/lib/checker.d.ts +21 -3
- package/dist/lib/checker.d.ts.map +1 -1
- package/dist/lib/checker.js +133 -49
- package/dist/lib/checker.js.map +1 -1
- package/dist/lib/datacenters.d.ts +15 -0
- package/dist/lib/datacenters.d.ts.map +1 -0
- package/dist/lib/datacenters.js +20 -0
- package/dist/lib/datacenters.js.map +1 -0
- package/dist/lib/parser.d.ts +18 -3
- package/dist/lib/parser.d.ts.map +1 -1
- package/dist/lib/parser.js +174 -78
- package/dist/lib/parser.js.map +1 -1
- package/dist/lib/ping.d.ts +13 -6
- package/dist/lib/ping.d.ts.map +1 -1
- package/dist/lib/ping.js +44 -44
- package/dist/lib/ping.js.map +1 -1
- package/dist/mtproto/exchange.d.ts +10 -0
- package/dist/mtproto/exchange.d.ts.map +1 -0
- package/dist/mtproto/exchange.js +20 -0
- package/dist/mtproto/exchange.js.map +1 -0
- package/dist/mtproto/fake-tls.d.ts +36 -44
- package/dist/mtproto/fake-tls.d.ts.map +1 -1
- package/dist/mtproto/fake-tls.js +174 -148
- package/dist/mtproto/fake-tls.js.map +1 -1
- package/dist/mtproto/messages.d.ts +23 -36
- package/dist/mtproto/messages.d.ts.map +1 -1
- package/dist/mtproto/messages.js +64 -90
- package/dist/mtproto/messages.js.map +1 -1
- package/dist/mtproto/obfuscation.d.ts +23 -20
- package/dist/mtproto/obfuscation.d.ts.map +1 -1
- package/dist/mtproto/obfuscation.js +64 -64
- package/dist/mtproto/obfuscation.js.map +1 -1
- package/dist/mtproto/secret.d.ts +28 -0
- package/dist/mtproto/secret.d.ts.map +1 -0
- package/dist/mtproto/secret.js +68 -0
- package/dist/mtproto/secret.js.map +1 -0
- package/dist/mtproto/transport.d.ts +28 -0
- package/dist/mtproto/transport.d.ts.map +1 -0
- package/dist/mtproto/transport.js +78 -0
- package/dist/mtproto/transport.js.map +1 -0
- package/dist/net/http-client.d.ts +37 -0
- package/dist/net/http-client.d.ts.map +1 -0
- package/dist/net/http-client.js +93 -0
- package/dist/net/http-client.js.map +1 -0
- package/dist/net/http-proxy.d.ts +26 -0
- package/dist/net/http-proxy.d.ts.map +1 -0
- package/dist/net/http-proxy.js +71 -0
- package/dist/net/http-proxy.js.map +1 -0
- package/dist/net/socks5.d.ts +15 -0
- package/dist/net/socks5.d.ts.map +1 -0
- package/dist/net/socks5.js +112 -0
- package/dist/net/socks5.js.map +1 -0
- package/dist/net/stream.d.ts +54 -0
- package/dist/net/stream.d.ts.map +1 -0
- package/dist/net/stream.js +142 -0
- package/dist/net/stream.js.map +1 -0
- package/dist/net/websocket.d.ts +19 -0
- package/dist/net/websocket.d.ts.map +1 -0
- package/dist/net/websocket.js +123 -0
- package/dist/net/websocket.js.map +1 -0
- package/dist/types/index.d.ts +40 -17
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/format.d.ts +7 -14
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +101 -87
- package/dist/utils/format.js.map +1 -1
- package/dist/webproxy/check.d.ts +15 -0
- package/dist/webproxy/check.d.ts.map +1 -0
- package/dist/webproxy/check.js +423 -0
- package/dist/webproxy/check.js.map +1 -0
- package/dist/webproxy/frames.d.ts +30 -0
- package/dist/webproxy/frames.d.ts.map +1 -0
- package/dist/webproxy/frames.js +59 -0
- package/dist/webproxy/frames.js.map +1 -0
- package/dist/webproxy/link.d.ts +27 -0
- package/dist/webproxy/link.d.ts.map +1 -0
- package/dist/webproxy/link.js +107 -0
- package/dist/webproxy/link.js.map +1 -0
- package/package.json +16 -11
- package/dist/mtproto/connection.d.ts +0 -59
- package/dist/mtproto/connection.d.ts.map +0 -1
- package/dist/mtproto/connection.js +0 -198
- package/dist/mtproto/connection.js.map +0 -1
- package/dist/mtproto/socks5.d.ts +0 -36
- package/dist/mtproto/socks5.d.ts.map +0 -1
- package/dist/mtproto/socks5.js +0 -148
- package/dist/mtproto/socks5.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/mtproto/transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Attempt } from '../lib/attempt.js';
|
|
2
|
+
import type { SocketStream } from './stream.js';
|
|
3
|
+
import { type HttpResponseHead } from './http-proxy.js';
|
|
4
|
+
export interface HttpResponse extends HttpResponseHead {
|
|
5
|
+
readonly body: Buffer;
|
|
6
|
+
}
|
|
7
|
+
export interface TlsEndpoint {
|
|
8
|
+
/** Where to connect (defaults to the hostname). */
|
|
9
|
+
readonly host?: string;
|
|
10
|
+
readonly port?: number;
|
|
11
|
+
/** Extra trusted CA (tests). */
|
|
12
|
+
readonly ca?: Buffer;
|
|
13
|
+
}
|
|
14
|
+
export interface TlsConnection {
|
|
15
|
+
readonly stream: SocketStream;
|
|
16
|
+
/** TCP connect time in ms. */
|
|
17
|
+
readonly tcp: number;
|
|
18
|
+
/** TLS handshake time in ms. */
|
|
19
|
+
readonly tls: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Open a certificate-verified TLS connection with SNI set to `hostname`,
|
|
23
|
+
* speaking HTTP/1.1 (needed for the WebSocket upgrade).
|
|
24
|
+
*/
|
|
25
|
+
export declare const openTls: (attempt: Attempt, hostname: string, endpoint?: TlsEndpoint) => Promise<TlsConnection>;
|
|
26
|
+
/**
|
|
27
|
+
* Minimal keep-alive HTTP/1.1 client over one connection (one request at a time).
|
|
28
|
+
*/
|
|
29
|
+
export declare class HttpConnection {
|
|
30
|
+
readonly stream: SocketStream;
|
|
31
|
+
private readonly hostname;
|
|
32
|
+
constructor(stream: SocketStream, hostname: string);
|
|
33
|
+
writeRequest(method: string, path: string, headers: Readonly<Record<string, string>>, body?: Buffer): void;
|
|
34
|
+
request(method: string, path: string, headers: Readonly<Record<string, string>>, body?: Buffer): Promise<HttpResponse>;
|
|
35
|
+
private readBody;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/net/http-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAK1E,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAU,SAAS,OAAO,EAAE,UAAU,MAAM,EAAE,WAAU,WAAgB,KAAG,OAAO,CAAC,aAAa,CAiBnH,CAAC;AA0BF;;GAEG;AACH,qBAAa,cAAc;IACb,QAAQ,CAAC,MAAM,EAAE,YAAY;IAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAA/C,MAAM,EAAE,YAAY,EAAmB,QAAQ,EAAE,MAAM;IAE5E,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAWpG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YAM9G,QAAQ;CAiBvB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { connect as tlsConnect } from 'tls';
|
|
2
|
+
import { readResponseHead } from './http-proxy.js';
|
|
3
|
+
const CRLF = Buffer.from('\r\n');
|
|
4
|
+
const MAX_BODY = 8 * 1024 * 1024;
|
|
5
|
+
/**
|
|
6
|
+
* Open a certificate-verified TLS connection with SNI set to `hostname`,
|
|
7
|
+
* speaking HTTP/1.1 (needed for the WebSocket upgrade).
|
|
8
|
+
*/
|
|
9
|
+
export const openTls = async (attempt, hostname, endpoint = {}) => {
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
let tcpAt = start;
|
|
12
|
+
const socket = tlsConnect({
|
|
13
|
+
host: endpoint.host ?? hostname,
|
|
14
|
+
port: endpoint.port ?? 443,
|
|
15
|
+
servername: hostname,
|
|
16
|
+
ALPNProtocols: ['http/1.1'],
|
|
17
|
+
...(endpoint.ca ? { ca: endpoint.ca } : {}),
|
|
18
|
+
});
|
|
19
|
+
socket.once('connect', () => {
|
|
20
|
+
tcpAt = Date.now();
|
|
21
|
+
});
|
|
22
|
+
const stream = attempt.newStream(socket, 'secureConnect');
|
|
23
|
+
await stream.ready();
|
|
24
|
+
const end = Date.now();
|
|
25
|
+
return { stream, tcp: tcpAt - start, tls: end - tcpAt };
|
|
26
|
+
};
|
|
27
|
+
const readChunked = async (stream) => {
|
|
28
|
+
const parts = [];
|
|
29
|
+
let total = 0;
|
|
30
|
+
for (;;) {
|
|
31
|
+
const line = (await stream.readUntil(CRLF, 1024)).toString('latin1');
|
|
32
|
+
const size = parseInt(line.split(';')[0].trim(), 16);
|
|
33
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
34
|
+
throw new Error('Invalid chunked response');
|
|
35
|
+
}
|
|
36
|
+
if (size === 0) {
|
|
37
|
+
while ((await stream.readUntil(CRLF, 8192)).length > 2) {
|
|
38
|
+
// Skip trailers.
|
|
39
|
+
}
|
|
40
|
+
return Buffer.concat(parts);
|
|
41
|
+
}
|
|
42
|
+
total += size;
|
|
43
|
+
if (total > MAX_BODY) {
|
|
44
|
+
throw new Error('Response body too large');
|
|
45
|
+
}
|
|
46
|
+
parts.push(await stream.read(size));
|
|
47
|
+
await stream.read(2);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Minimal keep-alive HTTP/1.1 client over one connection (one request at a time).
|
|
52
|
+
*/
|
|
53
|
+
export class HttpConnection {
|
|
54
|
+
stream;
|
|
55
|
+
hostname;
|
|
56
|
+
constructor(stream, hostname) {
|
|
57
|
+
this.stream = stream;
|
|
58
|
+
this.hostname = hostname;
|
|
59
|
+
}
|
|
60
|
+
writeRequest(method, path, headers, body) {
|
|
61
|
+
const lines = [`${method} ${path} HTTP/1.1`, `Host: ${this.hostname}`];
|
|
62
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
63
|
+
lines.push(`${name}: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
if (body || method === 'POST' || method === 'DELETE') {
|
|
66
|
+
lines.push(`Content-Length: ${body?.length ?? 0}`);
|
|
67
|
+
}
|
|
68
|
+
this.stream.write(Buffer.concat([Buffer.from(`${lines.join('\r\n')}\r\n\r\n`, 'latin1'), body ?? Buffer.alloc(0)]));
|
|
69
|
+
}
|
|
70
|
+
async request(method, path, headers, body) {
|
|
71
|
+
this.writeRequest(method, path, headers, body);
|
|
72
|
+
const head = await readResponseHead(this.stream);
|
|
73
|
+
return { ...head, body: await this.readBody(method, head) };
|
|
74
|
+
}
|
|
75
|
+
async readBody(method, head) {
|
|
76
|
+
if (method === 'HEAD' || head.status === 204 || head.status === 304 || (head.status >= 100 && head.status < 200)) {
|
|
77
|
+
return Buffer.alloc(0);
|
|
78
|
+
}
|
|
79
|
+
if (head.headers.get('transfer-encoding')?.toLowerCase().includes('chunked')) {
|
|
80
|
+
return readChunked(this.stream);
|
|
81
|
+
}
|
|
82
|
+
const length = head.headers.get('content-length');
|
|
83
|
+
if (length !== undefined) {
|
|
84
|
+
const size = Number(length);
|
|
85
|
+
if (!Number.isSafeInteger(size) || size < 0 || size > MAX_BODY) {
|
|
86
|
+
throw new Error('Invalid Content-Length');
|
|
87
|
+
}
|
|
88
|
+
return this.stream.read(size);
|
|
89
|
+
}
|
|
90
|
+
return this.stream.readToEnd(MAX_BODY);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/net/http-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SocketStream } from './stream.js';
|
|
2
|
+
export declare class HttpProxyError extends Error {
|
|
3
|
+
readonly status?: number | undefined;
|
|
4
|
+
constructor(message: string, status?: number | undefined);
|
|
5
|
+
}
|
|
6
|
+
export interface HttpCredentials {
|
|
7
|
+
readonly username?: string;
|
|
8
|
+
readonly password?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface HttpResponseHead {
|
|
11
|
+
readonly status: number;
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
readonly headers: ReadonlyMap<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export declare const readResponseHead: (stream: SocketStream) => Promise<HttpResponseHead>;
|
|
16
|
+
/**
|
|
17
|
+
* Open a TCP tunnel with the CONNECT method (what Telegram Desktop does through an HTTP proxy).
|
|
18
|
+
*/
|
|
19
|
+
export declare const httpConnect: (stream: SocketStream, host: string, port: number, credentials: HttpCredentials) => Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Send one MTProto message with the HTTP transport (POST http://<dc>:80/api)
|
|
22
|
+
* through the proxy and return the response body. Telegram Desktop falls back
|
|
23
|
+
* to this transport when TCP through the proxy does not work.
|
|
24
|
+
*/
|
|
25
|
+
export declare const httpTransportRequest: (stream: SocketStream, host: string, port: number, credentials: HttpCredentials, body: Buffer) => Promise<Buffer>;
|
|
26
|
+
//# sourceMappingURL=http-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-proxy.d.ts","sourceRoot":"","sources":["../../src/net/http-proxy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,qBAAa,cAAe,SAAQ,KAAK;IACV,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;gBAAzC,OAAO,EAAE,MAAM,EAAW,MAAM,CAAC,EAAE,MAAM,YAAA;CAItD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAYD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,gBAAgB,GAAU,QAAQ,YAAY,KAAG,OAAO,CAAC,gBAAgB,CAerF,CAAC;AASF;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,YAAY,EACpB,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,aAAa,eAAe,KAC3B,OAAO,CAAC,IAAI,CAUd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,YAAY,EACpB,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,aAAa,eAAe,EAC5B,MAAM,MAAM,KACX,OAAO,CAAC,MAAM,CAmBhB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isIPv6 } from 'net';
|
|
2
|
+
export class HttpProxyError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
constructor(message, status) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.name = 'HttpProxyError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const HEADER_END = Buffer.from('\r\n\r\n');
|
|
11
|
+
const MAX_HEADER = 16 * 1024;
|
|
12
|
+
const hostPort = (host, port) => `${isIPv6(host) ? `[${host}]` : host}:${port}`;
|
|
13
|
+
const authHeader = (credentials) => credentials.username || credentials.password
|
|
14
|
+
? `Proxy-Authorization: Basic ${Buffer.from(`${credentials.username ?? ''}:${credentials.password ?? ''}`).toString('base64')}\r\n`
|
|
15
|
+
: '';
|
|
16
|
+
export const readResponseHead = async (stream) => {
|
|
17
|
+
const raw = (await stream.readUntil(HEADER_END, MAX_HEADER)).toString('latin1');
|
|
18
|
+
const [statusLine, ...lines] = raw.split('\r\n');
|
|
19
|
+
const match = /^HTTP\/\d(?:\.\d)?\s+(\d{3})\s*(.*)$/.exec(statusLine);
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new HttpProxyError('Not an HTTP proxy (invalid status line)');
|
|
22
|
+
}
|
|
23
|
+
const headers = new Map();
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
const colon = line.indexOf(':');
|
|
26
|
+
if (colon > 0) {
|
|
27
|
+
headers.set(line.slice(0, colon).trim().toLowerCase(), line.slice(colon + 1).trim());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { status: Number(match[1]), reason: match[2], headers };
|
|
31
|
+
};
|
|
32
|
+
const statusError = (head, action) => {
|
|
33
|
+
if (head.status === 407) {
|
|
34
|
+
return new HttpProxyError('HTTP proxy requires authentication (407) or credentials are wrong', 407);
|
|
35
|
+
}
|
|
36
|
+
return new HttpProxyError(`HTTP proxy refused ${action}: ${head.status} ${head.reason}`.trim(), head.status);
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Open a TCP tunnel with the CONNECT method (what Telegram Desktop does through an HTTP proxy).
|
|
40
|
+
*/
|
|
41
|
+
export const httpConnect = async (stream, host, port, credentials) => {
|
|
42
|
+
const target = hostPort(host, port);
|
|
43
|
+
stream.write(Buffer.from(`CONNECT ${target} HTTP/1.1\r\nHost: ${target}\r\nProxy-Connection: keep-alive\r\n${authHeader(credentials)}\r\n`, 'latin1'));
|
|
44
|
+
const head = await readResponseHead(stream);
|
|
45
|
+
if (head.status < 200 || head.status >= 300) {
|
|
46
|
+
throw statusError(head, 'CONNECT');
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Send one MTProto message with the HTTP transport (POST http://<dc>:80/api)
|
|
51
|
+
* through the proxy and return the response body. Telegram Desktop falls back
|
|
52
|
+
* to this transport when TCP through the proxy does not work.
|
|
53
|
+
*/
|
|
54
|
+
export const httpTransportRequest = async (stream, host, port, credentials, body) => {
|
|
55
|
+
const target = hostPort(host, port);
|
|
56
|
+
stream.write(Buffer.concat([
|
|
57
|
+
Buffer.from(`POST http://${target}/api HTTP/1.1\r\nHost: ${target}\r\nConnection: keep-alive\r\n` +
|
|
58
|
+
`Content-Type: application/x-www-form-urlencoded\r\nContent-Length: ${body.length}\r\n${authHeader(credentials)}\r\n`, 'latin1'),
|
|
59
|
+
body,
|
|
60
|
+
]));
|
|
61
|
+
const head = await readResponseHead(stream);
|
|
62
|
+
if (head.status !== 200) {
|
|
63
|
+
throw statusError(head, 'the HTTP transport request');
|
|
64
|
+
}
|
|
65
|
+
const length = Number(head.headers.get('content-length'));
|
|
66
|
+
if (!Number.isInteger(length) || length <= 0 || length > 1 << 20) {
|
|
67
|
+
throw new HttpProxyError('HTTP transport response has no valid Content-Length');
|
|
68
|
+
}
|
|
69
|
+
return stream.read(length);
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=http-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-proxy.js","sourceRoot":"","sources":["../../src/net/http-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SocketStream } from './stream.js';
|
|
2
|
+
export declare class Socks5Error extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export interface Socks5Credentials {
|
|
6
|
+
readonly username?: string;
|
|
7
|
+
readonly password?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* SOCKS5 handshake + CONNECT (RFC 1928 / RFC 1929), as Telegram clients do it:
|
|
11
|
+
* offer username/password auth only when credentials are set, and connect to
|
|
12
|
+
* the DC by IP address.
|
|
13
|
+
*/
|
|
14
|
+
export declare const socks5Connect: (stream: SocketStream, host: string, port: number, credentials: Socks5Credentials, onStage?: (stage: string) => void) => Promise<void>;
|
|
15
|
+
//# sourceMappingURL=socks5.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socks5.d.ts","sourceRoot":"","sources":["../../src/net/socks5.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAaD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAsCD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,YAAY,EACpB,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,aAAa,iBAAiB,EAC9B,UAAS,CAAC,KAAK,EAAE,MAAM,KAAK,IAAe,KAC1C,OAAO,CAAC,IAAI,CA2Dd,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { isIPv4, isIPv6 } from 'net';
|
|
2
|
+
export class Socks5Error extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'Socks5Error';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const REPLY_MESSAGES = {
|
|
9
|
+
0x01: 'general SOCKS server failure',
|
|
10
|
+
0x02: 'connection not allowed by ruleset',
|
|
11
|
+
0x03: 'network unreachable',
|
|
12
|
+
0x04: 'host unreachable',
|
|
13
|
+
0x05: 'connection refused by destination',
|
|
14
|
+
0x06: 'TTL expired',
|
|
15
|
+
0x07: 'command not supported',
|
|
16
|
+
0x08: 'address type not supported',
|
|
17
|
+
};
|
|
18
|
+
const encodeAddress = (host) => {
|
|
19
|
+
if (isIPv4(host)) {
|
|
20
|
+
return Buffer.from([0x01, ...host.split('.').map(Number)]);
|
|
21
|
+
}
|
|
22
|
+
if (isIPv6(host)) {
|
|
23
|
+
const groups = expandIPv6(host);
|
|
24
|
+
const out = Buffer.alloc(17);
|
|
25
|
+
out[0] = 0x04;
|
|
26
|
+
groups.forEach((group, i) => out.writeUInt16BE(group, 1 + i * 2));
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
const name = Buffer.from(host, 'utf8');
|
|
30
|
+
if (name.length > 255) {
|
|
31
|
+
throw new Socks5Error('Destination host name too long');
|
|
32
|
+
}
|
|
33
|
+
return Buffer.concat([Buffer.from([0x03, name.length]), name]);
|
|
34
|
+
};
|
|
35
|
+
const expandIPv6 = (address) => {
|
|
36
|
+
const [head, tail] = address.split('::');
|
|
37
|
+
const parse = (part) => part ? part.split(':').filter(Boolean).map((group) => parseInt(group, 16)) : [];
|
|
38
|
+
const left = parse(head);
|
|
39
|
+
const right = parse(tail);
|
|
40
|
+
const zeros = tail === undefined ? [] : new Array(8 - left.length - right.length).fill(0);
|
|
41
|
+
return [...left, ...zeros, ...right];
|
|
42
|
+
};
|
|
43
|
+
const toLengthByte = (value, label) => {
|
|
44
|
+
const bytes = Buffer.from(value, 'utf8');
|
|
45
|
+
if (bytes.length > 255) {
|
|
46
|
+
throw new Socks5Error(`SOCKS5 ${label} is longer than 255 bytes`);
|
|
47
|
+
}
|
|
48
|
+
return Buffer.concat([Buffer.from([bytes.length]), bytes]);
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* SOCKS5 handshake + CONNECT (RFC 1928 / RFC 1929), as Telegram clients do it:
|
|
52
|
+
* offer username/password auth only when credentials are set, and connect to
|
|
53
|
+
* the DC by IP address.
|
|
54
|
+
*/
|
|
55
|
+
export const socks5Connect = async (stream, host, port, credentials, onStage = () => { }) => {
|
|
56
|
+
const hasAuth = Boolean(credentials.username || credentials.password);
|
|
57
|
+
onStage('SOCKS5 greeting');
|
|
58
|
+
stream.write(Buffer.from(hasAuth ? [0x05, 0x02, 0x00, 0x02] : [0x05, 0x01, 0x00]));
|
|
59
|
+
const choice = await stream.read(2);
|
|
60
|
+
if (choice[0] !== 0x05) {
|
|
61
|
+
throw new Socks5Error('Not a SOCKS5 server');
|
|
62
|
+
}
|
|
63
|
+
if (choice[1] === 0x02) {
|
|
64
|
+
if (!hasAuth) {
|
|
65
|
+
throw new Socks5Error('SOCKS5 proxy requires a username and password');
|
|
66
|
+
}
|
|
67
|
+
onStage('SOCKS5 authentication');
|
|
68
|
+
stream.write(Buffer.concat([
|
|
69
|
+
Buffer.from([0x01]),
|
|
70
|
+
toLengthByte(credentials.username ?? '', 'username'),
|
|
71
|
+
toLengthByte(credentials.password ?? '', 'password'),
|
|
72
|
+
]));
|
|
73
|
+
const status = await stream.read(2);
|
|
74
|
+
if (status[1] !== 0x00) {
|
|
75
|
+
throw new Socks5Error('SOCKS5 authentication failed (wrong username or password)');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (choice[1] === 0xff) {
|
|
79
|
+
throw new Socks5Error(hasAuth
|
|
80
|
+
? 'SOCKS5 proxy rejected all authentication methods'
|
|
81
|
+
: 'SOCKS5 proxy requires authentication');
|
|
82
|
+
}
|
|
83
|
+
else if (choice[1] !== 0x00) {
|
|
84
|
+
throw new Socks5Error(`SOCKS5 proxy chose unsupported auth method 0x${choice[1].toString(16)}`);
|
|
85
|
+
}
|
|
86
|
+
onStage('SOCKS5 connect');
|
|
87
|
+
const portBuffer = Buffer.alloc(2);
|
|
88
|
+
portBuffer.writeUInt16BE(port, 0);
|
|
89
|
+
stream.write(Buffer.concat([Buffer.from([0x05, 0x01, 0x00]), encodeAddress(host), portBuffer]));
|
|
90
|
+
const reply = await stream.read(4);
|
|
91
|
+
if (reply[0] !== 0x05) {
|
|
92
|
+
throw new Socks5Error('Invalid SOCKS5 connect reply');
|
|
93
|
+
}
|
|
94
|
+
if (reply[1] !== 0x00) {
|
|
95
|
+
throw new Socks5Error(`SOCKS5 connect to Telegram failed: ${REPLY_MESSAGES[reply[1]] ?? `error 0x${reply[1].toString(16)}`}`);
|
|
96
|
+
}
|
|
97
|
+
// Skip the bound address.
|
|
98
|
+
switch (reply[3]) {
|
|
99
|
+
case 0x01:
|
|
100
|
+
await stream.read(4 + 2);
|
|
101
|
+
break;
|
|
102
|
+
case 0x04:
|
|
103
|
+
await stream.read(16 + 2);
|
|
104
|
+
break;
|
|
105
|
+
case 0x03:
|
|
106
|
+
await stream.read((await stream.read(1))[0] + 2);
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
throw new Socks5Error('Invalid address type in SOCKS5 reply');
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=socks5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socks5.js","sourceRoot":"","sources":["../../src/net/socks5.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Socket } from 'net';
|
|
2
|
+
/**
|
|
3
|
+
* A byte pipe that higher layers (fake TLS, obfuscation) can stack on.
|
|
4
|
+
*/
|
|
5
|
+
export interface Pipe {
|
|
6
|
+
write(data: Buffer): void;
|
|
7
|
+
read(length: number): Promise<Buffer>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Raised when the remote side closes the connection.
|
|
11
|
+
*/
|
|
12
|
+
export declare class StreamClosedError extends Error {
|
|
13
|
+
constructor();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Promise-based wrapper around a TCP socket: exact-length reads, and a single
|
|
17
|
+
* `fail()` entry point used for timeouts and aborts.
|
|
18
|
+
*
|
|
19
|
+
* Buffered data is always delivered before a close/error is reported, so a
|
|
20
|
+
* server that answers and immediately hangs up is still read correctly.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SocketStream implements Pipe {
|
|
23
|
+
private buffer;
|
|
24
|
+
private pending;
|
|
25
|
+
private failure;
|
|
26
|
+
private connected;
|
|
27
|
+
readonly socket: Socket;
|
|
28
|
+
/**
|
|
29
|
+
* @param socket - existing socket; treated as connected unless `readyEvent` is given
|
|
30
|
+
* @param readyEvent - event that marks the socket as ready (e.g. 'secureConnect' for TLS)
|
|
31
|
+
*/
|
|
32
|
+
constructor(socket?: Socket, readyEvent?: string);
|
|
33
|
+
connect(host: string, port: number): Promise<void>;
|
|
34
|
+
/** Resolves once the socket is connected (or its ready event fired). */
|
|
35
|
+
ready(): Promise<void>;
|
|
36
|
+
write(data: Buffer): void;
|
|
37
|
+
read(length: number): Promise<Buffer>;
|
|
38
|
+
/**
|
|
39
|
+
* Read up to and including `delimiter`. Fails if it does not show up within `maxLength` bytes.
|
|
40
|
+
*/
|
|
41
|
+
readUntil(delimiter: Buffer, maxLength: number): Promise<Buffer>;
|
|
42
|
+
/**
|
|
43
|
+
* Read everything until the remote side closes the connection.
|
|
44
|
+
*/
|
|
45
|
+
readToEnd(maxLength: number): Promise<Buffer>;
|
|
46
|
+
/**
|
|
47
|
+
* Abort the stream: pending and future reads reject with `err`.
|
|
48
|
+
* Only the first failure is kept.
|
|
49
|
+
*/
|
|
50
|
+
fail(err: Error): void;
|
|
51
|
+
destroy(): void;
|
|
52
|
+
private waitFor;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/net/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,IAAI;IACvC,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,SAAS,CAAU;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAgBhD,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,wEAAwE;IACxE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMzB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWrC;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBhE;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAc7C;;;OAGG;IACH,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI;IAQtB,OAAO,IAAI,IAAI;IAIf,OAAO,CAAC,OAAO;CAwBhB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Socket } from 'net';
|
|
2
|
+
/**
|
|
3
|
+
* Raised when the remote side closes the connection.
|
|
4
|
+
*/
|
|
5
|
+
export class StreamClosedError extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('Connection closed by remote');
|
|
8
|
+
this.name = 'StreamClosedError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Promise-based wrapper around a TCP socket: exact-length reads, and a single
|
|
13
|
+
* `fail()` entry point used for timeouts and aborts.
|
|
14
|
+
*
|
|
15
|
+
* Buffered data is always delivered before a close/error is reported, so a
|
|
16
|
+
* server that answers and immediately hangs up is still read correctly.
|
|
17
|
+
*/
|
|
18
|
+
export class SocketStream {
|
|
19
|
+
buffer = Buffer.alloc(0);
|
|
20
|
+
pending = null;
|
|
21
|
+
failure = null;
|
|
22
|
+
connected;
|
|
23
|
+
socket;
|
|
24
|
+
/**
|
|
25
|
+
* @param socket - existing socket; treated as connected unless `readyEvent` is given
|
|
26
|
+
* @param readyEvent - event that marks the socket as ready (e.g. 'secureConnect' for TLS)
|
|
27
|
+
*/
|
|
28
|
+
constructor(socket, readyEvent) {
|
|
29
|
+
this.socket = socket ?? new Socket();
|
|
30
|
+
this.connected = socket !== undefined && readyEvent === undefined;
|
|
31
|
+
this.socket.setNoDelay(true);
|
|
32
|
+
this.socket.on(readyEvent ?? 'connect', () => {
|
|
33
|
+
this.connected = true;
|
|
34
|
+
this.pending?.();
|
|
35
|
+
});
|
|
36
|
+
this.socket.on('data', (chunk) => {
|
|
37
|
+
this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
|
|
38
|
+
this.pending?.();
|
|
39
|
+
});
|
|
40
|
+
this.socket.on('error', (err) => this.fail(err));
|
|
41
|
+
this.socket.on('close', () => this.fail(new StreamClosedError()));
|
|
42
|
+
}
|
|
43
|
+
connect(host, port) {
|
|
44
|
+
if (!this.failure) {
|
|
45
|
+
this.socket.connect({ host, port });
|
|
46
|
+
}
|
|
47
|
+
return this.ready();
|
|
48
|
+
}
|
|
49
|
+
/** Resolves once the socket is connected (or its ready event fired). */
|
|
50
|
+
ready() {
|
|
51
|
+
return this.waitFor(() => (this.connected ? true : undefined)).then(() => undefined);
|
|
52
|
+
}
|
|
53
|
+
write(data) {
|
|
54
|
+
if (!this.failure && data.length > 0) {
|
|
55
|
+
this.socket.write(data);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
read(length) {
|
|
59
|
+
return this.waitFor(() => {
|
|
60
|
+
if (this.buffer.length < length) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const out = Buffer.from(this.buffer.subarray(0, length));
|
|
64
|
+
this.buffer = this.buffer.subarray(length);
|
|
65
|
+
return out;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read up to and including `delimiter`. Fails if it does not show up within `maxLength` bytes.
|
|
70
|
+
*/
|
|
71
|
+
readUntil(delimiter, maxLength) {
|
|
72
|
+
return this.waitFor(() => {
|
|
73
|
+
const index = this.buffer.indexOf(delimiter);
|
|
74
|
+
if (index === -1) {
|
|
75
|
+
if (this.buffer.length > maxLength) {
|
|
76
|
+
throw new Error('Response header too large');
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const end = index + delimiter.length;
|
|
81
|
+
const out = Buffer.from(this.buffer.subarray(0, end));
|
|
82
|
+
this.buffer = this.buffer.subarray(end);
|
|
83
|
+
return out;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Read everything until the remote side closes the connection.
|
|
88
|
+
*/
|
|
89
|
+
readToEnd(maxLength) {
|
|
90
|
+
return this.waitFor(() => {
|
|
91
|
+
if (this.buffer.length > maxLength) {
|
|
92
|
+
throw new Error('Response body too large');
|
|
93
|
+
}
|
|
94
|
+
if (!(this.failure instanceof StreamClosedError)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
const out = Buffer.from(this.buffer);
|
|
98
|
+
this.buffer = Buffer.alloc(0);
|
|
99
|
+
return out;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Abort the stream: pending and future reads reject with `err`.
|
|
104
|
+
* Only the first failure is kept.
|
|
105
|
+
*/
|
|
106
|
+
fail(err) {
|
|
107
|
+
if (!this.failure) {
|
|
108
|
+
this.failure = err;
|
|
109
|
+
}
|
|
110
|
+
this.socket.destroy();
|
|
111
|
+
this.pending?.();
|
|
112
|
+
}
|
|
113
|
+
destroy() {
|
|
114
|
+
this.socket.destroy();
|
|
115
|
+
}
|
|
116
|
+
waitFor(attempt) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const tick = () => {
|
|
119
|
+
try {
|
|
120
|
+
const value = attempt();
|
|
121
|
+
if (value !== undefined) {
|
|
122
|
+
this.pending = null;
|
|
123
|
+
resolve(value);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
this.pending = null;
|
|
129
|
+
reject(err);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (this.failure) {
|
|
133
|
+
this.pending = null;
|
|
134
|
+
reject(this.failure);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
this.pending = tick;
|
|
138
|
+
tick();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/net/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HttpConnection } from './http-client.js';
|
|
2
|
+
export declare class WebSocketError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Minimal RFC 6455 client: binary messages only, answers pings.
|
|
7
|
+
*/
|
|
8
|
+
export declare class WebSocketConnection {
|
|
9
|
+
private readonly stream;
|
|
10
|
+
private constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Upgrade an HTTP/1.1 connection. The server must echo `protocol` exactly.
|
|
13
|
+
*/
|
|
14
|
+
static open(http: HttpConnection, path: string, protocol: string, origin: string): Promise<WebSocketConnection>;
|
|
15
|
+
send(data: Buffer, opcode?: number): void;
|
|
16
|
+
/** Next complete binary message. */
|
|
17
|
+
receive(): Promise<Buffer>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/net/websocket.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASvD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,mBAAmB;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;IAA3C,OAAO;IAEP;;OAEG;WACU,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBrH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAsB,GAAG,IAAI;IAuBxD,oCAAoC;IAC9B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CAoDjC"}
|