1616# You should have received a copy of the GNU Lesser General Public License
1717# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
1818
19+ import os
20+ import hashlib
1921import asyncio
2022import logging
2123from typing import Optional , Tuple , Union
2224
25+ from pyrogram .crypto import aes
2326from .tcp import TCP , ProxyDict
2427
2528log = logging .getLogger (__name__ )
2831class TCPAbridged (TCP ):
2932 def __init__ (
3033 self ,
34+ dc_id : int ,
3135 ipv6 : bool = False ,
3236 proxy : Optional [Union [str , ProxyDict ]] = None ,
3337 crypto_executor_workers : int = 1 ,
3438 loop : Optional [asyncio .AbstractEventLoop ] = None ,
3539 ) -> None :
3640 super ().__init__ (ipv6 , proxy , crypto_executor_workers , loop )
41+ self .dc_id = dc_id
42+ self .encrypt = None
43+ self .decrypt = None
44+ self .secret = None
45+ self .hostname = None
46+ self .port = None
47+ if isinstance (proxy , dict ) and proxy .get ("scheme" , "" ).lower () == "mtproxy" :
48+ self .hostname = proxy .get ("hostname" )
49+ self .port = proxy .get ("port" )
50+ self .secret = proxy .get ("secret" )
3751
52+ async def connect_via_mtproxy (self , address ):
53+ self .marker_event .clear ()
54+
55+ nonce = bytearray (os .urandom (64 ))
56+
57+ while (
58+ nonce [0 ] == 0xef
59+ or nonce [:4 ] in (b"HEAD" , b"POST" , b"GET " , b"OPTI" , b"\xee " * 4 )
60+ or nonce [4 :8 ] == b"\x00 " * 4
61+ ):
62+ nonce = bytearray (os .urandom (64 ))
63+
64+ temp = bytearray (nonce [55 :7 :- 1 ])
65+
66+ secret = self .secret
67+
68+ if isinstance (secret , str ):
69+ if secret .startswith ("dd" ):
70+ secret = secret [2 :]
71+ secret = bytes .fromhex (secret )
72+
73+ encrypt_key = hashlib .sha256 (
74+ bytes (nonce [8 :40 ]) + secret
75+ ).digest ()
76+
77+ decrypt_key = hashlib .sha256 (
78+ bytes (temp [:32 ]) + secret
79+ ).digest ()
80+
81+ self .encrypt = (
82+ encrypt_key ,
83+ bytes (nonce [40 :56 ]),
84+ bytearray (1 )
85+ )
86+
87+ self .decrypt = (
88+ decrypt_key ,
89+ bytes (temp [32 :48 ]),
90+ bytearray (1 )
91+ )
92+
93+ nonce [56 :60 ] = b'\xef \xef \xef \xef '
94+
95+ nonce [60 :62 ] = self .dc_id .to_bytes (
96+ 2 ,
97+ "little" ,
98+ signed = True
99+ )
100+
101+ encrypted = aes .ctr256_encrypt (
102+ nonce ,
103+ * self .encrypt
104+ )
105+
106+ nonce [56 :64 ] = encrypted [56 :64 ]
107+
108+ await super ().connect ((self .hostname , self .port ))
109+
110+ await super ().send (
111+ nonce ,
112+ wait_for_marker = False
113+ )
114+
115+ self .marker_event .set ()
116+
38117 async def connect (self , address : Tuple [str , int ]) -> None :
118+ if self .hostname and self .port and self .secret :
119+ return await self .connect_via_mtproxy (address )
120+
39121 self .marker_event .clear ()
40122 await super ().connect (address )
41123 await super ().send (b"\xef " , wait_for_marker = False )
42124 self .marker_event .set ()
43125
44- async def send (self , data : bytes , * args ) -> None :
126+ async def send_via_mtproxy (self , data : bytes , * args ):
45127 length = len (data ) // 4
46128
129+ payload = (
130+ bytes ([length ])
131+ if length <= 126
132+ else b"\x7f " + length .to_bytes (3 , "little" )
133+ ) + data
134+
135+ payload = await self .loop .run_in_executor (
136+ self .crypto_executor ,
137+ aes .ctr256_encrypt ,
138+ payload ,
139+ * self .encrypt
140+ )
141+ await super ().send (payload )
142+
143+ async def send (self , data : bytes , * args ) -> None :
144+ if self .hostname and self .port and self .secret :
145+ return await self .send_via_mtproxy (data , * args )
146+
147+ length = len (data ) // 4
47148 await super ().send (
48149 (bytes ([length ])
49- if length <= 126
50- else b"\x7f " + length .to_bytes (3 , "little" ))
150+ if length <= 126
151+ else b"\x7f " + length .to_bytes (3 , "little" ))
51152 + data
52153 )
53154
155+ async def recv_via_mtproxy (self , length : int = 0 ):
156+ length = await super ().recv (1 )
157+
158+ if length is None :
159+ return None
160+
161+ length = aes .ctr256_decrypt (
162+ length ,
163+ * self .decrypt
164+ )
165+
166+ if length == b"\x7f " :
167+ length = await super ().recv (3 )
168+
169+ if length is None :
170+ return None
171+
172+ length = aes .ctr256_decrypt (
173+ length ,
174+ * self .decrypt
175+ )
176+
177+ packet_length = int .from_bytes (
178+ length ,
179+ "little"
180+ ) * 4
181+
182+ data = await super ().recv (packet_length )
183+
184+ if data is None :
185+ return None
186+
187+ return await self .loop .run_in_executor (
188+ self .crypto_executor ,
189+ aes .ctr256_decrypt ,
190+ data ,
191+ * self .decrypt
192+ )
193+
54194 async def recv (self , length : int = 0 ) -> Optional [bytes ]:
195+ if self .hostname and self .port and self .secret :
196+ return await self .recv_via_mtproxy (length )
197+
55198 length = await super ().recv (1 )
56199
57200 if length is None :
@@ -63,4 +206,4 @@ async def recv(self, length: int = 0) -> Optional[bytes]:
63206 if length is None :
64207 return None
65208
66- return await super ().recv (int .from_bytes (length , "little" ) * 4 )
209+ return await super ().recv (int .from_bytes (length , "little" ) * 4 )
0 commit comments