diff --git a/aiopogo/__init__.py b/aiopogo/__init__.py index 6737b4f7..4cafe06e 100755 --- a/aiopogo/__init__.py +++ b/aiopogo/__init__.py @@ -1,5 +1,5 @@ __title__ = 'aiopogo' -__version__ = '1.8.3' +__version__ = '1.9.0' __author__ = 'David Christenson' __license__ = 'MIT License' __copyright__ = 'Copyright (c) 2017 David Christenson ' diff --git a/aiopogo/auth_ptc.py b/aiopogo/auth_ptc.py index aef6982c..f7dae440 100755 --- a/aiopogo/auth_ptc.py +++ b/aiopogo/auth_ptc.py @@ -10,7 +10,7 @@ from .exceptions import ActivationRequiredException, AuthConnectionException, AuthException, AuthTimeoutException, InvalidCredentialsException, ProxyException, SocksError, UnexpectedAuthError class AuthPtc(Auth): - def __init__(self, username=None, password=None, proxy=None, timeout=None, locale=None): + def __init__(self, username=None, password=None, proxy=None, proxy_auth=None, timeout=None, locale=None): Auth.__init__(self) self.provider = 'ptc' @@ -20,7 +20,8 @@ def __init__(self, username=None, password=None, proxy=None, timeout=None, local self.timeout = timeout or 10.0 self.proxy = proxy - self.socks = proxy and proxy.startswith('socks') + self.socks = proxy and proxy.scheme in ('socks4', 'socks5') + self.proxy_auth = proxy_auth async def user_login(self, username=None, password=None): self._username = username or self._username @@ -44,7 +45,7 @@ async def user_login(self, username=None, password=None): raise_for_status=True, conn_timeout=5.0, read_timeout=self.timeout) as session: - async with session.get('https://sso.pokemon.com/sso/oauth2.0/authorize', params={'client_id': 'mobile-app_pokemon-go', 'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error', 'locale': self.locale}, proxy=self.proxy) as resp: + async with session.get('https://sso.pokemon.com/sso/oauth2.0/authorize', params={'client_id': 'mobile-app_pokemon-go', 'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error', 'locale': self.locale}, proxy=self.proxy, proxy_auth=self.proxy_auth) as resp: data = await resp.json(loads=json_loads, encoding='utf-8', content_type=None) assert 'lt' in data @@ -53,7 +54,7 @@ async def user_login(self, username=None, password=None): data['password'] = self._password data['locale'] = self.locale - async with session.post('https://sso.pokemon.com/sso/login', params={'service': 'http://sso.pokemon.com/sso/oauth2.0/callbackAuthorize'}, headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data, timeout=8.0, proxy=self.proxy, allow_redirects=False) as resp: + async with session.post('https://sso.pokemon.com/sso/login', params={'service': 'http://sso.pokemon.com/sso/oauth2.0/callbackAuthorize'}, headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data, timeout=8.0, proxy=self.proxy, proxy_auth=self.proxy_auth, allow_redirects=False) as resp: try: self._access_token = resp.cookies['CASTGC'].value except (AttributeError, KeyError, TypeError): diff --git a/aiopogo/pgoapi.py b/aiopogo/pgoapi.py index 4cffc60e..053eae8f 100755 --- a/aiopogo/pgoapi.py +++ b/aiopogo/pgoapi.py @@ -1,10 +1,19 @@ from logging import getLogger +from yarl import URL +from aiohttp import BasicAuth +try: + from aiosocks import Socks4Auth, Socks5Auth +except ImportError: + class Socks4Auth(Exception): + def __init__(*args, **kwargs): + raise ImportError('You must install aiosocks to use a SOCKS proxy.') + Socks5Auth = Socks4Auth + from . import __title__, __version__ from .rpc_api import RpcApi, RpcState from .auth_ptc import AuthPtc from .auth_google import AuthGoogle -from .utilities import parse_api_endpoint from .hash_server import HashServer from .exceptions import AuthTokenExpiredException, InvalidCredentialsException, NoPlayerPositionSetException, ServerApiEndpointRedirectException from .protos.pogoprotos.networking.requests.request_type_pb2 import RequestType @@ -25,11 +34,12 @@ def __init__(self, provider=None, lat=None, lon=None, alt=None, proxy=None, devi self.altitude = alt self.proxy = proxy + self.proxy_auth = None self.device_info = device_info - async def set_authentication(self, provider='ptc', username=None, password=None, proxy=None, timeout=10, locale='en_US', refresh_token=None): + async def set_authentication(self, provider='ptc', username=None, password=None, timeout=10, locale='en_US', refresh_token=None): if provider == 'ptc': - self.auth_provider = AuthPtc(username, password, proxy=proxy or self.proxy, timeout=timeout) + self.auth_provider = AuthPtc(username, password, proxy=self._proxy, proxy_auth=self.proxy_auth, timeout=timeout) elif provider == 'google': self.auth_provider = AuthGoogle(proxy=proxy, refresh_token=refresh_token) if refresh_token: @@ -63,9 +73,30 @@ def api_endpoint(self): @api_endpoint.setter def api_endpoint(self, api_url): if api_url.startswith("https"): - self._api_endpoint = api_url + self._api_endpoint = URL(api_url) + else: + self._api_endpoint = URL('https://' + api_url + '/rpc') + + @property + def proxy(self): + return self._proxy + + @proxy.setter + def proxy(self, proxy): + if proxy is None: + self._proxy = proxy else: - self._api_endpoint = parse_api_endpoint(api_url) + self._proxy = URL(proxy) + if self._proxy.user: + scheme = self._proxy.scheme + if scheme == 'http': + self.proxy_auth = BasicAuth(self._proxy.user, self._proxy.password) + elif scheme == 'socks5': + self.proxy_auth = Socks5Auth(self._proxy.user, self._proxy.password) + elif scheme == 'socks4': + self.proxy_auth = Socks4Auth(self._proxy.user) + else: + raise ValueError('Proxy protocol must be http, socks5, or socks4.') @property def start_time(self): @@ -102,7 +133,7 @@ async def call(self): request = RpcApi(auth_provider, parent.state) while True: try: - response = await request.request(parent.api_endpoint, self._req_method_list, position, parent.device_info, parent.proxy) + response = await request.request(parent.api_endpoint, self._req_method_list, position, parent.device_info, parent._proxy, parent.proxy_auth) break except AuthTokenExpiredException: self.log.info('Access token rejected! Requesting new one...') diff --git a/aiopogo/rpc_api.py b/aiopogo/rpc_api.py index d609e6bb..c6038a5f 100755 --- a/aiopogo/rpc_api.py +++ b/aiopogo/rpc_api.py @@ -38,14 +38,14 @@ def get_class(self, class_): module_, class_ = class_.rsplit('.', 1) return getattr(import_module(module_), to_camel_case(class_)) - async def _make_rpc(self, endpoint, request_proto_plain, proxy): + async def _make_rpc(self, endpoint, request_proto_plain, proxy, proxy_auth): self.log.debug('Execution of RPC') session = SESSIONS.get(proxy) request_proto_serialized = request_proto_plain.SerializeToString() try: - async with session.post(endpoint, data=request_proto_serialized, proxy=proxy) as resp: + async with session.post(endpoint, data=request_proto_serialized, proxy=proxy, proxy_auth=proxy_auth) as resp: return await resp.read() except (ClientHttpProxyError, ClientProxyConnectionError, SocksError) as e: raise ProxyException('Proxy connection error during RPC request.') from e @@ -77,10 +77,10 @@ def get_request_name(subrequests): except (ValueError, TypeError): return 'unknown' - async def request(self, endpoint, subrequests, player_position, device_info=None, proxy=None): + async def request(self, endpoint, subrequests, player_position, device_info=None, proxy=None, proxy_auth=None): request_proto = await self._build_main_request(subrequests, player_position, device_info) - response = await self._make_rpc(endpoint, request_proto, proxy) + response = await self._make_rpc(endpoint, request_proto, proxy, proxy_auth) response_dict = self._parse_main_response(response, subrequests) if 'auth_ticket' in response_dict: diff --git a/aiopogo/session.py b/aiopogo/session.py index 816287e8..012ee2bd 100644 --- a/aiopogo/session.py +++ b/aiopogo/session.py @@ -17,7 +17,7 @@ def __init__(self): self.loop = get_event_loop() def get(self, proxy=None): - socks = proxy and proxy.startswith('socks') + socks = proxy and proxy.scheme in ('socks4', 'socks5') try: return self.socks_session if socks else self.session except AttributeError: diff --git a/aiopogo/utilities.py b/aiopogo/utilities.py index 4aa685ef..4b9bdd8d 100755 --- a/aiopogo/utilities.py +++ b/aiopogo/utilities.py @@ -21,12 +21,6 @@ def get_time_ms(): return int(time() * 1000) -def parse_api_endpoint(api_url): - if not api_url.startswith("https"): - api_url = 'https://{}/rpc'.format(api_url) - return api_url - - class IdGenerator: '''Lehmer random number generator''' M = 0x7fffffff # 2^31 - 1 (A large prime number) diff --git a/setup.py b/setup.py index 97616a4c..7daf7b2a 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ author='David Christenson', author_email='mail@noctem.xyz', description='Asynchronous Pokemon API lib', - version='1.8.3', + version='1.9.0', url='https://github.com/Noctem/aiopogo', packages=find_packages(), install_requires=[