diff --git a/bbot/core/helpers/command.py b/bbot/core/helpers/command.py index 06fc8a91f5..59751cbeed 100644 --- a/bbot/core/helpers/command.py +++ b/bbot/core/helpers/command.py @@ -2,6 +2,7 @@ import asyncio import logging import traceback +from signal import SIGINT from subprocess import CompletedProcess, CalledProcessError from .misc import smart_decode, smart_encode @@ -9,7 +10,7 @@ log = logging.getLogger("bbot.core.helpers.command") -async def run(self, *command, check=False, text=True, **kwargs): +async def run(self, *command, check=False, text=True, idle_timeout=None, **kwargs): """Runs a command asynchronously and gets its output as a string. This method is a simple helper for executing a command and capturing its output. @@ -20,6 +21,7 @@ async def run(self, *command, check=False, text=True, **kwargs): check (bool, optional): If set to True, raises an error if the subprocess exits with a non-zero status. Defaults to False. text (bool, optional): If set to True, decodes the subprocess output to string. Defaults to True. + idle_timeout (int, optional): Sets a limit on the number of seconds the process can run before throwing a TimeoutError **kwargs (dict): Additional keyword arguments for the subprocess. Returns: @@ -45,7 +47,15 @@ async def run(self, *command, check=False, text=True, **kwargs): _input = b"\n".join(smart_encode(i) for i in _input) + b"\n" else: _input = smart_encode(_input) - stdout, stderr = await proc.communicate(_input) + + try: + if idle_timeout is not None: + stdout, stderr = await asyncio.wait_for(proc.communicate(_input), timeout=idle_timeout) + else: + stdout, stderr = await proc.communicate(_input) + except asyncio.exceptions.TimeoutError: + proc.send_signal(SIGINT) + raise # surface stderr if text: @@ -65,7 +75,7 @@ async def run(self, *command, check=False, text=True, **kwargs): proc_tracker.remove(proc) -async def run_live(self, *command, check=False, text=True, **kwargs): +async def run_live(self, *command, check=False, text=True, idle_timeout=None, **kwargs): """Runs a command asynchronously and iterates through its output line by line in realtime. This method is useful for executing a command and capturing its output on-the-fly, as it is generated. @@ -76,6 +86,7 @@ async def run_live(self, *command, check=False, text=True, **kwargs): check (bool, optional): If set to True, raises an error if the subprocess exits with a non-zero status. Defaults to False. text (bool, optional): If set to True, decodes the subprocess output to string. Defaults to True. + idle_timeout (int, optional): Sets a limit on the number of seconds the process can remain idle (no lines sent to stdout) before throwing a TimeoutError **kwargs (dict): Additional keyword arguments for the subprocess. Yields: @@ -102,7 +113,13 @@ async def run_live(self, *command, check=False, text=True, **kwargs): while 1: try: - line = await proc.stdout.readline() + if idle_timeout is not None: + line = await asyncio.wait_for(proc.stdout.readline(), timeout=idle_timeout) + else: + line = await proc.stdout.readline() + except asyncio.exceptions.TimeoutError: + proc.send_signal(SIGINT) + raise except ValueError as e: command_str = " ".join([str(c) for c in command]) log.warning(f"Error executing command {command_str}: {e}") diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index b77aaa2b75..568d8924a2 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1454,7 +1454,7 @@ def search_dict_values(d, *regexes): ... ] ... } ... } - >>> url_regexes = re.compile(r'https?://[^\\s<>"]+|www\.[^\\s<>"]+') + >>> url_regexes = re.compile(r'https?://[^\\s<>"]+|www\\.[^\\s<>"]+') >>> list(search_dict_values(dict_to_search, url_regexes)) ["https://www.evilcorp.com"] """ @@ -2666,3 +2666,38 @@ async def as_completed(coros): for task in done: tasks.pop(task) yield task + + +def truncate_filename(file_path, max_length=255): + """ + Truncate the filename while preserving the file extension to ensure the total path length does not exceed the maximum length. + + Args: + file_path (str): The original file path. + max_length (int): The maximum allowed length for the total path. Default is 255. + + Returns: + pathlib.Path: A new Path object with the truncated filename. + + Raises: + ValueError: If the directory path is too long to accommodate any filename within the limit. + + Example: + >>> truncate_filename('/path/to/example_long_filename.txt', 20) + PosixPath('/path/to/example.txt') + """ + p = Path(file_path) + directory, stem, suffix = p.parent, p.stem, p.suffix + + max_filename_length = max_length - len(str(directory)) - len(suffix) - 1 # 1 for the '/' separator + + if max_filename_length <= 0: + raise ValueError("The directory path is too long to accommodate any filename within the limit.") + + if len(stem) > max_filename_length: + truncated_stem = stem[:max_filename_length] + else: + truncated_stem = stem + + new_path = directory / (truncated_stem + suffix) + return new_path diff --git a/bbot/core/helpers/regexes.py b/bbot/core/helpers/regexes.py index 6e80801a67..890cedf407 100644 --- a/bbot/core/helpers/regexes.py +++ b/bbot/core/helpers/regexes.py @@ -20,9 +20,24 @@ word_num_regex = re.compile(r"[^\W_]+") num_regex = re.compile(r"\d+") -_ipv6_regex = r"[A-F0-9:]*:[A-F0-9:]*:[A-F0-9:]*" +_ipv4_regex = r"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}" +ipv4_regex = re.compile(_ipv4_regex, re.I) + +# IPv6 is complicated, so we have accomodate alternative patterns, +# :(:[A-F0-9]{1,4}){1,7} == ::1, ::ffff:1 +# ([A-F0-9]{1,4}:){1,7}: == 2001::, 2001:db8::, 2001:db8:0:1:2:3:: +# ([A-F0-9]{1,4}:){1,6}:([A-F0-9]{1,4}) == 2001::1, 2001:db8::1, 2001:db8:0:1:2:3::1 +# ([A-F0-9]{1,4}:){7,7}([A-F0-9]{1,4}) == 1:1:1:1:1:1:1:1, ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + +_ipv6_regex = r"(:(:[A-F0-9]{1,4}){1,7}|([A-F0-9]{1,4}:){1,7}:|([A-F0-9]{1,4}:){1,6}:([A-F0-9]{1,4})|([A-F0-9]{1,4}:){7,7}([A-F0-9]{1,4}))" ipv6_regex = re.compile(_ipv6_regex, re.I) +_ip_range_regexes = ( + _ipv4_regex + r"\/[0-9]{1,2}", + _ipv6_regex + r"\/[0-9]{1,3}", +) +ip_range_regexes = list(re.compile(r, re.I) for r in _ip_range_regexes) + # dns names with periods _dns_name_regex = r"(?:\w(?:[\w-]{0,100}\w)?\.)+(?:[xX][nN]--)?[^\W_]{1,63}\.?" dns_name_regex = re.compile(_dns_name_regex, re.I) @@ -73,6 +88,17 @@ "EMAIL_ADDRESS", (r"^" + _email_regex + r"$",), ), + ( + "IP_ADDRESS", + ( + r"^" + _ipv4_regex + r"$", + r"^" + _ipv6_regex + r"$", + ), + ), + ( + "IP_RANGE", + tuple(r"^" + r + r"$" for r in _ip_range_regexes), + ), ( "OPEN_TCP_PORT", tuple(r"^" + r + r"$" for r in _open_port_regexes), diff --git a/bbot/core/helpers/web.py b/bbot/core/helpers/web.py index adcebcfeeb..f560ad791c 100644 --- a/bbot/core/helpers/web.py +++ b/bbot/core/helpers/web.py @@ -13,6 +13,7 @@ from httpx._models import Cookies from socksio.exceptions import SOCKSError +from bbot.core.helpers.misc import truncate_filename from bbot.core.errors import WordlistError, CurlError from bbot.core.helpers.ratelimiter import RateLimiter @@ -258,6 +259,7 @@ async def download(self, url, **kwargs): """ success = False filename = kwargs.pop("filename", self.parent_helper.cache_filename(url)) + filename = truncate_filename(filename) follow_redirects = kwargs.pop("follow_redirects", True) max_size = kwargs.pop("max_size", None) warn = kwargs.pop("warn", True) diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index 46d475cca5..dd3abdbf09 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -11,7 +11,11 @@ class ajaxpro(BaseModule): watched_events = ["HTTP_RESPONSE", "URL"] produced_events = ["VULNERABILITY", "FINDING"] flags = ["active", "safe", "web-thorough"] - meta = {"description": "Check for potentially vulnerable Ajaxpro instances"} + meta = { + "description": "Check for potentially vulnerable Ajaxpro instances", + "created_date": "2024-01-18", + "author": "@liquidsec", + } async def handle_event(self, event): if event.type == "URL": diff --git a/bbot/modules/anubisdb.py b/bbot/modules/anubisdb.py index 9864e3c6d8..88a0a3f269 100644 --- a/bbot/modules/anubisdb.py +++ b/bbot/modules/anubisdb.py @@ -5,7 +5,11 @@ class anubisdb(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query jldc.me's database for subdomains"} + meta = { + "description": "Query jldc.me's database for subdomains", + "created_date": "2022-10-04", + "author": "@TheTechromancer", + } options = {"limit": 1000} options_desc = { "limit": "Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)" diff --git a/bbot/modules/azure_realm.py b/bbot/modules/azure_realm.py index 33772921e6..7fcbbb5b4d 100644 --- a/bbot/modules/azure_realm.py +++ b/bbot/modules/azure_realm.py @@ -5,7 +5,11 @@ class azure_realm(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["URL_UNVERIFIED"] flags = ["affiliates", "subdomain-enum", "cloud-enum", "web-basic", "web-thorough", "passive", "safe"] - meta = {"description": 'Retrieves the "AuthURL" from login.microsoftonline.com/getuserrealm'} + meta = { + "description": 'Retrieves the "AuthURL" from login.microsoftonline.com/getuserrealm', + "created_date": "2023-07-12", + "author": "@TheTechromancer", + } async def setup(self): self.processed = set() diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index 909acbe205..c75271756e 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -8,7 +8,11 @@ class azure_tenant(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["affiliates", "subdomain-enum", "cloud-enum", "passive", "safe"] - meta = {"description": "Query Azure for tenant sister domains"} + meta = { + "description": "Query Azure for tenant sister domains", + "created_date": "2024-07-04", + "author": "@TheTechromancer", + } base_url = "https://autodiscover-s.outlook.com" in_scope_only = True diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 9abfebc84c..b46923129c 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -13,14 +13,18 @@ class baddns(BaseModule): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] produced_events = ["FINDING", "VULNERABILITY"] flags = ["active", "safe", "web-basic", "baddns", "cloud-enum", "subdomain-hijack"] - meta = {"description": "Check hosts for domain/subdomain takeovers"} + meta = { + "description": "Check hosts for domain/subdomain takeovers", + "created_date": "2024-01-18", + "author": "@liquidsec", + } options = {"custom_nameservers": [], "only_high_confidence": False} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "only_high_confidence": "Do not emit low-confidence or generic detections", } max_event_handlers = 8 - deps_pip = ["baddns~=1.1.0"] + deps_pip = ["baddns~=1.1.789"] def select_modules(self): selected_modules = [] diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index a42fe2e21f..69f93bbe51 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -11,14 +11,18 @@ class baddns_zone(baddns_module): watched_events = ["DNS_NAME"] produced_events = ["FINDING", "VULNERABILITY"] flags = ["active", "safe", "subdomain-enum", "baddns", "cloud-enum"] - meta = {"description": "Check hosts for DNS zone transfers and NSEC walks"} + meta = { + "description": "Check hosts for DNS zone transfers and NSEC walks", + "created_date": "2024-01-29", + "author": "@liquidsec", + } options = {"custom_nameservers": [], "only_high_confidence": False} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "only_high_confidence": "Do not emit low-confidence or generic detections", } max_event_handlers = 8 - deps_pip = ["baddns~=1.1.0"] + deps_pip = ["baddns~=1.1.789"] def select_modules(self): selected_modules = [] diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index 7fde4a8e30..19b0de7200 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -9,7 +9,11 @@ class badsecrets(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING", "VULNERABILITY", "TECHNOLOGY"] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Library for detecting known or weak secrets across many web frameworks"} + meta = { + "description": "Library for detecting known or weak secrets across many web frameworks", + "created_date": "2022-11-19", + "author": "@liquidsec", + } deps_pip = ["badsecrets~=0.4.490"] @property diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index 435ceae08f..fa5cf1f1bc 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -9,7 +9,12 @@ class bevigil(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME", "URL_UNVERIFIED"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Retrieve OSINT data from mobile applications using BeVigil", "auth_required": True} + meta = { + "description": "Retrieve OSINT data from mobile applications using BeVigil", + "created_date": "2022-10-26", + "author": "@alt-glitch", + "auth_required": True, + } options = {"api_key": "", "urls": False} options_desc = {"api_key": "BeVigil OSINT API Key", "urls": "Emit URLs in addition to DNS_NAMEs"} diff --git a/bbot/modules/binaryedge.py b/bbot/modules/binaryedge.py index 64970c861d..15d195c013 100644 --- a/bbot/modules/binaryedge.py +++ b/bbot/modules/binaryedge.py @@ -5,7 +5,12 @@ class binaryedge(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the BinaryEdge API", "auth_required": True} + meta = { + "description": "Query the BinaryEdge API", + "created_date": "2024-08-18", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": "", "max_records": 1000} options_desc = { "api_key": "BinaryEdge API key", diff --git a/bbot/modules/bucket_amazon.py b/bbot/modules/bucket_amazon.py index ddb6d05f3c..c61c218fc1 100644 --- a/bbot/modules/bucket_amazon.py +++ b/bbot/modules/bucket_amazon.py @@ -5,7 +5,11 @@ class bucket_amazon(bucket_template): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] flags = ["active", "safe", "cloud-enum", "web-basic", "web-thorough"] - meta = {"description": "Check for S3 buckets related to target"} + meta = { + "description": "Check for S3 buckets related to target", + "created_date": "2022-11-04", + "author": "@TheTechromancer", + } options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/bucket_azure.py b/bbot/modules/bucket_azure.py index 81e441b5f8..375a565d53 100644 --- a/bbot/modules/bucket_azure.py +++ b/bbot/modules/bucket_azure.py @@ -5,7 +5,11 @@ class bucket_azure(bucket_template): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] flags = ["active", "safe", "cloud-enum", "web-basic", "web-thorough"] - meta = {"description": "Check for Azure storage blobs related to target"} + meta = { + "description": "Check for Azure storage blobs related to target", + "created_date": "2022-11-04", + "author": "@TheTechromancer", + } options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/bucket_digitalocean.py b/bbot/modules/bucket_digitalocean.py index c467fde6ee..8e1e008fc0 100644 --- a/bbot/modules/bucket_digitalocean.py +++ b/bbot/modules/bucket_digitalocean.py @@ -5,7 +5,11 @@ class bucket_digitalocean(bucket_template): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] flags = ["active", "safe", "slow", "cloud-enum", "web-thorough"] - meta = {"description": "Check for DigitalOcean spaces related to target"} + meta = { + "description": "Check for DigitalOcean spaces related to target", + "created_date": "2022-11-08", + "author": "@TheTechromancer", + } options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index facaa021e3..8b7dcbbb64 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -10,7 +10,9 @@ class bucket_file_enum(BaseModule): watched_events = ["STORAGE_BUCKET"] produced_events = ["URL_UNVERIFIED"] meta = { - "description": "Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS" + "description": "Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS", + "created_date": "2023-11-14", + "author": "@TheTechromancer", } flags = ["passive", "safe", "cloud-enum"] options = { diff --git a/bbot/modules/bucket_firebase.py b/bbot/modules/bucket_firebase.py index 9c883bc9c4..c3117286e4 100644 --- a/bbot/modules/bucket_firebase.py +++ b/bbot/modules/bucket_firebase.py @@ -5,7 +5,11 @@ class bucket_firebase(bucket_template): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] flags = ["active", "safe", "cloud-enum", "web-basic", "web-thorough"] - meta = {"description": "Check for open Firebase databases related to target"} + meta = { + "description": "Check for open Firebase databases related to target", + "created_date": "2023-03-20", + "author": "@TheTechromancer", + } options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/bucket_google.py b/bbot/modules/bucket_google.py index 0bd22f0f13..75b41b2359 100644 --- a/bbot/modules/bucket_google.py +++ b/bbot/modules/bucket_google.py @@ -9,7 +9,11 @@ class bucket_google(bucket_template): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] flags = ["active", "safe", "cloud-enum", "web-basic", "web-thorough"] - meta = {"description": "Check for Google object storage related to target"} + meta = { + "description": "Check for Google object storage related to target", + "created_date": "2022-11-04", + "author": "@TheTechromancer", + } options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index 0b5793657a..7d6197089c 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -17,7 +17,12 @@ class builtwith(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["affiliates", "subdomain-enum", "passive", "safe"] - meta = {"description": "Query Builtwith.com for subdomains", "auth_required": True} + meta = { + "description": "Query Builtwith.com for subdomains", + "created_date": "2022-08-23", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": "", "redirects": True} options_desc = {"api_key": "Builtwith API key", "redirects": "Also look up inbound and outbound redirects"} base_url = "https://api.builtwith.com" diff --git a/bbot/modules/bypass403.py b/bbot/modules/bypass403.py index c584634016..546f52fe29 100644 --- a/bbot/modules/bypass403.py +++ b/bbot/modules/bypass403.py @@ -79,7 +79,7 @@ class bypass403(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Check 403 pages for common bypasses"} + meta = {"description": "Check 403 pages for common bypasses", "created_date": "2022-07-05", "author": "@liquidsec"} in_scope_only = True async def do_checks(self, compare_helper, event, collapse_threshold): diff --git a/bbot/modules/c99.py b/bbot/modules/c99.py index 8e05a1c4b8..8db5775cb2 100644 --- a/bbot/modules/c99.py +++ b/bbot/modules/c99.py @@ -5,7 +5,12 @@ class c99(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the C99 API for subdomains", "auth_required": True} + meta = { + "description": "Query the C99 API for subdomains", + "created_date": "2022-07-08", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "c99.nl API key"} diff --git a/bbot/modules/censys.py b/bbot/modules/censys.py index b8609adf8f..cb8a7c9560 100644 --- a/bbot/modules/censys.py +++ b/bbot/modules/censys.py @@ -9,7 +9,12 @@ class censys(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the Censys API", "auth_required": True} + meta = { + "description": "Query the Censys API", + "created_date": "2022-08-04", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_id": "", "api_secret": "", "max_pages": 5} options_desc = { "api_id": "Censys.io API ID", diff --git a/bbot/modules/certspotter.py b/bbot/modules/certspotter.py index 4441b9d98f..9d7e00d87e 100644 --- a/bbot/modules/certspotter.py +++ b/bbot/modules/certspotter.py @@ -5,7 +5,11 @@ class certspotter(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query Certspotter's API for subdomains"} + meta = { + "description": "Query Certspotter's API for subdomains", + "created_date": "2022-07-28", + "author": "@TheTechromancer", + } base_url = "https://api.certspotter.com/v1" diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index 3eb7635732..e98fedd840 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -5,7 +5,12 @@ class chaos(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query ProjectDiscovery's Chaos API for subdomains", "auth_required": True} + meta = { + "description": "Query ProjectDiscovery's Chaos API for subdomains", + "created_date": "2022-08-14", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "Chaos API key"} diff --git a/bbot/modules/code_repository.py b/bbot/modules/code_repository.py index 5c55e41c31..1a946d13c8 100644 --- a/bbot/modules/code_repository.py +++ b/bbot/modules/code_repository.py @@ -5,7 +5,11 @@ class code_repository(BaseModule): watched_events = ["URL_UNVERIFIED"] produced_events = ["CODE_REPOSITORY"] - meta = {"description": "Look for code repository links in webpages"} + meta = { + "description": "Look for code repository links in webpages", + "created_date": "2024-05-15", + "author": "@domwhewell-sage", + } flags = ["passive", "safe", "repo-enum"] # platform name : (regex, case_sensitive) diff --git a/bbot/modules/columbus.py b/bbot/modules/columbus.py index 2e89013591..4c09f3a5de 100644 --- a/bbot/modules/columbus.py +++ b/bbot/modules/columbus.py @@ -5,7 +5,11 @@ class columbus(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query the Columbus Project API for subdomains"} + meta = { + "description": "Query the Columbus Project API for subdomains", + "created_date": "2023-06-01", + "author": "@TheTechromancer", + } base_url = "https://columbus.elmasy.com/api/lookup" diff --git a/bbot/modules/credshed.py b/bbot/modules/credshed.py index 3826440077..eee229e766 100644 --- a/bbot/modules/credshed.py +++ b/bbot/modules/credshed.py @@ -9,6 +9,8 @@ class credshed(BaseModule): flags = ["passive", "safe"] meta = { "description": "Send queries to your own credshed server to check for known credentials of your targets", + "created_date": "2023-10-12", + "author": "@SpamFaux", "auth_required": True, } options = {"username": "", "password": "", "credshed_url": ""} diff --git a/bbot/modules/crobat.py b/bbot/modules/crobat.py index 7ece44fdbc..f7baacf370 100644 --- a/bbot/modules/crobat.py +++ b/bbot/modules/crobat.py @@ -6,5 +6,5 @@ class crobat(subdomain_enum): produced_events = ["DNS_NAME"] # tag "subdomain-enum" removed 2023-02-24 because API is offline flags = ["passive", "safe"] - meta = {"description": "Query Project Crobat for subdomains"} + meta = {"description": "Query Project Crobat for subdomains", "created_date": "2022-06-03", "author": "@j3tj3rk"} base_url = "https://sonar.omnisint.io" diff --git a/bbot/modules/crt.py b/bbot/modules/crt.py index 9773f72d48..27d088a0dd 100644 --- a/bbot/modules/crt.py +++ b/bbot/modules/crt.py @@ -5,7 +5,11 @@ class crt(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query crt.sh (certificate transparency) for subdomains"} + meta = { + "description": "Query crt.sh (certificate transparency) for subdomains", + "created_date": "2022-05-13", + "author": "@TheTechromancer", + } base_url = "https://crt.sh" reject_wildcards = False diff --git a/bbot/modules/deadly/dastardly.py b/bbot/modules/deadly/dastardly.py index bfba6c6364..73df81bdfb 100644 --- a/bbot/modules/deadly/dastardly.py +++ b/bbot/modules/deadly/dastardly.py @@ -6,7 +6,11 @@ class dastardly(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING", "VULNERABILITY"] flags = ["active", "aggressive", "slow", "web-thorough"] - meta = {"description": "Lightweight web application security scanner"} + meta = { + "description": "Lightweight web application security scanner", + "created_date": "2023-12-11", + "author": "@domwhewell-sage", + } deps_pip = ["lxml~=4.9.2"] deps_ansible = [ diff --git a/bbot/modules/deadly/ffuf.py b/bbot/modules/deadly/ffuf.py index 8382f1e669..ce9dba83f8 100644 --- a/bbot/modules/deadly/ffuf.py +++ b/bbot/modules/deadly/ffuf.py @@ -11,7 +11,7 @@ class ffuf(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] flags = ["aggressive", "active"] - meta = {"description": "A fast web fuzzer written in Go"} + meta = {"description": "A fast web fuzzer written in Go", "created_date": "2022-04-10", "author": "@pmueller"} options = { "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", diff --git a/bbot/modules/deadly/nuclei.py b/bbot/modules/deadly/nuclei.py index 9234f74947..af5a7ac536 100644 --- a/bbot/modules/deadly/nuclei.py +++ b/bbot/modules/deadly/nuclei.py @@ -8,7 +8,11 @@ class nuclei(BaseModule): watched_events = ["URL"] produced_events = ["FINDING", "VULNERABILITY", "TECHNOLOGY"] flags = ["active", "aggressive"] - meta = {"description": "Fast and customisable vulnerability scanner"} + meta = { + "description": "Fast and customisable vulnerability scanner", + "created_date": "2022-03-12", + "author": "@TheTechromancer", + } options = { "version": "3.2.0", diff --git a/bbot/modules/deadly/vhost.py b/bbot/modules/deadly/vhost.py index e2908dbbe4..07fc331bb9 100644 --- a/bbot/modules/deadly/vhost.py +++ b/bbot/modules/deadly/vhost.py @@ -8,7 +8,7 @@ class vhost(ffuf): watched_events = ["URL"] produced_events = ["VHOST", "DNS_NAME"] flags = ["active", "aggressive", "slow"] - meta = {"description": "Fuzz for virtual hosts"} + meta = {"description": "Fuzz for virtual hosts", "created_date": "2022-05-02", "author": "@liquidsec"} special_vhost_list = ["127.0.0.1", "localhost", "host.docker.internal"] options = { diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index c1a35c4195..89c5d6a179 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -7,7 +7,12 @@ class dehashed(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["PASSWORD", "HASHED_PASSWORD", "USERNAME"] flags = ["passive", "safe", "email-enum"] - meta = {"description": "Execute queries against dehashed.com for exposed credentials", "auth_required": True} + meta = { + "description": "Execute queries against dehashed.com for exposed credentials", + "created_date": "2023-10-12", + "author": "@SpamFaux", + "auth_required": True, + } options = {"username": "", "api_key": ""} options_desc = {"username": "Email Address associated with your API key", "api_key": "DeHashed API Key"} target_only = True diff --git a/bbot/modules/digitorus.py b/bbot/modules/digitorus.py index 0da4877440..48c060346a 100644 --- a/bbot/modules/digitorus.py +++ b/bbot/modules/digitorus.py @@ -7,7 +7,11 @@ class digitorus(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query certificatedetails.com for subdomains"} + meta = { + "description": "Query certificatedetails.com for subdomains", + "created_date": "2023-07-25", + "author": "@TheTechromancer", + } base_url = "https://certificatedetails.com" diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index eef8e2d8ca..b44c6464f9 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -153,7 +153,7 @@ class dnscommonsrv(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Check for common SRV records"} + meta = {"description": "Check for common SRV records", "created_date": "2022-05-15", "author": "@TheTechromancer"} options = {"top": 50, "max_event_handlers": 10} options_desc = { "top": "How many of the top SRV records to check", diff --git a/bbot/modules/dnsdumpster.py b/bbot/modules/dnsdumpster.py index 06986f216c..a1d9815654 100644 --- a/bbot/modules/dnsdumpster.py +++ b/bbot/modules/dnsdumpster.py @@ -7,7 +7,11 @@ class dnsdumpster(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query dnsdumpster for subdomains"} + meta = { + "description": "Query dnsdumpster for subdomains", + "created_date": "2022-03-12", + "author": "@TheTechromancer", + } base_url = "https://dnsdumpster.com" diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index 86c7a07a71..775b5a181f 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -9,7 +9,11 @@ class docker_pull(BaseModule): watched_events = ["CODE_REPOSITORY"] produced_events = ["FILESYSTEM"] flags = ["passive", "safe", "slow"] - meta = {"description": "Download images from a docker repository"} + meta = { + "description": "Download images from a docker repository", + "created_date": "2024-03-24", + "author": "@domwhewell-sage", + } options = {"all_tags": False, "output_folder": ""} options_desc = { "all_tags": "Download all tags from each registry (Default False)", diff --git a/bbot/modules/dockerhub.py b/bbot/modules/dockerhub.py index 5829e57d9d..fcfc189c32 100644 --- a/bbot/modules/dockerhub.py +++ b/bbot/modules/dockerhub.py @@ -5,7 +5,11 @@ class dockerhub(BaseModule): watched_events = ["SOCIAL", "ORG_STUB"] produced_events = ["SOCIAL", "CODE_REPOSITORY", "URL_UNVERIFIED"] flags = ["passive", "safe"] - meta = {"description": "Search for docker repositories of discovered orgs/usernames"} + meta = { + "description": "Search for docker repositories of discovered orgs/usernames", + "created_date": "2024-03-12", + "author": "@domwhewell-sage", + } site_url = "https://hub.docker.com" api_url = f"{site_url}/v2" diff --git a/bbot/modules/dotnetnuke.py b/bbot/modules/dotnetnuke.py index ea3d7b9206..2845a51924 100644 --- a/bbot/modules/dotnetnuke.py +++ b/bbot/modules/dotnetnuke.py @@ -20,7 +20,11 @@ class dotnetnuke(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["VULNERABILITY", "TECHNOLOGY"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Scan for critical DotNetNuke (DNN) vulnerabilities"} + meta = { + "description": "Scan for critical DotNetNuke (DNN) vulnerabilities", + "created_date": "2023-11-21", + "author": "@liquidsec", + } async def setup(self): self.event_dict = {} diff --git a/bbot/modules/emailformat.py b/bbot/modules/emailformat.py index 000c3d5cf3..be797c678a 100644 --- a/bbot/modules/emailformat.py +++ b/bbot/modules/emailformat.py @@ -5,7 +5,11 @@ class emailformat(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] flags = ["passive", "email-enum", "safe"] - meta = {"description": "Query email-format.com for email addresses"} + meta = { + "description": "Query email-format.com for email addresses", + "created_date": "2022-07-11", + "author": "@TheTechromancer", + } in_scope_only = False per_domain_only = True diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index 562ae681fd..f9e6acd402 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -33,7 +33,11 @@ class ffuf_shortnames(ffuf): watched_events = ["URL_HINT"] produced_events = ["URL_UNVERIFIED"] flags = ["aggressive", "active", "iis-shortnames", "web-thorough"] - meta = {"description": "Use ffuf in combination IIS shortnames"} + meta = { + "description": "Use ffuf in combination IIS shortnames", + "created_date": "2022-07-05", + "author": "@liquidsec", + } options = { "wordlist": "", # default is defined within setup function diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index e82463a489..98b4d9f015 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -15,7 +15,11 @@ class filedownload(BaseModule): watched_events = ["URL_UNVERIFIED", "HTTP_RESPONSE"] produced_events = [] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Download common filetypes such as PDF, DOCX, PPTX, etc."} + meta = { + "description": "Download common filetypes such as PDF, DOCX, PPTX, etc.", + "created_date": "2023-10-11", + "author": "@TheTechromancer", + } options = { "extensions": [ "bak", # Backup File diff --git a/bbot/modules/fingerprintx.py b/bbot/modules/fingerprintx.py index 41efa75b6a..5e69eb3e22 100644 --- a/bbot/modules/fingerprintx.py +++ b/bbot/modules/fingerprintx.py @@ -7,7 +7,11 @@ class fingerprintx(BaseModule): watched_events = ["OPEN_TCP_PORT"] produced_events = ["PROTOCOL"] flags = ["active", "safe", "service-enum", "slow"] - meta = {"description": "Fingerprint exposed services like RDP, SSH, MySQL, etc."} + meta = { + "description": "Fingerprint exposed services like RDP, SSH, MySQL, etc.", + "created_date": "2023-01-30", + "author": "@TheTechromancer", + } options = {"version": "1.1.4"} options_desc = {"version": "fingerprintx version"} _batch_size = 10 diff --git a/bbot/modules/fullhunt.py b/bbot/modules/fullhunt.py index 1485dc6b5c..90f83bcfc1 100644 --- a/bbot/modules/fullhunt.py +++ b/bbot/modules/fullhunt.py @@ -5,7 +5,12 @@ class fullhunt(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the fullhunt.io API for subdomains", "auth_required": True} + meta = { + "description": "Query the fullhunt.io API for subdomains", + "created_date": "2022-08-24", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "FullHunt API Key"} diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py index 9d75f4a9e6..5db762b8ce 100644 --- a/bbot/modules/generic_ssrf.py +++ b/bbot/modules/generic_ssrf.py @@ -152,7 +152,7 @@ class generic_ssrf(BaseModule): watched_events = ["URL"] produced_events = ["VULNERABILITY"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Check for generic SSRFs"} + meta = {"description": "Check for generic SSRFs", "created_date": "2022-07-30", "author": "@liquidsec"} in_scope_only = True deps_apt = ["curl"] diff --git a/bbot/modules/git.py b/bbot/modules/git.py index 0b19f7e6a1..1fb3235ee3 100644 --- a/bbot/modules/git.py +++ b/bbot/modules/git.py @@ -7,7 +7,11 @@ class git(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Check for exposed .git repositories"} + meta = { + "description": "Check for exposed .git repositories", + "created_date": "2023-05-30", + "author": "@TheTechromancer", + } in_scope_only = True diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index 2778efdde7..7942d498a9 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -1,4 +1,5 @@ from pathlib import Path +from subprocess import CalledProcessError from bbot.modules.templates.github import github @@ -6,7 +7,11 @@ class git_clone(github): watched_events = ["CODE_REPOSITORY"] produced_events = ["FILESYSTEM"] flags = ["passive", "safe", "slow"] - meta = {"description": "Clone code github repositories"} + meta = { + "description": "Clone code github repositories", + "created_date": "2024-03-08", + "author": "@domwhewell-sage", + } options = {"api_key": "", "output_folder": ""} options_desc = {"api_key": "Github token", "output_folder": "Folder to clone repositories to"} @@ -46,9 +51,11 @@ async def clone_git_repository(self, repository_url): else: url = repository_url command = ["git", "-C", self.output_dir, "clone", url] - output = await self.run_process(command) - if output.returncode == 0: - folder_name = output.stderr.split("Cloning into '")[1].split("'")[0] - return self.output_dir / folder_name - else: - return None + try: + output = await self.run_process(command, env={"GIT_TERMINAL_PROMPT": "0"}, check=True) + except CalledProcessError as e: + self.debug(f"Error cloning {url}. STDERR: {repr(e.stderr)}") + return + + folder_name = output.stderr.split("Cloning into '")[1].split("'")[0] + return self.output_dir / folder_name diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index 6a3ea57a54..146cf42e59 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -5,7 +5,12 @@ class github_codesearch(github): watched_events = ["DNS_NAME"] produced_events = ["CODE_REPOSITORY", "URL_UNVERIFIED"] flags = ["passive", "subdomain-enum", "safe"] - meta = {"description": "Query Github's API for code containing the target domain name", "auth_required": True} + meta = { + "description": "Query Github's API for code containing the target domain name", + "created_date": "2023-12-14", + "author": "@domwhewell-sage", + "auth_required": True, + } options = {"api_key": "", "limit": 100} options_desc = {"api_key": "Github token", "limit": "Limit code search to this many results"} diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index 93cefa9ee9..ef6ffd6d36 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -5,7 +5,11 @@ class github_org(github): watched_events = ["ORG_STUB", "SOCIAL"] produced_events = ["CODE_REPOSITORY"] flags = ["passive", "subdomain-enum", "safe"] - meta = {"description": "Query Github's API for organization and member repositories"} + meta = { + "description": "Query Github's API for organization and member repositories", + "created_date": "2023-12-14", + "author": "@domwhewell-sage", + } options = {"api_key": "", "include_members": True, "include_member_repos": False} options_desc = { "api_key": "Github token", diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index 03d8e55f01..bf8f7eb6d2 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -8,7 +8,11 @@ class github_workflows(github): watched_events = ["CODE_REPOSITORY"] produced_events = ["FILESYSTEM"] flags = ["passive", "safe"] - meta = {"description": "Download a github repositories workflow logs"} + meta = { + "description": "Download a github repositories workflow logs", + "created_date": "2024-04-29", + "author": "@domwhewell-sage", + } options = {"api_key": "", "num_logs": 1} options_desc = { "api_key": "Github token", diff --git a/bbot/modules/gitlab.py b/bbot/modules/gitlab.py index 1369efa783..7aa91190dc 100644 --- a/bbot/modules/gitlab.py +++ b/bbot/modules/gitlab.py @@ -5,7 +5,11 @@ class gitlab(BaseModule): watched_events = ["HTTP_RESPONSE", "TECHNOLOGY", "SOCIAL"] produced_events = ["TECHNOLOGY", "SOCIAL", "CODE_REPOSITORY", "FINDING"] flags = ["active", "safe"] - meta = {"description": "Detect GitLab instances and query them for repositories"} + meta = { + "description": "Detect GitLab instances and query them for repositories", + "created_date": "2024-03-11", + "author": "@TheTechromancer", + } options = {"api_key": ""} options_desc = {"api_key": "Gitlab access token"} diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 3271ef93fd..3305b0f09e 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -1,4 +1,6 @@ +import asyncio import sqlite3 +import multiprocessing from pathlib import Path from contextlib import suppress from shutil import copyfile, copymode @@ -10,24 +12,26 @@ class gowitness(BaseModule): watched_events = ["URL", "SOCIAL"] produced_events = ["WEBSCREENSHOT", "URL", "URL_UNVERIFIED", "TECHNOLOGY"] flags = ["active", "safe", "web-screenshots"] - meta = {"description": "Take screenshots of webpages"} + meta = {"description": "Take screenshots of webpages", "created_date": "2022-07-08", "author": "@TheTechromancer"} options = { "version": "2.4.2", - "threads": 4, + "threads": 0, "timeout": 10, "resolution_x": 1440, "resolution_y": 900, "output_path": "", "social": True, + "idle_timeout": 1800, } options_desc = { - "version": "gowitness version", - "threads": "threads used to run", - "timeout": "preflight check timeout", - "resolution_x": "screenshot resolution x", - "resolution_y": "screenshot resolution y", - "output_path": "where to save screenshots", + "version": "Gowitness version", + "threads": "How many gowitness threads to spawn (default is number of CPUs x 2)", + "timeout": "Preflight check timeout", + "resolution_x": "Screenshot resolution x", + "resolution_y": "Screenshot resolution y", + "output_path": "Where to save screenshots", "social": "Whether to screenshot social media webpages", + "idle_timeout": "Skip the current gowitness batch if it stalls for longer than this many seconds", } deps_ansible = [ { @@ -82,8 +86,13 @@ class gowitness(BaseModule): scope_distance_modifier = 2 async def setup(self): + num_cpus = multiprocessing.cpu_count() + default_thread_count = min(20, num_cpus * 2) self.timeout = self.config.get("timeout", 10) - self.threads = self.config.get("threads", 4) + self.idle_timeout = self.config.get("idle_timeout", 1800) + self.threads = self.config.get("threads", 0) + if not self.threads: + self.threads = default_thread_count self.proxy = self.scan.config.get("http_proxy", "") self.resolution_x = self.config.get("resolution_x") self.resolution_y = self.config.get("resolution_y") @@ -155,8 +164,13 @@ async def handle_batch(self, *events): event_dict[key] = e stdin = "\n".join(list(event_dict)) - async for line in self.run_process_live(self.command, input=stdin): - self.debug(line) + try: + async for line in self.run_process_live(self.command, input=stdin, idle_timeout=self.idle_timeout): + self.debug(line) + except asyncio.exceptions.TimeoutError: + urls_str = ",".join(event_dict) + self.warning(f"Gowitness timed out while visiting the following URLs: {urls_str}", trace=False) + return # emit web screenshots for filename, screenshot in self.new_screenshots.items(): @@ -212,6 +226,8 @@ def construct_command(self): command += ["file", "-f", "-"] # threads command += ["--threads", str(self.threads)] + # timeout + command += ["--timeout", str(self.timeout)] return command @property diff --git a/bbot/modules/hackertarget.py b/bbot/modules/hackertarget.py index d23f5c6cf4..aee94ccd36 100644 --- a/bbot/modules/hackertarget.py +++ b/bbot/modules/hackertarget.py @@ -5,7 +5,11 @@ class hackertarget(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the hackertarget.com API for subdomains"} + meta = { + "description": "Query the hackertarget.com API for subdomains", + "created_date": "2022-07-28", + "author": "@TheTechromancer", + } base_url = "https://api.hackertarget.com" diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index 4adaa766a7..bba8f0aca1 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -6,7 +6,11 @@ class host_header(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Try common HTTP Host header spoofing techniques"} + meta = { + "description": "Try common HTTP Host header spoofing techniques", + "created_date": "2022-07-27", + "author": "@liquidsec", + } in_scope_only = True per_hostport_only = True diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 2e5dc0ffc4..2c2fcfe72a 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -11,7 +11,11 @@ class httpx(BaseModule): watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] produced_events = ["URL", "HTTP_RESPONSE"] flags = ["active", "safe", "web-basic", "web-thorough", "social-enum", "subdomain-enum", "cloud-enum"] - meta = {"description": "Visit webpages. Many other modules rely on httpx"} + meta = { + "description": "Visit webpages. Many other modules rely on httpx", + "created_date": "2022-07-08", + "author": "@TheTechromancer", + } options = { "threads": 50, diff --git a/bbot/modules/hunt.py b/bbot/modules/hunt.py index add45b665d..a86c66cef6 100644 --- a/bbot/modules/hunt.py +++ b/bbot/modules/hunt.py @@ -275,7 +275,11 @@ class hunt(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "safe", "web-thorough"] - meta = {"description": "Watch for commonly-exploitable HTTP parameters"} + meta = { + "description": "Watch for commonly-exploitable HTTP parameters", + "created_date": "2022-07-20", + "author": "@liquidsec", + } # accept all events regardless of scope distance scope_distance_modifier = None diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index 792ca6d98b..2f4d22bad2 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -5,7 +5,12 @@ class hunterio(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS", "DNS_NAME", "URL_UNVERIFIED"] flags = ["passive", "email-enum", "subdomain-enum", "safe"] - meta = {"description": "Query hunter.io for emails", "auth_required": True} + meta = { + "description": "Query hunter.io for emails", + "created_date": "2022-04-25", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "Hunter.IO API key"} diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 7d558a23aa..86a98dc863 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -17,7 +17,11 @@ class iis_shortnames(BaseModule): watched_events = ["URL"] produced_events = ["URL_HINT"] flags = ["active", "safe", "web-basic", "web-thorough", "iis-shortnames"] - meta = {"description": "Check for IIS shortname vulnerability"} + meta = { + "description": "Check for IIS shortname vulnerability", + "created_date": "2022-04-15", + "author": "@pmueller", + } options = {"detect_only": True, "max_node_count": 50} options_desc = { "detect_only": "Only detect the vulnerability and do not run the shortname scanner", @@ -63,11 +67,10 @@ async def directory_confirm(self, target, method, url_hint, affirmative_status_c directory_confirm_result = await self.helpers.request( method=method, url=url, allow_redirects=False, retries=2, timeout=10 ) - - if directory_confirm_result.status_code == affirmative_status_code: - return True - else: - return False + if directory_confirm_result is not None: + if directory_confirm_result.status_code == affirmative_status_code: + return True + return False async def duplicate_check(self, target, method, url_hint, affirmative_status_code): duplicates = [] diff --git a/bbot/modules/internal/aggregate.py b/bbot/modules/internal/aggregate.py index b1f11b04e7..54e3a52ccc 100644 --- a/bbot/modules/internal/aggregate.py +++ b/bbot/modules/internal/aggregate.py @@ -3,7 +3,11 @@ class aggregate(BaseReportModule): flags = ["passive", "safe"] - meta = {"description": "Summarize statistics at the end of a scan"} + meta = { + "description": "Summarize statistics at the end of a scan", + "created_date": "2022-07-25", + "author": "@TheTechromancer", + } async def report(self): self.log_table(*self.scan.stats._make_table(), table_name="scan-stats") diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 40067c69e2..33254d9ef6 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -338,7 +338,11 @@ class excavate(BaseInternalModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["URL_UNVERIFIED"] flags = ["passive"] - meta = {"description": "Passively extract juicy tidbits from scan data"} + meta = { + "description": "Passively extract juicy tidbits from scan data", + "created_date": "2022-06-27", + "author": "@liquidsec", + } scope_distance_modifier = None diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index d5b65af4de..2d7ea71626 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -26,7 +26,11 @@ class speculate(BaseInternalModule): ] produced_events = ["DNS_NAME", "OPEN_TCP_PORT", "IP_ADDRESS", "FINDING", "ORG_STUB"] flags = ["passive"] - meta = {"description": "Derive certain event types from others by common sense"} + meta = { + "description": "Derive certain event types from others by common sense", + "created_date": "2022-05-03", + "author": "@liquidsec", + } options = {"max_hosts": 65536, "ports": "80,443"} options_desc = { diff --git a/bbot/modules/internetdb.py b/bbot/modules/internetdb.py index 847db0c7ad..3003b2e9fc 100644 --- a/bbot/modules/internetdb.py +++ b/bbot/modules/internetdb.py @@ -38,7 +38,11 @@ class internetdb(BaseModule): watched_events = ["IP_ADDRESS", "DNS_NAME"] produced_events = ["TECHNOLOGY", "VULNERABILITY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] flags = ["passive", "safe", "portscan", "subdomain-enum"] - meta = {"description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities"} + meta = { + "description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities", + "created_date": "2023-12-22", + "author": "@TheTechromancer", + } _qsize = 500 diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index e192b2abba..6e2bf4a259 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -9,7 +9,12 @@ class IP2Location(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["GEOLOCATION"] flags = ["passive", "safe"] - meta = {"description": "Query IP2location.io's API for geolocation information. ", "auth_required": True} + meta = { + "description": "Query IP2location.io's API for geolocation information. ", + "created_date": "2023-09-12", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": "", "lang": ""} options_desc = { "api_key": "IP2location.io API Key", diff --git a/bbot/modules/ipneighbor.py b/bbot/modules/ipneighbor.py index fe9673f5b9..e4cc1dd55c 100644 --- a/bbot/modules/ipneighbor.py +++ b/bbot/modules/ipneighbor.py @@ -7,7 +7,11 @@ class ipneighbor(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["IP_ADDRESS"] flags = ["passive", "subdomain-enum", "aggressive"] - meta = {"description": "Look beside IPs in their surrounding subnet"} + meta = { + "description": "Look beside IPs in their surrounding subnet", + "created_date": "2022-06-08", + "author": "@TheTechromancer", + } options = {"num_bits": 4} options_desc = {"num_bits": "Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts)"} scope_distance_modifier = 1 diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index 98f1395056..0d81674a4d 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -10,7 +10,12 @@ class Ipstack(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["GEOLOCATION"] flags = ["passive", "safe"] - meta = {"description": "Query IPStack's GeoIP API", "auth_required": True} + meta = { + "description": "Query IPStack's GeoIP API", + "created_date": "2022-11-26", + "author": "@tycoonslive", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "IPStack GeoIP API Key"} scope_distance_modifier = 1 diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 45053755a1..4bc88d3c71 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -8,7 +8,11 @@ class leakix(subdomain_enum_apikey): options = {"api_key": ""} # NOTE: API key is not required (but having one will get you more results) options_desc = {"api_key": "LeakIX API Key"} - meta = {"description": "Query leakix.net for subdomains"} + meta = { + "description": "Query leakix.net for subdomains", + "created_date": "2022-07-11", + "author": "@TheTechromancer", + } base_url = "https://leakix.net" diff --git a/bbot/modules/masscan.py b/bbot/modules/masscan.py index ddeb76163d..502d5dc813 100644 --- a/bbot/modules/masscan.py +++ b/bbot/modules/masscan.py @@ -8,7 +8,11 @@ class masscan(portscanner): flags = ["active", "portscan", "aggressive"] watched_events = ["IP_ADDRESS", "IP_RANGE"] produced_events = ["OPEN_TCP_PORT"] - meta = {"description": "Port scan with masscan. By default, scans top 100 ports."} + meta = { + "description": "Port scan with masscan. By default, scans top 100 ports.", + "created_date": "2023-01-27", + "author": "@TheTechromancer", + } options = { "top_ports": 100, "ports": "", diff --git a/bbot/modules/massdns.py b/bbot/modules/massdns.py index e453ee8d45..ce172681a2 100644 --- a/bbot/modules/massdns.py +++ b/bbot/modules/massdns.py @@ -25,7 +25,11 @@ class massdns(subdomain_enum): flags = ["subdomain-enum", "passive", "aggressive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Brute-force subdomains with massdns (highly effective)"} + meta = { + "description": "Brute-force subdomains with massdns (highly effective)", + "created_date": "2023-03-29", + "author": "@TheTechromancer", + } options = { "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", "max_resolvers": 1000, diff --git a/bbot/modules/myssl.py b/bbot/modules/myssl.py index a08c885eda..047ced9288 100644 --- a/bbot/modules/myssl.py +++ b/bbot/modules/myssl.py @@ -5,7 +5,11 @@ class myssl(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query myssl.com's API for subdomains"} + meta = { + "description": "Query myssl.com's API for subdomains", + "created_date": "2023-07-10", + "author": "@TheTechromancer", + } base_url = "https://myssl.com/api/v1/discover_sub_domain" diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 726d633fee..11bb2a8b18 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -19,7 +19,11 @@ class newsletters(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "safe"] - meta = {"description": "Searches for Newsletter Submission Entry Fields on Websites"} + meta = { + "description": "Searches for Newsletter Submission Entry Fields on Websites", + "created_date": "2024-02-02", + "author": "@stryker2k2", + } # Parse through Website to find a Text Entry Box of 'type = email' # and ensure that there is placeholder text within it. diff --git a/bbot/modules/nmap.py b/bbot/modules/nmap.py index ccdb0974e4..16e7064beb 100644 --- a/bbot/modules/nmap.py +++ b/bbot/modules/nmap.py @@ -6,7 +6,11 @@ class nmap(portscanner): watched_events = ["IP_ADDRESS", "DNS_NAME", "IP_RANGE"] produced_events = ["OPEN_TCP_PORT"] flags = ["active", "portscan", "aggressive", "web-thorough"] - meta = {"description": "Port scan with nmap. By default, scans top 100 ports."} + meta = { + "description": "Port scan with nmap. By default, scans top 100 ports.", + "created_date": "2022-03-12", + "author": "@TheTechromancer", + } options = { "top_ports": 100, "ports": "", diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index c69beb941d..ad963c4b51 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -69,7 +69,11 @@ class ntlm(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["FINDING", "DNS_NAME"] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Watch for HTTP endpoints that support NTLM authentication"} + meta = { + "description": "Watch for HTTP endpoints that support NTLM authentication", + "created_date": "2022-07-25", + "author": "@liquidsec", + } options = {"try_all": False} options_desc = {"try_all": "Try every NTLM endpoint"} diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 13a483aadc..32418848d4 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -7,7 +7,11 @@ class OAUTH(BaseModule): watched_events = ["DNS_NAME", "URL_UNVERIFIED"] produced_events = ["DNS_NAME"] flags = ["affiliates", "subdomain-enum", "cloud-enum", "web-basic", "web-thorough", "active", "safe"] - meta = {"description": "Enumerate OAUTH and OpenID Connect services"} + meta = { + "description": "Enumerate OAUTH and OpenID Connect services", + "created_date": "2023-07-12", + "author": "@TheTechromancer", + } options = {"try_all": False} options_desc = {"try_all": "Check for OAUTH/IODC on every subdomain and URL."} diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index 72f2e1d5ba..5a2319e3d4 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -5,7 +5,11 @@ class otx(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query otx.alienvault.com for subdomains"} + meta = { + "description": "Query otx.alienvault.com for subdomains", + "created_date": "2022-08-24", + "author": "@TheTechromancer", + } base_url = "https://otx.alienvault.com" diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 0372dc1bd2..82a67e97c5 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -33,7 +33,11 @@ class asset_inventory(CSV): "HTTP_RESPONSE", ] produced_events = ["IP_ADDRESS", "OPEN_TCP_PORT"] - meta = {"description": "Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV"} + meta = { + "description": "Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV", + "created_date": "2022-09-30", + "author": "@liquidsec", + } options = {"output_file": "", "use_previous": False, "recheck": False, "summary_netmask": 16} options_desc = { "output_file": "Set a custom output file", diff --git a/bbot/modules/output/csv.py b/bbot/modules/output/csv.py index fe8af7e89e..3fd28f5459 100644 --- a/bbot/modules/output/csv.py +++ b/bbot/modules/output/csv.py @@ -6,7 +6,7 @@ class CSV(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Output to CSV"} + meta = {"description": "Output to CSV", "created_date": "2022-04-07", "author": "@TheTechromancer"} options = {"output_file": ""} options_desc = {"output_file": "Output to CSV file"} diff --git a/bbot/modules/output/discord.py b/bbot/modules/output/discord.py index 06684bd301..3a921a9000 100644 --- a/bbot/modules/output/discord.py +++ b/bbot/modules/output/discord.py @@ -3,7 +3,11 @@ class Discord(WebhookOutputModule): watched_events = ["*"] - meta = {"description": "Message a Discord channel when certain events are encountered"} + meta = { + "description": "Message a Discord channel when certain events are encountered", + "created_date": "2023-08-14", + "author": "@TheTechromancer", + } options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW"} options_desc = { "webhook_url": "Discord webhook URL", diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index e96c5d97c4..1b05906337 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -5,7 +5,11 @@ class Emails(Human): watched_events = ["EMAIL_ADDRESS"] flags = ["email-enum"] - meta = {"description": "Output any email addresses found belonging to the target domain"} + meta = { + "description": "Output any email addresses found belonging to the target domain", + "created_date": "2023-12-23", + "author": "@domwhewell-sage", + } options = {"output_file": ""} options_desc = {"output_file": "Output to file"} in_scope_only = True diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 0146107366..e4ed2ddbc0 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -5,7 +5,11 @@ class HTTP(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Send every event to a custom URL via a web request"} + meta = { + "description": "Send every event to a custom URL via a web request", + "created_date": "2022-04-13", + "author": "@TheTechromancer", + } options = { "url": "", "method": "POST", diff --git a/bbot/modules/output/human.py b/bbot/modules/output/human.py index e1f4746c42..37b8122147 100644 --- a/bbot/modules/output/human.py +++ b/bbot/modules/output/human.py @@ -6,7 +6,7 @@ class Human(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Output to text"} + meta = {"description": "Output to text", "created_date": "2022-04-07", "author": "@TheTechromancer"} options = {"output_file": "", "console": True} options_desc = {"output_file": "Output to file", "console": "Output to console"} vuln_severity_map = {"LOW": "HUGEWARNING", "MEDIUM": "HUGEWARNING", "HIGH": "CRITICAL", "CRITICAL": "CRITICAL"} diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index bf8517db95..e4dcdfd01d 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -6,7 +6,11 @@ class JSON(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Output to Newline-Delimited JSON (NDJSON)"} + meta = { + "description": "Output to Newline-Delimited JSON (NDJSON)", + "created_date": "2022-04-07", + "author": "@TheTechromancer", + } options = {"output_file": "", "console": False, "siem_friendly": False} options_desc = { "output_file": "Output to file", diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 2cc0835443..f7ecc3a842 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -25,7 +25,7 @@ class neo4j(BaseOutputModule): """ watched_events = ["*"] - meta = {"description": "Output to Neo4j"} + meta = {"description": "Output to Neo4j", "created_date": "2022-04-07", "author": "@TheTechromancer"} options = {"uri": "bolt://localhost:7687", "username": "neo4j", "password": "bbotislife"} options_desc = { "uri": "Neo4j server + port", diff --git a/bbot/modules/output/python.py b/bbot/modules/output/python.py index 3aebfeb527..81ceb360ed 100644 --- a/bbot/modules/output/python.py +++ b/bbot/modules/output/python.py @@ -3,7 +3,7 @@ class python(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Output via Python API"} + meta = {"description": "Output via Python API", "created_date": "2022-09-13", "author": "@TheTechromancer"} async def _worker(self): pass diff --git a/bbot/modules/output/slack.py b/bbot/modules/output/slack.py index 1dda469428..438ef4973c 100644 --- a/bbot/modules/output/slack.py +++ b/bbot/modules/output/slack.py @@ -5,7 +5,11 @@ class Slack(WebhookOutputModule): watched_events = ["*"] - meta = {"description": "Message a Slack channel when certain events are encountered"} + meta = { + "description": "Message a Slack channel when certain events are encountered", + "created_date": "2023-08-14", + "author": "@TheTechromancer", + } options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW"} options_desc = { "webhook_url": "Discord webhook URL", diff --git a/bbot/modules/output/splunk.py b/bbot/modules/output/splunk.py index 242f1759e1..de3e8d131c 100644 --- a/bbot/modules/output/splunk.py +++ b/bbot/modules/output/splunk.py @@ -5,7 +5,11 @@ class Splunk(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Send every event to a splunk instance through HTTP Event Collector"} + meta = { + "description": "Send every event to a splunk instance through HTTP Event Collector", + "created_date": "2024-02-17", + "author": "@w0Tx", + } options = { "url": "", "hectoken": "", diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index bfb7174ac8..e8c0ec5a3e 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -5,7 +5,11 @@ class Subdomains(Human): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] flags = ["subdomain-enum"] - meta = {"description": "Output only resolved, in-scope subdomains"} + meta = { + "description": "Output only resolved, in-scope subdomains", + "created_date": "2023-07-31", + "author": "@TheTechromancer", + } options = {"output_file": "", "include_unresolved": False} options_desc = {"output_file": "Output to file", "include_unresolved": "Include unresolved subdomains in output"} accept_dupes = False diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index 3f018038d0..e4f87fb71c 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -3,7 +3,11 @@ class Teams(WebhookOutputModule): watched_events = ["*"] - meta = {"description": "Message a Teams channel when certain events are encountered"} + meta = { + "description": "Message a Teams channel when certain events are encountered", + "created_date": "2023-08-14", + "author": "@TheTechromancer", + } options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW"} options_desc = { "webhook_url": "Discord webhook URL", diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 793f26c329..ba69f9b2a6 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -5,7 +5,11 @@ class web_report(BaseOutputModule): watched_events = ["URL", "TECHNOLOGY", "FINDING", "VULNERABILITY", "VHOST"] - meta = {"description": "Create a markdown report with web assets"} + meta = { + "description": "Create a markdown report with web assets", + "created_date": "2023-02-08", + "author": "@liquidsec", + } options = { "output_file": "", "css_theme_file": "https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css", diff --git a/bbot/modules/output/websocket.py b/bbot/modules/output/websocket.py index 76edcba4b4..c8f54097ac 100644 --- a/bbot/modules/output/websocket.py +++ b/bbot/modules/output/websocket.py @@ -7,7 +7,7 @@ class Websocket(BaseOutputModule): watched_events = ["*"] - meta = {"description": "Output to websockets"} + meta = {"description": "Output to websockets", "created_date": "2022-04-15", "author": "@TheTechromancer"} options = {"url": "", "token": "", "preserve_graph": True} options_desc = { "url": "Web URL", diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 251931f580..6a113f7f7a 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -11,6 +11,8 @@ class paramminer_cookies(paramminer_headers): flags = ["active", "aggressive", "slow", "web-paramminer"] meta = { "description": "Smart brute-force to check for common HTTP cookie parameters", + "created_date": "2022-06-27", + "author": "@liquidsec", } options = { "wordlist": "", # default is defined within setup function diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 7891e05cfb..c596dd0ec3 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -9,7 +9,11 @@ class paramminer_getparams(paramminer_headers): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "aggressive", "slow", "web-paramminer"] - meta = {"description": "Use smart brute-force to check for common HTTP GET parameters"} + meta = { + "description": "Use smart brute-force to check for common HTTP GET parameters", + "created_date": "2022-06-28", + "author": "@liquidsec", + } scanned_hosts = [] options = { "wordlist": "", # default is defined within setup function diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index c7418912f0..5aac4b304b 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -11,7 +11,11 @@ class paramminer_headers(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "aggressive", "slow", "web-paramminer"] - meta = {"description": "Use smart brute-force to check for common HTTP header parameters"} + meta = { + "description": "Use smart brute-force to check for common HTTP header parameters", + "created_date": "2022-04-15", + "author": "@pmueller", + } options = { "wordlist": "", # default is defined within setup function "http_extract": True, diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index dfed92939a..e22dfc3e52 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -5,7 +5,12 @@ class passivetotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the PassiveTotal API for subdomains", "auth_required": True} + meta = { + "description": "Query the PassiveTotal API for subdomains", + "created_date": "2022-08-08", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"username": "", "api_key": ""} options_desc = {"username": "RiskIQ Username", "api_key": "RiskIQ API Key"} diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 2c378f5853..54157930a0 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -5,7 +5,11 @@ class pgp(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] flags = ["passive", "email-enum", "safe"] - meta = {"description": "Query common PGP servers for email addresses"} + meta = { + "description": "Query common PGP servers for email addresses", + "created_date": "2022-08-10", + "author": "@TheTechromancer", + } options = { "search_urls": [ "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=", diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index 5a63f824e3..bfdc2f90d9 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -5,7 +5,11 @@ class postman(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["URL_UNVERIFIED"] flags = ["passive", "subdomain-enum", "safe"] - meta = {"description": "Query Postman's API for related workspaces, collections, requests"} + meta = { + "description": "Query Postman's API for related workspaces, collections, requests", + "created_date": "2023-12-23", + "author": "@domwhewell-sage", + } base_url = "https://www.postman.com/_api" diff --git a/bbot/modules/rapiddns.py b/bbot/modules/rapiddns.py index 088288ddbf..55cca4dfe5 100644 --- a/bbot/modules/rapiddns.py +++ b/bbot/modules/rapiddns.py @@ -5,7 +5,11 @@ class rapiddns(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query rapiddns.io for subdomains"} + meta = { + "description": "Query rapiddns.io for subdomains", + "created_date": "2022-08-24", + "author": "@TheTechromancer", + } base_url = "https://rapiddns.io" diff --git a/bbot/modules/report/affiliates.py b/bbot/modules/report/affiliates.py index bb6323664d..73b2867e29 100644 --- a/bbot/modules/report/affiliates.py +++ b/bbot/modules/report/affiliates.py @@ -5,7 +5,11 @@ class affiliates(BaseReportModule): watched_events = ["*"] produced_events = [] flags = ["passive", "safe", "affiliates"] - meta = {"description": "Summarize affiliate domains at the end of a scan"} + meta = { + "description": "Summarize affiliate domains at the end of a scan", + "created_date": "2022-07-25", + "author": "@TheTechromancer", + } scope_distance_modifier = None accept_dupes = True diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index f906c785e6..32590c0dd2 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -5,7 +5,11 @@ class asn(BaseReportModule): watched_events = ["IP_ADDRESS"] produced_events = ["ASN"] flags = ["passive", "subdomain-enum", "safe"] - meta = {"description": "Query ripe and bgpview.io for ASNs"} + meta = { + "description": "Query ripe and bgpview.io for ASNs", + "created_date": "2022-07-25", + "author": "@TheTechromancer", + } scope_distance_modifier = 1 # we accept dupes to avoid missing data # because sometimes IP addresses are re-emitted with lower scope distances @@ -102,7 +106,7 @@ async def get_asn(self, ip, retries=1): continue return res self.warning(f"Error retrieving ASN for {ip}") - return [] + return [], "" async def get_asn_ripe(self, ip): url = f"https://stat.ripe.net/data/network-info/data.json?resource={ip}" diff --git a/bbot/modules/riddler.py b/bbot/modules/riddler.py index d525acbade..dbc86e6e0b 100644 --- a/bbot/modules/riddler.py +++ b/bbot/modules/riddler.py @@ -5,7 +5,11 @@ class riddler(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query riddler.io for subdomains"} + meta = { + "description": "Query riddler.io for subdomains", + "created_date": "2022-08-25", + "author": "@TheTechromancer", + } base_url = "https://riddler.io" diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index 717900beee..8faf596641 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -5,7 +5,7 @@ class robots(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Look for and parse robots.txt"} + meta = {"description": "Look for and parse robots.txt", "created_date": "2023-02-01", "author": "@liquidsec"} options = {"include_sitemap": False, "include_allow": True, "include_disallow": True} options_desc = { diff --git a/bbot/modules/secretsdb.py b/bbot/modules/secretsdb.py index 3fc8ad5392..62246e1cc7 100644 --- a/bbot/modules/secretsdb.py +++ b/bbot/modules/secretsdb.py @@ -8,7 +8,11 @@ class secretsdb(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] flags = ["active", "safe", "web-basic", "web-thorough"] - meta = {"description": "Detect common secrets with secrets-patterns-db"} + meta = { + "description": "Detect common secrets with secrets-patterns-db", + "created_date": "2023-03-17", + "author": "@TheTechromancer", + } options = { "min_confidence": 99, "signatures": "https://raw.githubusercontent.com/blacklanternsecurity/secrets-patterns-db/master/db/rules-stable.yml", diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index 8d1d1b6a07..a91db29128 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -5,7 +5,12 @@ class securitytrails(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query the SecurityTrails API for subdomains", "auth_required": True} + meta = { + "description": "Query the SecurityTrails API for subdomains", + "created_date": "2022-07-03", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "SecurityTrails API key"} diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index 4d19b237e7..2336e02435 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -5,7 +5,12 @@ class shodan_dns(shodan): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query Shodan for subdomains", "auth_required": True} + meta = { + "description": "Query Shodan for subdomains", + "created_date": "2022-07-03", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "Shodan API key"} diff --git a/bbot/modules/sitedossier.py b/bbot/modules/sitedossier.py index 86872c0523..da11ac82fa 100644 --- a/bbot/modules/sitedossier.py +++ b/bbot/modules/sitedossier.py @@ -5,7 +5,11 @@ class sitedossier(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query sitedossier.com for subdomains"} + meta = { + "description": "Query sitedossier.com for subdomains", + "created_date": "2023-08-04", + "author": "@TheTechromancer", + } base_url = "http://www.sitedossier.com/parentdomain" max_pages = 10 diff --git a/bbot/modules/skymem.py b/bbot/modules/skymem.py index 4bd76c70d8..24f8ce309f 100644 --- a/bbot/modules/skymem.py +++ b/bbot/modules/skymem.py @@ -7,7 +7,11 @@ class skymem(emailformat): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] flags = ["passive", "email-enum", "safe"] - meta = {"description": "Query skymem.info for email addresses"} + meta = { + "description": "Query skymem.info for email addresses", + "created_date": "2022-07-11", + "author": "@TheTechromancer", + } base_url = "https://www.skymem.info" diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index 8ee344452c..6a3c5a85a5 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -12,7 +12,7 @@ class smuggler(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] flags = ["active", "aggressive", "slow", "web-thorough"] - meta = {"description": "Check for HTTP smuggling"} + meta = {"description": "Check for HTTP smuggling", "created_date": "2022-07-06", "author": "@liquidsec"} in_scope_only = True per_hostport_only = True diff --git a/bbot/modules/social.py b/bbot/modules/social.py index 3688d74025..4dbf05948a 100644 --- a/bbot/modules/social.py +++ b/bbot/modules/social.py @@ -5,7 +5,11 @@ class social(BaseModule): watched_events = ["URL_UNVERIFIED"] produced_events = ["SOCIAL"] - meta = {"description": "Look for social media links in webpages"} + meta = { + "description": "Look for social media links in webpages", + "created_date": "2023-03-28", + "author": "@TheTechromancer", + } flags = ["passive", "safe", "social-enum"] # platform name : (regex, case_sensitive) diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index caca5feca4..13b868febe 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -13,6 +13,8 @@ class sslcert(BaseModule): flags = ["affiliates", "subdomain-enum", "email-enum", "active", "safe", "web-basic", "web-thorough"] meta = { "description": "Visit open ports and retrieve SSL certificates", + "created_date": "2022-03-30", + "author": "@TheTechromancer", } options = {"timeout": 5.0, "skip_non_ssl": True} options_desc = {"timeout": "Socket connect timeout in seconds", "skip_non_ssl": "Don't try common non-SSL ports"} @@ -72,7 +74,7 @@ async def handle_event(self, event): f"Skipping Subject Alternate Names (SANs) on {netloc} because number of hostnames ({len(dns_names):,}) exceeds threshold ({abort_threshold})" ) dns_names = dns_names[:1] + [n for n in dns_names[1:] if self.scan.in_scope(n)] - for event_type, results in (("DNS_NAME", dns_names), ("EMAIL_ADDRESS", emails)): + for event_type, results in (("DNS_NAME", set(dns_names)), ("EMAIL_ADDRESS", emails)): for event_data in results: if event_data is not None and event_data != event: self.debug(f"Discovered new {event_type} via SSL certificate parsing: [{event_data}]") diff --git a/bbot/modules/subdomaincenter.py b/bbot/modules/subdomaincenter.py index c5c69293cb..9fdce8c495 100644 --- a/bbot/modules/subdomaincenter.py +++ b/bbot/modules/subdomaincenter.py @@ -5,7 +5,11 @@ class subdomaincenter(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - meta = {"description": "Query subdomain.center's API for subdomains"} + meta = { + "description": "Query subdomain.center's API for subdomains", + "created_date": "2023-07-26", + "author": "@TheTechromancer", + } base_url = "https://api.subdomain.center" retries = 2 diff --git a/bbot/modules/sublist3r.py b/bbot/modules/sublist3r.py index 3c13cf3081..502352bc9b 100644 --- a/bbot/modules/sublist3r.py +++ b/bbot/modules/sublist3r.py @@ -8,6 +8,8 @@ class sublist3r(subdomain_enum): flags = ["passive", "safe"] meta = { "description": "Query sublist3r's API for subdomains", + "created_date": "2022-03-29", + "author": "@Want-EyeTea", } base_url = "https://api.sublist3r.com/search.php" diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index c86da8897e..64a6437c35 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -9,7 +9,11 @@ class telerik(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["VULNERABILITY", "FINDING"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Scan for critical Telerik vulnerabilities"} + meta = { + "description": "Scan for critical Telerik vulnerabilities", + "created_date": "2022-04-10", + "author": "@liquidsec", + } telerikVersions = [ "2007.1423", diff --git a/bbot/modules/threatminer.py b/bbot/modules/threatminer.py index bbc1e23c3d..b4ccad4b8d 100644 --- a/bbot/modules/threatminer.py +++ b/bbot/modules/threatminer.py @@ -7,6 +7,8 @@ class threatminer(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] meta = { "description": "Query threatminer's API for subdomains", + "created_date": "2022-07-28", + "author": "@TheTechromancer", } base_url = "https://api.threatminer.org/v2" diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 5acb45a124..e5f8dd26dd 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -6,7 +6,11 @@ class trufflehog(BaseModule): watched_events = ["FILESYSTEM"] produced_events = ["FINDING", "VULNERABILITY"] flags = ["passive", "safe"] - meta = {"description": "TruffleHog is a tool for finding credentials"} + meta = { + "description": "TruffleHog is a tool for finding credentials", + "created_date": "2024-03-12", + "author": "@domwhewell-sage", + } options = { "version": "3.75.1", diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index 983595fe16..209e51a116 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -6,7 +6,11 @@ class url_manipulation(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Attempt to identify URL parsing/routing based vulnerabilities"} + meta = { + "description": "Attempt to identify URL parsing/routing based vulnerabilities", + "created_date": "2022-09-27", + "author": "@liquidsec", + } in_scope_only = True options = {"allow_redirects": True} diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index 4c3811af09..d9e6cbb43c 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -7,6 +7,8 @@ class urlscan(subdomain_enum): produced_events = ["DNS_NAME", "URL_UNVERIFIED"] meta = { "description": "Query urlscan.io for subdomains", + "created_date": "2022-06-09", + "author": "@TheTechromancer", } options = {"urls": False} options_desc = {"urls": "Emit URLs in addition to DNS_NAMEs"} diff --git a/bbot/modules/viewdns.py b/bbot/modules/viewdns.py index 0d996bf09a..2c1ea73bf4 100644 --- a/bbot/modules/viewdns.py +++ b/bbot/modules/viewdns.py @@ -13,6 +13,8 @@ class viewdns(BaseModule): flags = ["affiliates", "passive", "safe"] meta = { "description": "Query viewdns.info's reverse whois for related domains", + "created_date": "2022-07-04", + "author": "@TheTechromancer", } base_url = "https://viewdns.info" in_scope_only = True diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index 8e0c03934b..6f0ba5e82d 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -5,7 +5,12 @@ class virustotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive", "safe"] - meta = {"description": "Query VirusTotal's API for subdomains", "auth_required": True} + meta = { + "description": "Query VirusTotal's API for subdomains", + "created_date": "2022-08-25", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": ""} options_desc = {"api_key": "VirusTotal API Key"} diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index a91bfd920b..c8f9c4b33f 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -16,7 +16,11 @@ class wafw00f(BaseModule): watched_events = ["URL"] produced_events = ["WAF"] flags = ["active", "aggressive"] - meta = {"description": "Web Application Firewall Fingerprinting Tool"} + meta = { + "description": "Web Application Firewall Fingerprinting Tool", + "created_date": "2023-02-15", + "author": "@liquidsec", + } deps_pip = ["wafw00f~=2.2.0"] diff --git a/bbot/modules/wappalyzer.py b/bbot/modules/wappalyzer.py index c87274a29b..ee65e22fe3 100644 --- a/bbot/modules/wappalyzer.py +++ b/bbot/modules/wappalyzer.py @@ -16,6 +16,8 @@ class wappalyzer(BaseModule): flags = ["active", "safe", "web-basic", "web-thorough"] meta = { "description": "Extract technologies from web responses", + "created_date": "2022-04-15", + "author": "@liquidsec", } deps_pip = ["python-Wappalyzer~=0.3.1", "aiohttp~=3.9.0b0"] # accept all events regardless of scope distance diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 92dc78db5c..0cf34ce2b1 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -9,6 +9,8 @@ class wayback(subdomain_enum): produced_events = ["URL_UNVERIFIED", "DNS_NAME"] meta = { "description": "Query archive.org's API for subdomains", + "created_date": "2022-04-01", + "author": "@pmueller", } options = {"urls": False, "garbage_threshold": 10} options_desc = { diff --git a/bbot/modules/zoomeye.py b/bbot/modules/zoomeye.py index ec921bc251..98397729a4 100644 --- a/bbot/modules/zoomeye.py +++ b/bbot/modules/zoomeye.py @@ -5,7 +5,12 @@ class zoomeye(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["affiliates", "subdomain-enum", "passive", "safe"] - meta = {"description": "Query ZoomEye's API for subdomains", "auth_required": True} + meta = { + "description": "Query ZoomEye's API for subdomains", + "created_date": "2022-08-03", + "author": "@TheTechromancer", + "auth_required": True, + } options = {"api_key": "", "max_pages": 20, "include_related": False} options_desc = { "api_key": "ZoomEye API key", diff --git a/bbot/test/test_step_1/test_command.py b/bbot/test/test_step_1/test_command.py index 8827bcdad0..42e41e4da8 100644 --- a/bbot/test/test_step_1/test_command.py +++ b/bbot/test/test_step_1/test_command.py @@ -1,3 +1,4 @@ +import time from ..bbot_fixtures import * from subprocess import CalledProcessError @@ -6,6 +7,23 @@ async def test_command(bbot_scanner, bbot_config): scan1 = bbot_scanner(config=bbot_config) + # test timeouts + command = ["sleep", "3"] + start = time.time() + with pytest.raises(asyncio.exceptions.TimeoutError): + await scan1.helpers.run(command, idle_timeout=1) + end = time.time() + elapsed = end - start + assert 0 < elapsed < 2 + + start = time.time() + with pytest.raises(asyncio.exceptions.TimeoutError): + async for line in scan1.helpers.run_live(command, idle_timeout=1): + print(line) + end = time.time() + elapsed = end - start + assert 0 < elapsed < 2 + # run assert "plumbus\n" == (await scan1.helpers.run(["echo", "plumbus"])).stdout assert b"plumbus\n" == (await scan1.helpers.run(["echo", "plumbus"], text=False)).stdout diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index c8045e5958..8f515961d8 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -469,6 +469,16 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_config, bbot_https await helpers.wordlist("/tmp/a9pseoysadf/asdkgjaosidf") test_file.unlink() + # filename truncation + super_long_filename = "/tmp/" + ("a" * 1024) + ".txt" + with pytest.raises(OSError): + with open(super_long_filename, "w") as f: + f.write("wat") + truncated_filename = helpers.truncate_filename(super_long_filename) + with open(truncated_filename, "w") as f: + f.write("wat") + truncated_filename.unlink() + # misc DNS helpers assert helpers.is_ptr("wsc-11-22-33-44-wat.evilcorp.com") == True assert helpers.is_ptr("wsc-11-22-33-wat.evilcorp.com") == False diff --git a/bbot/test/test_step_1/test_regexes.py b/bbot/test/test_step_1/test_regexes.py index 7807e6c79f..15f10d4da7 100644 --- a/bbot/test/test_step_1/test_regexes.py +++ b/bbot/test/test_step_1/test_regexes.py @@ -6,6 +6,141 @@ from bbot.core.errors import ValidationError +# NOTE: :2001:db8:: will currently cause an exception... +# e.g. raised unknown error: split_port() failed to parse netloc ":2001:db8::" + + +def test_ip_regexes(): + bad_ip = [ + "203.0..113.0", # double dot typeo + ".0.113.0", # Partial match + "203.0.113.", # Partial match + "203.0.113.0:80", # correctly formatted with :port appended + "255.255.255.256", # octet greater than 255 + "256.255.255.255", # octet greater than 255 + "2001:db8:::80", # incorrectly formatted with :port appended + "[2001:db8::]:80", # correctly formatted with :port appended + "2001:db8:g::", # includes non-hex character, + "2001.db8.80", # weird dot separated thing that might actually resolve as a DNS_NAME + "9e:3e:53:29:43:64", # MAC address, poor regex patterning will often detect these. + ] + + good_ip = [ + "0.0.0.0", + "10.0.0.0", + "10.255.255.255", + "127.0.0.0", + "127.0.0.1", + "172.16.0.0", + "172.31.255.255", + "192.168.0.0", + "192.168.255.255", + "203.0.113.0", + "203.0.113.0/24", + "255.255.255.255", + "::1", + "2001:db8::", + "2001:db8::1", + "2001:db8::1/128", + "1:1:1:1:1:1:1:1", + "1::1", + "ffff::ffff", + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + ] + + ip_address_regexes = regexes.event_type_regexes["IP_ADDRESS"] + + for ip in bad_ip: + for r in ip_address_regexes: + assert not r.match(ip), f"BAD IP ADDRESS: {ip} matched regex: {r}" + + try: + event_type, _ = get_event_type(ip) + if event_type == "OPEN_TCP_PORT": + if ip.startswith("["): + assert ip == "[2001:db8::]:80" + else: + assert ip == "203.0.113.0:80" + continue + if event_type == "DNS_NAME": + if ip.startswith("2001"): + assert ip == "2001.db8.80" + elif ip.startswith("255"): + assert ip == "255.255.255.256" + elif ip.startswith("256"): + assert ip == "256.255.255.255" + else: + assert ip == "203.0.113." + continue + pytest.fail(f"BAD IP ADDRESS: {ip} matched returned event type: {event_type}") + except ValidationError: + continue + except Exception as e: + pytest.fail(f"BAD IP ADDRESS: {ip} raised unknown error: {e}") + + for ip in good_ip: + event_type, _ = get_event_type(ip) + if not event_type == "IP_ADDRESS": + if ip.endswith("/24"): + assert ( + ip == "203.0.113.0/24" and event_type == "IP_RANGE" + ), f"Event type for IP_ADDRESS {ip} was not properly detected" + else: + assert ( + ip == "2001:db8::1/128" and event_type == "IP_RANGE" + ), f"Event type for IP_ADDRESS {ip} was not properly detected" + else: + matches = list(r.match(ip) for r in ip_address_regexes) + assert any(matches), f"Good IP ADDRESS {ip} did not match regexes" + + +def test_ip_range_regexes(): + bad_ip_ranges = [ + "203.0.113.0", + "203.0.113.0/", + "203.0.113.0/a", + "2001:db8::/", + "2001:db8::/a", + "evilcorp.com", + "[2001:db8::]:80", + ] + + good_ip_ranges = [ + "203.0.113.0/8", + "203.0.113.255/32", + "2001:db8::/128", + "2001:db8::/4", + ] + + ip_range_regexes = regexes.event_type_regexes["IP_RANGE"] + + for bad_ip_range in bad_ip_ranges: + for r in ip_range_regexes: + assert not r.match(bad_ip_range), f"BAD IP_RANGE: {bad_ip_range} matched regex: {r}" + + event_type = "" + try: + event_type, _ = get_event_type(bad_ip_range) + if event_type == "DNS_NAME": + assert bad_ip_range == "evilcorp.com" + continue + if event_type == "IP_ADDRESS": + assert bad_ip_range == "203.0.113.0" + continue + if event_type == "OPEN_TCP_PORT": + assert bad_ip_range == "[2001:db8::]:80" + continue + pytest.fail(f"BAD IP_RANGE: {bad_ip_range} matched returned event type: {event_type}") + except ValidationError: + continue + except Exception as e: + pytest.fail(f"BAD IP_RANGE: {bad_ip_range} raised unknown error: {e}: {traceback.format_exc()}") + + for good_ip_range in good_ip_ranges: + matches = list(r.match(good_ip_range) for r in ip_range_regexes) + assert any(matches), f"Good IP_RANGE {good_ip_range} did not match regexes" + + def test_dns_name_regexes(): bad_dns = [ "-evilcorp.com", # DNS names cannot begin with a dash diff --git a/bbot/test/test_step_2/module_tests/test_module_smuggler.py b/bbot/test/test_step_2/module_tests/test_module_smuggler.py index c887d684a5..a40194b826 100644 --- a/bbot/test/test_step_2/module_tests/test_module_smuggler.py +++ b/bbot/test/test_step_2/module_tests/test_module_smuggler.py @@ -4,9 +4,9 @@ ______ _ / _____) | | ( (____ ____ _ _ ____ ____| | _____ ____ - \____ \| \| | | |/ _ |/ _ | || ___ |/ ___) + \\____ \| \| | | |/ _ |/ _ | || ___ |/ ___) _____) ) | | | |_| ( (_| ( (_| | || ____| | - (______/|_|_|_|____/ \___ |\___ |\_)_____)_| + (______/|_|_|_|____/ \\___ |\\___ |\\_)_____)_| (_____(_____| @defparam v1.1 diff --git a/bbot/test/test_step_2/module_tests/test_module_viewdns.py b/bbot/test/test_step_2/module_tests/test_module_viewdns.py index 5a235b0194..d196981ba1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_viewdns.py +++ b/bbot/test/test_step_2/module_tests/test_module_viewdns.py @@ -21,188 +21,6 @@ def check(self, module_test, events): - - - - - - - - - - - - - - - diff --git a/docs/release_history.md b/docs/release_history.md index 4b5b15bac0..9de5ef6cab 100644 --- a/docs/release_history.md +++ b/docs/release_history.md @@ -1,7 +1,60 @@ +## v1.1.7 +May 15th, 2024 + +### New Modules +- https://github.com/blacklanternsecurity/bbot/pull/1037 +- https://github.com/blacklanternsecurity/bbot/pull/1122 +- https://github.com/blacklanternsecurity/bbot/pull/1176 +- https://github.com/blacklanternsecurity/bbot/pull/1164 +- https://github.com/blacklanternsecurity/bbot/pull/1169 +- https://github.com/blacklanternsecurity/bbot/pull/1175 +- https://github.com/blacklanternsecurity/bbot/pull/1209 +- https://github.com/blacklanternsecurity/bbot/pull/1335 +- https://github.com/blacklanternsecurity/bbot/pull/1380 + +### Improvements +- https://github.com/blacklanternsecurity/bbot/pull/1132 +- https://github.com/blacklanternsecurity/bbot/pull/1156 +- https://github.com/blacklanternsecurity/bbot/pull/1160 +- https://github.com/blacklanternsecurity/bbot/pull/1162 +- https://github.com/blacklanternsecurity/bbot/pull/1165 +- https://github.com/blacklanternsecurity/bbot/pull/1179 +- https://github.com/blacklanternsecurity/bbot/pull/1182 +- https://github.com/blacklanternsecurity/bbot/pull/1185 +- https://github.com/blacklanternsecurity/bbot/pull/1186 +- https://github.com/blacklanternsecurity/bbot/pull/1197 +- https://github.com/blacklanternsecurity/bbot/pull/1198 +- https://github.com/blacklanternsecurity/bbot/pull/1205 +- https://github.com/blacklanternsecurity/bbot/pull/1217 +- https://github.com/blacklanternsecurity/bbot/pull/1233 +- https://github.com/blacklanternsecurity/bbot/pull/1283 +- https://github.com/blacklanternsecurity/bbot/pull/1288 +- https://github.com/blacklanternsecurity/bbot/pull/1296 +- https://github.com/blacklanternsecurity/bbot/pull/1306 +- https://github.com/blacklanternsecurity/bbot/pull/1313 +- https://github.com/blacklanternsecurity/bbot/pull/1349 +- https://github.com/blacklanternsecurity/bbot/pull/1343 + +### Bugfixes +- https://github.com/blacklanternsecurity/bbot/pull/1136 +- https://github.com/blacklanternsecurity/bbot/pull/1140 +- https://github.com/blacklanternsecurity/bbot/pull/1152 +- https://github.com/blacklanternsecurity/bbot/pull/1154 +- https://github.com/blacklanternsecurity/bbot/pull/1181 +- https://github.com/blacklanternsecurity/bbot/pull/1247 +- https://github.com/blacklanternsecurity/bbot/pull/1249 +- https://github.com/blacklanternsecurity/bbot/pull/1273 +- https://github.com/blacklanternsecurity/bbot/pull/1277 +- https://github.com/blacklanternsecurity/bbot/pull/1287 +- https://github.com/blacklanternsecurity/bbot/pull/1298 +- https://github.com/blacklanternsecurity/bbot/pull/1308 +- https://github.com/blacklanternsecurity/bbot/pull/1336 +- https://github.com/blacklanternsecurity/bbot/pull/1348 + ## v1.1.6 February 21, 2024 -## Improvements +### Improvements - https://github.com/blacklanternsecurity/bbot/pull/1001 - https://github.com/blacklanternsecurity/bbot/pull/1006 - https://github.com/blacklanternsecurity/bbot/pull/1010 @@ -22,7 +75,7 @@ February 21, 2024 - https://github.com/blacklanternsecurity/bbot/pull/1101 - https://github.com/blacklanternsecurity/bbot/pull/1103 -## Bigfixes +### Bigfixes - https://github.com/blacklanternsecurity/bbot/pull/1005 - https://github.com/blacklanternsecurity/bbot/pull/1022 - https://github.com/blacklanternsecurity/bbot/pull/1030 @@ -37,7 +90,7 @@ February 21, 2024 - https://github.com/blacklanternsecurity/bbot/pull/1094 - https://github.com/blacklanternsecurity/bbot/pull/1098 -## New Modules +### New Modules - https://github.com/blacklanternsecurity/bbot/pull/1072 - https://github.com/blacklanternsecurity/bbot/pull/1091 diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 3a02bcc9aa..d54fa6d509 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -236,13 +236,14 @@ Many modules accept their own configuration options. These options have the abil | modules.filedownload.max_filesize | str | Cancel download if filesize is greater than this size | 10MB | | modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | | modules.gitlab.api_key | str | Gitlab access token | | -| modules.gowitness.output_path | str | where to save screenshots | | -| modules.gowitness.resolution_x | int | screenshot resolution x | 1440 | -| modules.gowitness.resolution_y | int | screenshot resolution y | 900 | +| modules.gowitness.idle_timeout | int | Skip the current gowitness batch if it stalls for longer than this many seconds | 1800 | +| modules.gowitness.output_path | str | Where to save screenshots | | +| modules.gowitness.resolution_x | int | Screenshot resolution x | 1440 | +| modules.gowitness.resolution_y | int | Screenshot resolution y | 900 | | modules.gowitness.social | bool | Whether to screenshot social media webpages | True | -| modules.gowitness.threads | int | threads used to run | 4 | -| modules.gowitness.timeout | int | preflight check timeout | 10 | -| modules.gowitness.version | str | gowitness version | 2.4.2 | +| modules.gowitness.threads | int | How many gowitness threads to spawn (default is number of CPUs x 2) | 0 | +| modules.gowitness.timeout | int | Preflight check timeout | 10 | +| modules.gowitness.version | str | Gowitness version | 2.4.2 | | modules.httpx.in_scope_only | bool | Only visit web resources that are in scope. | True | | modules.httpx.max_response_size | int | Max response size in bytes | 5242880 | | modules.httpx.probe_all_ips | bool | Probe all the ips associated with same host | False | diff --git a/poetry.lock b/poetry.lock index 1f6d2500e5..276248431d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,13 +46,13 @@ resolvelib = ">=0.5.3,<1.1.0" [[package]] name = "ansible-runner" -version = "2.3.6" +version = "2.4.0" description = "\"Consistent Ansible Python API and CLI with container and process isolation runtime capabilities\"" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "ansible-runner-2.3.6.tar.gz", hash = "sha256:b2174a12dcad2dc2f342ea82876898f568a0b66c53568600bf80577158fcba1c"}, - {file = "ansible_runner-2.3.6-py3-none-any.whl", hash = "sha256:4f153d9c3000a61b82d7253ca292849e3ad2c5d68dfff4377a6b98c4e6ff6c3e"}, + {file = "ansible-runner-2.4.0.tar.gz", hash = "sha256:82d02b2548830f37a53517b65c823c4af371069406c7d213b5c9041d45e0c5b6"}, + {file = "ansible_runner-2.4.0-py3-none-any.whl", hash = "sha256:a3f592ae4cdfa62a72ad15de60da9c8210f376d67f495c4a78d4cf1dc7ccdf89"}, ] [package.dependencies] @@ -61,7 +61,6 @@ packaging = "*" pexpect = ">=4.5" python-daemon = "*" pyyaml = "*" -six = "*" [[package]] name = "antlr4-python3-runtime" @@ -870,165 +869,153 @@ files = [ [[package]] name = "lxml" -version = "5.2.1" +version = "5.2.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1f7785f4f789fdb522729ae465adcaa099e2a3441519df750ebdccc481d961a1"}, - {file = "lxml-5.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cc6ee342fb7fa2471bd9b6d6fdfc78925a697bf5c2bcd0a302e98b0d35bfad3"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:794f04eec78f1d0e35d9e0c36cbbb22e42d370dda1609fb03bcd7aeb458c6377"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817d420c60a5183953c783b0547d9eb43b7b344a2c46f69513d5952a78cddf3"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2213afee476546a7f37c7a9b4ad4d74b1e112a6fafffc9185d6d21f043128c81"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b070bbe8d3f0f6147689bed981d19bbb33070225373338df755a46893528104a"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e02c5175f63effbd7c5e590399c118d5db6183bbfe8e0d118bdb5c2d1b48d937"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3dc773b2861b37b41a6136e0b72a1a44689a9c4c101e0cddb6b854016acc0aa8"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:d7520db34088c96cc0e0a3ad51a4fd5b401f279ee112aa2b7f8f976d8582606d"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:bcbf4af004f98793a95355980764b3d80d47117678118a44a80b721c9913436a"}, - {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2b44bec7adf3e9305ce6cbfa47a4395667e744097faed97abb4728748ba7d47"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1c5bb205e9212d0ebddf946bc07e73fa245c864a5f90f341d11ce7b0b854475d"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2c9d147f754b1b0e723e6afb7ba1566ecb162fe4ea657f53d2139bbf894d050a"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3545039fa4779be2df51d6395e91a810f57122290864918b172d5dc7ca5bb433"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a91481dbcddf1736c98a80b122afa0f7296eeb80b72344d7f45dc9f781551f56"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2ddfe41ddc81f29a4c44c8ce239eda5ade4e7fc305fb7311759dd6229a080052"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a7baf9ffc238e4bf401299f50e971a45bfcc10a785522541a6e3179c83eabf0a"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31e9a882013c2f6bd2f2c974241bf4ba68c85eba943648ce88936d23209a2e01"}, - {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0a15438253b34e6362b2dc41475e7f80de76320f335e70c5528b7148cac253a1"}, - {file = "lxml-5.2.1-cp310-cp310-win32.whl", hash = "sha256:6992030d43b916407c9aa52e9673612ff39a575523c5f4cf72cdef75365709a5"}, - {file = "lxml-5.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:da052e7962ea2d5e5ef5bc0355d55007407087392cf465b7ad84ce5f3e25fe0f"}, - {file = "lxml-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:70ac664a48aa64e5e635ae5566f5227f2ab7f66a3990d67566d9907edcbbf867"}, - {file = "lxml-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1ae67b4e737cddc96c99461d2f75d218bdf7a0c3d3ad5604d1f5e7464a2f9ffe"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f18a5a84e16886898e51ab4b1d43acb3083c39b14c8caeb3589aabff0ee0b270"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6f2c8372b98208ce609c9e1d707f6918cc118fea4e2c754c9f0812c04ca116d"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:394ed3924d7a01b5bd9a0d9d946136e1c2f7b3dc337196d99e61740ed4bc6fe1"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d077bc40a1fe984e1a9931e801e42959a1e6598edc8a3223b061d30fbd26bbc"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:764b521b75701f60683500d8621841bec41a65eb739b8466000c6fdbc256c240"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3a6b45da02336895da82b9d472cd274b22dc27a5cea1d4b793874eead23dd14f"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:5ea7b6766ac2dfe4bcac8b8595107665a18ef01f8c8343f00710b85096d1b53a"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:e196a4ff48310ba62e53a8e0f97ca2bca83cdd2fe2934d8b5cb0df0a841b193a"}, - {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:200e63525948e325d6a13a76ba2911f927ad399ef64f57898cf7c74e69b71095"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dae0ed02f6b075426accbf6b2863c3d0a7eacc1b41fb40f2251d931e50188dad"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:ab31a88a651039a07a3ae327d68ebdd8bc589b16938c09ef3f32a4b809dc96ef"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:df2e6f546c4df14bc81f9498bbc007fbb87669f1bb707c6138878c46b06f6510"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5dd1537e7cc06efd81371f5d1a992bd5ab156b2b4f88834ca852de4a8ea523fa"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9b9ec9c9978b708d488bec36b9e4c94d88fd12ccac3e62134a9d17ddba910ea9"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8e77c69d5892cb5ba71703c4057091e31ccf534bd7f129307a4d084d90d014b8"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d5c70e04aac1eda5c829a26d1f75c6e5286c74743133d9f742cda8e53b9c2f"}, - {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c94e75445b00319c1fad60f3c98b09cd63fe1134a8a953dcd48989ef42318534"}, - {file = "lxml-5.2.1-cp311-cp311-win32.whl", hash = "sha256:4951e4f7a5680a2db62f7f4ab2f84617674d36d2d76a729b9a8be4b59b3659be"}, - {file = "lxml-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:5c670c0406bdc845b474b680b9a5456c561c65cf366f8db5a60154088c92d102"}, - {file = "lxml-5.2.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:abc25c3cab9ec7fcd299b9bcb3b8d4a1231877e425c650fa1c7576c5107ab851"}, - {file = "lxml-5.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6935bbf153f9a965f1e07c2649c0849d29832487c52bb4a5c5066031d8b44fd5"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d793bebb202a6000390a5390078e945bbb49855c29c7e4d56a85901326c3b5d9"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd5562927cdef7c4f5550374acbc117fd4ecc05b5007bdfa57cc5355864e0a4"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e7259016bc4345a31af861fdce942b77c99049d6c2107ca07dc2bba2435c1d9"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:530e7c04f72002d2f334d5257c8a51bf409db0316feee7c87e4385043be136af"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59689a75ba8d7ffca577aefd017d08d659d86ad4585ccc73e43edbfc7476781a"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f9737bf36262046213a28e789cc82d82c6ef19c85a0cf05e75c670a33342ac2c"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:3a74c4f27167cb95c1d4af1c0b59e88b7f3e0182138db2501c353555f7ec57f4"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:68a2610dbe138fa8c5826b3f6d98a7cfc29707b850ddcc3e21910a6fe51f6ca0"}, - {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f0a1bc63a465b6d72569a9bba9f2ef0334c4e03958e043da1920299100bc7c08"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c2d35a1d047efd68027817b32ab1586c1169e60ca02c65d428ae815b593e65d4"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:79bd05260359170f78b181b59ce871673ed01ba048deef4bf49a36ab3e72e80b"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:865bad62df277c04beed9478fe665b9ef63eb28fe026d5dedcb89b537d2e2ea6"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:44f6c7caff88d988db017b9b0e4ab04934f11e3e72d478031efc7edcac6c622f"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:71e97313406ccf55d32cc98a533ee05c61e15d11b99215b237346171c179c0b0"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:057cdc6b86ab732cf361f8b4d8af87cf195a1f6dc5b0ff3de2dced242c2015e0"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f3bbbc998d42f8e561f347e798b85513ba4da324c2b3f9b7969e9c45b10f6169"}, - {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491755202eb21a5e350dae00c6d9a17247769c64dcf62d8c788b5c135e179dc4"}, - {file = "lxml-5.2.1-cp312-cp312-win32.whl", hash = "sha256:8de8f9d6caa7f25b204fc861718815d41cbcf27ee8f028c89c882a0cf4ae4134"}, - {file = "lxml-5.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:f2a9efc53d5b714b8df2b4b3e992accf8ce5bbdfe544d74d5c6766c9e1146a3a"}, - {file = "lxml-5.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:70a9768e1b9d79edca17890175ba915654ee1725975d69ab64813dd785a2bd5c"}, - {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c38d7b9a690b090de999835f0443d8aa93ce5f2064035dfc48f27f02b4afc3d0"}, - {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5670fb70a828663cc37552a2a85bf2ac38475572b0e9b91283dc09efb52c41d1"}, - {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:958244ad566c3ffc385f47dddde4145088a0ab893504b54b52c041987a8c1863"}, - {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6241d4eee5f89453307c2f2bfa03b50362052ca0af1efecf9fef9a41a22bb4f"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2a66bf12fbd4666dd023b6f51223aed3d9f3b40fef06ce404cb75bafd3d89536"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:9123716666e25b7b71c4e1789ec829ed18663152008b58544d95b008ed9e21e9"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:0c3f67e2aeda739d1cc0b1102c9a9129f7dc83901226cc24dd72ba275ced4218"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d5792e9b3fb8d16a19f46aa8208987cfeafe082363ee2745ea8b643d9cc5b45"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:88e22fc0a6684337d25c994381ed8a1580a6f5ebebd5ad41f89f663ff4ec2885"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:21c2e6b09565ba5b45ae161b438e033a86ad1736b8c838c766146eff8ceffff9"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:afbbdb120d1e78d2ba8064a68058001b871154cc57787031b645c9142b937a62"}, - {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:627402ad8dea044dde2eccde4370560a2b750ef894c9578e1d4f8ffd54000461"}, - {file = "lxml-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:e89580a581bf478d8dcb97d9cd011d567768e8bc4095f8557b21c4d4c5fea7d0"}, - {file = "lxml-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:59565f10607c244bc4c05c0c5fa0c190c990996e0c719d05deec7030c2aa8289"}, - {file = "lxml-5.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:857500f88b17a6479202ff5fe5f580fc3404922cd02ab3716197adf1ef628029"}, - {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56c22432809085b3f3ae04e6e7bdd36883d7258fcd90e53ba7b2e463efc7a6af"}, - {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a55ee573116ba208932e2d1a037cc4b10d2c1cb264ced2184d00b18ce585b2c0"}, - {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:6cf58416653c5901e12624e4013708b6e11142956e7f35e7a83f1ab02f3fe456"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:64c2baa7774bc22dd4474248ba16fe1a7f611c13ac6123408694d4cc93d66dbd"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:74b28c6334cca4dd704e8004cba1955af0b778cf449142e581e404bd211fb619"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7221d49259aa1e5a8f00d3d28b1e0b76031655ca74bb287123ef56c3db92f213"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3dbe858ee582cbb2c6294dc85f55b5f19c918c2597855e950f34b660f1a5ede6"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:04ab5415bf6c86e0518d57240a96c4d1fcfc3cb370bb2ac2a732b67f579e5a04"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:6ab833e4735a7e5533711a6ea2df26459b96f9eec36d23f74cafe03631647c41"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f443cdef978430887ed55112b491f670bba6462cea7a7742ff8f14b7abb98d75"}, - {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9e2addd2d1866fe112bc6f80117bcc6bc25191c5ed1bfbcf9f1386a884252ae8"}, - {file = "lxml-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:f51969bac61441fd31f028d7b3b45962f3ecebf691a510495e5d2cd8c8092dbd"}, - {file = "lxml-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b0b58fbfa1bf7367dde8a557994e3b1637294be6cf2169810375caf8571a085c"}, - {file = "lxml-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:804f74efe22b6a227306dd890eecc4f8c59ff25ca35f1f14e7482bbce96ef10b"}, - {file = "lxml-5.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08802f0c56ed150cc6885ae0788a321b73505d2263ee56dad84d200cab11c07a"}, - {file = "lxml-5.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f8c09ed18ecb4ebf23e02b8e7a22a05d6411911e6fabef3a36e4f371f4f2585"}, - {file = "lxml-5.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3d30321949861404323c50aebeb1943461a67cd51d4200ab02babc58bd06a86"}, - {file = "lxml-5.2.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b560e3aa4b1d49e0e6c847d72665384db35b2f5d45f8e6a5c0072e0283430533"}, - {file = "lxml-5.2.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:058a1308914f20784c9f4674036527e7c04f7be6fb60f5d61353545aa7fcb739"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:adfb84ca6b87e06bc6b146dc7da7623395db1e31621c4785ad0658c5028b37d7"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:417d14450f06d51f363e41cace6488519038f940676ce9664b34ebf5653433a5"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a2dfe7e2473f9b59496247aad6e23b405ddf2e12ef0765677b0081c02d6c2c0b"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bf2e2458345d9bffb0d9ec16557d8858c9c88d2d11fed53998512504cd9df49b"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:58278b29cb89f3e43ff3e0c756abbd1518f3ee6adad9e35b51fb101c1c1daaec"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:64641a6068a16201366476731301441ce93457eb8452056f570133a6ceb15fca"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:78bfa756eab503673991bdcf464917ef7845a964903d3302c5f68417ecdc948c"}, - {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:11a04306fcba10cd9637e669fd73aa274c1c09ca64af79c041aa820ea992b637"}, - {file = "lxml-5.2.1-cp38-cp38-win32.whl", hash = "sha256:66bc5eb8a323ed9894f8fa0ee6cb3e3fb2403d99aee635078fd19a8bc7a5a5da"}, - {file = "lxml-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:9676bfc686fa6a3fa10cd4ae6b76cae8be26eb5ec6811d2a325636c460da1806"}, - {file = "lxml-5.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cf22b41fdae514ee2f1691b6c3cdeae666d8b7fa9434de445f12bbeee0cf48dd"}, - {file = "lxml-5.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec42088248c596dbd61d4ae8a5b004f97a4d91a9fd286f632e42e60b706718d7"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd53553ddad4a9c2f1f022756ae64abe16da1feb497edf4d9f87f99ec7cf86bd"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feaa45c0eae424d3e90d78823f3828e7dc42a42f21ed420db98da2c4ecf0a2cb"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddc678fb4c7e30cf830a2b5a8d869538bc55b28d6c68544d09c7d0d8f17694dc"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:853e074d4931dbcba7480d4dcab23d5c56bd9607f92825ab80ee2bd916edea53"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4691d60512798304acb9207987e7b2b7c44627ea88b9d77489bbe3e6cc3bd4"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:beb72935a941965c52990f3a32d7f07ce869fe21c6af8b34bf6a277b33a345d3"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:6588c459c5627fefa30139be4d2e28a2c2a1d0d1c265aad2ba1935a7863a4913"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:588008b8497667f1ddca7c99f2f85ce8511f8f7871b4a06ceede68ab62dff64b"}, - {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6787b643356111dfd4032b5bffe26d2f8331556ecb79e15dacb9275da02866e"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7c17b64b0a6ef4e5affae6a3724010a7a66bda48a62cfe0674dabd46642e8b54"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:27aa20d45c2e0b8cd05da6d4759649170e8dfc4f4e5ef33a34d06f2d79075d57"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d4f2cc7060dc3646632d7f15fe68e2fa98f58e35dd5666cd525f3b35d3fed7f8"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff46d772d5f6f73564979cd77a4fffe55c916a05f3cb70e7c9c0590059fb29ef"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96323338e6c14e958d775700ec8a88346014a85e5de73ac7967db0367582049b"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:52421b41ac99e9d91934e4d0d0fe7da9f02bfa7536bb4431b4c05c906c8c6919"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7a7efd5b6d3e30d81ec68ab8a88252d7c7c6f13aaa875009fe3097eb4e30b84c"}, - {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ed777c1e8c99b63037b91f9d73a6aad20fd035d77ac84afcc205225f8f41188"}, - {file = "lxml-5.2.1-cp39-cp39-win32.whl", hash = "sha256:644df54d729ef810dcd0f7732e50e5ad1bd0a135278ed8d6bcb06f33b6b6f708"}, - {file = "lxml-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:9ca66b8e90daca431b7ca1408cae085d025326570e57749695d6a01454790e95"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9b0ff53900566bc6325ecde9181d89afadc59c5ffa39bddf084aaedfe3b06a11"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd6037392f2d57793ab98d9e26798f44b8b4da2f2464388588f48ac52c489ea1"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9c07e7a45bb64e21df4b6aa623cb8ba214dfb47d2027d90eac197329bb5e94"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3249cc2989d9090eeac5467e50e9ec2d40704fea9ab72f36b034ea34ee65ca98"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f42038016852ae51b4088b2862126535cc4fc85802bfe30dea3500fdfaf1864e"}, - {file = "lxml-5.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:533658f8fbf056b70e434dff7e7aa611bcacb33e01f75de7f821810e48d1bb66"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:622020d4521e22fb371e15f580d153134bfb68d6a429d1342a25f051ec72df1c"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efa7b51824aa0ee957ccd5a741c73e6851de55f40d807f08069eb4c5a26b2baa"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c6ad0fbf105f6bcc9300c00010a2ffa44ea6f555df1a2ad95c88f5656104817"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e233db59c8f76630c512ab4a4daf5a5986da5c3d5b44b8e9fc742f2a24dbd460"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a014510830df1475176466b6087fc0c08b47a36714823e58d8b8d7709132a96"}, - {file = "lxml-5.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d38c8f50ecf57f0463399569aa388b232cf1a2ffb8f0a9a5412d0db57e054860"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5aea8212fb823e006b995c4dda533edcf98a893d941f173f6c9506126188860d"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff097ae562e637409b429a7ac958a20aab237a0378c42dabaa1e3abf2f896e5f"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f5d65c39f16717a47c36c756af0fb36144069c4718824b7533f803ecdf91138"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3d0c3dd24bb4605439bf91068598d00c6370684f8de4a67c2992683f6c309d6b"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e32be23d538753a8adb6c85bd539f5fd3b15cb987404327c569dfc5fd8366e85"}, - {file = "lxml-5.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cc518cea79fd1e2f6c90baafa28906d4309d24f3a63e801d855e7424c5b34144"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a0af35bd8ebf84888373630f73f24e86bf016642fb8576fba49d3d6b560b7cbc"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8aca2e3a72f37bfc7b14ba96d4056244001ddcc18382bd0daa087fd2e68a354"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ca1e8188b26a819387b29c3895c47a5e618708fe6f787f3b1a471de2c4a94d9"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c8ba129e6d3b0136a0f50345b2cb3db53f6bda5dd8c7f5d83fbccba97fb5dcb5"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e998e304036198b4f6914e6a1e2b6f925208a20e2042563d9734881150c6c246"}, - {file = "lxml-5.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d3be9b2076112e51b323bdf6d5a7f8a798de55fb8d95fcb64bd179460cdc0704"}, - {file = "lxml-5.2.1.tar.gz", hash = "sha256:3f7765e69bbce0906a7c74d5fe46d2c7a7596147318dbc08e4a2431f3060e306"}, + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632"}, + {file = "lxml-5.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f"}, + {file = "lxml-5.2.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393"}, + {file = "lxml-5.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526"}, + {file = "lxml-5.2.2-cp310-cp310-win32.whl", hash = "sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30"}, + {file = "lxml-5.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545"}, + {file = "lxml-5.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d"}, + {file = "lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa"}, + {file = "lxml-5.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b"}, + {file = "lxml-5.2.2-cp311-cp311-win32.whl", hash = "sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438"}, + {file = "lxml-5.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391"}, + {file = "lxml-5.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466"}, + {file = "lxml-5.2.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c"}, + {file = "lxml-5.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836"}, + {file = "lxml-5.2.2-cp312-cp312-win32.whl", hash = "sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a"}, + {file = "lxml-5.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48"}, + {file = "lxml-5.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce"}, + {file = "lxml-5.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9"}, + {file = "lxml-5.2.2-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264"}, + {file = "lxml-5.2.2-cp36-cp36m-win32.whl", hash = "sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3"}, + {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, + {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, + {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, + {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, + {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, + {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, + {file = "lxml-5.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5"}, + {file = "lxml-5.2.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b"}, + {file = "lxml-5.2.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1"}, + {file = "lxml-5.2.2-cp38-cp38-win32.whl", hash = "sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30"}, + {file = "lxml-5.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30"}, + {file = "lxml-5.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a"}, + {file = "lxml-5.2.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472"}, + {file = "lxml-5.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9"}, + {file = "lxml-5.2.2-cp39-cp39-win32.whl", hash = "sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf"}, + {file = "lxml-5.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2"}, + {file = "lxml-5.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8"}, + {file = "lxml-5.2.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db"}, + {file = "lxml-5.2.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a"}, + {file = "lxml-5.2.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324"}, + {file = "lxml-5.2.2.tar.gz", hash = "sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87"}, ] [package.extras] @@ -1149,34 +1136,34 @@ files = [ [[package]] name = "mkdocs" -version = "1.5.3" +version = "1.6.0" description = "Project documentation with Markdown." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, - {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, + {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, + {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, ] [package.dependencies] click = ">=7.0" colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" -importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} jinja2 = ">=2.11.1" -markdown = ">=3.2.1" +markdown = ">=3.3.6" markupsafe = ">=2.0.1" mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" packaging = ">=20.5" pathspec = ">=0.11.1" -platformdirs = ">=2.2.0" pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" watchdog = ">=2.0" [package.extras] i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] [[package]] name = "mkdocs-autorefs" @@ -1210,15 +1197,32 @@ beautifulsoup4 = ">=4.6.3" libsass = ">=0.15" mkdocs = ">=1.1" +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + [[package]] name = "mkdocs-material" -version = "9.5.18" +version = "9.5.25" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.18-py3-none-any.whl", hash = "sha256:1e0e27fc9fe239f9064318acf548771a4629d5fd5dfd45444fd80a953fe21eb4"}, - {file = "mkdocs_material-9.5.18.tar.gz", hash = "sha256:a43f470947053fa2405c33995f282d24992c752a50114f23f30da9d8d0c57e62"}, + {file = "mkdocs_material-9.5.25-py3-none-any.whl", hash = "sha256:68fdab047a0b9bfbefe79ce267e8a7daaf5128bcf7867065fcd201ee335fece1"}, + {file = "mkdocs_material-9.5.25.tar.gz", hash = "sha256:d0662561efb725b712207e0ee01f035ca15633f29a64628e24f01ec99d7078f4"}, ] [package.dependencies] @@ -1226,7 +1230,7 @@ babel = ">=2.10,<3.0" colorama = ">=0.4,<1.0" jinja2 = ">=3.0,<4.0" markdown = ">=3.2,<4.0" -mkdocs = ">=1.5.3,<1.6.0" +mkdocs = ">=1.6,<2.0" mkdocs-material-extensions = ">=1.3,<2.0" paginate = ">=0.5,<1.0" pygments = ">=2.16,<3.0" @@ -1252,13 +1256,13 @@ files = [ [[package]] name = "mkdocstrings" -version = "0.24.3" +version = "0.25.1" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocstrings-0.24.3-py3-none-any.whl", hash = "sha256:5c9cf2a32958cd161d5428699b79c8b0988856b0d4a8c5baf8395fc1bf4087c3"}, - {file = "mkdocstrings-0.24.3.tar.gz", hash = "sha256:f327b234eb8d2551a306735436e157d0a22d45f79963c60a8b585d5f7a94c1d2"}, + {file = "mkdocstrings-0.25.1-py3-none-any.whl", hash = "sha256:da01fcc2670ad61888e8fe5b60afe9fee5781017d67431996832d63e887c2e51"}, + {file = "mkdocstrings-0.25.1.tar.gz", hash = "sha256:c3a2515f31577f311a9ee58d089e4c51fc6046dbd9e9b4c3de4c3194667fe9bf"}, ] [package.dependencies] @@ -1410,13 +1414,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest- [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -1444,13 +1448,13 @@ plugin = ["poetry (>=1.2.0,<2.0.0)"] [[package]] name = "pre-commit" -version = "3.7.0" +version = "3.7.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.7.0-py2.py3-none-any.whl", hash = "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab"}, - {file = "pre_commit-3.7.0.tar.gz", hash = "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060"}, + {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, + {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, ] [package.dependencies] @@ -1564,18 +1568,18 @@ files = [ [[package]] name = "pydantic" -version = "2.7.0" +version = "2.7.1" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, - {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, + {file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"}, + {file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.1" +pydantic-core = "2.18.2" typing-extensions = ">=4.6.1" [package.extras] @@ -1583,90 +1587,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.1" +version = "2.18.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, - {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, - {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, - {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, - {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, - {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, - {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, - {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, - {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, - {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, - {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, - {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, + {file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"}, + {file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"}, + {file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"}, + {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"}, + {file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"}, + {file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"}, + {file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"}, + {file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"}, + {file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"}, + {file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"}, + {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"}, + {file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"}, + {file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"}, + {file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"}, + {file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"}, + {file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"}, + {file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"}, + {file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"}, + {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"}, + {file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"}, + {file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"}, + {file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"}, + {file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"}, + {file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"}, + {file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"}, + {file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"}, + {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"}, + {file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"}, + {file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"}, + {file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"}, + {file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"}, + {file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"}, + {file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"}, + {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"}, + {file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"}, + {file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"}, + {file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"}, + {file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"}, + {file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"}, + {file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"}, ] [package.dependencies] @@ -1735,13 +1739,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pytest" -version = "8.1.1" +version = "8.2.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, - {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, + {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, + {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, ] [package.dependencies] @@ -1749,21 +1753,21 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.4,<2.0" +pluggy = ">=1.5,<2.0" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.23.6" +version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, - {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, + {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, + {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, ] [package.dependencies] @@ -2520,4 +2524,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "f65140794e365b3fe93ff86e026591e528ab20ebcd278d4562a6cabe90ccac80" +content-hash = "e4f9f370977b072794f49e3b9ac6fb383eb633b839d62693c02ef05494141b93" diff --git a/pyproject.toml b/pyproject.toml index 8d07dd3e5f..b66fcfb94a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,7 +70,7 @@ mkdocs = "^1.5.2" mkdocs-extra-sass-plugin = "^0.1.0" mkdocs-material = "^9.2.5" mkdocs-material-extensions = "^1.1.1" -mkdocstrings = ">=0.22,<0.25" +mkdocstrings = ">=0.22,<0.26" mkdocstrings-python = "^1.6.0" livereload = "^2.6.3" @@ -91,7 +91,7 @@ extend-exclude = "(test_step_1/test_manager_*)" [tool.poetry-dynamic-versioning] enable = true metadata = false -format-jinja = 'v1.1.7{% if branch == "dev" %}.{{ distance }}rc{% endif %}' +format-jinja = 'v1.1.8{% if branch == "dev" %}.{{ distance }}rc{% endif %}' [tool.poetry-dynamic-versioning.substitution] files = ["*/__init__.py"]