DsSearchQueryArray
Combines an array of queries to as few as possible whilst staying under the maximum term count.
python · ReliaQuest Digital Risk Protection
Source
from urllib.parse import urlparse import demistomock as demisto # noqa: F401 from CommonServerPython import * QUOTED_STRINGS_PATTERN = r"\"[^\"]*\"" KEYWORDS_PATTERN = " (AND|OR|NOT) " NON_WORD_PATTERN = r"\W+" def append_arg(terms: Set[str], arg: Union[str, List[str]], filter_fn=lambda _: True): """ Append the given argument to the given set. Handles the case where an arg is a list and applies a filter function to remove unwanted search terms. :param terms: set of terms to append new terms to :param filter_fn: a function to be used with the builtin filter function to exclude unwanted terms """ asList = argToList(arg) new_terms: List[str] = list(filter(filter_fn, asList)) if len(new_terms): terms.update(new_terms) def extract_terms(args: Dict[str, Any]) -> Set[str]: """ Extract terms for each type of supported argument. Ensure this list remains up to date with the args declared in the YML file. :param args: dictionary of arguments passed to the command :return: set of string terms """ terms: Set[str] = set() if "sha1" in args: append_arg(terms, args["sha1"]) if "md5" in args: append_arg(terms, args["md5"]) if "sha256" in args: append_arg(terms, args["sha256"]) if "domain" in args: append_arg(terms, args["domain"], filter_fn=check_domain_name) if "ip" in args: append_arg(terms, args["ip"], filter_fn=check_ip) if "url" in args: append_arg(terms, args["url"], filter_fn=check_url) if "cve" in args: append_arg(terms, args["cve"]) return terms def convert_to_ds_query_array(args: Dict[str, Any]): """ Convert the provided args into a list of Shadow Search queries. Implements term-counting as Shadow Search has a maximum number of terms permitted per query. :param args: the arguments supplied to the command :return: a list of Shadow Search query strings """ terms = extract_terms(args) res = [] query = sorted(terms, key=lambda x: count_terms(x)) init = [] # type: List[str] term_count = 0 for q in query: if term_count + count_terms(q) > 35: res.append(" OR ".join(init)) init = [q] term_count = count_terms(q) else: init.append(q) term_count += count_terms(q) if len(init): res.append(" OR ".join(init)) return res def check_ip(ip): """ Filter function that excludes the inet any address (0.0.0.0). """ return ip != "0.0.0.0" def check_domain_name(domain): """ Filter function that removes the Digital Shadows portal hostname and subdomains of it. """ if not domain.startswith("."): domain = "." + domain return not domain.endswith(".portal-digitalshadows.com") def check_url(url): """ Filter function that removes URLs associated with Digital Shadows portal hostname and subdomains of it. """ domain = urlparse(url).netloc return check_domain_name(domain) def count_terms(query): """Count the query terms in a given string""" query = re.sub(QUOTED_STRINGS_PATTERN, "x", query) query = re.sub(KEYWORDS_PATTERN, " ", query) query = re.sub(NON_WORD_PATTERN, " ", query) query = query.strip() term_count = 0 if len(query) > 0: term_count = query.count(" ") + 1 return term_count def main(): try: return_results(convert_to_ds_query_array(demisto.args())) except Exception as exception: demisto.error(traceback.format_exc()) # print the traceback return_error(f"Failed to execute BaseScript. Error: {exception!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
Combines an array of queries to as few as possible whilst staying under the maximum term count.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | transformer |
| Cortex XSOAR Version | 6.0.0 |
Inputs
| Argument Name | Description |
|---|---|
| field | Input field to extract data from for e.g. IP.Address |
Outputs
Outputs an array of query or a single query string.