diff --git a/src/lib/appManagers/apiUpdatesManager.ts b/src/lib/appManagers/apiUpdatesManager.ts index b40e6357..f70fa2b5 100644 --- a/src/lib/appManagers/apiUpdatesManager.ts +++ b/src/lib/appManagers/apiUpdatesManager.ts @@ -20,6 +20,7 @@ import appUsersManager from "./appUsersManager"; import appChatsManager from "./appChatsManager"; import appPeersManager from "./appPeersManager"; import appStateManager from './appStateManager'; +import serverTimeManager from '../mtproto/serverTimeManager'; type UpdatesState = { pendingPtsUpdates: {pts: number, pts_count: number}[], @@ -302,8 +303,8 @@ export class ApiUpdatesManager { updatesState.date = nextState.date; } else { updatesState.pts = differenceResult.pts; + updatesState.date = (Date.now() / 1000 | 0) + serverTimeManager.serverTimeOffset; delete updatesState.seq; - delete updatesState.date; this.channelStates = {}; diff --git a/src/lib/mtproto/authorizer.ts b/src/lib/mtproto/authorizer.ts index 76596e04..e5593aef 100644 --- a/src/lib/mtproto/authorizer.ts +++ b/src/lib/mtproto/authorizer.ts @@ -20,6 +20,7 @@ import { logger, LogTypes } from "../logger"; import { bytesCmp, bytesToHex, bytesFromHex, bytesXor } from "../../helpers/bytes"; import DEBUG from "../../config/debug"; import { cmp, int2bigInt, one, pow, str2bigInt, sub } from "../../vendor/leemon"; +import { Awaited } from "../../types"; /* let fNewNonce: any = bytesFromHex('8761970c24cb2329b5b2459752c502f3057cb7e8dbab200e526e8767fdc73b3c').reverse(); let fNonce: any = bytesFromHex('b597720d11faa5914ef485c529cde414').reverse(); @@ -91,11 +92,11 @@ export class Authorizer { resultArray.set(headerArray); resultArray.set(requestArray, headerArray.length); - /* var headerBuffer = header.getBuffer(), + /* const headerBuffer = header.getBuffer(), headerArray = new Int32Array(headerBuffer); - var headerLength = headerBuffer.byteLength; + const headerLength = headerBuffer.byteLength; - var resultBuffer = new ArrayBuffer(headerLength + requestLength), + const resultBuffer = new ArrayBuffer(headerLength + requestLength), resultArray = new Int32Array(resultBuffer); resultArray.set(headerArray); @@ -155,7 +156,7 @@ export class Authorizer { } public async mtpSendReqPQ(auth: AuthOptions) { - var request = new TLSerialization({mtproto: true}); + const request = new TLSerialization({mtproto: true}); request.storeMethod('req_pq_multi', {nonce: auth.nonce}); @@ -165,14 +166,16 @@ export class Authorizer { if(DEBUG) { this.log('Send req_pq', auth.nonce.hex); } + + let deserializer: TLDeserialization; try { - var deserializer = await this.mtpSendPlainRequest(auth.dcId, request.getBytes(true)); + deserializer = await this.mtpSendPlainRequest(auth.dcId, request.getBytes(true)); } catch(error) { this.log.error('req_pq error', error.message); throw error; } - var response = deserializer.fetchObject('ResPQ'); + const response = deserializer.fetchObject('ResPQ'); if(response._ !== 'resPQ') { throw new Error('[MT] resPQ response invalid: ' + response._); @@ -192,7 +195,7 @@ export class Authorizer { this.log('Got ResPQ', bytesToHex(auth.serverNonce), bytesToHex(auth.pq), auth.fingerprints); } - let publicKey = await rsaKeysManager.select(auth.fingerprints); + const publicKey = await rsaKeysManager.select(auth.fingerprints); if(!publicKey) { throw new Error('[MT] No public key found'); } @@ -203,8 +206,9 @@ export class Authorizer { this.log('PQ factorization start', auth.pq); } + let pAndQ: Awaited>; try { - var pAndQ = await CryptoWorker.factorize(auth.pq); + pAndQ = await CryptoWorker.factorize(auth.pq); } catch(error) { this.log.error('worker error factorize', error); throw error; @@ -216,8 +220,8 @@ export class Authorizer { if(DEBUG) { this.log('PQ factorization done', pAndQ); } - /* let p = new Uint32Array(new Uint8Array(auth.p).buffer)[0]; - let q = new Uint32Array(new Uint8Array(auth.q).buffer)[0]; + /* const p = new Uint32Array(new Uint8Array(auth.p).buffer)[0]; + const q = new Uint32Array(new Uint8Array(auth.q).buffer)[0]; console.log(dT(), 'PQ factorization done', pAndQ, p.toString(16), q.toString(16)); */ return this.mtpSendReqDhParams(auth); @@ -234,7 +238,7 @@ export class Authorizer { // auth.newNonce = fNewNonce ? fNewNonce : auth.newNonce; // console.log("TCL: Authorizer -> mtpSendReqDhParams -> auth.newNonce", auth.newNonce); - let p_q_inner_data = { + const p_q_inner_data = { _: 'p_q_inner_data', pq: auth.pq, p: auth.p, @@ -244,29 +248,28 @@ export class Authorizer { new_nonce: auth.newNonce }; - let data = new TLSerialization({mtproto: true}); + const data = new TLSerialization({mtproto: true}); data.storeObject(p_q_inner_data, 'P_Q_inner_data', 'DECRYPTED_DATA'); /* console.log('p_q_inner_data', p_q_inner_data, bytesToHex(bytesFromArrayBuffer(data.getBuffer())), sha1BytesSync(data.getBuffer()), bytesFromArrayBuffer(await CryptoWorker.sha1Hash(data.getBuffer()))); */ - let uint8Data = data.getBytes(true); - let sha1Hashed = await CryptoWorker.sha1Hash(uint8Data); + const uint8Data = data.getBytes(true); + const sha1Hashed = await CryptoWorker.sha1Hash(uint8Data); - //var dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes() as number[]); - let dataWithHash = sha1Hashed.concat(uint8Data); + //const dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes() as number[]); + const dataWithHash = sha1Hashed.concat(uint8Data); //dataWithHash = addPadding(dataWithHash, 255); //dataWithHash = dataWithHash.concat(bytesFromHex('96228ea7790e71caaabc2ab67f4412e9aa224c664d232cc08617a32ce1796aa052da4a737083211689858f461e4473fd6394afd3aa0c8014840dc13f47beaf4fc3b9229aea9cfa83f9f6e676e50ee7676542fb75606879ee7e65cf3a2295b4ba0934ceec1011560c62395a6e9593bfb117cd0da75ba56723672d100ac17ec4d805aa59f7852e3a25a79ee4')); //console.log('sha1Hashed', bytesToHex(sha1Hashed), 'dataWithHash', bytesToHex(dataWithHash), dataWithHash.length); - let rsaEncrypted = await CryptoWorker.rsaEncrypt(auth.publicKey, dataWithHash); - //let rsaEncrypted = await CryptoWorker.rsaEncrypt(auth.publicKey, dataWithHash); + const rsaEncrypted = await CryptoWorker.rsaEncrypt(auth.publicKey, dataWithHash); //console.log('rsaEncrypted', rsaEncrypted, new Uint8Array(rsaEncrypted).hex); - let req_DH_params = { + const req_DH_params = { nonce: auth.nonce, server_nonce: auth.serverNonce, p: auth.p, @@ -275,23 +278,24 @@ export class Authorizer { encrypted_data: rsaEncrypted }; - var request = new TLSerialization({mtproto: true}); + const request = new TLSerialization({mtproto: true}); request.storeMethod('req_DH_params', req_DH_params); - let requestBytes = request.getBytes(true); + const requestBytes = request.getBytes(true); if(DEBUG) { this.log('Send req_DH_params', req_DH_params/* , requestBytes.hex */); } + let deserializer: TLDeserialization; try { - var deserializer = await this.mtpSendPlainRequest(auth.dcId, requestBytes); + deserializer = await this.mtpSendPlainRequest(auth.dcId, requestBytes); } catch(error) { this.log.error('Send req_DH_params FAIL!', error); throw error; } - var response = deserializer.fetchObject('Server_DH_Params', 'RESPONSE'); + const response = deserializer.fetchObject('Server_DH_Params', 'RESPONSE'); if(DEBUG) { this.log('Sent req_DH_params, response:', response); @@ -310,8 +314,8 @@ export class Authorizer { } if(response._ === 'server_DH_params_fail') { - //var newNonceHash = sha1BytesSync(auth.newNonce).slice(-16); - var newNonceHash = (await CryptoWorker.sha1Hash(auth.newNonce)).slice(-16); + //const newNonceHash = sha1BytesSync(auth.newNonce).slice(-16); + const newNonceHash = (await CryptoWorker.sha1Hash(auth.newNonce)).slice(-16); if(!bytesCmp(newNonceHash, response.new_nonce_hash)) { throw new Error('[MT] server_DH_params_fail new_nonce_hash mismatch'); } @@ -350,16 +354,16 @@ export class Authorizer { console.log(auth.newNonce.concat(auth.newNonce)); */ - //var answerWithHash = aesDecryptSync(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv); - var answerWithHash = new Uint8Array(await CryptoWorker.aesDecrypt(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv)); + //const answerWithHash = aesDecryptSync(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv); + const answerWithHash = new Uint8Array(await CryptoWorker.aesDecrypt(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv)); - var hash = answerWithHash.slice(0, 20); - var answerWithPadding = answerWithHash.slice(20); + const hash = answerWithHash.slice(0, 20); + const answerWithPadding = answerWithHash.slice(20); // console.log('hash', hash); - var deserializer = new TLDeserialization(answerWithPadding, {mtproto: true}); - var response = deserializer.fetchObject('Server_DH_inner_data'); + const deserializer = new TLDeserialization(answerWithPadding, {mtproto: true}); + const response = deserializer.fetchObject('Server_DH_inner_data'); if(response._ !== 'server_DH_inner_data') { throw new Error('[MT] server_DH_inner_data response invalid: ' + response); @@ -384,7 +388,7 @@ export class Authorizer { this.mtpVerifyDhParams(auth.g, auth.dhPrime, auth.gA); - var offset = deserializer.getOffset(); + const offset = deserializer.getOffset(); //if(!bytesCmp(hash, sha1BytesSync(answerWithPadding.slice(0, offset)))) { if(!bytesCmp(hash, await CryptoWorker.sha1Hash(answerWithPadding.slice(0, offset)))) { @@ -399,7 +403,7 @@ export class Authorizer { this.log('Verifying DH params', g, dhPrime, gA); } - var dhPrimeHex = bytesToHex(dhPrime); + const dhPrimeHex = bytesToHex(dhPrime); if(g !== 3 || dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') { // The verified value is from https://core.telegram.org/mtproto/security_guidelines throw new Error('[MT] DH params are not verified: unknown dhPrime'); @@ -409,9 +413,9 @@ export class Authorizer { this.log('dhPrime cmp OK'); } - //var gABigInt = new BigInteger(bytesToHex(gA), 16); + //const gABigInt = new BigInteger(bytesToHex(gA), 16); const _gABigInt = str2bigInt(bytesToHex(gA), 16); - //var dhPrimeBigInt = new BigInteger(dhPrimeHex, 16); + //const dhPrimeBigInt = new BigInteger(dhPrimeHex, 16); const _dhPrimeBigInt = str2bigInt(dhPrimeHex, 16); //this.log('gABigInt.compareTo(BigInteger.ONE) <= 0', gABigInt.compareTo(BigInteger.ONE), BigInteger.ONE.compareTo(BigInteger.ONE), greater(_gABigInt, one)); @@ -432,14 +436,14 @@ export class Authorizer { } - //var two = new BigInteger(/* null */''); + //const two = new BigInteger(/* null */''); //two.fromInt(2); const _two = int2bigInt(2, 32, 0); //this.log('_two:', bigInt2str(_two, 16), two.toString(16)); - let perf = performance.now(); - //var twoPow = two.pow(2048 - 64); + // let perf = performance.now(); + //const twoPow = two.pow(2048 - 64); //console.log('jsbn pow', performance.now() - perf); - perf = performance.now(); + // perf = performance.now(); const _twoPow = pow(_two, 2048 - 64); //console.log('leemon pow', performance.now() - perf); //this.log('twoPow:', twoPow.toString(16), bigInt2str(_twoPow, 16)); @@ -462,19 +466,20 @@ export class Authorizer { } public async mtpSendSetClientDhParams(auth: AuthOptions): Promise { - var gBytes = bytesFromHex(auth.g.toString(16)); + const gBytes = bytesFromHex(auth.g.toString(16)); auth.b = new Array(256); auth.b = [...new Uint8Array(auth.b.length).randomize()]; //MTProto.secureRandom.nextBytes(auth.b); + let gB: number[]; try { - var gB = await CryptoWorker.modPow(gBytes, auth.b, auth.dhPrime); + gB = await CryptoWorker.modPow(gBytes, auth.b, auth.dhPrime); } catch(error) { throw error; } - var data = new TLSerialization({mtproto: true}); + const data = new TLSerialization({mtproto: true}); data.storeObject({ _: 'client_DH_inner_data', nonce: auth.nonce, @@ -483,13 +488,13 @@ export class Authorizer { g_b: gB }, 'Client_DH_Inner_Data'); - //var dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes()); - var dataWithHash = (await CryptoWorker.sha1Hash(data.getBuffer())).concat(data.getBytes()); + //const dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes()); + const dataWithHash = (await CryptoWorker.sha1Hash(data.getBuffer())).concat(data.getBytes()); - //var encryptedData = aesEncryptSync(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); - var encryptedData = await CryptoWorker.aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); + //const encryptedData = aesEncryptSync(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); + const encryptedData = await CryptoWorker.aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); - var request = new TLSerialization({mtproto: true}); + const request = new TLSerialization({mtproto: true}); request.storeMethod('set_client_DH_params', { nonce: auth.nonce, server_nonce: auth.serverNonce, @@ -500,13 +505,14 @@ export class Authorizer { this.log('Send set_client_DH_params'); } + let deserializer: TLDeserialization; try { - var deserializer = await this.mtpSendPlainRequest(auth.dcId, request.getBytes(true)); + deserializer = await this.mtpSendPlainRequest(auth.dcId, request.getBytes(true)); } catch(err) { throw err; } - let response = deserializer.fetchObject('Set_client_DH_params_answer'); + const response = deserializer.fetchObject('Set_client_DH_params_answer'); if(response._ !== 'dh_gen_ok' && response._ !== 'dh_gen_retry' && response._ !== 'dh_gen_fail') { throw new Error('[MT] Set_client_DH_params_answer response invalid: ' + response._); @@ -520,14 +526,15 @@ export class Authorizer { throw new Error('[MT] Set_client_DH_params_answer server_nonce mismatch'); } + let authKey: number[]; try { - var authKey = await CryptoWorker.modPow(auth.gA, auth.b, auth.dhPrime); + authKey = await CryptoWorker.modPow(auth.gA, auth.b, auth.dhPrime); } catch(err) { throw authKey; } - //var authKeyHash = sha1BytesSync(authKey), - let authKeyHash = await CryptoWorker.sha1Hash(new Uint8Array(authKey)), + //const authKeyHash = sha1BytesSync(authKey), + const authKeyHash = await CryptoWorker.sha1Hash(new Uint8Array(authKey)), authKeyAux = authKeyHash.slice(0, 8), authKeyId = authKeyHash.slice(-8); @@ -536,14 +543,14 @@ export class Authorizer { } switch(response._) { case 'dh_gen_ok': - var newNonceHash1 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([1], authKeyAux))).slice(-16); - //var newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16); + const newNonceHash1 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([1], authKeyAux))).slice(-16); + //const newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16); if(!bytesCmp(newNonceHash1, response.new_nonce_hash1)) { throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash1 mismatch'); } - var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8)); + const serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8)); if(DEBUG) { this.log('Auth successfull!', authKeyId, authKey, serverSalt); } @@ -556,8 +563,8 @@ export class Authorizer { break; case 'dh_gen_retry': - //var newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16); - var newNonceHash2 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([2], authKeyAux))).slice(-16); + //const newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16); + const newNonceHash2 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([2], authKeyAux))).slice(-16); if(!bytesCmp(newNonceHash2, response.new_nonce_hash2)) { throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash2 mismatch'); } @@ -565,8 +572,8 @@ export class Authorizer { return this.mtpSendSetClientDhParams(auth); case 'dh_gen_fail': - //var newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16); - var newNonceHash3 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([3], authKeyAux))).slice(-16); + //const newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16); + const newNonceHash3 = (await CryptoWorker.sha1Hash(auth.newNonce.concat([3], authKeyAux))).slice(-16); if(!bytesCmp(newNonceHash3, response.new_nonce_hash3)) { throw new Error('[MT] Set_client_DH_params_answer new_nonce_hash3 mismatch'); } @@ -581,8 +588,8 @@ export class Authorizer { return this.cached[dcId]; } - let nonce = /* fNonce ? fNonce : */new Uint8Array(16).randomize(); - /* var nonce = new Array(16); + const nonce = /* fNonce ? fNonce : */new Uint8Array(16).randomize(); + /* const nonce = new Array(16); MTProto.secureRandom.nextBytes(nonce); */ if(!dcConfigurator.chooseServer(dcId)) { @@ -590,7 +597,7 @@ export class Authorizer { } try { - let promise = this.mtpSendReqPQ({dcId, nonce}); + const promise = this.mtpSendReqPQ({dcId, nonce}); this.cached[dcId] = promise; return await promise; } catch(err) { diff --git a/src/lib/mtproto/serverTimeManager.ts b/src/lib/mtproto/serverTimeManager.ts index 8f7476eb..9af403c5 100644 --- a/src/lib/mtproto/serverTimeManager.ts +++ b/src/lib/mtproto/serverTimeManager.ts @@ -9,32 +9,48 @@ * https://github.com/zhukov/webogram/blob/master/LICENSE */ +import type { ApplyServerTimeOffsetTask } from './timeManager'; import { MOUNT_CLASS_TO } from '../../config/debug'; -import { tsNow } from '../../helpers/date'; +// import { tsNow } from '../../helpers/date'; import sessionStorage from '../sessionStorage'; +import apiManager from './mtprotoworker'; export class ServerTimeManager { - public timestampNow = tsNow(true); - public midnightNoOffset = this.timestampNow - (this.timestampNow % 86400); - public midnightOffseted = new Date(); + /* private midnightNoOffset: number; + private midnightOffseted: Date; - public midnightOffset = this.midnightNoOffset - (Math.floor(+this.midnightOffseted / 1000)); + private midnightOffset: number; */ - public serverTimeOffset = 0; // in seconds - public timeParams = { - midnightOffset: this.midnightOffset, - serverTimeOffset: this.serverTimeOffset - }; + public serverTimeOffset: number; // in seconds + /* private timeParams: { + midnightOffset: number, + serverTimeOffset: number + }; */ constructor() { + /* const timestampNow = tsNow(true); + this.midnightNoOffset = timestampNow - (timestampNow % 86400); + this.midnightOffseted = new Date(); this.midnightOffseted.setHours(0, 0, 0, 0); + + this.midnightOffset = this.midnightNoOffset - (Math.floor(+this.midnightOffseted / 1000)); */ + + this.serverTimeOffset = 0; + /* this.timeParams = { + midnightOffset: this.midnightOffset, + serverTimeOffset: this.serverTimeOffset + }; */ sessionStorage.get('server_time_offset').then((to) => { if(to) { this.serverTimeOffset = to; - this.timeParams.serverTimeOffset = to; + // this.timeParams.serverTimeOffset = to; } }); + + apiManager.addTaskListener('applyServerTimeOffset', (task: ApplyServerTimeOffsetTask) => { + this.serverTimeOffset = task.payload; + }); } } diff --git a/src/lib/mtproto/timeManager.ts b/src/lib/mtproto/timeManager.ts index 05ad2fc1..cb4a4957 100644 --- a/src/lib/mtproto/timeManager.ts +++ b/src/lib/mtproto/timeManager.ts @@ -13,6 +13,8 @@ import sessionStorage from '../sessionStorage'; import { longFromInts } from './bin_utils'; import { nextRandomInt } from '../../helpers/random'; import { MOUNT_CLASS_TO } from '../../config/debug'; +import { WorkerTaskVoidTemplate } from '../../types'; +import { notifySomeone } from '../../helpers/context'; /* let lol: any = {}; @@ -21,9 +23,14 @@ for(var i = 0; i < 100; i++) { } */ +export interface ApplyServerTimeOffsetTask extends WorkerTaskVoidTemplate { + type: 'applyServerTimeOffset', + payload: TimeManager['timeOffset'] +}; + export class TimeManager { - private lastMessageId = [0, 0]; - private timeOffset = 0; + private lastMessageId: [number, number] = [0, 0]; + private timeOffset: number = 0; constructor() { sessionStorage.get('server_time_offset').then((to) => { @@ -39,7 +46,7 @@ export class TimeManager { timeMSec = timeTicks % 1000, random = nextRandomInt(0xFFFF); - let messageId = [timeSec, (timeMSec << 21) | (random << 3) | 4]; + let messageId: TimeManager['lastMessageId'] = [timeSec, (timeMSec << 21) | (random << 3) | 4]; if(this.lastMessageId[0] > messageId[0] || this.lastMessageId[0] === messageId[0] && this.lastMessageId[1] >= messageId[1]) { messageId = [this.lastMessageId[0], this.lastMessageId[1] + 4]; @@ -72,6 +79,14 @@ export class TimeManager { //console.log('[TimeManager]: Apply server time', serverTime, localTime, newTimeOffset, changed); + /// #if MTPROTO_WORKER + const task: ApplyServerTimeOffsetTask = { + type: 'applyServerTimeOffset', + payload: newTimeOffset + }; + notifySomeone(task); + /// #endif + return changed; } } diff --git a/src/types.d.ts b/src/types.d.ts index 700a3273..b5d16be0 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -48,6 +48,8 @@ export type AnyFunction = (...args: any) => any; export type AnyToVoidFunction = (...args: any) => void; export type NoneToVoidFunction = () => void; +export type Awaited = T extends PromiseLike ? Awaited : T; + export type AuthState = AuthState.signIn | AuthState.signQr | AuthState.authCode | AuthState.password | AuthState.signUp | AuthState.signedIn; export namespace AuthState { export type signIn = {