GramJS: Add more security checks (#3419)
This commit is contained in:
parent
6d8f415bc1
commit
823fd9add7
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user