package faketls

import (
	
	
	
	

	
	utls 

	
)

// clientRandomOffset is the offset of the 32-byte ClientRandom field inside a
// TLS ClientHello record:
//
//	5 bytes record header (type + version + length)
//	1 byte  handshake type
//	3 bytes handshake length
//	2 bytes client version
const (
	clientRandomOffset = 11
	clientRandomLength = 32
)

// generateClientHello builds a browser-like TLS ClientHello record using uTLS.
//
// Instead of hand-crafting the bytes (as older clients did), we mimic the
// fingerprint of a recent Chrome release so that the handshake is
// indistinguishable from a real browser connecting to the cloak domain. uTLS
// tracks browser fingerprints upstream, keeping us in line with the approach
// taken by the official Telegram clients.
//
// See https://github.com/refraction-networking/utls and
// https://github.com/tdlib/td/blob/master/td/mtproto/TlsInit.cpp.
func ( io.Reader,  string) ([]byte, error) {
	 := &utls.Config{
		ServerName: ,
		// uTLS uses Rand for the ClientHello random, session ID and key shares.
		Rand: ,
	}

	// The connection is never used: BuildHandshakeState only assembles the
	// ClientHello in memory, it does not perform any I/O.
	 := utls.UClient(nil, , utls.HelloChrome_Auto)
	if  := .BuildHandshakeState();  != nil {
		return nil, errors.Wrap(, "build handshake state")
	}

	 := .HandshakeState.Hello.Raw
	// hello is the handshake message; wrap it into a TLS handshake record.
	 := make([]byte, 0, 5+len())
	 = append(, byte(RecordTypeHandshake), Version10Bytes[0], Version10Bytes[1])
	 = binary.BigEndian.AppendUint16(, uint16(len()))
	 = append(, ...)
	return , nil
}

// writeClientHello writes faketls ClientHello.
//
// The ClientHello carries the MTProxy digest in its ClientRandom field: the
// HMAC-SHA256 of the whole record (computed with the ClientRandom zeroed) using
// the proxy secret as key, with the lower 4 bytes XORed with the current
// timestamp.
//
// See https://github.com/tdlib/td/blob/27d3fdd09d90f6b77ecbcce50b1e86dc4b3dd366/td/mtproto/TlsInit.cpp#L380-L384
// and https://tools.ietf.org/html/rfc5246#section-7.4.1.1.
func (
	 io.Writer,
	 io.Reader,
	 clock.Clock,
	 string,
	 []byte,
) ( [32]byte,  error) {
	,  := generateClientHello(, )
	if  != nil {
		return [32]byte{}, errors.Wrap(, "generate ClientHello")
	}
	if len() < clientRandomOffset+clientRandomLength {
		return [32]byte{}, errors.Errorf("ClientHello is too short: %d bytes", len())
	}

	 := [clientRandomOffset : clientRandomOffset+clientRandomLength]
	// Zero the ClientRandom before computing the digest, exactly as the proxy
	// does when it validates the handshake.
	for  := range  {
		[] = 0
	}

	 := hmac.New(sha256.New, )
	if ,  := .Write();  != nil {
		return [32]byte{}, errors.Wrap(, "hmac write")
	}
	copy(, .Sum(nil))

	// Overwrite last 4 bytes using final := original ^ timestamp.
	 := binary.LittleEndian.Uint32([clientRandomLength-4:])
	 ^= uint32(.Now().Unix())
	binary.LittleEndian.PutUint32([clientRandomLength-4:], )

	// Copy ClientRandom for later use.
	copy([:], )
	_,  = .Write()
	return , 
}