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
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
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
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)
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
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
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