def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Take email and look it up in breaches. Breaches info is provided by monitor.firefox.com (haveibeenpwned.com) """ email = kwargs.get("email") if not isinstance(email, str): return ScriptResponse.error( result=None, message= f"Can't make query. Incorrect input type (got {type(email)}, need {type('')}).", ) email_hash = sha1(email.encode()).hexdigest() with Session() as session: session.headers.update(Defaults.headers) resp = session.get(r"https://monitor.firefox.com") if resp.status_code != 200: return ScriptResponse.error( message= f"Can't look up email in breaches. Server response: {resp.status_code}.", ) csrf_re = findall(r'(?<="_csrf" value=").*(?=">)', resp.text) if not csrf_re: return ScriptResponse.error(message=f"Can't find csrf token.") csrf = csrf_re[0] resp = session.post( r"https://monitor.firefox.com/scan", data={ "_csrf": csrf, "emailHash": email_hash }, ) if resp.status_code != 200: return ScriptResponse.error( message= f"Can't look up email in breaches. Server response: {resp.status_code}.", ) breaches = [] soup = BeautifulSoup(resp.text, "html.parser") for breach in soup.find_all("a", class_="breach-card"): title = breach.find("span", class_="breach-title").text info = breach.find_all("span", class_="breach-value") if len(info) < 2: continue breaches.append({ "title": title, "date": info[0].text, "compromised": info[1].text }) return ScriptResponse.success( result=breaches, message=f"Email {email} is found in {len(breaches)} breaches.", )
async def __run(*args, **kwargs): try: username = kwargs.get("username") bad_symbols = list(set(username).intersection(string.punctuation)) if bad_symbols: return ScriptResponse.error( message=f"Invalid characters: {', '.join(bad_symbols)}") social = asyncio.Queue() for site in Networks().net: await social.put("https://{site}{username}".format( site=site, username=username)) temp_result = await asyncio.gather(*[ asyncio.create_task(check_nickname_async(username, social)) for _ in range(10) ]) result = {username: []} for sub_massive in temp_result: for site in sub_massive: result[username].append(site) return ScriptResponse.success( result=result, message="Found {count} user accounts".format( count=len(result[username])), ) except Exception as err: return ScriptResponse.error(message=str(err))
def run(self, *args, **kwargs): """ Returns hash of favicon.ico of given url. :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ url = kwargs.get("url") try: response = get(f"{url}/favicon.ico") except RequestException as req_err: return ScriptResponse.error( result=None, message=f"Can't connect to {url}!" f"Error message: {req_err}", ) favicon = encodebytes(response.content) favicon_hash = hash(favicon) return ScriptResponse.success( result=favicon_hash, message=f"Successfully made favicon hash of {url}! " f"Use https://www.shodan.io/search?query=http.favicon.hash:{favicon_hash}", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: email = kwargs.get("email") result = self.email_verifier(email) if not result: return ScriptResponse.success( result=result, message=f"Sorry, email {email} does not exist" ) return ScriptResponse.success(result=result, message=f"Email {email} exists")
def exec_script( path: str or Path, script_class: str = "Runner", function: str = "run", args: list or None = None, kwargs: dict or None = None, ) -> ScriptResponse or dict: """ Load and exec python script :param path: name of the script to load :param script_class: class to initialize when script is started :param function: name of the function to run from script :param args: args to pass into the module :param kwargs: kwargs to pass into the module :return: result of the function """ if args is None: args = [] if kwargs is None: kwargs = {} loader = SourceFileLoader(fullname=script_class, path=str(path)) module = ModuleType(name=loader.name) result = {"script": Path(path).parent.stem} # Check if don't forget to install all the dependencies, and that module can # be successfully loaded. # fmt: off try: loader.exec_module(module) except Exception as unexp_err: message = f"Unexpected module error: {str(unexp_err)}" logger.warning(message) result.update(ScriptResponse.error(message=message)) return result # fmt: on # Module successfully loaded. We can set some module-scope variables that # we missed. module.__file__ = path # Execute the runner and check if something goes wrong. # fmt: off try: module_class = getattr(module, script_class) applicable = set(module_class.required).intersection(kwargs.keys()) # If the current script is not applicable for the current set of arguments - skip it if not applicable: return class_instance = module_class(logger=path.parent.stem) result.update(getattr(class_instance, function)(*args, **kwargs)) except Exception as unexp_err: result.update(ScriptResponse.error(message=f"Unexpected execution error: {str(unexp_err)}")) # fmt: on # In any possible case, return result from the module or ScriptResponse.error + script name return result
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Main runner function for the script :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ result = self.user_greeting(user=kwargs.get("username")) if not result: return ScriptResponse.success(message="Sorry, no greetings for this user!") return ScriptResponse.success( result=result, message=f"Successfully finished! (args: {args}, kwargs: {kwargs})", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: # fmt: off response = self.__get_ip_info(kwargs.get("ip")) try: msg = ( "Query successful!" if response["status"] == "success" else "Query failed!" ) # we don't need duplicate status, let's get rid of it response.pop("status", None) return ScriptResponse.success(result=response, message=msg) except TypeError as type_err: return ScriptResponse.error(message=f"Error occurred while trying to get data: error status") except Exception as unexp_err: return ScriptResponse.error(message=f"Error occurred while trying to get data: {str(unexp_err)}")
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Parses torrents by ip. :param args: args from core runner. :param kwargs: kwargs from core runner. :return: ScriptResponse with dictionary of torrents. """ ip = kwargs.get("ip") api_key = kwargs.get("torrent_api_key", Defaults.API_KEY) if not ip: return ScriptResponse.error(message="No IP was provided") response = get( f"https://api.antitor.com/history/peer/?ip={ip}&key={api_key}" ).json() return ScriptResponse.success(message=f"Script finished for {ip}", result=response)
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Return basic success response :param args: args :param kwargs: kwargs :return: ScriptResponse message """ return ScriptResponse.success(message="Script finished")
def run(self, *args, **kwargs): """ Returns HTTP response status code :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ url = kwargs.get("url") status = get(url=url).status_code return ScriptResponse.success( result=status, message=f"Got HTTP response status from {url}")
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Main runner function for the script :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ hostname = kwargs.get("hostname") return ScriptResponse.success(result=self.__get_host(hostname), message="Success")
def run(self, *args, **kwargs): """ Try to find http title :param args: args from core runner :param kwargs: kwargs from core runner :return: http title if it's exist """ url = kwargs.get("url") try: response = requests.get(url, verify=False).text except Exception as get_err: return ScriptResponse.error(result=None, message=str(get_err)) search_title = search(r"<title>(.*)</title>", response) result = search_title.group(1) if search_title else None return ScriptResponse.success( result=result, message=f"Successfully found the title for {url}" if result else "Can not get the title or bad url", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Checks Secure, HttpOnly, Prefixed, Same-site flags for the cookies of a specified URL. :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse with dictionary containing flags mentioned above. """ url = kwargs.get("url") if not url: return ScriptResponse.error(message="Url was not provided!") result = {} response = get(url) for cookie in response.cookies: result[cookie.name] = { "Path": cookie.path, "Secure": cookie.secure, "HttpOnly": self.__has_http_only(cookie), "Prefix": cookie.name.startswith( ("__Secure-", "__Host-")) if cookie.name else False, "Same-Site": cookie.__dict__.get("_rest").get("SameSite", "None"), } return ScriptResponse.success( result=result, message=f"Successfully finished cookie policy check for {url}", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Main runner function for the script :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ try: result = self.__phone_to_region(phone=kwargs.get("phone")) except Exception: return ScriptResponse.error(result=None, message="Something went wrong!") result = result.split("~") if result[1] != "0": return ScriptResponse.success(result=None, message="Sorry, no such number!") return ScriptResponse.success( result=(result[-1], result[-2]), message= f"Found region: {result[-1]} | found operator: {result[-2]} | for phone number {result[0]}", )
def run(self, *args, **kwargs): """ Returns list of allowed methods. E.g. ['GET', 'POST']. Also checks if method is forbidden or somehow filtered. Needs url to run. :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ allowed_methods = [] filtered_methods = [] forbidden_methods = [] server_error = [] url = kwargs.get("url") # Copy original methods list to avoid class variable modifications methods = list(Defaults.METHODS) # Append random method to check if server is not faking. methods.append(get_random_method()) for method in methods: try: status = request(method, url).status_code method_result = {"method": method, "status": status} # 2xx - success # 405 - method not allowed if 200 <= status < 300: allowed_methods.append(method_result) elif status == 405: forbidden_methods.append(method_result) else: filtered_methods.append(method_result) except RequestException as req_err: method_result = {"method": method, "status": req_err} server_error.append(method_result) return ScriptResponse.success( result={ "allowed": allowed_methods, "forbidden": forbidden_methods, "filtered": filtered_methods, "server_error": server_error, }, message=f"URL: {url} - " f"allowed: {len(allowed_methods)}, " f"forbidden: {len(forbidden_methods)}, " f"filtered: {len(filtered_methods)}, " f"server_error: {len(server_error)}", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Main runner function for the script :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ try: tm = time() email_gen = EmailGenerator() username = kwargs.get("username") if not username: raise KeyError("EmailGenerator can't work without username!") result = email_gen.generate(username) except Exception as err: return ScriptResponse.error(message=str(err)) else: return ScriptResponse.success( result=result, message= f"Successfully finished! Got {len(result)} logins, script lasted {(time() - tm):.2f} seconds", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Main runner function for the script :param args: args from core runner :param kwargs: kwargs from core runner :return: ScriptResponse message """ try: phone = kwargs.get("phone") region = kwargs.get("region") parsed_num = parse(phone, region) except NumberParseException: return ScriptResponse.error( result=None, message="Not viable number or not international format") except Exception: return ScriptResponse.error(result=None, message="Something went wrong!") try: result = [ phone for phone_format in [ PhoneNumberFormat.NATIONAL, PhoneNumberFormat.INTERNATIONAL, PhoneNumberFormat.E164, ] for phone in self.__gen_all( format_number(parsed_num, phone_format)) ] except Exception: return ScriptResponse.error(result=None, message="Something went wrong!") return ScriptResponse.success( result=result, message=f"All possible number formats for phone number {phone}", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: fullname = kwargs.get("fullname") if not fullname: return ScriptResponse.error(result="Couldn't run the script", message="No name was provided") response = get( "http://www.fedsfm.ru/documents/terrorists-catalog-portal-act") if response.status_code != 200: return ScriptResponse.error( result="Couldn't run the script", message="Extremists name base is not available", ) occurences = findall(rf"<li>\d+\. ({fullname.upper()}.*);</li>", response.text) return ScriptResponse.success( result={ "found": bool(occurences), "occurrences": occurences }, message="Person found on the Russian extremists list" if bool(occurences) else "Person not found on the Russian extremists list", )
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ A method that performs RDAP lookup. You can get the following information: - query - The IP address - asn - The Autonomous System Number - asn_date - The ASN Allocation date - asn_registry - The assigned ASN registry - asn_cidr - The assigned ASN CIDR - asn_country_code - The assigned ASN country code - asn_description - The ASN description - network - Network information which consists of the following fields: - cidr - Network routing block and IP address belongs to - country - Country code registered with the RIR in ISO 3166-1 format - end_address - The last IP address in a network block - events - List of event dictionaries with the following fields: - action - The reason for an event - timestamp - The date an event occured in ISO 8601 format - actor - The identifier for an event initiator (if any) - handle - Unique identifier for a registered object - ip_version - IP protocol version (v4 or v6) of an IP address - links - HTTP/HTTPS links provided for an RIR object - name - he identifier assigned to the network registration for an IP address - parent_handle - Unique identifier for the parent network of a registered network - start_address - The first IP address in a network block - status - List indicating the state of a registered object - type - The RIR classification of a registered network objects - The objects (entities) referenced by an RIR network or by other entities with the following fields: - contact - Contact information registered with an RIR object. See "contacts" in "nir" section for more info. - entities - List of object names referenced by an RIR object. Map these to other objects dictionary keys. - events - List of event dictionaries. See "events" in "network" section for more info. - events_actor - List of event (no actor) dictionaries - handle - Unique identifier for a registered object - links - List of HTTP/HTTPS links provided for an RIR object - roles - List of roles assigned to a registered object - status - List indicating the state of a registered object nir - The National Internet Registry results which consists of the following fields: - cidr - Network routing block and IP address belongs to - range - Network range an IP address belongs to - name - he identifier assigned to the network registration for an IP address - handle - Unique identifier for a registered object - country - Country code registered with the RIR in ISO 3166-1 format - address - The mailing address for a registered network - postal_code - The postal code for a registered network - nameservers - he nameservers listed for a registered network - created - Network registration date in ISO 8601 format - updated - Network registration updated date in ISO 8601 format - contacts - Dictionary with keys: admin, tech. Values map to contact dictionaries if found: - name - The contact’s name - organization - The contact’s organization - division - The contact’s division of the organization - email - Contact email address - reply_email - Contact reply email address - updated - Updated date in ISO 8601 format - phone - Contact phone number - fax - Contact fax number - title - The contact’s position or job title :param args: variable length argument list. :param kwargs: arbitrary keyword arguments. :return: ScriptResponse.error with error message: returned if IP address is invalid or RDAP query failed. ScriptResponse.success with RDAP lookup results: returned if IP address is valid and RDAP query was successful. """ try: ip = self.__validate_ip(kwargs.get("ip")) except ValueError: return ScriptResponse.error(message="Invalid IP address") try: rdap = IPWhois(ip).lookup_rdap() except Exception as e: return ScriptResponse.error( message=f"RDAP lookup failed. Unknown error occurred: {str(e)}" ) # notices and remarks sections contains some useless info, let's get rid of it rdap["network"].pop("notices", None) for obj in rdap["objects"].keys(): rdap["objects"][obj].pop("notices", None) rdap["objects"][obj].pop("remarks", None) # entities section contains objects section keys, so we don't need it rdap.pop("entities", None) return ScriptResponse.success(result=rdap, message="RDAP lookup successful")
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: """ Make a Google search and return top results. :param args: user args :param kwargs: user kwargs :return: ScriptResponse message """ query = kwargs.get("email", "") if not isinstance(query, str): return ScriptResponse.error( result=None, message= f"Can't make query. Incorrect input type (got {type(query)}, need {type('')}).", ) query = query.replace(" ", "+") url = f'https://www.google.com/search?q="{query}"' headers = {"User-Agent": Defaults.USER_AGENT} resp = get(url, headers=headers) for attempt in range(5): if resp.status_code == 429: time_to_wait = randint(1, 5 + attempt) sleep(time_to_wait) resp = get(url, headers=headers) else: break if resp.status_code == 413: return ScriptResponse.success( result=None, message=f"Can't make query. Request is too long.", ) elif resp.status_code == 429: return ScriptResponse.success( result=None, message=f"Can't make query. Too many requests.", ) elif resp.status_code != 200: return ScriptResponse.success( result=None, message= f"Can't make query. Server response: {resp.status_code}.", ) results = [] soup = BeautifulSoup(resp.content, "html.parser") for g in soup.find_all("div", class_="r"): anchors = g.find_all("a") if not anchors: continue link = anchors[0]["href"] title = g.find("h3").text item = {"title": title, "link": link} results.append(item) return ScriptResponse.success(result=results, message="Search finished successfully.")
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error: try: country_code, phone_number = self.__split_phone_number(kwargs.get("phone")) except Exception as e: return ScriptResponse.success(message=str(e)) self.__driver.get(Constants.BASE_URL) # fill the first name and the last name self.__fill_form_field((By.ID, "ij_first_name"), Constants.FIRST_NAME) self.__fill_form_field((By.ID, "ij_last_name"), Constants.LAST_NAME) # let's fill the birthdate. First, we need to click the dropdown button and then we can select necessary item # dropdown list for day selection has id="dropdown1", for month selection has id="dropdown2", for year selection # has id="dropdown3". We will choose the first element in every list. for i in range(1, 4): self.__click_elem((By.ID, "dropdown{}".format(i))) self.__click_elem( ( By.ID, "option_list_options_container_{}_{}".format( i, Constants.BIRTHDATE ), ) ) # sometimes gender option doesn't appear. We need to click submit button and wait self.__click_elem((By.ID, "ij_submit")) self.__click_elem((By.CSS_SELECTOR, "div[role='radio']")) self.__click_elem((By.ID, "ij_submit")) # we need to wait for url to change and for page to load WebDriverWait(self.__driver, Defaults.MAX_TIMEOUT).until( ec.url_changes(Constants.FINISH_URL) ) self.__wait_page_load() # we need to choose necessary country code # first, we need to click dropdown button to get access to all VK country codes self.__click_elem((By.ID, "dropdown1")) # wait for list of codes to appear WebDriverWait(self.__driver, Defaults.MAX_TIMEOUT).until( ec.visibility_of_element_located((By.ID, "list_options_container_1")) ) phone_codes = self.__driver.find_element_by_id( "list_options_container_1" ).find_elements_by_tag_name("li") for code in phone_codes: if country_code in code.text: code.click() break self.__fill_form_field((By.ID, "join_phone"), phone_number) self.__click_elem((By.ID, "join_send_phone")) self.__wait_page_load() try: WebDriverWait(self.__driver, Defaults.MAX_TIMEOUT).until( ec.presence_of_element_located((By.ID, "join_called_phone")) ) self.__driver.quit() return ScriptResponse.success( message="There is a user with such phone number!" ) except TimeoutException: self.__driver.quit() return ScriptResponse.success( message="User with such phone number doesn't exist!" )