diff --git a/src/global/helpers/users.ts b/src/global/helpers/users.ts index 4c093efb9..d13e4a7e6 100644 --- a/src/global/helpers/users.ts +++ b/src/global/helpers/users.ts @@ -100,7 +100,7 @@ export function getUserStatus( if (!wasOnline) return lang('LastSeen.Offline'); const serverTimeOffset = getServerTimeOffset(); - const now = new Date(new Date().getTime() + serverTimeOffset * 1000); + const now = new Date(Date.now() + serverTimeOffset * 1000); const wasOnlineDate = new Date(wasOnline * 1000); if (wasOnlineDate >= now) { diff --git a/src/lib/gramjs/client/TelegramClient.js b/src/lib/gramjs/client/TelegramClient.js index 80a2787dc..72a1af64f 100644 --- a/src/lib/gramjs/client/TelegramClient.js +++ b/src/lib/gramjs/client/TelegramClient.js @@ -291,7 +291,7 @@ class TelegramClient { // for Telegram to keep delivering updates, otherwise they will // just stop even if we're connected. Do so every 30 minutes. - if (new Date().getTime() - this._lastRequest > 30 * 60 * 1000) { + if (Date.now() - this._lastRequest > 30 * 60 * 1000) { try { await this.pingCallback(); } catch (e) { @@ -877,7 +877,7 @@ class TelegramClient { } const sender = dcId === undefined ? this._sender : await this.getSender(dcId); - this._lastRequest = new Date().getTime(); + this._lastRequest = Date.now(); const state = new RequestState(request, abortSignal); diff --git a/src/lib/gramjs/network/Authenticator.ts b/src/lib/gramjs/network/Authenticator.ts index 135ecb277..de04c3f41 100644 --- a/src/lib/gramjs/network/Authenticator.ts +++ b/src/lib/gramjs/network/Authenticator.ts @@ -156,11 +156,15 @@ export async function doAuthentication(sender: MTProtoPlainSender, log: any) { const ige = new IGE(key, iv); const plainTextAnswer = ige.decryptIge(serverDhParams.encryptedAnswer); const reader = new BinaryReader(plainTextAnswer); - reader.read(20); // hash sum + const hash = reader.read(20); // hash sum const serverDhInner = reader.tgReadObject(); if (!(serverDhInner instanceof Api.ServerDHInnerData)) { throw new Error(`Step 3 answer was ${serverDhInner}`); } + const sha1Answer = await Helpers.sha1(serverDhInner.getBytes()); + if (!(hash.equals(sha1Answer))) { + throw new SecurityError('Step 3 Invalid hash answer'); + } if (serverDhInner.nonce.neq(resPQ.nonce)) { throw new SecurityError('Step 3 Invalid nonce in encrypted answer'); @@ -185,7 +189,7 @@ export async function doAuthentication(sender: MTProtoPlainSender, log: any) { false, ); const ga = Helpers.readBigIntFromBuffer(serverDhInner.gA, false, false); - const timeOffset = serverDhInner.serverTime - Math.floor(new Date().getTime() / 1000); + const timeOffset = serverDhInner.serverTime - Math.floor(Date.now() / 1000); const b = Helpers.readBigIntFromBuffer( Helpers.generateRandomBytes(256), false, diff --git a/src/lib/gramjs/network/MTProtoState.js b/src/lib/gramjs/network/MTProtoState.js index 0f748bea0..a7a4c1300 100644 --- a/src/lib/gramjs/network/MTProtoState.js +++ b/src/lib/gramjs/network/MTProtoState.js @@ -284,6 +284,16 @@ class MTProtoState { // reader isn't used for anything else after this, it's unnecessary. const obj = reader.tgReadObject(); + // We only check for objects that telegram has returned to us (Updates) not ones we send. + if (obj?.constructor.name.startsWith('Update')) { + const now = Math.floor(Date.now() / 1000); + const msgLocalTime = this.getMsgIdTimeLocal(remoteMsgId); + + if (msgLocalTime && ((msgLocalTime - now) > 30 || (now - msgLocalTime) > 300)) { + // 30 sec in the future or 300 sec in the past + throw new SecurityError('The message time is incorrect.'); + } + } return new TLMessage(remoteMsgId, remoteSequence, obj); } } @@ -294,7 +304,7 @@ class MTProtoState { * @private */ _getNewMsgId() { - const now = new Date().getTime() / 1000 + this.timeOffset; + const now = Date.now() / 1000 + this.timeOffset; const nanoseconds = Math.floor((now - Math.floor(now)) * 1e9); let newMsgId = (BigInt(Math.floor(now)) .shiftLeft(BigInt(32))).or(BigInt(nanoseconds) @@ -306,6 +316,17 @@ class MTProtoState { return newMsgId; } + /** + * Returns the understood time by the message id (server time + local offset) + */ + getMsgIdTimeLocal(msgId) { + if (this._lastMsgId.eq(0)) { + // this means it's the first message sent/received so don't check yet + return false; + } + return msgId.shiftRight(BigInt(32)).toJSNumber() - this.timeOffset; + } + /** * Updates the time offset to the correct * one given a known valid message ID. @@ -314,7 +335,7 @@ class MTProtoState { updateTimeOffset(correctMsgId) { const bad = this._getNewMsgId(); const old = this.timeOffset; - const now = Math.floor(new Date().getTime() / 1000); + const now = Math.floor(Date.now() / 1000); const correct = correctMsgId.shiftRight(BigInt(32)); this.timeOffset = correct - now; diff --git a/src/lib/gramjs/tl/MTProtoRequest.js b/src/lib/gramjs/tl/MTProtoRequest.js index 73216c3a1..e3fb80bd6 100644 --- a/src/lib/gramjs/tl/MTProtoRequest.js +++ b/src/lib/gramjs/tl/MTProtoRequest.js @@ -17,7 +17,7 @@ class MTProtoRequest { // these should not be overrode onSendSuccess() { - this.sendTime = new Date().getTime(); + this.sendTime = Date.now(); this.sent = true; } @@ -26,7 +26,7 @@ class MTProtoRequest { } needResend() { - return this.dirty || (this.confirmed && !this.confirmReceived && new Date().getTime() - this.sendTime > 3000); + return this.dirty || (this.confirmed && !this.confirmReceived && Date.now() - this.sendTime > 3000); } // These should be overrode