Replace pysocks with python-proxy

This commit is contained in:
Lonami Exo 2019-06-07 20:25:32 +02:00
parent 9752f66eab
commit ad7e62baf3
9 changed files with 74 additions and 54 deletions

View File

@ -1,4 +1,4 @@
cryptg
pysocks
pproxy
hachoir3
pillow

View File

@ -107,7 +107,7 @@ Signing In behind a Proxy
=========================
If you need to use a proxy to access Telegram,
you will need to `install PySocks`__ and then change:
you will need to `install python-proxy`__ and then change:
.. code-block:: python
@ -117,12 +117,20 @@ with
.. code-block:: python
TelegramClient('anon', api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 4444))
TelegramClient('anon', api_id, api_hash, proxy='socks5://127.0.0.1:4444')
# You can also use a ``dict`` (it will be translated to the same URI as above)
TelegramClient('anon', api_id, api_hash, proxy={
'scheme': 'socks5',
'hostname': '127.0.0.1',
'port': 4444
})
(of course, replacing the IP and port with the IP and port of the proxy).
The ``proxy=`` argument should be a tuple, a list or a dict,
consisting of parameters described `in PySocks usage`__.
consisting of parameters described `in python-proxy usage`__.
.. __: https://github.com/Anorov/PySocks#installation
.. __: https://github.com/Anorov/PySocks#usage-1
.. __: https://github.com/qwj/python-proxy#quickstart
.. __: https://github.com/qwj/python-proxy#uri-syntax

View File

@ -67,12 +67,11 @@ class TelegramBaseClient(abc.ABC):
By default this is ``False`` as IPv6 support is not
too widespread yet.
proxy (`tuple` | `list` | `dict`, optional):
An iterable consisting of the proxy info. If `connection` is
one of `MTProxy`, then it should contain MTProxy credentials:
``('hostname', port, 'secret')``. Otherwise, it's meant to store
function parameters for PySocks, like ``(type, 'hostname', port)``.
See https://github.com/Anorov/PySocks#usage-1 for more.
proxy (`str` | `dict`, optional):
The URI with all the required proxy information, or a dictionary
with the fields to use (like ``schemepython``, ``hostname``, etc.).
See https://github.com/qwj/python-proxy#uri-syntax for details.
timeout (`int` | `float`, optional):
The timeout in seconds to be used when connecting.
@ -171,7 +170,7 @@ class TelegramBaseClient(abc.ABC):
*,
connection: 'typing.Type[Connection]' = ConnectionTcpFull,
use_ipv6: bool = False,
proxy: typing.Union[tuple, dict] = None,
proxy: typing.Union[str, dict] = None,
timeout: int = 10,
request_retries: int = 5,
connection_retries: int =5,
@ -254,14 +253,14 @@ class TelegramBaseClient(abc.ABC):
self._request_retries = request_retries
self._connection_retries = connection_retries
self._retry_delay = retry_delay or 0
self._proxy = proxy
self._proxy = helpers._get_proxy_uri(proxy)
self._timeout = timeout
self._auto_reconnect = auto_reconnect
assert isinstance(connection, type)
self._connection = connection
init_proxy = None if not issubclass(connection, TcpMTProxy) else \
types.InputClientProxy(*connection.address_info(proxy))
types.InputClientProxy(*connection.address_info(self._proxy))
# Used on connection. Capture the variables in a lambda since
# exporting clients need to create this InvokeWithLayerRequest.

View File

@ -131,6 +131,43 @@ def _sync_exit(self, *args):
return loop.run_until_complete(self.__aexit__(*args))
def _get_proxy_uri(proxy):
if not proxy:
return None
elif isinstance(proxy, str):
return proxy
elif isinstance(proxy, dict):
fmt = {
'scheme': 'socks5',
'cipher': '',
'netloc': '',
'localbind': '',
'plugins': '',
'rules': '',
'auth': ''
}
fmt.update(proxy)
if 'hostname' in fmt:
fmt['netloc'] = '{}:{}'.format(fmt.pop('hostname'), fmt.pop('port'))
if 'username' in fmt:
fmt['auth'] = '{}:{}'.format(fmt.pop('username'), fmt.pop('password'))
fix = {
'cipher': '{}@',
'localbind': '@{}',
'plugins': ',{}',
'rules': '?{}',
'auth': '#{}'
}
for k, v in fix.items():
if fmt[k]:
fmt[k] = v.format(fmt[k])
return '{scheme}://{cipher}{netloc}/{localbind}{plugins}{rules}{auth}'.format(**fmt)
else:
raise TypeError('{!r} is not a valid proxy (must be str URI or dict)'.format(proxy))
# endregion
# region Cryptographic related utils

View File

@ -43,43 +43,19 @@ class Connection(abc.ABC):
async def _connect(self, timeout=None, ssl=None):
if not self._proxy:
connect_coroutine = asyncio.open_connection(
self._ip, self._port, loop=self._loop, ssl=ssl)
else:
import pproxy
# FIXME https://github.com/qwj/python-proxy/issues/41
connect_coroutine = pproxy.Connection(
self._proxy).tcp_connect(self._ip, self._port)
self._reader, self._writer = await asyncio.wait_for(
asyncio.open_connection(
self._ip, self._port, loop=self._loop, ssl=ssl),
connect_coroutine,
loop=self._loop, timeout=timeout
)
else:
import socks
if ':' in self._ip:
mode, address = socket.AF_INET6, (self._ip, self._port, 0, 0)
else:
mode, address = socket.AF_INET, (self._ip, self._port)
s = socks.socksocket(mode, socket.SOCK_STREAM)
if isinstance(self._proxy, dict):
s.set_proxy(**self._proxy)
else:
s.set_proxy(*self._proxy)
s.setblocking(False)
await asyncio.wait_for(
self._loop.sock_connect(s, address),
timeout=timeout,
loop=self._loop
)
if ssl:
s.settimeout(timeout)
s = ssl_mod.wrap_socket(
s,
do_handshake_on_connect=True,
ssl_version=ssl_mod.PROTOCOL_SSLv23,
ciphers='ADH-AES256-SHA'
)
s.setblocking(False)
self._reader, self._writer = \
await asyncio.open_connection(sock=s, loop=self._loop)
self._codec = self.packet_codec(self)
self._init_conn()
await self._writer.drain()

View File

@ -126,6 +126,7 @@ class TcpMTProxy(ObfuscatedConnection):
@staticmethod
def address_info(proxy_info):
raise NotImplementedError('New proxy format is not implemented')
if proxy_info is None:
raise ValueError("No proxy info specified for MTProxy connection")
return proxy_info[:2]

View File

@ -116,9 +116,8 @@ class InteractiveTelegramClient(TelegramClient):
try:
loop.run_until_complete(self.connect())
except IOError:
# We handle IOError and not ConnectionError because
# PySocks' errors do not subclass ConnectionError
# (so this will work with and without proxies).
# To avoid issues in the future, we except the most
# generic IOError as possible (instead of ConnectionError)
print('Initial connection failed. Retrying...')
loop.run_until_complete(self.connect())

View File

@ -22,7 +22,7 @@ def get_env(name, message, cast=str):
session = os.environ.get('TG_SESSION', 'printer')
api_id = get_env('TG_API_ID', 'Enter your API ID: ', int)
api_hash = get_env('TG_API_HASH', 'Enter your API hash: ')
proxy = None # https://github.com/Anorov/PySocks
proxy = None # https://github.com/qwj/python-proxy#uri-syntax
# Create and start the client so we can make requests (we don't here)
client = TelegramClient(session, api_id, api_hash, proxy=proxy).start()

View File

@ -27,7 +27,7 @@ def get_env(name, message, cast=str):
session = os.environ.get('TG_SESSION', 'printer')
api_id = get_env('TG_API_ID', 'Enter your API ID: ', int)
api_hash = get_env('TG_API_HASH', 'Enter your API hash: ')
proxy = None # https://github.com/Anorov/PySocks
proxy = None # https://github.com/qwj/python-proxy#uri-syntax
# This is our update handler. It is called when a new update arrives.