Example #1
0
        def function(**kwargs):
            name = func.upper()

            position = kwargs.pop('position')
            callback = kwargs.pop('callback')

            if kwargs:
                method = {RequestType.Value(name): kwargs}
                self.log.debug(
                    "Adding '%s' to RPC request including arguments", name)
                self.log.debug("Arguments of '%s': \n\r%s", name, kwargs)
            else:
                method = RequestType.Value(name)
                self.log.debug("Adding '%s' to RPC request", name)

            self.call_method(method, position, callback)
Example #2
0
    def __getattr__(self, func):
        def function(**kwargs):

            if '_call_direct' in kwargs:
                del kwargs['_call_direct']
                self.log.info('Creating a new direct request...')
            elif not self._req_method_list:
                self.log.info('Creating a new request...')

            name = func.upper()
            if kwargs:
                self._req_method_list.append({RequestType.Value(name): kwargs})
                self.log.info("Adding '%s' to RPC request including arguments",
                              name)
                self.log.debug("Arguments of '%s': \n\r%s", name, kwargs)
            else:
                self._req_method_list.append(RequestType.Value(name))
                self.log.info("Adding '%s' to RPC request", name)

            return self

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #3
0
    def _build_sub_requests(self, mainrequest, subrequest_list):
        self.log.debug('Generating sub RPC requests...')

        for entry in subrequest_list:
            if isinstance(entry, dict):

                entry_id = list(entry.items())[0][0]
                entry_content = entry[entry_id]

                entry_name = RequestType.Name(entry_id)

                proto_name = to_camel_case(entry_name.lower()) + 'Message'
                proto_classname = 'POGOProtos.Networking.Requests.Messages.' + proto_name + '_pb2.' + proto_name
                subrequest_extension = self.get_class(proto_classname)()

                self.log.debug("Subrequest class: %s", proto_classname)

                for (key, value) in entry_content.items():
                    if isinstance(value, list):
                        self.log.debug("Found list: %s - trying as repeated", key)
                        for i in value:
                            try:
                                self.log.debug("%s -> %s", key, i)
                                r = getattr(subrequest_extension, key)
                                r.append(i)
                            except Exception as e:
                                self.log.warning('Argument %s with value %s unknown inside %s (Exception: %s)', key, i, proto_name, e)
                    elif isinstance(value, dict):
                        for k in value.keys():
                            try:
                                r = getattr(subrequest_extension, key)
                                setattr(r, k, value[k])
                            except Exception as e:
                                self.log.warning('Argument %s with value %s unknown inside %s (Exception: %s)', key, str(value), proto_name, e)
                    else:
                        try:
                            setattr(subrequest_extension, key, value)
                        except Exception as e:
                            try:
                                self.log.debug("%s -> %s", key, value)
                                r = getattr(subrequest_extension, key)
                                r.append(value)
                            except Exception as e:
                                self.log.warning('Argument %s with value %s unknown inside %s (Exception: %s)', key, value, proto_name, e)

                subrequest = mainrequest.requests.add()
                subrequest.request_type = entry_id
                subrequest.request_message = subrequest_extension.SerializeToString()

            elif isinstance(entry, int):
                subrequest = mainrequest.requests.add()
                subrequest.request_type = entry
            else:
                raise Exception('Unknown value in request list')

        return mainrequest
    def _parse_sub_responses(self, response_proto, subrequests_list,
                             response_proto_dict):
        self.log.debug('Parsing sub RPC responses...')
        response_proto_dict['responses'] = {}

        if response_proto_dict.get('status_code', 1) == 53:
            exception = ServerApiEndpointRedirectException()
            exception.set_redirected_endpoint(response_proto_dict['api_url'])
            raise exception

        if 'returns' in response_proto_dict:
            del response_proto_dict['returns']

        list_len = len(subrequests_list) - 1
        i = 0
        for subresponse in response_proto.returns:
            if i > list_len:
                self.log.info("Error - something strange happend...")

            request_entry = subrequests_list[i]
            if isinstance(request_entry, int):
                entry_id = request_entry
            else:
                entry_id = list(request_entry.items())[0][0]

            entry_name = RequestType.Name(entry_id)
            proto_name = to_camel_case(entry_name.lower()) + 'Response'
            proto_classname = 'POGOProtos.Networking.Responses.' + proto_name + '_pb2.' + proto_name

            self.log.debug("Parsing class: %s", proto_classname)

            subresponse_return = None
            try:
                subresponse_extension = self.get_class(proto_classname)()
            except Exception as e:
                subresponse_extension = None
                error = 'Protobuf definition for {} not found'.format(
                    proto_classname)
                subresponse_return = error
                self.log.debug(error)

            if subresponse_extension:
                try:
                    subresponse_extension.ParseFromString(subresponse)
                    subresponse_return = protobuf_to_dict(
                        subresponse_extension)
                except:
                    error = "Protobuf definition for {} seems not to match".format(
                        proto_classname)
                    subresponse_return = error
                    self.log.debug(error)

            response_proto_dict['responses'][entry_name] = subresponse_return
            i += 1

        return response_proto_dict
Example #5
0
    def __getattr__(self, func):
        def function(**kwargs):
            request = self.create_request()
            getattr(request, func)(_call_direct=True, **kwargs )
            return request.call()

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #6
0
    def __getattr__(self, func):
        def function(**kwargs):
            request = self.create_request()
            getattr(request, func)(_call_direct=True, **kwargs)
            return request.call()

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #7
0
    def __getattr__(self, func):
        def function(**kwargs):
            name = func.upper()

            position = kwargs.pop('position')
            callback = kwargs.pop('callback')

            if kwargs:
                method = {RequestType.Value(name): kwargs}
                self.log.debug(
                    "Adding '%s' to RPC request including arguments", name)
                self.log.debug("Arguments of '%s': \n\r%s", name, kwargs)
            else:
                method = RequestType.Value(name)
                self.log.debug("Adding '%s' to RPC request", name)

            self.call_method(method, position, callback)

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #8
0
    def __getattr__(self, func):
        def function(**kwargs):
            name = func.upper()

            position = kwargs.pop('position')
            callback = kwargs.pop('callback')

            if kwargs:
                method = {RequestType.Value(name): kwargs}
                self.log.debug(
                   "Adding '%s' to RPC request including arguments", name)
                self.log.debug("Arguments of '%s': \n\r%s", name, kwargs)
            else:
                method = RequestType.Value(name)
                self.log.debug("Adding '%s' to RPC request", name)

            self.call_method(method, position, callback)

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #9
0
    def __getattr__(self, func):
        def function(**kwargs):

            if '_call_direct' in kwargs:
                del kwargs['_call_direct']
                self.log.info('Creating a new direct request...')
            elif not self._req_method_list:
                self.log.info('Creating a new request...')

            name = func.upper()
            if kwargs:
                self._req_method_list.append({RequestType.Value(name): kwargs})
                self.log.info("Adding '%s' to RPC request including arguments", name)
                self.log.debug("Arguments of '%s': \n\r%s", name, kwargs)
            else:
                self._req_method_list.append(RequestType.Value(name))
                self.log.info("Adding '%s' to RPC request", name)

            return self

        if func.upper() in RequestType.keys():
            return function
        else:
            raise AttributeError
Example #10
0
 def list_curr_methods(self):
     for i in self._req_method_list:
         print("{} ({})".format(RequestType.Name(i), i))
Example #11
0
class PGoApiWorker(Thread):
    THROTTLE_TIME = 10.0
    # In case the server returns a status code 3, this has to be requested
    SC_3_REQUESTS = [RequestType.Value("GET_PLAYER")]

    def __init__(self, signature_lib_path, work_queue, auth_queue):
        Thread.__init__(self)
        self.log = logging.getLogger(__name__)
        self._running = True

        self._work_queue = work_queue
        self._auth_queue = auth_queue
        self.rpc_api = RpcApi(None)
        self.rpc_api.activate_signature(signature_lib_path)

    def _get_auth_provider(self):
        while True:  # Maybe change this loop to something more beautiful?
            next_call, auth_provider = self._auth_queue.get()
            if (time.time() + self.THROTTLE_TIME < next_call):
                # Probably one of the sidelined auth providers, skip it
                self._auth_queue.put((next_call, auth_provider))
            else:
                # Sleep until the auth provider is ready
                if (time.time() < next_call):  # Kind of a side effect -> bad
                    time.sleep(max(next_call - time.time(), 0))
                return (next_call, auth_provider)

    def run(self):
        while self._running:
            method, position, callback = self._work_queue.get()
            if not self._running:
                self._work_queue.put((method, position, callback))
                self._work_queue.task_done()
                continue

            next_call, auth_provider = self._get_auth_provider()
            if not self._running:
                self._auth_queue.put((next_call, auth_provider))
                self._work_queue.put((method, position, callback))
                self._work_queue.task_done()
                continue

            # Let's do this.
            self.rpc_api._auth_provider = auth_provider
            try:
                response = self.call(auth_provider, [method], position)
                next_call = time.time() + self.THROTTLE_TIME
            except Exception as e:
                # Too many login retries lead to an AuthException
                # So let us sideline this auth provider for 5 minutes
                if isinstance(e, AuthException):
                    self.log.error(
                        "AuthException in worker thread. Username: {}".format(
                            auth_provider.username))
                    next_call = time.time() + 5 * 60
                else:
                    self.log.error(
                        "Error in worker thread. Returning empty response. Error: {}"
                        .format(e))
                    next_call = time.time() + self.THROTTLE_TIME

                self._work_queue.put((method, position, callback))
                response = {}

            self._work_queue.task_done()
            self.rpc_api._auth_provider = None
            self._auth_queue.put((next_call, auth_provider))
            callback(response)

    def stop(self):
        self._running = False

    def call(self, auth_provider, req_method_list, position):
        if not req_method_list:
            raise EmptySubrequestChainException()

        lat, lng, alt = position
        if (lat is None) or (lng is None) or (alt is None):
            raise NoPlayerPositionSetException()

        self.log.debug('Execution of RPC')
        response = None

        again = True  # Status code 53 or not logged in?
        retries = 5
        while again:
            self._login_if_necessary(auth_provider, position)

            try:
                response = self.rpc_api.request(
                    auth_provider.get_api_endpoint(), req_method_list,
                    position)
                if not response:
                    raise ValueError(
                        'Request returned problematic response: {}'.format(
                            response))
            except (NotLoggedInException, AuthTokenExpiredException):
                pass  # Trying again will trigger login in _login_if_necessary
            except ServerApiEndpointRedirectException as e:
                auth_provider.set_api_endpoint('https://{}/rpc'.format(
                    e.get_redirected_endpoint()))
            except Exception as e:  # Never crash the worker
                if isinstance(e, ServerBusyOrOfflineException):
                    self.log.info('Server seems to be busy or offline!')
                else:
                    self.log.info(
                        'Unexpected error during request: {}'.format(e))
                if retries == 0:
                    return {}
                retries -= 1
            else:
                if 'api_url' in response:
                    auth_provider.set_api_endpoint('https://{}/rpc'.format(
                        response['api_url']))

                if 'status_code' in response and response['status_code'] == 3:
                    self.log.info(
                        "Status code 3 returned. Performing get_player request."
                    )
                    req_method_list = self.SC_3_REQUESTS + req_method_list
                    auth_provider.code_three_counter += 1
                elif 'responses' in response and not response['responses']:
                    self.log.info(
                        "Received empty map_object response. Logging out and retrying."
                    )
                    auth_provider._access_token_expiry = time.time(
                    )  # This will trigger a login in _login_if_necessary
                    auth_provider.code_three_counter = 0
                else:
                    again = False
                    auth_provider.code_three_counter = 0

                if auth_provider.code_three_counter > 1:
                    self.log.info(
                        "Received two consecutive status_code 3 on account {}, probably banned."
                        .format(auth_provider.username))

        return response

    def _login(self, auth_provider, position):
        self.log.info('Attempting login: {}'.format(auth_provider.username))
        consecutive_fails = 0

        while not auth_provider.user_login():
            sleep_t = min(math.exp(consecutive_fails / 1.7), 5 * 60)
            self.log.info(
                'Login failed, retrying in {:.2f} seconds'.format(sleep_t))
            consecutive_fails += 1
            time.sleep(sleep_t)
            if consecutive_fails == 5:
                raise AuthException('Login failed five times.')

        self.log.info('Login successful: {}'.format(auth_provider.username))

    def _login_if_necessary(self, auth_provider, position):
        if not auth_provider.is_login(
        ) or auth_provider._access_token_expiry < time.time() + 120:
            if auth_provider.is_login():
                self.log.info(
                    "{} access token has or is about to expire".format(
                        auth_provider.username))
            self._login(auth_provider, position)
Example #12
0
    def _build_main_request(self, subrequests, player_position=None):
        self.log.debug('Generating main RPC request...')

        request = RequestEnvelope()
        request.status_code = 2
        request.request_id = self.get_rpc_id()
        request.accuracy = random.choice((5, 5, 5, 10, 10, 30, 50, 65))

        if player_position:
            request.latitude, request.longitude, altitude = player_position

        # generate sub requests before SignalAgglomUpdates generation
        request = self._build_sub_requests(request, subrequests)

        ticket = self._auth_provider.get_ticket()
        if ticket:
            self.log.debug(
                'Found Session Ticket - using this instead of oauth token')
            request.auth_ticket.expire_timestamp_ms, request.auth_ticket.start, request.auth_ticket.end = ticket
            ticket_serialized = request.auth_ticket.SerializeToString()

        else:
            self.log.debug(
                'No Session Ticket found - using OAUTH Access Token')
            request.auth_info.provider = self._auth_provider.get_name()
            request.auth_info.token.contents = self._auth_provider.get_access_token(
            )
            request.auth_info.token.unknown2 = 59
            ticket_serialized = request.auth_info.SerializeToString(
            )  #Sig uses this when no auth_ticket available

        if self._signal_agglom_gen:
            sig = SignalAgglomUpdates()

            sig.field22 = self.session_hash
            sig.epoch_timestamp_ms = get_time(ms=True)
            sig.timestamp_ms_since_start = get_time(
                ms=True) - RpcApi.START_TIME
            if sig.timestamp_ms_since_start < 5000:
                sig.timestamp_ms_since_start = random.randint(5000, 8000)

            self._hash_engine.hash(sig.epoch_timestamp_ms, request.latitude,
                                   request.longitude, request.accuracy,
                                   ticket_serialized, sig.field22,
                                   request.requests)
            sig.location_hash_by_token_seed = self._hash_engine.get_location_auth_hash(
            )
            sig.location_hash = self._hash_engine.get_location_hash()
            for req_hash in self._hash_engine.get_request_hashes():
                sig.request_hashes.append(req_hash)

            loc = sig.location_updates.add()
            sen = sig.sensor_updates.add()

            sen.timestamp = random.randint(sig.timestamp_ms_since_start - 5000,
                                           sig.timestamp_ms_since_start - 100)
            loc.timestamp_ms = random.randint(
                sig.timestamp_ms_since_start - 30000,
                sig.timestamp_ms_since_start - 1000)

            loc.name = random.choice(
                ('network', 'network', 'network', 'network', 'fused'))
            loc.latitude = request.latitude
            loc.longitude = request.longitude

            if not altitude:
                loc.altitude = random.triangular(300, 400, 350)
            else:
                loc.altitude = altitude

            if random.random() > .95:
                # no reading for roughly 1 in 20 updates
                loc.device_course = -1
                loc.device_speed = -1
            else:
                self.course = random.triangular(0, 360, self.course)
                loc.device_course = self.course
                loc.device_speed = random.triangular(0.2, 4.25, 1)

            loc.provider_status = 3
            loc.location_type = 1
            if request.accuracy >= 65:
                loc.vertical_accuracy = random.triangular(35, 100, 65)
                loc.horizontal_accuracy = random.choice(
                    (request.accuracy, 65, 65, random.uniform(66, 80), 200))
            else:
                if request.accuracy > 10:
                    loc.vertical_accuracy = random.choice(
                        (24, 32, 48, 48, 64, 64, 96, 128))
                else:
                    loc.vertical_accuracy = random.choice(
                        (3, 4, 6, 6, 8, 12, 24))
                loc.horizontal_accuracy = request.accuracy

            sen.acceleration_x = random.triangular(-3, 1, 0)
            sen.acceleration_y = random.triangular(-2, 3, 0)
            sen.acceleration_z = random.triangular(-4, 2, 0)
            sen.magnetic_field_x = random.triangular(-50, 50, 0)
            sen.magnetic_field_y = random.triangular(-60, 50, -5)
            sen.magnetic_field_z = random.triangular(-60, 40, -30)
            sen.magnetic_field_accuracy = random.choice((-1, 1, 1, 2, 2, 2, 2))
            sen.attitude_pitch = random.triangular(-1.5, 1.5, 0.2)
            sen.attitude_yaw = random.uniform(-3, 3)
            sen.attitude_roll = random.triangular(-2.8, 2.5, 0.25)
            sen.rotation_rate_x = random.triangular(-6, 4, 0)
            sen.rotation_rate_y = random.triangular(-5.5, 5, 0)
            sen.rotation_rate_z = random.triangular(-5, 3, 0)
            sen.gravity_x = random.triangular(-1, 1, 0.15)
            sen.gravity_y = random.triangular(-1, 1, -.2)
            sen.gravity_z = random.triangular(-1, .7, -0.8)
            sen.status = 3

            sig.field25 = 9156899491064153954

            if self.device_info:
                for key in self.device_info:
                    setattr(sig.device_info, key, self.device_info[key])

            signal_agglom_proto = sig.SerializeToString()

            try:
                if request.requests[0].request_type in (
                        RequestType.Value('GET_MAP_OBJECTS'),
                        RequestType.Value('GET_PLAYER')):
                    plat = request.platform_requests.add()
                    plat_eight = PlatEight()
                    plat_eight.field1 = 'e40c3e64817d9c96d99d28f6488a2efc40b11046'
                    plat.type = 8
                    plat.request_message = plat_eight.SerializeToString()
            except (IndexError, AttributeError):
                pass

            sig_request = SendEncryptedSignatureRequest()
            sig_request.encrypted_signature = self._generate_signature(
                signal_agglom_proto, sig.timestamp_ms_since_start)

            plat = request.platform_requests.add()
            plat.type = 6
            plat.request_message = sig_request.SerializeToString()

        request.ms_since_last_locationfix = 989

        self.log.debug('Generated protobuf request: \n\r%s', request)

        return request