// /* eslint-disable no-restricted-globals */ // todo fixme // import type { IPacketCodec } from '@mtcute/node' // import { WrappedCodec } from '@mtcute/node' // import type { ICryptoProvider } from '@mtcute/node/utils.js' // import { bigIntModInv, bigIntModPow, bigIntToBuffer, bufferToBigInt } from '@mtcute/node/utils.js' // const MAX_TLS_PACKET_LENGTH = 2878 // const TLS_FIRST_PREFIX = Buffer.from('140303000101', 'hex') // // ref: https://github.com/tdlib/td/blob/master/td/mtproto/TlsInit.cpp // const KEY_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn // // 2^255 - 19 // const QUAD_RES_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn // // (mod - 1) / 2 = 2^254 - 10 // const QUAD_RES_POW = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6n // function _getY2(x: bigint, mod: bigint): bigint { // // returns y = x^3 + x^2 * 486662 + x // let y = x // y = (y + 486662n) % mod // y = (y * x) % mod // y = (y + 1n) % mod // y = (y * x) % mod // return y // } // function _getDoubleX(x: bigint, mod: bigint): bigint { // // returns x_2 = (x^2 - 1)^2/(4*y^2) // let denominator = _getY2(x, mod) // denominator = (denominator * 4n) % mod // let numerator = (x * x) % mod // numerator = (numerator - 1n) % mod // numerator = (numerator * numerator) % mod // denominator = bigIntModInv(denominator, mod) // numerator = (numerator * denominator) % mod // return numerator // } // function _isQuadraticResidue(a: bigint): boolean { // const r = bigIntModPow(a, QUAD_RES_POW, QUAD_RES_MOD) // return r === 1n // } // interface TlsOperationHandler { // string: (buf: Buffer) => void // zero: (size: number) => void // random: (size: number) => void // domain: () => void // grease: (seed: number) => void // beginScope: () => void // endScope: () => void // key: () => void // } // function executeTlsOperations(h: TlsOperationHandler): void { // h.string(Buffer.from('1603010200010001fc0303', 'hex')) // h.zero(32) // h.string(Buffer.from('20', 'hex')) // h.random(32) // h.string(Buffer.from('0020', 'hex')) // h.grease(0) // h.string(Buffer.from('130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f003501000193', 'hex')) // h.grease(2) // h.string(Buffer.from('00000000', 'hex')) // h.beginScope() // h.beginScope() // h.string(Buffer.from('00', 'hex')) // h.beginScope() // h.domain() // h.endScope() // h.endScope() // h.endScope() // h.string(Buffer.from('00170000ff01000100000a000a0008', 'hex')) // h.grease(4) // h.string( // Buffer.from( // '001d00170018000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d0012001004030804040105030805050108060601001200000033002b0029', // 'hex', // ), // ) // h.grease(4) // h.string(Buffer.from('000100001d0020', 'hex')) // h.key() // h.string(Buffer.from('002d00020101002b000b0a', 'hex')) // h.grease(6) // h.string(Buffer.from('0304030303020301001b0003020002', 'hex')) // h.grease(3) // h.string(Buffer.from('0001000015', 'hex')) // } // // i dont know why is this needed, since it is always padded to 517 bytes // // this was in tdlib sources, so whatever. not used here though, and works just fine // // class TlsHelloCounter implements TlsOperationHandler { // // size = 0 // // // // private _domain: Buffer // // // // constructor(domain: Buffer) { // // this._domain = domain // // } // // // // string(buf: Buffer) { // // this.size += buf.length // // } // // // // random(size: number) { // // this.size += size // // } // // // // zero(size: number) { // // this.size += size // // } // // // // domain() { // // this.size += this._domain.length // // } // // // // grease() { // // this.size += 2 // // } // // // // key() { // // this.size += 32 // // } // // // // beginScope() { // // this.size += 2 // // } // // // // endScope() { // // // no-op, since this does not affect size // // } // // // // finish(): number { // // const zeroPad = 515 - this.size // // this.beginScope() // // this.zero(zeroPad) // // this.endScope() // // // // return this.size // // } // // } // function initGrease(crypto: ICryptoProvider, size: number): Buffer { // const buf = crypto.randomBytes(size) // for (let i = 0; i < size; i++) { // buf[i] = (buf[i] & 0xF0) + 0x0A // } // for (let i = 1; i < size; i += 2) { // if (buf[i] === buf[i - 1]) { // buf[i] ^= 0x10 // } // } // return Buffer.from(buf) // } // class TlsHelloWriter implements TlsOperationHandler { // buf: Buffer // pos = 0 // private _domain: Buffer // private _grease // private _scopes: number[] = [] // constructor( // readonly crypto: ICryptoProvider, // size: number, // domain: Buffer, // ) { // this._domain = domain // this.buf = Buffer.allocUnsafe(size) // this._grease = initGrease(this.crypto, 7) // } // string(buf: Buffer) { // buf.copy(this.buf, this.pos) // this.pos += buf.length // } // random(size: number) { // this.string(Buffer.from(this.crypto.randomBytes(size))) // } // zero(size: number) { // this.string(Buffer.alloc(size, 0)) // } // domain() { // this.string(this._domain) // } // grease(seed: number) { // this.buf[this.pos] = this.buf[this.pos + 1] = this._grease[seed] // this.pos += 2 // } // key() { // for (;;) { // const key = this.crypto.randomBytes(32) // key[31] &= 127 // let x = bufferToBigInt(key) // const y = _getY2(x, KEY_MOD) // if (_isQuadraticResidue(y)) { // for (let i = 0; i < 3; i++) { // x = _getDoubleX(x, KEY_MOD) // } // const key = bigIntToBuffer(x, 32, true) // this.string(Buffer.from(key)) // return // } // } // } // beginScope() { // this._scopes.push(this.pos) // this.pos += 2 // } // endScope() { // const begin = this._scopes.pop() // if (begin === undefined) { // throw new Error('endScope called without beginScope') // } // const end = this.pos // const size = end - begin - 2 // this.buf.writeUInt16BE(size, begin) // } // async finish(secret: Buffer): Promise { // const padSize = 515 - this.pos // const unixTime = ~~(Date.now() / 1000) // this.beginScope() // this.zero(padSize) // this.endScope() // const hash = Buffer.from(await this.crypto.hmacSha256(this.buf, secret)) // const old = hash.readInt32LE(28) // hash.writeInt32LE(old ^ unixTime, 28) // hash.copy(this.buf, 11) // return this.buf // } // } // /** @internal */ // export async function generateFakeTlsHeader(domain: string, secret: Buffer, crypto: ICryptoProvider): Promise { // const domainBuf = Buffer.from(domain) // const writer = new TlsHelloWriter(crypto, 517, domainBuf) // executeTlsOperations(writer) // return writer.finish(secret) // } // /** // * Fake TLS packet codec, used for some MTProxies. // * // * Must only be used inside {@link MtProxyTcpTransport} // * @internal // */ // export class FakeTlsPacketCodec extends WrappedCodec implements IPacketCodec { // protected _stream: Buffer = Buffer.alloc(0) // private _header!: Buffer // private _isFirstTls = true // async tag(): Promise { // this._header = Buffer.from(await this._inner.tag()) // return Buffer.alloc(0) // } // private _encodeTls(packet: Buffer): Buffer { // if (this._header.length) { // packet = Buffer.concat([this._header, packet]) // this._header = Buffer.alloc(0) // } // const header = Buffer.from([0x17, 0x03, 0x03, 0x00, 0x00]) // header.writeUInt16BE(packet.length, 3) // if (this._isFirstTls) { // this._isFirstTls = false // return Buffer.concat([TLS_FIRST_PREFIX, header, packet]) // } // return Buffer.concat([header, packet]) // } // async encode(packet: Buffer): Promise { // packet = Buffer.from(await this._inner.encode(packet)) // if (packet.length + this._header.length > MAX_TLS_PACKET_LENGTH) { // const ret: Buffer[] = [] // while (packet.length) { // const buf = packet.slice(0, MAX_TLS_PACKET_LENGTH - this._header.length) // packet = packet.slice(buf.length) // ret.push(this._encodeTls(buf)) // } // return Buffer.concat(ret) // } // return this._encodeTls(packet) // } // feed(data: Buffer): void { // this._stream = Buffer.concat([this._stream, data]) // for (;;) { // if (this._stream.length < 5) return // if (!(this._stream[0] === 0x17 && this._stream[1] === 0x03 && this._stream[2] === 0x03)) { // this.emit('error', new Error('Invalid TLS header')) // return // } // const length = this._stream.readUInt16BE(3) // if (length < this._stream.length - 5) return // this._inner.feed(this._stream.slice(5, length + 5)) // this._stream = this._stream.slice(length + 5) // } // } // reset(): void { // this._stream = Buffer.alloc(0) // this._isFirstTls = true // } // }