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,
                                          proxy=self._proxy)

        try:
            refresh_token = user_login.get('Token', None)
        except ConnectionError as e:
            raise AuthException("Caught ConnectionError: %s", e)

        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()
        return self._login
예제 #2
0
    def set_authentication(self,
                           provider=None,
                           oauth2_refresh_token=None,
                           username=None,
                           password=None):
        if provider == 'ptc':
            self._auth_provider = AuthPtc()
        elif provider == 'google':
            self._auth_provider = AuthGoogle()
        elif provider is None:
            self._auth_provider = None
        else:
            raise AuthException(
                "Invalid authentication provider - only ptc/google available.")

        self.log.debug('Auth provider: %s', provider)

        if oauth2_refresh_token is not None:
            self._auth_provider.set_refresh_token(oauth2_refresh_token)
        elif username is not None and password is not None:
            self._auth_provider.user_login(username, password)
        else:
            raise AuthException(
                "Invalid Credential Input - Please provide username/password or an oauth2 refresh token"
            )
예제 #3
0
    def user_login(self, username, password):
        self.log.info('Google User Login for: {}'.format(username))

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

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

        if user_login and user_login.get('Error', None) == 'NeedsBrowser':
            raise AuthGoogleTwoFactorRequiredException(
                user_login['Url'], user_login['ErrorDetail'])

        try:
            refresh_token = user_login.get('Token', None)
        except ConnectionError as e:
            raise AuthException("Caught ConnectionError: %s", e)

        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()
        return self._login
예제 #4
0
    def login(self, provider, username, password, lat = None, lng = None, alt = None, app_simulation = True):

        if (lat is not None) and (lng is not None) and (alt is not None):
            self._position_lat = lat
            self._position_lng = lng
            self._position_alt = alt

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

        if provider == 'ptc':
            self._auth_provider = AuthPtc()
        elif provider == 'google':
            self._auth_provider = AuthGoogle()
        else:
            raise AuthException("Invalid authentication provider - only ptc/google available.")

        self.log.debug('Auth provider: %s', provider)

        if not self._auth_provider.login(username, password):
            self.log.info('Login process failed')
            return False

        if app_simulation:
            self.log.info('Starting RPC login sequence (app simulation)')

            # making a standard call, like it is also done by the client
            request = self.create_request()

            request.get_player()
            request.get_hatched_eggs()
            request.get_inventory()
            request.check_awarded_badges()
            request.download_settings(hash="05daf51635c82611d1aac95c0b051d3ec088a930")

            response = request.call()
        else:
            self.log.info('Starting minimal RPC login sequence')
            response = self.get_player()

        if not response:
            self.log.info('Login failed!')
            return False

        if 'api_url' in response:
            self._api_endpoint = ('https://{}/rpc'.format(response['api_url']))
            self.log.debug('Setting API endpoint to: %s', self._api_endpoint)
        else:
            self.log.error('Login failed - unexpected server response!')
            return False

        if app_simulation:
            self.log.info('Finished RPC login sequence (app simulation)')
        else:
            self.log.info('Finished minimal RPC login sequence')

        self.log.info('Login process completed')

        return True
예제 #5
0
    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:
            if force_refresh:
                self.log.info('Forced request of PTC Access Token!')
            else:
                self.log.info('Request PTC Access Token...')

            data = {
                '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,
            }

            try:
                r = self._session.post(self.PTC_LOGIN_OAUTH,
                                       data=data,
                                       timeout=self.timeout)
            except Timeout:
                raise AuthTimeoutException('Auth POST timed out.')
            except RequestException as e:
                raise AuthException('Caught RequestException: {}'.format(e))

            token_data = parse_qs(r.text)

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

                # set expiration to an hour less than value received because Pokemon OAuth
                # login servers return an access token with an explicit expiry time of
                # three hours, however, the token stops being valid after two hours.
                # See issue #86
                expires = int(token_data.get('expires', [0])[0]) - 3600
                if expires > 0:
                    self._access_token_expiry = expires + get_time()
                else:
                    self._access_token_expiry = 0

                self._login = True

                self.log.info('PTC Access Token successfully retrieved.')
                self.log.debug('PTC Access Token: {}'.format(
                    self._access_token))
            else:
                self._access_token = None
                self._login = False
                if force_refresh:
                    self.log.info(
                        'Reauthenticating with refresh token failed, using credentials instead.'
                    )
                    return self.user_login(retry=False)
                raise AuthException("Could not retrieve a PTC Access Token")
예제 #6
0
    def user_login(self, username=None, password=None, retry=True):
        self._username = username or self._username
        self._password = password or self._password
        if not isinstance(self._username, string_types) or not isinstance(
                self._password, string_types):
            raise InvalidCredentialsException(
                "Username/password not correctly specified")

        self.log.info('PTC User Login for: {}'.format(self._username))
        self._session.cookies.clear()
        now = get_time()

        try:
            r = self._session.get(self.PTC_LOGIN_URL1, timeout=self.timeout)
        except Timeout:
            raise AuthTimeoutException('Auth GET timed out.')
        except RequestException as e:
            raise AuthException('Caught RequestException: {}'.format(e))

        try:
            data = r.json()
            data.update({
                '_eventId': 'submit',
                'username': self._username,
                'password': self._password,
            })
        except (ValueError, AttributeError) as e:
            self.log.error(
                'PTC User Login Error - invalid JSON response: {}'.format(e))
            raise AuthException('Invalid JSON response: {}'.format(e))

        try:
            r = self._session.post(self.PTC_LOGIN_URL2,
                                   data=data,
                                   timeout=self.timeout,
                                   allow_redirects=False)
        except Timeout:
            raise AuthTimeoutException('Auth POST timed out.')
        except RequestException as e:
            raise AuthException('Caught RequestException: {}'.format(e))

        try:
            qs = parse_qs(urlsplit(r.headers['Location'])[3])
            self._refresh_token = qs.get('ticket')[0]
        except Exception as e:
            raise AuthException('Could not retrieve token! {}'.format(e))

        self._access_token = self._session.cookies.get('CASTGC')
        if self._access_token:
            self._login = True
            self._access_token_expiry = int(now) + 7200
            self.log.info('PTC User Login successful.')
        elif self._refresh_token and retry:
            self.get_access_token()
        else:
            self._login = False
            raise AuthException("Could not retrieve a PTC Access Token")
        return self._login
예제 #7
0
    def login(self, provider, username, password, cached=False):
        if not isinstance(username, basestring) or not isinstance(
                password, basestring):
            raise AuthException("Username/password not correctly specified")

        if provider == 'ptc':
            self._auth_provider = AuthPtc()
        elif provider == 'google':
            self._auth_provider = AuthGoogle()
        else:
            raise AuthException(
                "Invalid authentication provider - only ptc/google available.")

        self.log.debug('Auth provider: %s', provider)

        if not self._auth_provider.login(username, password):
            self.log.info('Login process failed')
            return False

        self.log.info('Starting RPC login sequence (app simulation)')
        self.get_player()
        self.get_hatched_eggs()
        self.get_inventory()
        self.check_awarded_badges()
        self.download_settings(hash="05daf51635c82611d1aac95c0b051d3ec088a930"
                               )  # not sure what this is but dont change it

        response = self.call()

        if not response:
            self.log.info('Login failed!')
        if os.path.isfile("auth_cache") and cached:
            response = pickle.load(open("auth_cache"))
        fname = "auth_cache_%s" % username
        if os.path.isfile(fname) and cached:
            response = pickle.load(open(fname))
        else:
            response = self.heartbeat()
            f = open(fname, "w")
            pickle.dump(response, f)
        if not response:
            self.log.info('Login failed!')
            return False

        if 'api_url' in response:
            self._api_endpoint = ('https://{}/rpc'.format(response['api_url']))
            self.log.debug('Setting API endpoint to: %s', self._api_endpoint)
        else:
            self.log.error('Login failed - unexpected server response!')
            return False

        if 'auth_ticket' in response:
            self._auth_provider.set_ticket(response['auth_ticket'].values())

        self.log.info('Finished RPC login sequence (app simulation)')
        self.log.info('Login process completed')

        return True
예제 #8
0
    def user_login(self, username, password):
        self.log.info('PTC 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")

        head = {'User-Agent': 'niantic'}

        try:
            r = self._session.get(self.PTC_LOGIN_URL, headers=head)
        except ConnectionError as e:
            raise AuthException("Caught ConnectionError: %s", e)

        try:
            jdata = json.loads(r.content.decode('utf-8'))
            data = {
                'lt': jdata['lt'],
                'execution': jdata['execution'],
                '_eventId': 'submit',
                'username': username,
                'password': password,
            }
        except ValueError as e:
            self.log.error(
                'PTC User Login Error - Field missing in response: %s', e)
            return False
        except KeyError as 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
        try:
            ticket = re.sub('.*ticket=', '', r1.history[0].headers['Location'])
        except Exception as e:
            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)', e)
            return False

        self._refresh_token = ticket
        self.log.info('PTC User Login successful.')

        self.get_access_token()
        return self._login
예제 #9
0
    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")
예제 #10
0
    def set_authentication(self,
                           provider=None,
                           oauth2_refresh_token=None,
                           username=None,
                           password=None,
                           proxy_config=None,
                           user_agent=None,
                           timeout=None):
        if provider == 'ptc':
            self._auth_provider = AuthPtc(user_agent=user_agent,
                                          timeout=timeout)
        elif provider == 'google':
            self._auth_provider = AuthGoogle()
        elif provider is None:
            self._auth_provider = None
        else:
            raise InvalidCredentialsException(
                "Invalid authentication provider - only ptc/google available.")

        self.log.debug('Auth provider: {}'.format(provider))

        if proxy_config:
            self._auth_provider.set_proxy(proxy_config)

        if oauth2_refresh_token is not None:
            self._auth_provider.set_refresh_token(oauth2_refresh_token)
        elif username and password:
            if not self._auth_provider.user_login(username, password):
                raise AuthException("User login failed!")
        else:
            raise InvalidCredentialsException(
                "Invalid Credential Input - Please provide username/password or an oauth2 refresh token"
            )
예제 #11
0
    def heartbeat(self):
        self.get_player()
        if self._heartbeat_number % 10 == 0:
            self.check_awarded_badges()
            self.get_inventory()

        res = self.call()

        if res.get("direction",-1) == 102:
            self.log.error("There were a problem responses for api call: %s. Restarting!!!", res)
            raise AuthException("Token probably expired?")

        self.log.debug('Heartbeat dictionary: \n\r{}'.format(json.dumps(res, indent=2)))

        if 'GET_PLAYER' in res['responses']:
            player_data = res['responses'].get('GET_PLAYER', {}).get('player_data', {})
            currencies = player_data.get('currencies', [])
            currency_data = ",".join(map(lambda x: "{0}: {1}".format(x.get('name', 'NA'), x.get('amount', 'NA')), currencies))
#            self.log.info("Username: %s, Currencies: %s", player_data.get('username', 'NA'), currency_data)

        if 'GET_INVENTORY' in res['responses']:
            with open("accounts/%s.json" % self.config['username'], "w") as f:
                res['responses']['lat'] = self._posf[0]
                res['responses']['lng'] = self._posf[1]
                res['responses']['alt'] = self._posf[2]
                f.write(json.dumps(res['responses'], indent=2))

            if self.print_info:
                self.log.info(get_inventory_data(res, self.pokemon_data))
                self.print_info = False

            self.log.debug(self.cleanup_inventory(res['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']))

        self._heartbeat_number += 1
        return res
예제 #12
0
    def heartbeat(self):
        self.get_player()
        if self._heartbeat_number % 10 == 0 or self._heartbeat_number == 0:  # every 10 heartbeats do a inventory check
            self.check_awarded_badges()
            self.get_inventory()
        res = self.call()
        if res.get("direction", -1) == 102:
            self.log.error(
                "There were a problem responses for api call: %s. Restarting!!!",
                res)
            raise AuthException("Token probably expired?")
        self.log.debug('Heartbeat dictionary: \n\r{}'.format(
            json.dumps(res, indent=2)))
        if 'GET_PLAYER' in res['responses']:
            player_data = res['responses'].get('GET_PLAYER',
                                               {}).get('player_data', {})
            if os.path.isfile("accounts/%s.json" % self.config['username']):
                with open("accounts/%s.json" % self.config['username'],
                          "r") as f:
                    file = f.read()
                    json_file = json.loads(file)
                inventory_items = json_file.get('GET_INVENTORY', {}).get(
                    'inventory_delta', {}).get('inventory_items', [])
                inventory_items_dict_list = map(
                    lambda x: x.get('inventory_item_data', {}),
                    inventory_items)
                player_stats = filter(lambda x: 'player_stats' in x,
                                      inventory_items_dict_list)[0].get(
                                          'player_stats', {})
            else:
                player_stats = {}
            currencies = player_data.get('currencies', [])
            currency_data = ",".join(
                map(
                    lambda x: "{0}: {1}".format(x.get('name', 'NA'),
                                                x.get('amount', 'NA')),
                    currencies))
        if 'GET_INVENTORY' in res['responses']:
            with open("accounts/%s.json" % self.config['username'], "w") as f:
                res['responses']['lat'] = self._posf[0]
                res['responses']['lng'] = self._posf[1]
                f.write(json.dumps(res['responses'], indent=2))
            self.log.info("\n List of Pokemon:\n" +
                          get_inventory_data(res, self.pokemon_names) +
                          "\nTotal Pokemon count: " +
                          str(get_pokemon_num(res)) +
                          "\nEgg Hatching status: " +
                          get_incubators_stat(res) + "\n")
            self.log.info(
                "\n Username: %s, Lvl: %s, XP: %s/%s \n Currencies: %s \n",
                player_data.get('username', 'NA'),
                player_stats.get('level', 'NA'),
                player_stats.get('experience', 'NA'),
                player_stats.get('next_level_xp', 'NA'), currency_data)
            self.log.debug(
                self.cleanup_inventory(res['responses']['GET_INVENTORY']
                                       ['inventory_delta']['inventory_items']))

        self._heartbeat_number += 1
        return res
예제 #13
0
    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:
            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()
                # set expiration to an hour less than value received because Pokemon OAuth
                # login servers return an access token with an explicit expiry time of
                # three hours, however, the token stops being valid after two hours.
                # See issue #86
                expires = int(token_data.get('expires', [0])[0]) - 3600
                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")
예제 #14
0
    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:
            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
0
    def user_login(self, username=None, password=None, retry=True):
        self._username = username or self._username
        self._password = password or self._password
        if not isinstance(self._username, string_types) or not isinstance(
                self._password, string_types):
            raise InvalidCredentialsException(
                "Username/password not correctly specified")

        self.log.info('PTC User Login for: {}'.format(self._username))
        self._session.cookies.clear()
        now = get_time()

        get_params = {
            'client_id': 'mobile-app_pokemon-go',
            'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
            'locale': self.locale
        }

        try:
            r = self._session.get(self.PTC_LOGIN_URL1_GET,
                                  params=get_params,
                                  timeout=self.timeout)
        except Timeout:
            raise AuthTimeoutException('Auth GET timed out.')
        except RequestException as e:
            raise AuthException('Caught RequestException: {}'.format(e))

        try:
            # Consumes response, so connection is released to pool.
            data = r.json()
            data.update({
                '_eventId': 'submit',
                'username': self._username,
                'password': self._password,
            })
        except (ValueError, AttributeError) as e:
            self.log.error(
                'PTC User Login Error - invalid JSON response: {}'.format(e))
            raise AuthException('Invalid JSON response: {}'.format(e))

        post_params = {
            'locale': self.locale,
            'service': 'http://sso.pokemon.com/sso/oauth2.0/callbackAuthorize'
        }

        post_headers = {'Content-Type': 'application/x-www-form-urlencoded'}

        try:
            r = self._session.post(self.PTC_LOGIN_URL2_POST,
                                   data=data,
                                   params=post_params,
                                   headers=post_headers,
                                   timeout=self.timeout,
                                   allow_redirects=False)
        except Timeout:
            raise AuthTimeoutException('Auth POST timed out.')
        except RequestException as e:
            raise AuthException('Caught RequestException: {}'.format(e))

        try:
            qs = parse_qs(urlsplit(r.headers['Location'])[3])
            self._refresh_token = qs.get('ticket')[0]
        except Exception as e:
            raise AuthException('Could not retrieve token! {}'.format(e))

        # We don't consume the response, so explicitly release connection.
        r.close()

        self._access_token = self._session.cookies.get('CASTGC')
        if self._access_token:
            self._login = True
            self._access_token_expiry = int(now) + 7200
            self.log.info('PTC User Login successful.')
        elif self._refresh_token and retry:
            self.get_access_token()
        else:
            self._login = False
            raise AuthException("Could not retrieve a PTC Access Token")
        return self._login
예제 #16
0
    def _heartbeat(self, res=False, login_response=False):
        if not isinstance(res, dict):
            # limit the amount of heartbeats, every second is just too much in my opinion!
            if (not self._heartbeat_number % self._heartbeat_frequency == 0
                    and not self._heartbeat_number %
                    self._full_heartbeat_frequency == 0):
                self._heartbeat_number += 1
                return

            # making a standard call to update position, etc
            req = self.api.create_request()
            req.get_player()
            if self._heartbeat_number % 10 == 0:
                req.check_awarded_badges()
                req.get_inventory()
            res = req.call()
            if not res or res.get("direction", -1) == 102:
                self.log.error(
                    "There were a problem responses for api call: %s. Restarting!!!",
                    res)
                self.api.force_refresh_access_token()
                raise AuthException("Token probably expired?")

        self.log.debug('Response dictionary: \n\r{}'.format(
            json.dumps(res, indent=2, default=lambda obj: obj.decode('utf8'))))

        responses = res.get('responses', {})
        if 'GET_PLAYER' in responses:
            self.player = Player(
                responses.get('GET_PLAYER', {}).get('player_data', {}))
            self.log.info(
                "Player Info: {0}, Pokemon Caught in this run: {1}".format(
                    self.player, self.pokemon_caught))

        if 'GET_INVENTORY' in responses:

            # update objects
            self.inventory.update_player_inventory(res=res)
            for inventory_item in self.inventory.inventory_items:
                if "player_stats" in inventory_item['inventory_item_data']:
                    self.player_stats = PlayerStats(
                        inventory_item['inventory_item_data']['player_stats'],
                        self.pokemon_caught, self.start_time, self.exp_start)
                    if self.exp_start is None:
                        self.exp_start = self.player_stats.run_exp_start
                    self.log.info("Player Stats: {}".format(self.player_stats))
            if self.config.list_inventory_before_cleanup:
                self.log.info("Player Inventory: %s", self.inventory)
            if not login_response:
                # self.log.debug(self.inventory.cleanup_inventory())
                self.inventory.cleanup_inventory()
                self.log.info("Player Inventory after cleanup: %s",
                              self.inventory)
            if self.config.list_pokemon_before_cleanup:
                self.log.info(
                    os.linesep.join(
                        map(str, self.inventory.get_caught_pokemon())))

            if not login_response:
                # maintenance
                self.incubate.incubate_eggs()
                self.inventory.use_lucky_egg()
                self.evolve.attempt_evolve()
                self.release.cleanup_pokemon()

            # save data dump
            with open("data_dumps/%s.json" % self.config.username, "w") as f:
                posf = self.get_position()
                responses['lat'] = posf[0]
                responses['lng'] = posf[1]
                responses['GET_PLAYER']['player_data'][
                    'hourly_exp'] = self.player_stats.run_hourly_exp
                f.write(
                    json.dumps(responses,
                               indent=2,
                               default=lambda obj: obj.decode('utf8')))

            # Farm precon
            if self.config.farm_items_enabled:
                pokeball_count = 0
                if not self.config.farm_ignore_pokeball_count:
                    pokeball_count += self.inventory.poke_balls
                if not self.config.farm_ignore_greatball_count:
                    pokeball_count += self.inventory.great_balls
                if not self.config.farm_ignore_ultraball_count:
                    pokeball_count += self.inventory.ultra_balls
                if not self.config.farm_ignore_masterball_count:
                    pokeball_count += self.inventory.master_balls
                if self.config.pokeball_farm_threshold > pokeball_count and not self._farm_mode_triggered:
                    self.should_catch_pokemon = False
                    self._farm_mode_triggered = True
                    self.log.info(
                        "Player only has %s Pokeballs, farming for more...",
                        pokeball_count)
                    if self.config.farm_override_step_size != -1:
                        self.step_size = self.config.farm_override_step_size
                        self.log.info("Player has changed speed to %s",
                                      self.step_size)
                elif self.config.pokeball_continue_threshold <= pokeball_count and self._farm_mode_triggered:
                    self.should_catch_pokemon = self.config.should_catch_pokemon  # Restore catch pokemon setting from config file
                    self._farm_mode_triggered = False
                    self.log.info(
                        "Player has %s Pokeballs, continuing to catch more!",
                        pokeball_count)
                    if self.config.farm_override_step_size != -1:
                        self.step_size = self.config.step_size
                        self.log.info(
                            "Player has returned to normal speed of %s",
                            self.step_size)

        if 'DOWNLOAD_SETTINGS' in responses:
            settings = responses.get('DOWNLOAD_SETTINGS',
                                     {}).get('settings', {})
            if settings.get('minimum_client_version', '0.0.0') > '0.33.0':
                self.log.error(
                    "Minimum client version has changed... the bot needs to be updated! Will now stop!"
                )
                exit(0)
            map_settings = settings.get('map_settings', {})

            get_map_objects_min_refresh_seconds = map_settings.get(
                'get_map_objects_min_refresh_seconds', 0.0)  # std. 5.0
            if get_map_objects_min_refresh_seconds != self.map_objects.get_api_rate_limit(
            ):
                self.map_objects.update_rate_limit(
                    get_map_objects_min_refresh_seconds)
            """
            fort_settings = settings.get('fort_settings', {})
            inventory_settings = settings.get('inventory_settings', {})

            get_map_objects_max_refresh_seconds = map_settings.get('get_map_objects_max_refresh_seconds', 30.0)
            get_map_objects_min_distance_meters = map_settings.get('get_map_objects_min_distance_meters', 10.0)
            encounter_range_meters = map_settings.get('encounter_range_meters', 50.0)
            poke_nav_range_meters = map_settings.get('poke_nav_range_meters', 201.0)
            pokemon_visible_range = map_settings.get('pokemon_visible_range', 70.0)
            get_map_objects_min_refresh_seconds = map_settings.get('get_map_objects_min_refresh_seconds', 5.0)
            google_maps_api_key = map_settings.get('google_maps_api_key', '')

            self.log.info('complete settings: %s', responses.get('DOWNLOAD_SETTINGS', {}))

            self.log.info('minimum_client_version: %s', str(settings.get('minimum_client_version', '0.0.0')))

            self.log.info('poke_nav_range_meters: %s', str(poke_nav_range_meters))
            self.log.info('pokemon_visible_range: %s', str(pokemon_visible_range))

            self.log.info('get_map_objects_min_refresh_seconds: %s', str(get_map_objects_min_refresh_seconds))
            self.log.info('get_map_objects_max_refresh_seconds: %s', str(get_map_objects_max_refresh_seconds))
            self.log.info('get_map_objects_min_distance_meters: %s', str(get_map_objects_min_distance_meters))
            self.log.info('encounter_range_meters: %s', str(encounter_range_meters))
            """

        self._heartbeat_number += 1
        return res