1919from hashlib import sha256
2020from io import BytesIO
2121from os import urandom
22+ from typing import Optional , List
2223
2324from pyrogram .raw .core import Message , Long
2425from . import aes
26+ from ..session .internals import MsgId
2527
2628
2729def kdf (auth_key : bytes , msg_key : bytes , outgoing : bool ) -> tuple :
@@ -49,13 +51,19 @@ def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_k
4951 return auth_key_id + msg_key + aes .ige256_encrypt (data + padding , aes_key , aes_iv )
5052
5153
52- def unpack (b : BytesIO , session_id : bytes , auth_key : bytes , auth_key_id : bytes ) -> Message :
54+ def unpack (
55+ b : BytesIO ,
56+ session_id : bytes ,
57+ auth_key : bytes ,
58+ auth_key_id : bytes ,
59+ stored_msg_ids : List [int ]
60+ ) -> Optional [Message ]:
5361 assert b .read (8 ) == auth_key_id , b .getvalue ()
5462
5563 msg_key = b .read (16 )
5664 aes_key , aes_iv = kdf (auth_key , msg_key , False )
5765 data = BytesIO (aes .ige256_decrypt (b .read (), aes_key , aes_iv ))
58- data .read (8 )
66+ data .read (8 ) # Salt
5967
6068 # https://core.telegram.org/mtproto/security_guidelines#checking-session-id
6169 assert data .read (8 ) == session_id
@@ -75,11 +83,41 @@ def unpack(b: BytesIO, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -
7583 raise ValueError (f"The server sent an unknown constructor: { hex (e .args [0 ])} \n { left } " )
7684
7785 # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
78- # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
7986 # 96 = 88 + 8 (incoming message)
8087 assert msg_key == sha256 (auth_key [96 :96 + 32 ] + data .getvalue ()).digest ()[8 :24 ]
8188
89+ # https://core.telegram.org/mtproto/security_guidelines#checking-message-length
90+ data .seek (32 ) # Get to the payload, skip salt (8) + session_id (8) + msg_id (8) + seq_no (4) + length (4)
91+ payload = data .read ()
92+ padding = payload [message .length :]
93+ assert 12 <= len (padding ) <= 1024
94+ assert len (payload ) % 4 == 0
95+
8296 # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
8397 assert message .msg_id % 2 != 0
8498
99+ if len (stored_msg_ids ) > 200 :
100+ stored_msg_ids = stored_msg_ids [50 :]
101+
102+ if stored_msg_ids :
103+ # Ignored message: msg_id is lower than all of the stored values
104+ if message .msg_id < stored_msg_ids [0 ]:
105+ return None
106+
107+ # Ignored message: msg_id is equal to any of the stored values
108+ if message .msg_id in stored_msg_ids :
109+ return None
110+
111+ time_diff = (message .msg_id - MsgId ()) / 2 ** 32
112+
113+ # Ignored message: msg_id belongs over 30 seconds in the future
114+ if time_diff > 30 :
115+ return None
116+
117+ # Ignored message: msg_id belongs over 300 seconds in the past
118+ if time_diff < - 300 :
119+ return None
120+
121+ stored_msg_ids .append (message .msg_id )
122+
85123 return message
0 commit comments