import { isNode } from "browser-or-node" ; import bigInt from "big-integer" ; import type { EntityLike } from "./define" ; import type { Api } from "./tl" ; export const IS_NODE = isNode ; const crypto = require ( isNode ? "crypto" : "./crypto/crypto" ) ; param buffer param little param signed returns { bigInt . BigInteger } export function readBigIntFromBuffer ( buffer , little = true , signed = false ) { let randBuffer = Buffer . from ( buffer ) ; const bytesNumber = randBuffer . length ; if ( little ) { randBuffer = randBuffer . reverse ( ) ; } let bigIntVar = bigInt ( randBuffer . toString ( "hex" ) , 16 ) as bigInt . BigInteger ; if ( signed && Math . floor ( bigIntVar . toString ( 2 ) . length / 8 ) >= bytesNumber ) { bigIntVar = bigIntVar . subtract ( bigInt ( 2 ) . pow ( bigInt ( bytesNumber * 8 ) ) ) ; } return bigIntVar ; } export function generateRandomBigInt ( ) { return readBigIntFromBuffer ( generateRandomBytes ( 8 ) , false ) ; } export function escapeRegex ( string ) { return string . replace ( /[-\/\\^$*+?.()|[\]{}]/g , "\\$&" ) ; } export function groupBy ( list , keyGetter ) { const map = new Map ( ) ; list . forEach ( ( item ) => { const key = keyGetter ( item ) ; const collection = map . get ( key ) ; if ( ! collection ) { map . set ( key , [ item ] ) ; } else { collection . push ( item ) ; } } ) ; return map ; } param object export function betterConsoleLog ( object ) { const toPrint = { } ; for ( const key in object ) { if ( object . hasOwnProperty ( key ) ) { if ( ! key . startsWith ( "_" ) && key != "originalArgs" ) { toPrint [ key ] = object [ key ] ; } } } return toPrint ; } /**
 * Helper to find if a given object is an array (or similar)
 */ export const isArrayLike = < T > ( x ) : x is Array < T > => x && typeof x . length === "number" && typeof x !== "function" && typeof x !== "string" ; param big param number returns { Buffer } export function toSignedLittleBuffer ( big , number = 8 ) { const bigNumber = returnBigInt ( big ) ; const byteArray = [ ] ; for ( let i = 0 ; i < number ; i ++ ) { byteArray [ i ] = bigNumber . shiftRight ( 8 * i ) . and ( 255 ) ; } return Buffer . from ( byteArray as unknown as number [ ] ) ; } param bigIntVar { BigInteger } param bytesNumber param little param signed returns { Buffer } export function readBufferFromBigInt ( bigIntVar , bytesNumber , little = true , signed = false ) { bigIntVar = bigInt ( bigIntVar ) ; const bitLength = bigIntVar . bitLength ( ) . toJSNumber ( ) ; const bytes = Math . ceil ( bitLength / 8 ) ; if ( bytesNumber < bytes ) { throw new Error ( "OverflowError: int too big to convert" ) ; } if ( ! signed && bigIntVar . lesser ( BigInt ( 0 ) ) ) { throw new Error ( "Cannot convert to unsigned" ) ; } let below = false ; if ( bigIntVar . lesser ( BigInt ( 0 ) ) ) { below = true ; bigIntVar = bigIntVar . abs ( ) ; } const hex = bigIntVar . toString ( 16 ) . padStart ( bytesNumber * 2 , "0" ) ; let littleBuffer = Buffer . from ( hex , "hex" ) ; if ( little ) { littleBuffer = littleBuffer . reverse ( ) ; } if ( signed && below ) { if ( little ) { let reminder = false ; if ( littleBuffer [ 0 ] !== 0 ) { littleBuffer [ 0 ] -= 1 ; } for ( let i = 0 ; i < littleBuffer . length ; i ++ ) { if ( littleBuffer [ i ] === 0 ) { reminder = true ; continue ; } if ( reminder ) { littleBuffer [ i ] -= 1 ; reminder = false ; } littleBuffer [ i ] = 255 - littleBuffer [ i ] ; } } else { littleBuffer [ littleBuffer . length - 1 ] = 256 - littleBuffer [ littleBuffer . length - 1 ] ; for ( let i = 0 ; i < littleBuffer . length - 1 ; i ++ ) { littleBuffer [ i ] = 255 - littleBuffer [ i ] ; } } } return littleBuffer ; } returns { BigInteger } export function generateRandomLong ( signed = true ) { return readBigIntFromBuffer ( generateRandomBytes ( 8 ) , true , signed ) ; } param n { number } param m { number } returns { number } export function mod ( n , m ) { return ( ( n % m ) + m ) % m ; } param n { bigInt . BigInteger } param m { bigInt . BigInteger } returns { bigInt . BigInteger } export function bigIntMod ( n , m ) { return n . remainder ( m ) . add ( m ) . remainder ( m ) ; } param count returns { Buffer } export function generateRandomBytes ( count ) { return Buffer . from ( crypto . randomBytes ( count ) ) ; } param sharedKey param msgKey param client returns { { iv : Buffer , key : Buffer } } export function stripText ( text , entities ) { if ( ! entities || ! entities . length ) { return text . trim ( ) ; } while ( text && text [ text . length - 1 ] . trim ( ) === "" ) { const e = entities [ entities . length - 1 ] ; if ( e . offset + e . length == text . length ) { if ( e . length == 1 ) { entities . pop ( ) ; if ( ! entities . length ) { return text . trim ( ) ; } } else { e . length -= 1 ; } } text = text . slice ( 0 , - 1 ) ; } while ( text && text [ 0 ] . trim ( ) === "" ) { for ( let i = 0 ; i < entities . length ; i ++ ) { const e = entities [ i ] ; if ( e . offset != 0 ) { e . offset -- ; continue ; } if ( e . length == 1 ) { entities . shift ( ) ; if ( ! entities . length ) { return text . trimLeft ( ) ; } } else { e . length -= 1 ; } } text = text . slice ( 1 ) ; } return text ; } param serverNonceBigInt param newNonceBigInt returns { { key : Buffer , iv : Buffer } } export async function generateKeyDataFromNonce ( serverNonceBigInt , newNonceBigInt ) { const serverNonce = toSignedLittleBuffer ( serverNonceBigInt , 16 ) ; const newNonce = toSignedLittleBuffer ( newNonceBigInt , 32 ) ; const [ hash1 , hash2 , hash3 ] = await Promise . all ( [ sha1 ( Buffer . concat ( [ newNonce , serverNonce ] ) ) , sha1 ( Buffer . concat ( [ serverNonce , newNonce ] ) ) , sha1 ( Buffer . concat ( [ newNonce , newNonce ] ) ) , ] ) ; const keyBuffer = Buffer . concat ( [ hash1 , hash2 . slice ( 0 , 12 ) ] ) ; const ivBuffer = Buffer . concat ( [ hash2 . slice ( 12 , 20 ) , hash3 , newNonce . slice ( 0 , 4 ) , ] ) ; return { key : keyBuffer , iv : ivBuffer , } ; } export function convertToLittle ( buf ) { const correct = Buffer . alloc ( buf . length * 4 ) ; for ( let i = 0 ; i < buf . length ; i ++ ) { correct . writeUInt32BE ( buf [ i ] , i * 4 ) ; } return correct ; } param data returns { Promise } export function sha1 ( data ) { const shaSum = crypto . createHash ( "sha1" ) ; shaSum . update ( data ) ; return shaSum . digest ( ) ; } param data returns { Promise } export function sha256 ( data ) { const shaSum = crypto . createHash ( "sha256" ) ; shaSum . update ( data ) ; return shaSum . digest ( ) ; } param a param b param n returns { bigInt . BigInteger } export function modExp ( a , b , n ) { a = a . remainder ( n ) ; let result = bigInt . one ; let x = a ; while ( b . greater ( bigInt . zero ) ) { const leastSignificantBit = b . remainder ( BigInt ( 2 ) ) ; b = b . divide ( BigInt ( 2 ) ) ; if ( leastSignificantBit . eq ( bigInt . one ) ) { result = result . multiply ( x ) ; result = result . remainder ( n ) ; } x = x . multiply ( x ) ; x = x . remainder ( n ) ; } return result ; } param integer { number param signed { boolean } returns { Buffer } export function getByteArray ( integer , signed = false ) { const bits = integer . toString ( 2 ) . length ; const byteLength = Math . floor ( ( bits + 8 - 1 ) / 8 ) ; return readBufferFromBigInt ( typeof integer == "number" ? bigInt ( integer ) : integer , byteLength , false , signed ) ; } export function returnBigInt ( num ) { if ( bigInt . isInstance ( num ) ) { return num ; } if ( typeof num == "number" ) { return bigInt ( num ) ; } if ( typeof num == "bigint" ) { return bigInt ( num ) ; } return bigInt ( num ) ; } param arrayOfBigInts export function getMinBigInt ( arrayOfBigInts ) { if ( arrayOfBigInts . length == 0 ) { return bigInt . zero ; } if ( arrayOfBigInts . length == 1 ) { return returnBigInt ( arrayOfBigInts [ 0 ] ) ; } let smallest = returnBigInt ( arrayOfBigInts [ 0 ] ) ; for ( let i = 1 ; i < arrayOfBigInts . length ; i ++ ) { if ( returnBigInt ( arrayOfBigInts [ i ] ) . lesser ( smallest ) ) { smallest = returnBigInt ( arrayOfBigInts [ i ] ) ; } } return smallest ; } param min param max returns { number } export function getRandomInt ( min , max ) { min = Math . ceil ( min ) ; max = Math . floor ( max ) ; return Math . floor ( Math . random ( ) * ( max - min + 1 ) ) + min ; } param ms returns { Promise } export const sleep = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ; returns { Buffer } export function bufferXor ( a , b ) { const res = [ ] ; for ( let i = 0 ; i < a . length ; i ++ ) { res . push ( a [ i ] ^ b [ i ] ) ; } return Buffer . from ( res ) ; } function makeCRCTable ( ) { let c ; const crcTable = [ ] ; for ( let n = 0 ; n < 256 ; n ++ ) { c = n ; for ( let k = 0 ; k < 8 ; k ++ ) { c = c & 1 ? 0xedb88320 ^ ( c >>> 1 ) : c >>> 1 ; } crcTable [ n ] = c ; } return crcTable ; } let crcTable = undefined ; export function crc32 ( buf ) { if ( ! crcTable ) { crcTable = makeCRCTable ( ) ; } if ( ! Buffer . isBuffer ( buf ) ) { buf = Buffer . from ( buf ) ; } let crc = - 1 ; for ( let index = 0 ; index < buf . length ; index ++ ) { const byte = buf [ index ] ; crc = crcTable [ ( crc ^ byte ) & 0xff ] ^ ( crc >>> 8 ) ; } return ( crc ^ - 1 ) >>> 0 ; } export class TotalList < T > extends Array < T > { public total ? : number ; constructor ( ) { super ( ) ; this . total = 0 ; } } export const _EntityType = { USER : 0 , CHAT : 1 , CHANNEL : 2 , } ; Object . freeze ( _EntityType ) ; export function _entityType ( entity ) { if ( typeof entity !== "object" || ! ( "SUBCLASS_OF_ID" in entity ) ) { throw new Error ( `${ entity } is not a TLObject, cannot determine entity type` ) ; } if ( ! [ 0x2d45687 , 0xc91c90b6 , 0xe669bf46 , 0x40f202fd , 0x2da17977 , 0xc5af5d94 , 0x1f4661b9 , 0xd49a2697 , ] . includes ( entity . SUBCLASS_OF_ID ) ) { throw new Error ( `${ entity } does not have any entity type` ) ; } const name = entity . className ; if ( name . includes ( "User" ) ) { return _EntityType . USER ; } else if ( name . includes ( "Chat" ) ) { return _EntityType . CHAT ; } else if ( name . includes ( "Channel" ) ) { return _EntityType . CHANNEL ; } else if ( name . includes ( "Self" ) ) { return _EntityType . USER ; } throw new Error ( `${ entity } does not have any entity type` ) ; }