Skip to content

Commit 376d1ac

Browse files
committed
test1
1 parent 9936b98 commit 376d1ac

4 files changed

Lines changed: 159 additions & 6 deletions

File tree

pyrogram/connection/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __init__(
6161

6262
async def connect(self) -> None:
6363
for i in range(Connection.MAX_CONNECTION_ATTEMPTS):
64-
self.protocol = self.protocol_factory(ipv6=self.ipv6, proxy=self.proxy, crypto_executor_workers=self.crypto_executor_workers, loop=self.loop)
64+
self.protocol = self.protocol_factory(dc_id=self.dc_id, ipv6=self.ipv6, proxy=self.proxy, crypto_executor_workers=self.crypto_executor_workers, loop=self.loop)
6565

6666
try:
6767
log.info("Connecting...")

pyrogram/connection/transport/tcp/tcp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class ProxyDict(TypedDict):
3636
scheme: str
3737
hostname: str
3838
port: int
39+
secret: Optional[str]
3940
username: Optional[str]
4041
password: Optional[str]
4142

@@ -154,7 +155,7 @@ async def _connect_via_direct(self, destination: Tuple[str, int]) -> None:
154155
log.info("Connection established")
155156

156157
async def _connect(self, destination: Tuple[str, int]) -> None:
157-
if self.proxy:
158+
if self.proxy and isinstance(self.proxy, dict) and self.proxy.get("scheme", "").lower() != "mtproxy":
158159
await self._connect_via_proxy(destination)
159160
else:
160161
await self._connect_via_direct(destination)

pyrogram/connection/transport/tcp/tcp_abridged.py

Lines changed: 147 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
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
1921
import asyncio
2022
import logging
2123
from typing import Optional, Tuple, Union
2224

25+
from pyrogram.crypto import aes
2326
from .tcp import TCP, ProxyDict
2427

2528
log = logging.getLogger(__name__)
@@ -28,30 +31,170 @@
2831
class 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)

pyrogram/session/session.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ async def start(self):
181181

182182
init_connection_params = self.client.init_connection_params
183183

184+
proxy = None
185+
186+
if isinstance(proxy, dict) and proxy.get("scheme", "").lower() == "mtproxy":
187+
proxy = raw.types.InputClientProxy(
188+
address=proxy.get("hostname", ""),
189+
port=proxy.get("port", 0)
190+
)
191+
184192
if isinstance(init_connection_params, dict):
185193
init_connection_params = utils.obj_to_jsonvalue(init_connection_params)
186194

@@ -198,6 +206,7 @@ async def start(self):
198206
lang_code=self.client.lang_code,
199207
query=raw.functions.help.GetConfig(),
200208
params=init_connection_params,
209+
proxy=proxy
201210
)
202211
),
203212
timeout=self.START_TIMEOUT

0 commit comments

Comments
 (0)