Ejemplo n.º 1
0
    def __call__(self, *args, **kwargs):
        logger.debug3("HTTP Request from {}".format(str(request.remote_addr)))
        origin = request.headers.get('Origin')
        abort = False
        if request.url_rule is not None and str(request.url_rule) == '/status/':
            auth = request.headers.get('Authorization', False)
            if self.application_args.mitm_status_password != "" and \
                    (not auth or auth != self.application_args.mitm_status_password):
                self.response = Response(status=500, headers={})
                abort = True
            else:
                abort = False
        elif request.url is not None and str(request.url_rule) == '/origin_generator':
            auth = request.headers.get('Authorization', None)
            if auth is None or not check_auth(auth, self.application_args,
                                              self.mapping_manager.get_auths()):
                logger.warning(
                    "Unauthorized attempt to POST from {}", str(request.remote_addr))
                self.response = Response(status=403, headers={})
                abort = True
        else:
            if not origin:
                logger.warning("Missing Origin header in request")
                self.response = Response(status=500, headers={})
                abort = True
            elif (self.mapping_manager.get_all_devicemappings().keys() is not None
                  and (origin is None or origin not in self.mapping_manager.get_all_devicemappings().keys())):
                logger.warning("MITMReceiver request without Origin or disallowed Origin: {}".format(origin))
                self.response = Response(status=403, headers={})
                abort = True
            elif self.mapping_manager.get_auths() is not None:
                auth = request.headers.get('Authorization', None)
                if auth is None or not check_auth(auth, self.application_args,
                                                  self.mapping_manager.get_auths()):
                    logger.warning(
                        "Unauthorized attempt to POST from {}", str(request.remote_addr))
                    self.response = Response(status=403, headers={})
                    abort = True

        if not abort:
            try:
                # TODO: use response data
                if len(request.data) > 0:
                    request_data = json.loads(request.data)
                else:
                    request_data = {}
                response_payload = self.action(origin, request_data, *args, **kwargs)
                if response_payload is None:
                    response_payload = ""
                if type(response_payload) is Response:
                    self.response = response_payload
                else:
                    self.response = Response(status=200, headers={"Content-Type": "application/json"})
                    self.response.data = response_payload
            except Exception as e:  # TODO: catch exact exception
                logger.warning(
                    "Could not get JSON data from request: {}", str(e))
                self.response = Response(status=500, headers={})
        return self.response
Ejemplo n.º 2
0
 def get(self, apk_type, apk_arch):
     apks = self.get_apk_list(apk_type, apk_arch)
     if flask.request.url.split('/')[-1] == 'download':
         try:
             auths = self._mapping_manager.get_auths()
             authBase64 = self.api_req.headers['Authorization']
             if auths and authBase64 and not check_auth(
                     authBase64, None, auths):
                 return flask.make_response(
                     'Please login with a valid origin and auth', 401)
         except KeyError:
             return flask.make_response(
                 'Please login with a valid origin and auth', 401)
         try:
             if (apks[1]) == 200:
                 mad_apk = apks[0]
                 return flask.Response(flask.stream_with_context(
                     chunk_generator(self.dbc, mad_apk['file_id'])),
                                       content_type=mad_apk['mimetype'],
                                       headers={
                                           'Content-Disposition':
                                           f'attachment; filename=%s' %
                                           (mad_apk['filename'])
                                       })
             else:
                 return apks
         except (KeyError, TypeError):
             return (None, 404)
         return apks
     else:
         return apks
Ejemplo n.º 3
0
    async def __authenticate_connection(self, websocket_client_connection: websockets.WebSocketClientProtocol) \
            -> Optional[str]:
        """
        :param websocket_client_connection:
        :return: origin (string) if the auth and everything else checks out, else None to signal abort
        """
        try:
            origin = str(
                websocket_client_connection.request_headers.get_all("Origin")
                [0])
        except IndexError:
            logger.warning(
                "Client from {} tried to connect without Origin header",
                str(
                    websocket_client_connection.request_headers.get_all(
                        "Origin")[0]))
            return None

        if not self.__data_manager.is_device_active(origin):
            logger.warning(
                'Origin %s is currently paused.  Unpause through MADmin to begin working',
                origin)
            return None
        logger.info("Client {} registering", str(origin))
        if self.__mapping_manager is None or origin not in self.__mapping_manager.get_all_devicemappings(
        ).keys():
            logger.warning(
                "Register attempt of unknown origin: {}. "
                "Have you forgot to hit 'APPLY SETTINGS' in MADmin?".format(
                    origin))
            return None

        valid_auths = self.__mapping_manager.get_auths()
        auth_base64 = None
        if valid_auths:
            try:
                auth_base64 = str(
                    websocket_client_connection.request_headers.get_all(
                        "Authorization")[0])
            except IndexError:
                logger.warning(
                    "Client from {} tried to connect without auth header",
                    str(
                        websocket_client_connection.request_headers.get_all(
                            "Origin")[0]))
                return None
        if valid_auths and auth_base64 and not check_auth(
                auth_base64, self.__args, valid_auths):
            logger.warning(
                "Invalid auth details received from {}",
                str(
                    websocket_client_connection.request_headers.get_all(
                        "Origin")[0]))
            return None
        return origin
Ejemplo n.º 4
0
    async def __authenticate_connection(self, websocket_client_connection: websockets.WebSocketClientProtocol) \
            -> Optional[str]:
        """
        :param websocket_client_connection:
        :return: origin (string) if the auth and everything else checks out, else None to signal abort
        """
        try:
            origin = str(
                websocket_client_connection.request_headers.get_all("Origin")
                [0])
        except IndexError:
            logger.warning(
                "Client from {} tried to connect without Origin header",
                websocket_client_connection.remote_address)
            return (None, False)
        origin_logger = get_origin_logger(logger, origin=origin)
        origin_logger.info("Client registering")
        if self.__mapping_manager is None:
            origin_logger.warning(
                "No configuration has been defined.  Please define in MADmin and click "
                "'APPLY SETTINGS'")
            (origin, False)
        elif origin not in self.__mapping_manager.get_all_devicemappings(
        ).keys():
            if (self.__data_manager.search('device', params={'origin':
                                                             origin})):
                origin_logger.warning(
                    "Device is created but not loaded.  Click 'APPLY SETTINGS' in MADmin to Update"
                )
            else:
                origin_logger.warning(
                    "Register attempt of unknown origin.  Please create the device in MADmin and "
                    " click 'APPLY SETTINGS'")
            return (origin, False)

        valid_auths = self.__mapping_manager.get_auths()
        auth_base64 = None
        if valid_auths:
            try:
                auth_base64 = str(
                    websocket_client_connection.request_headers.get_all(
                        "Authorization")[0])
            except IndexError:
                origin_logger.warning(
                    "Client tried to connect without auth header")
                return (origin, False)
        if valid_auths and auth_base64 and not check_auth(
                origin_logger, auth_base64, self.__args, valid_auths):
            return (origin, False)
        return (origin, True)
Ejemplo n.º 5
0
 def get(self, apk_type, apk_arch):
     apks = get_apk_list(self.dbc, apk_type, apk_arch)
     if flask.request.url.split('/')[-1] == 'download':
         try:
             auths = self._mapping_manager.get_auths()
             authBase64 = self.api_req.headers['Authorization']
             if auths and authBase64 and not check_auth(
                     authBase64, None, auths):
                 return flask.make_response(
                     'Please login with a valid origin and auth', 401)
         except KeyError:
             return flask.make_response(
                 'Please login with a valid origin and auth', 401)
         try:
             return download_file(self.dbc, apk_type, apk_arch)
         except (KeyError, TypeError):
             return (None, 404)
         return apks
     else:
         return apks
Ejemplo n.º 6
0
    def __call__(self, *args, **kwargs):
        logger.debug2("HTTP Request from {}", request.remote_addr)
        origin = request.headers.get('Origin')
        origin_logger = get_origin_logger(logger, origin=origin)
        abort = False
        if request.url_rule is not None and str(
                request.url_rule) == '/status/':
            auth = request.headers.get('Authorization', False)
            if self.application_args.mitm_status_password != "" and \
                    (not auth or auth != self.application_args.mitm_status_password):
                self.response = Response(status=500, headers={})
                abort = True
            else:
                abort = False
        elif 'autoconfig/' in str(request.url):
            auth = request.headers.get('Authorization', None)
            if not check_auth(logger, auth, self.application_args,
                              self.mapping_manager.get_auths()):
                origin_logger.warning("Unauthorized attempt to POST from {}",
                                      request.remote_addr)
                self.response = Response(status=403, headers={})
                abort = True
            if 'mymac' in str(request.url):
                devs = self.__data_manager.search('device',
                                                  params={'origin': origin})
                if not devs:
                    abort = False
                    origin_logger.warning(
                        "Unauthorized attempt to POST from {}",
                        request.remote_addr)
                    self.response = Response(status=403, headers={})
        elif str(request.url_rule) == '/origin_generator':
            auth = request.headers.get('Authorization', None)
            if not check_auth(logger, auth, self.application_args,
                              self.mapping_manager.get_auths()):
                origin_logger.warning("Unauthorized attempt to POST from {}",
                                      request.remote_addr)
                self.response = Response(status=403, headers={})
                abort = True
        elif 'download' in request.url:
            auth = request.headers.get('Authorization', None)
            if not check_auth(logger, auth, self.application_args,
                              self.mapping_manager.get_auths()):
                origin_logger.warning("Unauthorized attempt to POST from {}",
                                      request.remote_addr)
                self.response = Response(status=403, headers={})
                abort = True
        else:
            if origin is None:
                origin_logger.warning("Missing Origin header in request")
                self.response = Response(status=500, headers={})
                abort = True
            elif self.mapping_manager.get_all_devicemappings().keys() is not None and \
                    origin not in self.mapping_manager.get_all_devicemappings().keys():
                origin_logger.warning(
                    "MITMReceiver request without Origin or disallowed Origin")
                self.response = Response(status=403, headers={})
                abort = True
            elif self.mapping_manager.get_auths() is not None:
                auth = request.headers.get('Authorization', None)
                if auth is None or not check_auth(
                        origin_logger, auth, self.application_args,
                        self.mapping_manager.get_auths()):
                    origin_logger.warning(
                        "Unauthorized attempt to POST from {}",
                        request.remote_addr)
                    self.response = Response(status=403, headers={})
                    abort = True

        if not abort:
            try:
                content_encoding = request.headers.get('Content-Encoding',
                                                       None)
                if content_encoding and content_encoding == "gzip":
                    # we need to unpack the data first
                    # https://stackoverflow.com/questions/28304515/receiving-gzip-with-flask
                    compressed_data = io.BytesIO(request.data)
                    text_data = gzip.GzipFile(fileobj=compressed_data,
                                              mode='r')
                    request_data = json.loads(text_data.read())
                else:
                    request_data = request.data

                content_type = request.headers.get('Content-Type', None)
                if content_type and content_type == "application/json":
                    request_data = json.loads(request_data)
                else:
                    request_data = request_data
                response_payload = self.action(origin, request_data, *args,
                                               **kwargs)
                if response_payload is None:
                    response_payload = ""
                if type(response_payload) is Response:
                    self.response = response_payload
                else:
                    self.response = Response(
                        status=200,
                        headers={"Content-Type": "application/json"})
                    self.response.data = response_payload
            except Exception as e:  # TODO: catch exact exception
                origin_logger.warning(
                    "Could not get JSON data from request: {}", e)
                self.response = Response(status=500, headers={})
        return self.response
Ejemplo n.º 7
0
    async def __register(
        self, websocket_client_connection: websockets.WebSocketClientProtocol
    ) -> bool:
        try:
            origin = str(
                websocket_client_connection.request_headers.get_all("Origin")
                [0])
        except IndexError:
            logger.warning(
                "Client from {} tried to connect without Origin header",
                str(
                    websocket_client_connection.request_headers.get_all(
                        "Origin")[0]))
            return False
        if not self.__data_manager.is_device_active(origin):
            logger.warning(
                'Origin %s is currently paused.  Unpause through MADmin to begin working',
                origin)
            return False
        logger.info("Client {} registering", str(origin))
        if self.__mapping_manager is None or origin not in self.__mapping_manager.get_all_devicemappings(
        ).keys():
            logger.warning(
                "Register attempt of unknown origin: {}. "
                "Have you forgot to hit 'APPLY SETTINGS' in MADmin?".format(
                    origin))
            return False

        if origin in self.__users_connecting:
            logger.info("Client {} is already connecting".format(origin))
            return False

        auths = self.__mapping_manager.get_auths()
        authBase64 = None
        if auths:
            try:
                authBase64 = str(
                    websocket_client_connection.request_headers.get_all(
                        "Authorization")[0])
            except IndexError:
                logger.warning(
                    "Client from {} tried to connect without auth header",
                    str(
                        websocket_client_connection.request_headers.get_all(
                            "Origin")[0]))
                return False

        worker_already_connected: bool = False
        async with self.__users_mutex:
            logger.debug("Checking if {} is already present", str(origin))
            if origin in self.__current_users:
                logger.warning(
                    "Worker with origin {} is already running, killing the running one and have client reconnect",
                    str(origin))
                self.__current_users.get(origin)[1].stop_worker()
                worker_already_connected = True
            else:
                self.__users_connecting.append(origin)

        if worker_already_connected:
            ## todo: do this better :D
            logger.debug(
                "Old worker thread is still alive - waiting 20 seconds")
            await asyncio.sleep(20)
            logger.info("Reconnect ...")
            return False

        # reset pref. error counter if exist
        await self.__reset_fail_counter(origin)
        try:
            if auths and authBase64 and not check_auth(authBase64, self.args,
                                                       auths):
                logger.warning(
                    "Invalid auth details received from {}",
                    str(
                        websocket_client_connection.request_headers.get_all(
                            "Origin")[0]))
                return False
            logger.info("Starting worker {}".format(origin))
            if self._configmode:
                dev_id = self.__mapping_manager.get_all_devicemappings(
                )[origin]['device_id']
                devicesettings = self.__mapping_manager.get_devicesettings_of(
                    origin)
                client_mapping = self.__mapping_manager.get_devicemappings_of(
                    origin)
                walker_area_array = client_mapping["walker"]
                walker_index = devicesettings.get('walker_area_index', 0)
                walker_settings = walker_area_array[walker_index]
                area_id = walker_settings['walkerarea']
                worker = WorkerConfigmode(
                    args=self.args,
                    dev_id=dev_id,
                    id=origin,
                    websocket_handler=self,
                    walker=None,
                    mapping_manager=self.__mapping_manager,
                    mitm_mapper=self.__mitm_mapper,
                    db_wrapper=self.__db_wrapper,
                    area_id=area_id,
                    routemanager_name=None)
                logger.debug("Starting worker for {}", str(origin))
                new_worker_thread = Thread(name='worker_%s' % origin,
                                           target=worker.start_worker)
                async with self.__users_mutex:
                    self.__current_users[origin] = [
                        new_worker_thread, worker, websocket_client_connection,
                        0
                    ]
                return True

            last_known_state = {}
            client_mapping = self.__mapping_manager.get_devicemappings_of(
                origin)
            devicesettings = self.__mapping_manager.get_devicesettings_of(
                origin)
            logger.info("Setting up routemanagers for {}", str(origin))

            if client_mapping.get("walker", None) is not None:
                if devicesettings is not None and "walker_area_index" not in devicesettings:
                    logger.debug("Initializing devicesettings")
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'walker_area_index', 0)
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'finished', False)
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'last_action_time', None)
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'last_cleanup_time', None)
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'job', False)
                    await asyncio.sleep(
                        1
                    )  # give the settings a moment... (dirty "workaround" against race condition)
                walker_index = devicesettings.get('walker_area_index', 0)

                if walker_index > 0:
                    # check status of last area
                    if not devicesettings.get('finished', False):
                        logger.info(
                            'Something wrong with last round - get back to old area'
                        )
                        walker_index -= 1
                        self.__mapping_manager.set_devicesetting_value_of(
                            origin, 'walker_area_index', walker_index)
                        # devicesettings['walker_area_index'] = walker_index

                walker_area_array = client_mapping["walker"]
                walker_settings = walker_area_array[walker_index]

                # preckeck walker setting
                while not pre_check_value(
                        walker_settings) and walker_index - 1 <= len(
                            walker_area_array):
                    walker_area_name = walker_area_array[walker_index][
                        'walkerarea']
                    logger.info(
                        '{} not using area {} - Walkervalue out of range',
                        str(origin),
                        str(
                            self.__mapping_manager.routemanager_get_name(
                                walker_area_name)))
                    if walker_index >= len(walker_area_array) - 1:
                        logger.error(
                            'Could not find any working area at this time - check your mappings for device: {}',
                            str(origin))
                        walker_index = 0
                        self.__mapping_manager.set_devicesetting_value_of(
                            origin, 'walker_area_index', walker_index)
                        walker_settings = walker_area_array[walker_index]
                        return False
                    walker_index += 1
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'walker_area_index', walker_index)
                    walker_settings = walker_area_array[walker_index]

                devicesettings = self.__mapping_manager.get_devicesettings_of(
                    origin)
                logger.debug("Checking walker_area_index length")
                if (devicesettings.get("walker_area_index", None) is None
                        or devicesettings['walker_area_index'] >=
                        len(walker_area_array)):
                    # check if array is smaller than expected - f.e. on the fly changes in mappings.json
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'walker_area_index', 0)
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'finished', False)
                    walker_index = 0

                walker_area_name = walker_area_array[walker_index][
                    'walkerarea']

                if walker_area_name not in self.__mapping_manager.get_all_routemanager_names(
                ):
                    raise WrongAreaInWalker()

                logger.debug('Devicesettings {}: {}', str(origin),
                             devicesettings)
                logger.info(
                    '{} using walker area {} [{}/{}]', str(origin),
                    str(
                        self.__mapping_manager.routemanager_get_name(
                            walker_area_name)), str(walker_index + 1),
                    str(len(walker_area_array)))
                walker_routemanager_mode = self.__mapping_manager.routemanager_get_mode(
                    walker_area_name)
                self.__mapping_manager.set_devicesetting_value_of(
                    origin, 'walker_area_index', walker_index + 1)
                self.__mapping_manager.set_devicesetting_value_of(
                    origin, 'finished', False)
                if walker_index >= len(walker_area_array) - 1:
                    self.__mapping_manager.set_devicesetting_value_of(
                        origin, 'walker_area_index', 0)

                # set global mon_iv
                routemanager_settings = self.__mapping_manager.routemanager_get_settings(
                    walker_area_name)
                if routemanager_settings is not None:
                    client_mapping['mon_ids_iv'] = \
                        self.__mapping_manager.get_monlist(routemanager_settings.get("mon_ids_iv", None),
                                                           walker_area_name)
            else:
                walker_routemanager_mode = None

            if "last_location" not in devicesettings:
                devicesettings['last_location'] = Location(0.0, 0.0)

            logger.debug("Setting up worker for {}", str(origin))
            dev_id = self.__mapping_manager.get_all_devicemappings(
            )[origin]['device_id']
            area_id = walker_settings['walkerarea']
            worker = None
            if walker_routemanager_mode is None:
                pass
            elif walker_routemanager_mode in [
                    "raids_mitm", "mon_mitm", "iv_mitm"
            ]:
                worker = WorkerMITM(
                    self.args,
                    dev_id,
                    origin,
                    last_known_state,
                    self,
                    area_id=area_id,
                    routemanager_name=walker_area_name,
                    mitm_mapper=self.__mitm_mapper,
                    mapping_manager=self.__mapping_manager,
                    db_wrapper=self.__db_wrapper,
                    pogo_window_manager=self.__pogoWindowManager,
                    walker=walker_settings)
            elif walker_routemanager_mode in ["pokestops"]:
                worker = WorkerQuests(
                    self.args,
                    dev_id,
                    origin,
                    last_known_state,
                    self,
                    area_id=area_id,
                    routemanager_name=walker_area_name,
                    mitm_mapper=self.__mitm_mapper,
                    mapping_manager=self.__mapping_manager,
                    db_wrapper=self.__db_wrapper,
                    pogo_window_manager=self.__pogoWindowManager,
                    walker=walker_settings)
            elif walker_routemanager_mode in ["idle"]:
                worker = WorkerConfigmode(
                    self.args,
                    dev_id,
                    origin,
                    self,
                    walker=walker_settings,
                    mapping_manager=self.__mapping_manager,
                    mitm_mapper=self.__mitm_mapper,
                    db_wrapper=self.__db_wrapper,
                    area_id=area_id,
                    routemanager_name=walker_area_name)
            else:
                logger.error("Mode not implemented")
                sys.exit(1)

            if worker is None:
                logger.error(
                    "Invalid walker mode for {}. Closing connection".format(
                        str(origin)))
                return False
            else:
                logger.debug("Starting worker for {}", str(origin))
                new_worker_thread = Thread(name='worker_%s' % origin,
                                           target=worker.start_worker)

                new_worker_thread.daemon = True
                async with self.__users_mutex:
                    self.__current_users[origin] = [
                        new_worker_thread, worker, websocket_client_connection,
                        0
                    ]
                new_worker_thread.start()
        except WrongAreaInWalker:
            logger.error('Unknown Area in Walker settings - check config')
            return False
        except Exception as e:
            logger.opt(exception=True).error(
                "Other unhandled exception during registration of {}: {}",
                origin, e)
            return False
        finally:
            async with self.__users_mutex:
                self.__users_connecting.remove(origin)
            await asyncio.sleep(5)
            logger.info("Done handling register of origin ", origin)
        return True