Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
632b7df
Rewrite of google/ptc auth in regard to refresh/access token and addes
tejado Aug 6, 2016
9b31550
Update proto
wchill Aug 6, 2016
5bdd8af
Merge pull request #1 from keyphact/fix-proto
keyphact Aug 6, 2016
916a51f
Update Signature.proto
globeriz Aug 6, 2016
972b892
Update Signature_pb2.py
globeriz Aug 6, 2016
b583558
Update Signature_pb2.py
globeriz Aug 6, 2016
1dbf5a1
Update utilities.py
cheesynoob Aug 6, 2016
dbd0634
iOSActivity should be Activity
globeriz Aug 6, 2016
d3d84df
Merge pull request #3 from keyphact/cheesynoob-patch-1
cheesynoob Aug 6, 2016
9938ae0
Update Signature.proto
globeriz Aug 6, 2016
f46e4bc
Update Signature_pb2.py
globeriz Aug 6, 2016
b7845a2
Fixed mistake in generateRequests
cheesynoob Aug 6, 2016
a5dcbde
Merge pull request #4 from keyphact/cheesynoob-patch-2
KevinCollmer Aug 6, 2016
0eacfe6
Merge pull request #2 from keyphact/fix-proto-1
classyjakey Aug 6, 2016
2c2b780
Quick fix to utilities functions
TalSk Aug 6, 2016
8b7a003
Merge pull request #5 from keyphact/tal-patch1
JosiahWhite Aug 6, 2016
3ecea0d
Added wrapper for signature encryption
tejado Aug 6, 2016
917bff0
Merge pull request #6 from tejado/master
keyphact Aug 7, 2016
91a700b
changed request altitude to int value
cheesynoob Aug 7, 2016
fd462be
Merge pull request #8 from keyphact/cheesynoob-patch-1
keyphact Aug 7, 2016
e206f4a
d2h fix and options for pokecli
dmadisetti Aug 7, 2016
b59cb1d
Merge res
dmadisetti Aug 7, 2016
64d539d
It works now
dmadisetti Aug 7, 2016
10d7cde
Works now
dmadisetti Aug 7, 2016
9c070a7
Merge pull request #9 from dmadisetti/patch-1
wchill Aug 7, 2016
75eba6b
Use six for chr() call for python3 compat, pep8 fixes
pbdeuchler Aug 7, 2016
249d3be
Merge pull request #11 from catchemallio/python3
wchill Aug 7, 2016
6b50289
Fix hex decoding on Python 3
Noctem Aug 7, 2016
06eaef1
Merge pull request #23 from Noctem/hexdecode
wchill Aug 7, 2016
d809601
Merge in Keys and Conflict res
dmadisetti Aug 7, 2016
691aff2
Added scripts\accept-tos.py (#30)
scottstamp Aug 7, 2016
23be9dd
correctly return the new access_token after refresh
rbignon Aug 8, 2016
e489594
Add a sane API timeout.
edevil Aug 8, 2016
8b1dca3
Fix index error on API endpoint (#63)
wchill Aug 9, 2016
5b7c7c5
Merge pull request #54 from edevil/api_timeout
keyphact Aug 9, 2016
a2755eb
Merge pull request #49 from rbignon/master
keyphact Aug 9, 2016
5e83cad
Allow using a proxy.
tschroeder-zendesk Aug 2, 2016
842e80c
Merge proxy support
Noctem Aug 9, 2016
39ea20d
Merge pull request #66 from Noctem/proxies
globeriz Aug 9, 2016
915cfa8
Add auth service as an optional parameter
OurFlagIsMined Aug 9, 2016
dc1b222
Added future as a requirement
pengstrom Aug 9, 2016
51ceb8a
Merge pull request #69 from OurFlagIsMined/patch-1
globeriz Aug 9, 2016
ef58322
Merge pull request #70 from pengstrom/pengstrom/add-future-requirement
globeriz Aug 9, 2016
68575cc
Now reusing sessions (#73)
cheesynoob Aug 9, 2016
b4bf0e0
Fixed missing import (#74)
cheesynoob Aug 9, 2016
7a0666f
Uses auth_info as seed when auth_ticket is unavailable (#74)
cheesynoob Aug 9, 2016
60096cc
Fix proxies with reused sessions (#77)
Noctem Aug 10, 2016
d10968f
Merge branch 'master' of https://github.com/keyphact/pgoapi
dmadisetti Aug 11, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,8 @@ ENV/
.ropeproject

# Personal load details
config.json
config.json

# Encrpytion libs
encrypt.dll
libencrypt.so
3 changes: 2 additions & 1 deletion config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"auth_service": "google",
"username": "example@gmail.com",
"password": "password11!!",
"location": "New York"
"location": "New York",
"encrypt": "./libencrypt.so"
}
2 changes: 1 addition & 1 deletion pgoapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import logging

__title__ = 'pgoapi'
__version__ = '1.1.6'
__version__ = '1.1.7'
__author__ = 'tjado'
__license__ = 'MIT License'
__copyright__ = 'Copyright (c) 2016 tjado <https://github.com/tejado>'
Expand Down
56 changes: 49 additions & 7 deletions pgoapi/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from __future__ import absolute_import

import logging
from pgoapi.utilities import get_time_ms, get_format_time_diff
from pgoapi.utilities import get_time, get_format_time_diff

class Auth:

Expand All @@ -36,8 +36,21 @@ def __init__(self):
self._auth_provider = None

self._login = False

"""
oauth2 uses refresh tokens (which basically never expires)
to get an access_token which is only valid for a certain time)
"""
self._refresh_token = None
self._access_token = None
self._access_token_expiry = 0
# TODO: can be removed
self._auth_token = None

"""
Pokemon Go uses internal tickets, like an internal
session to keep a user logged in over a certain time (30 minutes)
"""
self._ticket_expire = None
self._ticket_start = None
self._ticket_end = None
Expand All @@ -49,7 +62,7 @@ def is_login(self):
return self._login

def get_token(self):
return self._auth_token
return self._access_token

def has_ticket(self):
if self._ticket_expire and self._ticket_start and self._ticket_end:
Expand All @@ -68,13 +81,13 @@ def is_new_ticket(self, new_ticket_time_ms):

def check_ticket(self):
if self.has_ticket():
now_ms = get_time_ms()
now_ms = get_time(ms = True)
if now_ms < (self._ticket_expire - 10000):
h, m, s = get_format_time_diff(now_ms, self._ticket_expire, True)
self.log.debug('Auth ticket still valid for further %02d:%02d:%02d hours (%s < %s)', h, m, s, now_ms, self._ticket_expire)
self.log.debug('Session Ticket still valid for further %02d:%02d:%02d hours (%s < %s)', h, m, s, now_ms, self._ticket_expire)
return True
else:
self.log.debug('Removed expired auth ticket (%s < %s)', now_ms, self._ticket_expire)
self.log.debug('Removed expired Session Ticket (%s < %s)', now_ms, self._ticket_expire)
self._ticket_expire, self._ticket_start, self._ticket_end = (None, None, None)
return False
else:
Expand All @@ -86,5 +99,34 @@ def get_ticket(self):
else:
return False

def login(self, username, password):
raise NotImplementedError()
def user_login(self, username, password):
raise NotImplementedError()

def set_refresh_token(self, username, password):
raise NotImplementedError()

def get_access_token(self, force_refresh = False):
raise NotImplementedError()


def check_access_token(self):
"""
Add few seconds to now so the token get refreshed
before it invalidates in the middle of the request
"""
now_s = get_time() + 120

if self._access_token is not None:
if self._access_token_expiry == 0:
self.log.debug('No Access Token Expiry found - assuming it is still valid!')
return True
elif self._access_token_expiry > now_s:
h, m, s = get_format_time_diff(now_s, self._access_token_expiry, False)
self.log.debug('Access Token still valid for further %02d:%02d:%02d hours (%s < %s)', h, m, s, now_s, self._access_token_expiry)
return True
else:
self.log.info('Access Token expired!')
return False
else:
self.log.debug('No Access Token available!')
return False
74 changes: 55 additions & 19 deletions pgoapi/auth_google.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@

from __future__ import absolute_import

import six
import logging

from pgoapi.auth import Auth
from pgoapi.exceptions import AuthException
from gpsoauth import perform_master_login, perform_oauth

class AuthGoogle(Auth):
Expand All @@ -39,24 +41,58 @@ class AuthGoogle(Auth):

def __init__(self):
Auth.__init__(self)

self._auth_provider = 'google'

def login(self, username, password):
self.log.info('Google login for: {}'.format(username))
login = perform_master_login(username, password, self.GOOGLE_LOGIN_ANDROID_ID)
login = perform_oauth(username, login.get('Token', ''), self.GOOGLE_LOGIN_ANDROID_ID, self.GOOGLE_LOGIN_SERVICE, self.GOOGLE_LOGIN_APP,
self.GOOGLE_LOGIN_CLIENT_SIG)

self._auth_token = login.get('Auth')

if self._auth_token is None:
self.log.info('Google Login failed.')
return False

self._login = True

self.log.info('Google Login successful.')
self.log.debug('Google Session Token: %s', self._auth_token[:25])

return True
self._refresh_token = None

def user_login(self, username, password):
self.log.info('Google User Login for: {}'.format(username))

if not isinstance(username, six.string_types) or not isinstance(password, six.string_types):
raise AuthException("Username/password not correctly specified")

user_login = perform_master_login(username, password, self.GOOGLE_LOGIN_ANDROID_ID)

refresh_token = user_login.get('Token', None)
if refresh_token is not None:
self._refresh_token = refresh_token
self.log.info('Google User Login successful.')
else:
self._refresh_token = None
raise AuthException("Invalid Google Username/password")

self.get_access_token()

def set_refresh_token(self, refresh_token):
self.log.info('Google Refresh Token provided by user')
self._refresh_token = refresh_token

def get_access_token(self, force_refresh = False):
token_validity = self.check_access_token()

if token_validity is True and force_refresh is False:
self.log.debug('Using cached Google Access Token')
return self._access_token
else:
if force_refresh:
self.log.info('Forced request of Google Access Token!')
else:
self.log.info('Request Google Access Token...')

token_data = perform_oauth(None, self._refresh_token, self.GOOGLE_LOGIN_ANDROID_ID, self.GOOGLE_LOGIN_SERVICE, self.GOOGLE_LOGIN_APP,
self.GOOGLE_LOGIN_CLIENT_SIG)

access_token = token_data.get('Auth', None)
if access_token is not None:
self._access_token = access_token
self._access_token_expiry = int(token_data.get('Expiry', 0))
self._login = True

self.log.info('Google Access Token successfully received.')
self.log.debug('Google Access Token: %s...', self._access_token[:25])
return self._access_token
else:
self._access_token = None
self._login = False
raise AuthException("Could not receive a Google Access Token")
96 changes: 69 additions & 27 deletions pgoapi/auth_ptc.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,20 @@
"""

from __future__ import absolute_import
from future.standard_library import install_aliases
install_aliases()

import re
import six
import json
import logging
import requests

from urllib.parse import parse_qs

from pgoapi.auth import Auth
from pgoapi.utilities import get_time
from pgoapi.exceptions import AuthException

class AuthPtc(Auth):

Expand All @@ -46,9 +53,11 @@ def __init__(self):
self._session = requests.session()
self._session.verify = True

def login(self, username, password):
def user_login(self, username, password):
self.log.info('PTC User Login for: {}'.format(username))

self.log.info('Login for: %s', username)
if not isinstance(username, six.string_types) or not isinstance(password, six.string_types):
raise AuthException("Username/password not correctly specified")

head = {'User-Agent': 'niantic'}
r = self._session.get(self.PTC_LOGIN_URL, headers=head)
Expand All @@ -63,11 +72,12 @@ def login(self, username, password):
'password': password,
}
except ValueError as e:
self.log.error('Field missing in response: %s' % e)
self.log.error('PTC User Login Error - Field missing in response: %s', e)
return False
except KeyError as e:
self.log.error('Field missing in response.content: %s' % e)
self.log.error('PTC User Login Error - Field missing in response.content: %s', e)
return False

r1 = self._session.post(self.PTC_LOGIN_URL, data=data, headers=head)

ticket = None
Expand All @@ -77,30 +87,62 @@ def login(self, username, password):
try:
self.log.error('Could not retrieve token: %s', r1.json()['errors'][0])
except Exception as e:
self.log.error('Could not retrieve token! (%s)', str(e))
self.log.error('Could not retrieve token! (%s)', e)
return False

data1 = {
'client_id': 'mobile-app_pokemon-go',
'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
'client_secret': self.PTC_LOGIN_CLIENT_SECRET,
'grant_type': 'refresh_token',
'code': ticket,
}

r2 = self._session.post(self.PTC_LOGIN_OAUTH, data=data1)
access_token = re.sub('&expires.*', '', r2.content.decode('utf-8'))
access_token = re.sub('.*access_token=', '', access_token)

if '-sso.pokemon.com' in access_token:
self.log.info('PTC Login successful')
self.log.debug('PTC Session Token: %s', access_token[:25])
self._auth_token = access_token
self._refresh_token = ticket
self.log.info('PTC User Login successful.')

self.get_access_token()

def set_refresh_token(self, refresh_token):
self.log.info('PTC Refresh Token provided by user')
self._refresh_token = refresh_token

def get_access_token(self, force_refresh = False):
token_validity = self.check_access_token()

if token_validity is True and force_refresh is False:
self.log.debug('Using cached PTC Access Token')
return self._access_token
else:
self.log.info('Seems not to be a PTC Session Token... login failed :(')
return False

self._login = True

return True
if force_refresh:
self.log.info('Forced request of PTC Access Token!')
else:
self.log.info('Request PTC Access Token...')

data1 = {
'client_id': 'mobile-app_pokemon-go',
'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
'client_secret': self.PTC_LOGIN_CLIENT_SECRET,
'grant_type': 'refresh_token',
'code': self._refresh_token,
}

r2 = self._session.post(self.PTC_LOGIN_OAUTH, data=data1)

qs = r2.content.decode('utf-8')
token_data = parse_qs(qs)

access_token = token_data.get('access_token', None)
if access_token is not None:
self._access_token = access_token[0]

now_s = get_time()
expires = int(token_data.get('expires', [0])[0])
if expires > 0:
self._access_token_expiry = expires + now_s
else:
self._access_token_expiry = 0

self._login = True

self.log.info('PTC Access Token successfully retrieved.')
self.log.debug('PTC Access Token: %s...', self._access_token[:25])
else:
self._access_token = None
self._login = False
raise AuthException("Could not retrieve a PTC Access Token")



15 changes: 14 additions & 1 deletion pgoapi/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,17 @@ class ServerSideAccessForbiddenException(Exception):
pass

class UnexpectedResponseException(Exception):
pass
pass

class AuthTokenExpiredException(Exception):
pass

class ServerApiEndpointRedirectException(Exception):
def __init__(self):
self._api_endpoint = None

def get_redirected_endpoint(self):
return self._api_endpoint

def set_redirected_endpoint(self, api_endpoint):
self._api_endpoint = api_endpoint
Loading