def _get_vnu_json_result(self): exec_result = self._exec_command(self.vnu_command_parts) if exec_result["code"] == 0: return exec_result["err"] else: msg = "v.Nu failed\n%s %s" % (exec_result["out"], exec_result["err"]) error_utils.exit_with_message(msg)
def _get_device_model(self): model = self._get_device_property("model") if not model: msg = "Unable to get device model information from ADB output:\n" + self._adb_devices_list[ 0] error_utils.exit_with_message(msg) self._device_model = model
def _assert_one_device_only(self): if self._devices_count == 0: error_utils.exit_with_message("No connected Android devices found") elif self._devices_count > 1: msg = "%s connected Android devices found" % self._devices_count msg += "\nPlease connect only one and try again" error_utils.exit_with_message(msg)
def _validate_required_options(self, cookie, section): required_options = ["name", "value"] for option in required_options: if option not in cookie: msg = "Missing '%s' option in [%s] cookie in config file '%s'" \ % (option, section, config.custom_cookies_file) error_utils.exit_with_message(msg)
def _check_vnu(self): command_parts = [self.java, "-jar", self.jar, "--version"] p = Popen(command_parts, stdout=PIPE, stderr=PIPE) (out, err) = p.communicate() if p.returncode == 0: return self._popen_decode(out) else: error_utils.exit_with_message("v.Nu failed | %s" % self._popen_decode(err))
def _return_value(self, expression): result = self._execute(expression) if "value" not in result: msg = "JavaScript execution failed" msg += "\nExpression: %s" % expression msg += "\nResult data: %s" % result error_utils.exit_with_message(msg) return result["value"]
def _error(self, message, name): if self.validation_mode == "argparse": raise ArgumentTypeError(message) elif self.validation_mode == "config": error_utils.exit_with_message( "Invalid '%s' value in config file: %s " % (name, message)) elif self.validation_mode == "interactive": error_utils.exit_with_message(message)
def _get_vnu_json_result(self): p = Popen(self.vnu_command_parts, stdout=PIPE, stderr=PIPE) (out, err) = p.communicate() if p.returncode == 0: return self._popen_decode(err) else: msg = "v.Nu failed\n%s %s" % (self._popen_decode(out), self._popen_decode(err)) error_utils.exit_with_message(msg)
def _validate_allowed_option(self, option_name): allowed_options = [ "name", "value", "domain", "path", "secure", "httponly" ] if option_name not in allowed_options: msg = "Unknown option '%s' in config file '%s'" % ( option_name, config.custom_cookies_file) error_utils.exit_with_message(msg)
def _check_error_code(self, url): if self.r.ok: return status_code, status_name = self._http_status() msg = "%s returned HTTP error: %s %s" % (url, status_code, status_name) if status_code == 401: msg += "\nHint: Use --http-auth option to provide HTTP authentication credentials" error_utils.exit_with_message(msg)
def _chrome_not_found(self): if config.chrome_binary: message = "Chrome was not found at location: %s" % config.chrome_binary else: message = "Chrome was not found in your system" message += "\nFind location of Chrome/Chromium in your system and configure it in one of the ways:" message += "\n* file: %s (option 'chrome_binary')" % config.ini_file message += "\n* command line parameter: --chrome-binary" error_utils.exit_with_message(message)
def _check_redirect_to_other_host(self, url): redirect_url = self._redirect_url() if not redirect_url: return if url_utils.hostname_from_url(url) == url_utils.hostname_from_url(redirect_url): return msg = "%s redirects to other host %s" % (url, redirect_url) msg += "\nPlease provide non-redirecting URL" error_utils.exit_with_message(msg)
def open_new_tab(self): endpoint = "/json/new" r = self._request_endpoint(endpoint) parsed = json.loads(r.text) socket_url_key = "webSocketDebuggerUrl" if socket_url_key not in parsed: error_utils.exit_with_message("Page socket '%s' not found in %s" % (socket_url_key, endpoint)) NewTabData = namedtuple("NewTabData", "socket_url target_id") return NewTabData(parsed[socket_url_key], parsed["id"])
def _enable_mobile_emulation(self): result = self._devtools_protocol.send_command("Emulation.canEmulate") if "result" not in result or not result["result"]: error_utils.exit_with_message( "Emulation is not supported in DevTools protocol") self._devtools_protocol.send_command( "Emulation.setDeviceMetricsOverride", self._device_metrics) self._devtools_protocol.send_command( "Emulation.setUserAgentOverride", {"userAgent": config.mobile_user_agent})
def _request_endpoint(self, endpoint): timeout = 5 url = self._host + endpoint start = time.time() while time.time() - start < timeout: try: return requests.get(url) except ConnectionError: time.sleep(1) msg = "Unable to connect to Chrome remote debugger URL: %s" % url error_utils.exit_with_message(msg)
def _handle_device_offline(self): if self._offline: print( "[WARN] Connected device detected as 'offline', trying once again..." ) self._adb_kill_server() self._update_devices_list() if self._offline: msg = "Connected device detected as 'offline'" msg += "\nTry disconnect USB and connect again" error_utils.exit_with_message(msg)
def _check_vnu(self): command_parts = [ config.java_binary, "-jar", config.validator_vnu_jar, "--version" ] exec_result = self._exec_command(command_parts) if exec_result["code"] == 0: return exec_result["out"] else: error_utils.exit_with_message("v.Nu failed | %s" % exec_result["err"])
def _try_to_connect_until_timeout(self, url): max_retries = 10 for i in range(0, max_retries): time.sleep(1) try: return requests.get(url) except ConnectionError: pass error_utils.exit_with_message( "Unable to connect to Chrome remote debugger on %s (see log file for details)" % url )
def chrome_binary(): if _is_windows(): from pagewalker.utilities import windows_registry registry = windows_registry.WindowsRegistry() chrome = registry.chrome_exe_path() if not chrome: error_utils.exit_with_message( "Path to chrome.exe not found. Please provide custom file location." ) return chrome else: return "google-chrome"
def _exec_adb(self, parameters): command_parts = [config.android_adb_binary] + parameters try: p = Popen(command_parts, stdout=PIPE, stderr=PIPE) except OSError: self._adb_not_found() return out, err = p.communicate() if p.returncode: msg = " ".join(command_parts) + "\n" + text_utils.bytes_to_string( err) error_utils.exit_with_message(msg) return text_utils.bytes_to_string(out)
def connect_to_remote_debugger(self): url = "http://localhost:%s/json" % config.chrome_debugging_port r = self._try_to_connect_until_timeout(url) parsed = json.loads(r.text) page_debugger_url = False for item in parsed: if item["type"] == "page": page_debugger_url = item["webSocketDebuggerUrl"] break if not page_debugger_url: error_utils.exit_with_message("Page socket debugger URL not found in %s" % url) self.page_socket = websocket.create_connection(page_debugger_url)
def check_valid_first_url(self): if config.mobile_emulation_enabled: self._user_agent = config.mobile_user_agent url = self._get_first_url() allow_redirects = True verify_ssl = False cookie_jar = self._prepare_cookie_jar(config.custom_cookies_data) if config.custom_cookies_data else None request_success, exception_type = self._http_get_only_headers(url, allow_redirects, verify_ssl, cookie_jar) if not request_success: error_utils.exit_with_message("Start URL error: %s" % exception_type) self._check_redirect_to_other_host(url) self._check_error_code(url) self._check_no_html_page(url)
def apply(self): config_types = config_validator.ConfigValidatorFile() validate_options = { "url": ["start_url", "initial_actions_url", "domain_blacklist_url"], "positive_non_zero_integer": [ "max_number_pages", "chrome_debugging_port", "chrome_timeout", "java_stack_size", "check_external_links_timeout", "check_external_links_threads" ], "positive_integer": ["wait_time_after_load", "domain_blacklist_cache_expiry"], "boolean": [ "scroll_after_load", "chrome_headless", "chrome_close_on_finish", "chrome_ignore_cert", "validator_enabled", "validator_check_css", "validator_show_warnings", "pages_list_only", "check_external_links", "domain_blacklist_enabled", "domain_blacklist_auto_update", "mobile_emulation_enabled", "android_browser_enabled" ], "dimension": ["window_size", "mobile_window_size"], "file": ["pages_list_file", "custom_cookies_file", "initial_actions_file"], "any": [ "chrome_binary", "http_basic_auth_data", "validator_vnu_jar", "java_binary", "mobile_user_agent", "android_adb_binary" ] } for name, value in self._get_non_empty_values("main").items(): if name in validate_options["url"]: setattr(config, name, config_types.url(value, name)) elif name in validate_options["positive_non_zero_integer"]: setattr(config, name, config_types.positive_non_zero_integer(value, name)) elif name in validate_options["positive_integer"]: setattr(config, name, config_types.positive_integer(value, name)) elif name in validate_options["boolean"]: setattr(config, name, config_types.boolean(value, name)) elif name in validate_options["dimension"]: setattr(config, name, config_types.dimension(value, name)) elif name in validate_options["file"]: setattr(config, name, config_types.file(value, name)) elif name in validate_options["any"]: setattr(config, name, value) else: error_utils.exit_with_message( "Unknown option '%s' in config file '%s'" % (name, config.ini_file))
def _wait_for_authorization(self): if self._authorized: return timeout = 60 msg = "\n*** Waiting max. %s seconds for authorization ***" % timeout msg += "\nAccept the connection from this computer on your Android device\n" print(msg) start = time.time() while time.time() - start < timeout: if self._authorized: return else: time.sleep(1) self._update_devices_list() error_utils.exit_with_message("Authorization timeout")
def start_session(self): self.debugger_socket.close_existing_session() filesystem_utils.clean_directory(self.profile_dir) chrome_log = open(self.log_file, "w") try: Popen(self.command_parts, stdout=chrome_log, stderr=chrome_log) except OSError: message = "Chrome not found at location: %s" % self.chrome message += "\nFind location of Chrome/Chromium in your system and configure it in:" message += "\n* config/default.ini file (option: chrome_binary)" message += "\n* or command line parameter --chrome-binary" error_utils.exit_with_message(message) self._print_start_message() self.debugger_socket.connect_to_remote_debugger() self._enable_features()
def _parse_pages_list_file(self): if not config.pages_list_file: return False with open(config.pages_list_file, "r") as f: lines = f.readlines() lines = [x.strip() for x in lines] pages_list = [] for line in lines: if line: if not line.startswith("/"): msg = "Invalid page in '%s' file. '%s' is not starting with '/'" % ( config.pages_list_file, line) error_utils.exit_with_message(msg) pages_list.append(line) if not pages_list: error_utils.exit_with_message( "File '%s' does not contain any pages" % config.pages_list_file) return pages_list
def _parse_pages_list_file(self, file_name): try: with open(file_name, "r") as f: lines = f.readlines() except IOError: error_utils.exit_with_message("Unable to open file '%s'" % file_name) return lines = [x.strip() for x in lines] pages_list = [] for line in lines: if line: if not line.startswith("/"): msg = "Invalid page in '%s' file. '%s' is not starting with '/'" % ( file_name, line) error_utils.exit_with_message(msg) pages_list.append(line) if not pages_list: error_utils.exit_with_message( "File '%s' does not contain any pages" % file_name) return pages_list
def _check_ini_file_exists(self): if not path.exists(config.ini_file): error_utils.exit_with_message("File '%s' not found" % config.ini_file)
def _error_missing_option(self, option, section): msg = "Missing '%s' in step [%s] in initial actions file '%s'" \ % (option, section, config.initial_actions_file) error_utils.exit_with_message(msg)
def _validate_known_actions(self, action): if action not in self.REQUIRED_OPTIONS: msg = "Unknown action '%s' in initial actions file '%s'" % ( action, config.initial_actions_file) error_utils.exit_with_message(msg)