From 3369b3bc592a5eec237df5e90c6df26aacccb4d8 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:26:28 +0200 Subject: [PATCH 01/82] Feature: improve settings and environment logic and phase out redundant environment keys (#3384) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Co-authored-by: ammar92 --- boefjes/.ci/docker-compose.yml | 14 ++++-- .../.ci/wiremock/mappings/organisations.json | 15 ------- boefjes/boefjes/api.py | 3 +- boefjes/boefjes/dependencies/plugins.py | 23 ++++------ boefjes/boefjes/job_handler.py | 45 ++++++++++++------- boefjes/boefjes/katalogus/plugins.py | 2 - ...fc302b852_remove_environment_keys_field.py | 37 +++++++++++++++ ...de6eb7824b_introduce_boefjeconfig_model.py | 6 +-- boefjes/boefjes/models.py | 1 - .../plugins/kat_binaryedge/boefje.json | 3 -- .../boefjes/plugins/kat_censys/boefje.json | 4 -- .../plugins/kat_cve_finding_types/boefje.json | 3 -- boefjes/boefjes/plugins/kat_dns/boefje.json | 4 -- .../plugins/kat_external_db/boefje.json | 7 --- .../boefjes/plugins/kat_leakix/boefje.json | 3 -- .../boefjes/plugins/kat_log4shell/boefje.json | 3 -- .../boefjes/plugins/kat_masscan/boefje.json | 4 -- .../plugins/kat_maxmind_geoip/boefje.json | 6 +-- .../plugins/kat_nmap_ip_range/boefje.json | 6 --- .../plugins/kat_nmap_ports/boefje.json | 3 -- .../boefjes/plugins/kat_nmap_tcp/boefje.json | 3 -- .../boefjes/plugins/kat_nmap_udp/boefje.json | 3 -- .../boefjes/plugins/kat_shodan/boefje.json | 3 -- .../kat_testssl_sh_ciphers/boefje.json | 5 +-- .../plugins/kat_webpage_analysis/boefje.json | 3 -- .../boefjes/plugins/kat_wpscan/boefje.json | 3 -- boefjes/boefjes/sql/db_models.py | 2 - boefjes/boefjes/sql/plugin_storage.py | 4 -- boefjes/boefjes/storage/interfaces.py | 7 +-- boefjes/pyproject.toml | 1 + boefjes/tests/conftest.py | 38 ++++++++++++++-- boefjes/tests/integration/test_bench.py | 4 +- .../tests/integration/test_get_environment.py | 22 +++++++++ .../test_migration_add_schema_field.py | 6 +-- .../integration/test_sql_repositories.py | 2 - .../boefjes_test_dir/kat_test/boefje.json | 1 - .../kat_test/kat_test_2/boefje.json | 1 - .../kat_test/kat_test_4/boefje.json | 1 - .../tests/katalogus/test_plugin_service.py | 30 +++---------- .../tests/modules/dummy_boefje/boefje.json | 3 +- .../dummy_boefje_environment/boefje.json | 3 +- .../boefje.json | 3 +- .../boefje.json | 3 +- .../dummy_boefje_missing_run/boefje.json | 3 +- .../boefje.json | 3 +- .../dummy_oci_boefje_no_main/boefje.json | 1 - boefjes/tests/test_tasks.py | 6 +-- .../source/developer_documentation/boefjes.md | 4 +- .../development_tutorial/creating_a_boefje.md | 25 +++++++++-- docs/source/introduction/makeyourown.rst | 43 ++++++++++++------ mula/scheduler/models/plugin.py | 1 - rocky/katalogus/client.py | 1 - rocky/tests/conftest.py | 1 - rocky/tests/stubs/katalogus_boefjes.json | 9 ---- rocky/tests/stubs/katalogus_normalizers.json | 5 --- rocky/tests/test_indemnification.py | 1 - 56 files changed, 223 insertions(+), 223 deletions(-) delete mode 100644 boefjes/.ci/wiremock/mappings/organisations.json create mode 100644 boefjes/boefjes/migrations/versions/870fc302b852_remove_environment_keys_field.py create mode 100644 boefjes/tests/integration/test_get_environment.py diff --git a/boefjes/.ci/docker-compose.yml b/boefjes/.ci/docker-compose.yml index 407d1678336..f3dc4ecc244 100644 --- a/boefjes/.ci/docker-compose.yml +++ b/boefjes/.ci/docker-compose.yml @@ -8,6 +8,7 @@ services: command: sh -c 'python -m pytest -v tests/integration' depends_on: - ci_katalogus-db + - ci_katalogus env_file: - .ci/.env.test volumes: @@ -103,8 +104,15 @@ services: hard: 262144 ci_katalogus: - image: "docker.io/wiremock/wiremock:2.34.0" - volumes: - - .ci/wiremock:/home/wiremock + build: + context: .. + dockerfile: boefjes/Dockerfile + args: + - ENVIRONMENT=dev + command: uvicorn boefjes.katalogus.root:app --host 0.0.0.0 --port 8080 + depends_on: + - ci_katalogus-db env_file: - .ci/.env.test + volumes: + - .:/app/boefjes diff --git a/boefjes/.ci/wiremock/mappings/organisations.json b/boefjes/.ci/wiremock/mappings/organisations.json deleted file mode 100644 index 13124e6222f..00000000000 --- a/boefjes/.ci/wiremock/mappings/organisations.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "request": { - "method": "GET", - "url": "/v1/organisations" - }, - "response": { - "status": 200, - "jsonBody": { - "_dev": { - "id": "_dev", - "name": "Development Organisation" - } - } - } -} diff --git a/boefjes/boefjes/api.py b/boefjes/boefjes/api.py index 72ac9ccc96c..22542898dfd 100644 --- a/boefjes/boefjes/api.py +++ b/boefjes/boefjes/api.py @@ -151,8 +151,7 @@ def get_task(task_id, scheduler_client): def create_boefje_meta(task, local_repository): boefje = task.data.boefje boefje_resource = local_repository.by_id(boefje.id) - env_keys = boefje_resource.environment_keys - environment = get_environment_settings(task.data, env_keys) if env_keys else {} + environment = get_environment_settings(task.data, boefje_resource.schema) organization = task.data.organization input_ooi = task.data.input_ooi diff --git a/boefjes/boefjes/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py index ccb3187c0e2..080ff6d7da7 100644 --- a/boefjes/boefjes/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -98,7 +98,7 @@ def clone_settings_to_organisation(self, from_organisation: str, to_organisation self.set_enabled_by_id(plugin_id, to_organisation, enabled=True) def upsert_settings(self, settings: dict, organisation_id: str, plugin_id: str): - self._assert_settings_match_schema(settings, organisation_id, plugin_id) + self._assert_settings_match_schema(settings, plugin_id) self._put_boefje(plugin_id) return self.config_storage.upsert(organisation_id, plugin_id, settings=settings) @@ -122,14 +122,14 @@ def _put_boefje(self, boefje_id: str) -> None: try: self.plugin_storage.boefje_by_id(boefje_id) - except PluginNotFound: + except PluginNotFound as e: try: plugin = self.local_repo.by_id(boefje_id) except KeyError: - raise + raise e if plugin.type != "boefje": - raise + raise e self.plugin_storage.create_boefje(plugin) def _put_normalizer(self, normalizer_id: str) -> None: @@ -150,12 +150,7 @@ def _put_normalizer(self, normalizer_id: str) -> None: def delete_settings(self, organisation_id: str, plugin_id: str): self.config_storage.delete(organisation_id, plugin_id) - try: - self._assert_settings_match_schema({}, organisation_id, plugin_id) - except SettingsNotConformingToSchema: - logger.warning("Making sure %s is disabled for %s because settings are deleted", plugin_id, organisation_id) - - self.set_enabled_by_id(plugin_id, organisation_id, False) + # We don't check the schema anymore because we can provide entries through the global environment as well def schema(self, plugin_id: str) -> dict | None: try: @@ -184,9 +179,7 @@ def description(self, plugin_id: str, organisation_id: str) -> str: return "" def set_enabled_by_id(self, plugin_id: str, organisation_id: str, enabled: bool): - if enabled: - all_settings = self.get_all_settings(organisation_id, plugin_id) - self._assert_settings_match_schema(all_settings, organisation_id, plugin_id) + # We don't check the schema anymore because we can provide entries through the global environment as well try: self._put_boefje(plugin_id) @@ -195,14 +188,14 @@ def set_enabled_by_id(self, plugin_id: str, organisation_id: str, enabled: bool) self.config_storage.upsert(organisation_id, plugin_id, enabled=enabled) - def _assert_settings_match_schema(self, all_settings: dict, organisation_id: str, plugin_id: str): + def _assert_settings_match_schema(self, all_settings: dict, plugin_id: str): schema = self.schema(plugin_id) if schema: # No schema means that there is nothing to assert try: validate(instance=all_settings, schema=schema) except ValidationError as e: - raise SettingsNotConformingToSchema(organisation_id, plugin_id, e.message) from e + raise SettingsNotConformingToSchema(plugin_id, e.message) from e def _set_plugin_enabled(self, plugin: PluginType, organisation_id: str) -> PluginType: with contextlib.suppress(KeyError, NotFound): diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index a7e0d4feca1..8b0d979d256 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -7,6 +7,8 @@ import httpx import structlog from httpx import HTTPError +from jsonschema.exceptions import ValidationError +from jsonschema.validators import validate from boefjes.clients.bytes_client import BytesAPIClient from boefjes.config import settings @@ -15,6 +17,7 @@ from boefjes.local_repository import LocalPluginRepository from boefjes.plugins.models import _default_mime_types from boefjes.runtime_interfaces import BoefjeJobRunner, Handler, NormalizerJobRunner +from boefjes.storage.interfaces import SettingsNotConformingToSchema from octopoes.api.models import Affirmation, Declaration, Observation from octopoes.connector.octopoes import OctopoesAPIConnector from octopoes.models import Reference, ScanLevel @@ -35,7 +38,7 @@ def get_octopoes_api_connector(org_code: str) -> OctopoesAPIConnector: return OctopoesAPIConnector(str(settings.octopoes_api), org_code) -def get_environment_settings(boefje_meta: BoefjeMeta, environment_keys: list[str]) -> dict[str, str]: +def get_environment_settings(boefje_meta: BoefjeMeta, schema: dict | None = None) -> dict[str, str]: try: katalogus_api = str(settings.katalogus_api).rstrip("/") response = httpx.get( @@ -43,22 +46,34 @@ def get_environment_settings(boefje_meta: BoefjeMeta, environment_keys: list[str timeout=30, ) response.raise_for_status() - environment = response.json() - - # Add prefixed BOEFJE_* global environment variables - for key, value in os.environ.items(): - if key.startswith("BOEFJE_"): - katalogus_key = key.split("BOEFJE_", 1)[1] - # Only pass the environment variable if it is not explicitly set through the katalogus, - # if and only if they are defined in boefje.json - if katalogus_key in environment_keys and katalogus_key not in environment: - environment[katalogus_key] = value - - return {k: str(v) for k, v in environment.items() if k in environment_keys} except HTTPError: logger.exception("Error getting environment settings") raise + allowed_keys = schema.get("properties", []) if schema else [] + new_env = { + key.split("BOEFJE_", 1)[1]: value + for key, value in os.environ.items() + if key.startswith("BOEFJE_") and key in allowed_keys + } + + settings_from_katalogus = response.json() + + for key, value in settings_from_katalogus.items(): + if key in allowed_keys: + new_env[key] = value + + # The schema, besides dictating that a boefje cannot run if it is not matched, also provides an extra safeguard: + # it is possible to inject code if arguments are passed that "escape" the call to a tool. Hence, we should enforce + # the schema somewhere and make the schema as strict as possible. + if schema is not None: + try: + validate(instance=new_env, schema=schema) + except ValidationError as e: + raise SettingsNotConformingToSchema(boefje_meta.boefje.id, e.message) from e + + return new_env + class BoefjeHandler(Handler): def __init__( @@ -97,10 +112,8 @@ def handle(self, boefje_meta: BoefjeMeta) -> None: boefje_meta.arguments["input"] = ooi.serialize() - env_keys = boefje_resource.environment_keys - boefje_meta.runnable_hash = boefje_resource.runnable_hash - boefje_meta.environment = get_environment_settings(boefje_meta, env_keys) if env_keys else {} + boefje_meta.environment = get_environment_settings(boefje_meta, boefje_resource.schema) mime_types = _default_mime_types(boefje_meta.boefje) diff --git a/boefjes/boefjes/katalogus/plugins.py b/boefjes/boefjes/katalogus/plugins.py index 134243ad963..6ecc4b031db 100644 --- a/boefjes/boefjes/katalogus/plugins.py +++ b/boefjes/boefjes/katalogus/plugins.py @@ -123,7 +123,6 @@ class BoefjeIn(BaseModel): version: str | None = None created: datetime.datetime | None = None description: str | None = None - environment_keys: list[str] = Field(default_factory=list) scan_level: int = 1 consumes: set[str] = Field(default_factory=set) produces: set[str] = Field(default_factory=set) @@ -167,7 +166,6 @@ class NormalizerIn(BaseModel): version: str | None = None created: datetime.datetime | None = None description: str | None = None - environment_keys: list[str] = Field(default_factory=list) consumes: list[str] = Field(default_factory=list) # mime types (and/ or boefjes) produces: list[str] = Field(default_factory=list) # oois diff --git a/boefjes/boefjes/migrations/versions/870fc302b852_remove_environment_keys_field.py b/boefjes/boefjes/migrations/versions/870fc302b852_remove_environment_keys_field.py new file mode 100644 index 00000000000..7bdfbd9e024 --- /dev/null +++ b/boefjes/boefjes/migrations/versions/870fc302b852_remove_environment_keys_field.py @@ -0,0 +1,37 @@ +"""Remove environment keys field + +Revision ID: 870fc302b852 +Revises: 5be152459a7b +Create Date: 2024-08-20 06:08:20.943924 + +""" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "870fc302b852" +down_revision = "5be152459a7b" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("boefje", "environment_keys") + op.drop_column("normalizer", "environment_keys") + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "normalizer", + sa.Column("environment_keys", postgresql.ARRAY(sa.VARCHAR(length=128)), autoincrement=False, nullable=False), + ) + op.add_column( + "boefje", + sa.Column("environment_keys", postgresql.ARRAY(sa.VARCHAR(length=128)), autoincrement=False, nullable=False), + ) + # ### end Alembic commands ### diff --git a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py index 40a44d504d3..d46f360b703 100644 --- a/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py +++ b/boefjes/boefjes/migrations/versions/f9de6eb7824b_introduce_boefjeconfig_model.py @@ -95,7 +95,7 @@ def upgrade() -> None: str(boefje.scan_level), list(boefje.consumes), list(boefje.produces), - boefje.environment_keys, + ["TEST_KEY"], boefje.oci_image, boefje.oci_arguments, boefje.version, @@ -137,7 +137,7 @@ def upgrade() -> None: str(boefje.scan_level), list(boefje.consumes), list(boefje.produces), - boefje.environment_keys, + ["TEST_KEY"], boefje.oci_image, boefje.oci_arguments, boefje.version, @@ -177,7 +177,7 @@ def upgrade() -> None: normalizer.description, normalizer.consumes, normalizer.produces, - normalizer.environment_keys, + ["TEST_KEY"], normalizer.version, ) for normalizer in normalizers_to_insert diff --git a/boefjes/boefjes/models.py b/boefjes/boefjes/models.py index 4881b26008a..028d1a1c9a6 100644 --- a/boefjes/boefjes/models.py +++ b/boefjes/boefjes/models.py @@ -17,7 +17,6 @@ class Plugin(BaseModel): version: str | None = None created: datetime.datetime | None = None description: str | None = None - environment_keys: list[str] = Field(default_factory=list) enabled: bool = False static: bool = True # We need to differentiate between local and remote plugins to know which ones can be deleted diff --git a/boefjes/boefjes/plugins/kat_binaryedge/boefje.json b/boefjes/boefjes/plugins/kat_binaryedge/boefje.json index 9dc2a85d8fb..e7d90e4ee98 100644 --- a/boefjes/boefjes/plugins/kat_binaryedge/boefje.json +++ b/boefjes/boefjes/plugins/kat_binaryedge/boefje.json @@ -6,8 +6,5 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "BINARYEDGE_API" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_censys/boefje.json b/boefjes/boefjes/plugins/kat_censys/boefje.json index 6aadac16fba..ef6c3ab9a67 100644 --- a/boefjes/boefjes/plugins/kat_censys/boefje.json +++ b/boefjes/boefjes/plugins/kat_censys/boefje.json @@ -6,9 +6,5 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "CENSYS_API_ID", - "CENSYS_API_SECRET" - ], "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json b/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json index 280ea27e565..f1315d93c33 100644 --- a/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json +++ b/boefjes/boefjes/plugins/kat_cve_finding_types/boefje.json @@ -5,9 +5,6 @@ "consumes": [ "CVEFindingType" ], - "environment_keys": [ - "CVEAPI_URL" - ], "scan_level": 0, "enabled": true } diff --git a/boefjes/boefjes/plugins/kat_dns/boefje.json b/boefjes/boefjes/plugins/kat_dns/boefje.json index 53391f0155d..5773364b9b6 100644 --- a/boefjes/boefjes/plugins/kat_dns/boefje.json +++ b/boefjes/boefjes/plugins/kat_dns/boefje.json @@ -5,9 +5,5 @@ "consumes": [ "Hostname" ], - "environment_keys": [ - "RECORD_TYPES", - "REMOTE_NS" - ], "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_external_db/boefje.json b/boefjes/boefjes/plugins/kat_external_db/boefje.json index 4de34b597ac..cbf7ee0c927 100644 --- a/boefjes/boefjes/plugins/kat_external_db/boefje.json +++ b/boefjes/boefjes/plugins/kat_external_db/boefje.json @@ -5,12 +5,5 @@ "consumes": [ "Network" ], - "environment_keys": [ - "DB_URL", - "DB_ACCESS_TOKEN", - "DB_ORGANIZATION_IDENTIFIER", - "DB_ENDPOINT_FORMAT", - "REQUESTS_CA_BUNDLE" - ], "scan_level": 0 } diff --git a/boefjes/boefjes/plugins/kat_leakix/boefje.json b/boefjes/boefjes/plugins/kat_leakix/boefje.json index 6bbc19c76ee..173f1b3169d 100644 --- a/boefjes/boefjes/plugins/kat_leakix/boefje.json +++ b/boefjes/boefjes/plugins/kat_leakix/boefje.json @@ -7,8 +7,5 @@ "IPAddressV6", "Hostname" ], - "environment_keys": [ - "LEAKIX_API" - ], "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_log4shell/boefje.json b/boefjes/boefjes/plugins/kat_log4shell/boefje.json index 1841a2c6d9a..40a9b6e9991 100644 --- a/boefjes/boefjes/plugins/kat_log4shell/boefje.json +++ b/boefjes/boefjes/plugins/kat_log4shell/boefje.json @@ -5,8 +5,5 @@ "consumes": [ "Hostname" ], - "environment_keys": [ - "REPLY_FQDN" - ], "scan_level": 4 } diff --git a/boefjes/boefjes/plugins/kat_masscan/boefje.json b/boefjes/boefjes/plugins/kat_masscan/boefje.json index b0681d7ba2a..fbdc03a6093 100644 --- a/boefjes/boefjes/plugins/kat_masscan/boefje.json +++ b/boefjes/boefjes/plugins/kat_masscan/boefje.json @@ -5,9 +5,5 @@ "consumes": [ "IPV4NetBlock" ], - "environment_keys": [ - "PORTS", - "MAX_RATE" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json b/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json index bd0386c9c20..eaeae4d2095 100644 --- a/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json +++ b/boefjes/boefjes/plugins/kat_maxmind_geoip/boefje.json @@ -6,9 +6,5 @@ "IPAddressV4", "IPAddressV6" ], - "scan_level": 1, - "environment_keys": [ - "MAXMIND_USER_ID", - "MAXMIND_LICENCE_KEY" - ] + "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_nmap_ip_range/boefje.json b/boefjes/boefjes/plugins/kat_nmap_ip_range/boefje.json index 4b4dc1a2d06..fe3baf38eb7 100644 --- a/boefjes/boefjes/plugins/kat_nmap_ip_range/boefje.json +++ b/boefjes/boefjes/plugins/kat_nmap_ip_range/boefje.json @@ -6,11 +6,5 @@ "IPV6NetBlock", "IPV4NetBlock" ], - "environment_keys": [ - "TOP_PORTS_TCP", - "TOP_PORTS_UDP", - "MIN_VLSM_IPV4", - "MIN_VLSM_IPV6" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_nmap_ports/boefje.json b/boefjes/boefjes/plugins/kat_nmap_ports/boefje.json index 506b6ffd478..87fdb592a06 100644 --- a/boefjes/boefjes/plugins/kat_nmap_ports/boefje.json +++ b/boefjes/boefjes/plugins/kat_nmap_ports/boefje.json @@ -6,8 +6,5 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "PORTS" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_nmap_tcp/boefje.json b/boefjes/boefjes/plugins/kat_nmap_tcp/boefje.json index f3d46684aeb..2ab5f018393 100644 --- a/boefjes/boefjes/plugins/kat_nmap_tcp/boefje.json +++ b/boefjes/boefjes/plugins/kat_nmap_tcp/boefje.json @@ -6,9 +6,6 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "TOP_PORTS" - ], "scan_level": 2, "oci_image": "ghcr.io/minvws/openkat/nmap:latest", "oci_arguments": [ diff --git a/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json b/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json index f9839e53e37..671ff93fe2a 100644 --- a/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json +++ b/boefjes/boefjes/plugins/kat_nmap_udp/boefje.json @@ -6,9 +6,6 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "TOP_PORTS_UDP" - ], "scan_level": 2, "oci_image": "ghcr.io/minvws/openkat/nmap:latest", "oci_arguments": [ diff --git a/boefjes/boefjes/plugins/kat_shodan/boefje.json b/boefjes/boefjes/plugins/kat_shodan/boefje.json index ad1e1c3787e..c1309e7e1ac 100644 --- a/boefjes/boefjes/plugins/kat_shodan/boefje.json +++ b/boefjes/boefjes/plugins/kat_shodan/boefje.json @@ -6,8 +6,5 @@ "IPAddressV4", "IPAddressV6" ], - "environment_keys": [ - "SHODAN_API" - ], "scan_level": 1 } diff --git a/boefjes/boefjes/plugins/kat_testssl_sh_ciphers/boefje.json b/boefjes/boefjes/plugins/kat_testssl_sh_ciphers/boefje.json index 91a7d6f9994..92626c95337 100644 --- a/boefjes/boefjes/plugins/kat_testssl_sh_ciphers/boefje.json +++ b/boefjes/boefjes/plugins/kat_testssl_sh_ciphers/boefje.json @@ -5,8 +5,5 @@ "consumes": [ "IPService" ], - "scan_level": 2, - "environment_keys": [ - "TIMEOUT" - ] + "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_webpage_analysis/boefje.json b/boefjes/boefjes/plugins/kat_webpage_analysis/boefje.json index c6c12b6e73c..e284ad6f61b 100644 --- a/boefjes/boefjes/plugins/kat_webpage_analysis/boefje.json +++ b/boefjes/boefjes/plugins/kat_webpage_analysis/boefje.json @@ -141,8 +141,5 @@ "video/x-msvideo", "video/x-sgi-movie" ], - "environment_keys": [ - "USERAGENT" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/plugins/kat_wpscan/boefje.json b/boefjes/boefjes/plugins/kat_wpscan/boefje.json index 83658bb2d56..9c1d0b343da 100644 --- a/boefjes/boefjes/plugins/kat_wpscan/boefje.json +++ b/boefjes/boefjes/plugins/kat_wpscan/boefje.json @@ -5,8 +5,5 @@ "consumes": [ "SoftwareInstance" ], - "environment_keys": [ - "WP_SCAN_API" - ], "scan_level": 2 } diff --git a/boefjes/boefjes/sql/db_models.py b/boefjes/boefjes/sql/db_models.py index e8e9740f8f4..f9b32a9a9ea 100644 --- a/boefjes/boefjes/sql/db_models.py +++ b/boefjes/boefjes/sql/db_models.py @@ -75,7 +75,6 @@ class BoefjeInDB(SQL_BASE): # Job specifications consumes = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) produces = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) - environment_keys = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) schema = Column(types.JSON(), nullable=True) # Image specifications @@ -99,5 +98,4 @@ class NormalizerInDB(SQL_BASE): # Job specifications consumes = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) produces = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) - environment_keys = Column(types.ARRAY(types.String(length=128)), default=lambda: [], nullable=False) version = Column(types.String(length=16), nullable=True) diff --git a/boefjes/boefjes/sql/plugin_storage.py b/boefjes/boefjes/sql/plugin_storage.py index c9bcffbaa2f..263d035ab76 100644 --- a/boefjes/boefjes/sql/plugin_storage.py +++ b/boefjes/boefjes/sql/plugin_storage.py @@ -111,7 +111,6 @@ def to_boefje_in_db(boefje: Boefje) -> BoefjeInDB: consumes=boefje.consumes, produces=boefje.produces, schema=boefje.schema, - environment_keys=boefje.environment_keys, oci_image=boefje.oci_image, oci_arguments=boefje.oci_arguments, version=boefje.version, @@ -127,7 +126,6 @@ def to_normalizer_in_db(normalizer: Normalizer) -> NormalizerInDB: description=normalizer.description, consumes=normalizer.consumes, produces=normalizer.produces, - environment_keys=normalizer.environment_keys, version=normalizer.version, static=normalizer.static, ) @@ -144,7 +142,6 @@ def to_boefje(boefje_in_db: BoefjeInDB) -> Boefje: consumes=boefje_in_db.consumes, produces=boefje_in_db.produces, schema=boefje_in_db.schema, - environment_keys=boefje_in_db.environment_keys, oci_image=boefje_in_db.oci_image, oci_arguments=boefje_in_db.oci_arguments, version=boefje_in_db.version, @@ -161,7 +158,6 @@ def to_normalizer(normalizer_in_db: NormalizerInDB) -> Normalizer: description=normalizer_in_db.description, consumes=normalizer_in_db.consumes, produces=normalizer_in_db.produces, - environment_keys=normalizer_in_db.environment_keys, version=normalizer_in_db.version, static=normalizer_in_db.static, ) diff --git a/boefjes/boefjes/storage/interfaces.py b/boefjes/boefjes/storage/interfaces.py index ff19ca7c9f8..3f3d58e4a63 100644 --- a/boefjes/boefjes/storage/interfaces.py +++ b/boefjes/boefjes/storage/interfaces.py @@ -11,11 +11,8 @@ def __init__(self, message: str): class SettingsNotConformingToSchema(StorageError): - def __init__(self, organisation_id: str, plugin_id: str, validation_error: str): - super().__init__( - f"Settings for organisation {organisation_id} and plugin {plugin_id} are not conform the plugin schema: " - f"{validation_error}" - ) + def __init__(self, plugin_id: str, validation_error: str): + super().__init__(f"Settings for plugin {plugin_id} are not conform the plugin schema: {validation_error}") class NotFound(StorageError): diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index 31c11e2cf98..b1ca215be31 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -87,6 +87,7 @@ line-length = 120 transform-concats = true [tool.pytest.ini_options] +markers = ["slow: marks tests as slow"] addopts = "-m 'not slow'" env = [ "D:KATALOGUS_DB_URI=postgresql://postgres:postgres@ci_katalogus-db:5432/ci_katalogus", diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index d94dc074344..079185699ed 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -16,12 +16,16 @@ from boefjes.clients.bytes_client import BytesAPIClient from boefjes.clients.scheduler_client import Queue, SchedulerClientInterface, Task, TaskStatus from boefjes.config import Settings, settings +from boefjes.dependencies.plugins import PluginService from boefjes.job_handler import bytes_api_client from boefjes.job_models import BoefjeMeta, NormalizerMeta +from boefjes.local_repository import get_local_repository from boefjes.models import Organisation from boefjes.runtime_interfaces import Handler, WorkerManager +from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage +from boefjes.sql.plugin_storage import SQLPluginStorage from octopoes.api.models import Declaration, Observation from octopoes.connector.octopoes import OctopoesAPIConnector from octopoes.models import OOI @@ -142,21 +146,47 @@ def api(tmp_path): @pytest.fixture -def organisation_repository(): +def session(): engine = get_engine() session = sessionmaker(bind=engine)() - yield SQLOrganisationStorage(session, settings) + yield session session.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) + session.commit() session.close() @pytest.fixture -def organisation(organisation_repository) -> Organisation: +def organisation_storage(session): + return SQLOrganisationStorage(session, settings) + + +@pytest.fixture +def config_storage(session): + return SQLConfigStorage(session, create_encrypter()) + + +@pytest.fixture +def plugin_storage(session): + return SQLPluginStorage(session, settings) + + +@pytest.fixture +def local_repo(): + return get_local_repository() + + +@pytest.fixture +def plugin_service(plugin_storage, config_storage, local_repo): + return PluginService(plugin_storage, config_storage, local_repo) + + +@pytest.fixture +def organisation(organisation_storage) -> Organisation: organisation = Organisation(id="test", name="Test org") - with organisation_repository as repo: + with organisation_storage as repo: repo.create(organisation) return organisation diff --git a/boefjes/tests/integration/test_bench.py b/boefjes/tests/integration/test_bench.py index a77d5732092..14123016904 100644 --- a/boefjes/tests/integration/test_bench.py +++ b/boefjes/tests/integration/test_bench.py @@ -19,7 +19,7 @@ def test_migration( octopoes_api_connector: OctopoesAPIConnector, bytes_client: BytesAPIClient, - organisation_repository: SQLOrganisationStorage, + organisation_storage: SQLOrganisationStorage, valid_time, ): octopoes_api_connector.session._timeout.connect = 60 @@ -87,7 +87,7 @@ def test_migration( bytes_client.save_normalizer_meta(normalizer_meta) total_oois = octopoes_api_connector.list_objects(set(), valid_time).count - total_processed, total_failed = upgrade(organisation_repository, valid_time) + total_processed, total_failed = upgrade(organisation_storage, valid_time) assert total_processed == len(hostname_range) assert total_failed == 0 diff --git a/boefjes/tests/integration/test_get_environment.py b/boefjes/tests/integration/test_get_environment.py new file mode 100644 index 00000000000..5aa209c0493 --- /dev/null +++ b/boefjes/tests/integration/test_get_environment.py @@ -0,0 +1,22 @@ +import pytest + +from boefjes.dependencies.plugins import PluginService +from boefjes.job_handler import get_environment_settings +from boefjes.models import Organisation +from tests.loading import get_boefje_meta + + +@pytest.mark.skipif("os.environ.get('CI') != '1'") +def test_environment_builds_up_correctly(plugin_service: PluginService, organisation: Organisation): + plugin_id = "dns-records" + schema = plugin_service.schema(plugin_id) + environment = get_environment_settings(get_boefje_meta(boefje_id=plugin_id), schema) + + assert environment == {} + + with plugin_service: + plugin_service.upsert_settings({"RECORD_TYPES": "CNAME,AAAA", "WRONG": "3"}, organisation.id, plugin_id) + + environment = get_environment_settings(get_boefje_meta(boefje_id=plugin_id), schema) + + assert environment == {"RECORD_TYPES": "CNAME,AAAA"} diff --git a/boefjes/tests/integration/test_migration_add_schema_field.py b/boefjes/tests/integration/test_migration_add_schema_field.py index bbd66fbafa7..158e99cce34 100644 --- a/boefjes/tests/integration/test_migration_add_schema_field.py +++ b/boefjes/tests/integration/test_migration_add_schema_field.py @@ -30,7 +30,7 @@ def setUp(self) -> None: str(boefje.scan_level), list(sorted(boefje.consumes)), list(sorted(boefje.produces)), - boefje.environment_keys, + ["RECORD_TYPES", "REMOTE_NS"], boefje.oci_image, boefje.oci_arguments, boefje.version, @@ -71,7 +71,7 @@ def test_fail_on_wrong_plugin_ids(self): "2", ["IPAddressV4", "IPAddressV6"], ["boefje/nmap-udp"], - ["TOP_PORTS_UDP"], + ["RECORD_TYPES", "REMOTE_NS"], "ghcr.io/minvws/openkat/nmap:latest", ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], None, @@ -144,7 +144,7 @@ def test_fail_on_wrong_plugin_ids(self): "2", ["IPAddressV4", "IPAddressV6"], ["boefje/nmap-udp"], - ["TOP_PORTS_UDP"], + ["RECORD_TYPES", "REMOTE_NS"], "ghcr.io/minvws/openkat/nmap:latest", ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], None, diff --git a/boefjes/tests/integration/test_sql_repositories.py b/boefjes/tests/integration/test_sql_repositories.py index ad4f804ad10..4dbe5d5c991 100644 --- a/boefjes/tests/integration/test_sql_repositories.py +++ b/boefjes/tests/integration/test_sql_repositories.py @@ -194,7 +194,6 @@ def test_rich_boefje_storage(self): version="v1.09", created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), description="My Boefje", - environment_keys=["api_key", "TOKEN"], scan_level=4, consumes=["Internet"], produces=[ @@ -244,7 +243,6 @@ def test_rich_normalizer_storage(self): version="v1.19", created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), description="My Normalizer", - environment_keys=["api_key", "TOKEN"], scan_level=4, consumes=["Internet"], produces=[ diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json index 518d9804e4b..321d8541364 100644 --- a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json +++ b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json @@ -5,6 +5,5 @@ "consumes": [ "DNSZone" ], - "environment_keys": [], "scan_level": 1 } diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json index 07c01db4d21..67dc80c70bf 100644 --- a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json +++ b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json @@ -8,6 +8,5 @@ "produces": [ "text/html" ], - "environment_keys": [], "scan_level": 1 } diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json index b00b312a437..d419ffd073f 100644 --- a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json +++ b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json @@ -8,6 +8,5 @@ "produces": [ "text/html" ], - "environment_keys": [], "scan_level": 1 } diff --git a/boefjes/tests/katalogus/test_plugin_service.py b/boefjes/tests/katalogus/test_plugin_service.py index a86b4aa6fbf..acb892eedee 100644 --- a/boefjes/tests/katalogus/test_plugin_service.py +++ b/boefjes/tests/katalogus/test_plugin_service.py @@ -55,27 +55,13 @@ def test_update_by_id(self): def test_update_by_id_bad_schema(self): plugin_id = "kat_test" - with self.assertRaises(SettingsNotConformingToSchema) as ctx: - self.service.set_enabled_by_id(plugin_id, self.organisation, True) - - msg = ( - "Settings for organisation test and plugin kat_test are not conform the plugin schema: 'api_key' is a " - "required property" - ) - self.assertEqual(ctx.exception.message, msg) - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) self.service.set_enabled_by_id(plugin_id, self.organisation, True) - value = 129 * "a" - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 129 * "a"}) with self.assertRaises(SettingsNotConformingToSchema) as ctx: - self.service.set_enabled_by_id(plugin_id, self.organisation, True) + self.service.upsert_settings({"api_key": 129 * "a"}, self.organisation, plugin_id) - msg = ( - f"Settings for organisation test and plugin kat_test are not conform the plugin schema: " - f"'{value}' is too long" - ) + msg = f"Settings for plugin kat_test are not conform the plugin schema: '{129 * 'a'}' is too long" self.assertEqual(ctx.exception.message, msg) def test_get_schema(self): @@ -93,7 +79,7 @@ def test_get_schema(self): schema = self.service.schema("kat_test_normalize") self.assertIsNone(schema) - def test_removing_mandatory_setting_disables_plugin(self): + def test_removing_mandatory_setting_does_not_disable_plugin_anymore(self): plugin_id = "kat_test" self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) @@ -105,20 +91,17 @@ def test_removing_mandatory_setting_disables_plugin(self): self.service.delete_settings(self.organisation, plugin_id) plugin = self.service.by_plugin_id(plugin_id, self.organisation) - self.assertFalse(plugin.enabled) + self.assertTrue(plugin.enabled) def test_adding_integer_settings_within_given_constraints(self): plugin_id = "kat_test_2" - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": "24"}) - with self.assertRaises(SettingsNotConformingToSchema) as ctx: - self.service.set_enabled_by_id(plugin_id, self.organisation, True) + self.service.upsert_settings({"api_key": "24"}, self.organisation, plugin_id) self.assertIn("'24' is not of type 'integer'", ctx.exception.message) - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 24}) - + self.service.upsert_settings({"api_key": 24}, self.organisation, plugin_id) self.service.set_enabled_by_id(plugin_id, self.organisation, True) plugin = self.service.by_plugin_id(plugin_id, self.organisation) @@ -155,7 +138,6 @@ def test_clone_many_settings(self): all_settings_1 = {"api_key": "123"} self.service.upsert_settings(all_settings_1, self.organisation, plugin_id_1) - self.service.clone_settings_to_organisation(self.organisation, "org2") all_settings_for_new_org = self.service.get_all_settings("org2", plugin_id_1) diff --git a/boefjes/tests/modules/dummy_boefje/boefje.json b/boefjes/tests/modules/dummy_boefje/boefje.json index 791539e798f..81b94057368 100644 --- a/boefjes/tests/modules/dummy_boefje/boefje.json +++ b/boefjes/tests/modules/dummy_boefje/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_boefje_environment/boefje.json b/boefjes/tests/modules/dummy_boefje_environment/boefje.json index 838cef1dae7..2ad7fdddefa 100644 --- a/boefjes/tests/modules/dummy_boefje_environment/boefje.json +++ b/boefjes/tests/modules/dummy_boefje_environment/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_boefje_environment_with_pycache/boefje.json b/boefjes/tests/modules/dummy_boefje_environment_with_pycache/boefje.json index 28f7090b2f0..009f2116c0f 100644 --- a/boefjes/tests/modules/dummy_boefje_environment_with_pycache/boefje.json +++ b/boefjes/tests/modules/dummy_boefje_environment_with_pycache/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_boefje_invalid_signature/boefje.json b/boefjes/tests/modules/dummy_boefje_invalid_signature/boefje.json index 47f325f09e9..3fca5d08ce7 100644 --- a/boefjes/tests/modules/dummy_boefje_invalid_signature/boefje.json +++ b/boefjes/tests/modules/dummy_boefje_invalid_signature/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_boefje_missing_run/boefje.json b/boefjes/tests/modules/dummy_boefje_missing_run/boefje.json index 838cef1dae7..2ad7fdddefa 100644 --- a/boefjes/tests/modules/dummy_boefje_missing_run/boefje.json +++ b/boefjes/tests/modules/dummy_boefje_missing_run/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_boefje_runtime_exception/boefje.json b/boefjes/tests/modules/dummy_boefje_runtime_exception/boefje.json index 197a6aa43f0..e7dcc24f271 100644 --- a/boefjes/tests/modules/dummy_boefje_runtime_exception/boefje.json +++ b/boefjes/tests/modules/dummy_boefje_runtime_exception/boefje.json @@ -3,6 +3,5 @@ "name": "dummy", "description": "", "consumes": [], - "produces": [], - "environment_keys": [] + "produces": [] } diff --git a/boefjes/tests/modules/dummy_oci_boefje_no_main/boefje.json b/boefjes/tests/modules/dummy_oci_boefje_no_main/boefje.json index 2ef96a5e2da..6e8c1bc69b3 100644 --- a/boefjes/tests/modules/dummy_oci_boefje_no_main/boefje.json +++ b/boefjes/tests/modules/dummy_oci_boefje_no_main/boefje.json @@ -4,6 +4,5 @@ "description": "", "consumes": [], "produces": [], - "environment_keys": [], "oci_image": "openkat/test" } diff --git a/boefjes/tests/test_tasks.py b/boefjes/tests/test_tasks.py index f0cbf5fac56..f9c319897a1 100644 --- a/boefjes/tests/test_tasks.py +++ b/boefjes/tests/test_tasks.py @@ -198,6 +198,6 @@ def test_correct_local_runner_hash(self) -> None: assert Path(path / "__pycache__/pytest__init__.cpython-311.pyc").is_file() assert Path(path / "__pycache__/pytest_main.cpython-311.pyc").is_file() - assert boefje_resource_1.runnable_hash == "4bae5e869bd17759bf750bf357fdee1eedff5768d407248b8ddcb63d0abdee19" - assert boefje_resource_2.runnable_hash == "e0c46fb915778b06f69cd5934b2157733cef84d67fc89c563c5bbd965ad52949" - assert boefje_resource_3.runnable_hash == "0185c90d3d1a4dc1490ec918374f84e8a480101f98db14d434638147dd82c626" + assert boefje_resource_1.runnable_hash == "7450ebc13f6856df925e90cd57f2769468a39723f18ba835749982b484564ec9" + assert boefje_resource_2.runnable_hash == "874e154b572a0315cfe4329bd3b756bf9cad77f6a87bb9b9b9bb6296f1d4b520" + assert boefje_resource_3.runnable_hash == "70c0b0ad3b2e70fd79e52dcf043096a50ed69db1359df0011499e66ab1510bbe" diff --git a/docs/source/developer_documentation/boefjes.md b/docs/source/developer_documentation/boefjes.md index 553dfddd74e..2a8c4737138 100644 --- a/docs/source/developer_documentation/boefjes.md +++ b/docs/source/developer_documentation/boefjes.md @@ -51,13 +51,13 @@ although this would be more complicated. ## Environment variables By design, Boefjes do not have access to the host system's environment variables. -If a Boefje requires access to an environment variable (e.g. `HTTP_PROXY` or `USER_AGENT`), it should note as such in its `boefje.json` manifest. +If a Boefje requires access to an environment variable (e.g. `HTTP_PROXY` or `USER_AGENT`), it should note as such in its `schema.json`. The system-wide variables can be set as environment variable to the boefjes runner by prefixing it with `BOEFJE_`. This is to prevent a Boefje from accessing variables it should not have access to, such as secrets. To illustrate: if `BOEFJE_HTTP_PROXY=https://proxy:8080` environment variable is configured, the Boefje can access it as `HTTP_PROXY`. This feature can also be used to set default values for KAT-alogus settings. For example, configuring the `BOEFJE_TOP_PORTS` environment variable will set the default value for the `TOP_PORTS` setting (used by the nmap Boefje). -This default value can be overridden by setting any value for `TOP_PORTS` in the KAT-alogus. +This default value can be overridden per organisation by setting any value for `TOP_PORTS` in the KAT-alogus. ## Technical Design diff --git a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md index dbb2f3bdc70..65e4d750f18 100644 --- a/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md +++ b/docs/source/developer_documentation/development_tutorial/creating_a_boefje.md @@ -28,7 +28,6 @@ This file contains information about our boefje. For example, this file contains "name": "Hello Katty", "description": "A simple boefje that can say hello", "consumes": ["IPAddressV4", "IPAddressV6"], - "environment_keys": ["MESSAGE", "NUMBER"], "scan_level": 0, "oci_image": "openkat/hello-katty" } @@ -38,7 +37,6 @@ This file contains information about our boefje. For example, this file contains - **`name`**: A name to display in the KAT-alogus. - **`description`**: A description in the KAT-alogus. - **`consumes`**: A list of OOI types that trigger the boefje to run. Whenever one of these OOIs gets added, this boefje will run with that OOI. In our case, we will run our boefje whenever a new IPAddressV4 or IPAddressV6 gets added. -- **`environment_keys`**: A list of inputs provided by the user. More information about these inputs can be found in `schema.json`. OpenKAT also provides some environment variables. - **`scan_level`**: A scan level that decides how intrusively this boefje will scan the provided OOIs. Since we will not make any external requests our boefje will have a scan level of 0. - **`oci_image`**: The name of the docker image that is provided inside `boefjes/Makefile` @@ -52,8 +50,9 @@ This file contains a description of the boefje to explain to the user what this ## `schema.json` -This JSON is used as the basis for a form for the user. When the user enables this boefje they can get the option to give extra information. For example, it can contain an API key that the script requires. -This is an example of a `schema.json` file: +To allow the user to pass information to a boefje runtime, add a schema.json file to the folder where your boefje is located. +This can be used, for example, to add an API key that the script requires. +It must conform to the https://json-schema.org/ standard, for example: ```json { @@ -78,6 +77,24 @@ This is an example of a `schema.json` file: } ``` +This JSON defines which additional environment variables can be set for the boefje. +There are two ways to do this. +Firstly, using this schema as an example, you could set the `BOEFJE_MESSAGE` environment variable in the boefje runtime. +Prepending the key with `BOEFJE_` provides an extra safeguard. +Note that setting an environment variable means this configuration is applied to _all_ organisations. +Secondly, if you want to avoid setting environment variables or configure it for just one organisation, +it is also possible to set the API key through the KAT-alogus. +Navigate to the boefje detail page of Shodan to find the schema as a form. +These values take precedence over the environment variables. +This is also a way to test whether the schema is properly understood for your boefje. +If encryption has been set up for the KATalogus, all keys provided through this form are stored encrypted in the database. + +Although the Shodan boefje defines an API key, the schema could contain anything your boefje needs. +However, OpenKAT currently officially only supports "string" and "integer" properties that are one level deep. +Because keys may be passed through environment variables, +schema validation does not happen right away when settings are added or boefjes enabled. +Schema validation happens right before spawning a boefje, meaning your tasks will fail if is missing a required variable. + - `title`: This should always contain a string containing 'Arguments'. - `type`: This should always contain a string containing 'object'. - `description`: A description of the boefje explaining in short what it can do. This will both be displayed inside the KAT-alogus and on the boefje's page. diff --git a/docs/source/introduction/makeyourown.rst b/docs/source/introduction/makeyourown.rst index 226b2dfcb5c..04d9979b694 100644 --- a/docs/source/introduction/makeyourown.rst +++ b/docs/source/introduction/makeyourown.rst @@ -15,7 +15,7 @@ What types of plugins are available? There are three types of plugins, deployed by OpenKAT to collect information, translate it into objects for the data model and then analyze it. Boefjes gather facts, Whiskers structure the information for the data model and Bits determine what you want to think about it; they are the business rules. Each action is cut into the smallest possible pieces. -- Boefjes gather factual information, such as by calling an external scanning tool like nmap or using a database like shodan. +- Boefjes gather factual information, such as by calling an external scanning tool like nmap or using a database like Shodan. - Whiskers analyze the information and turn it into objects for the data model in Octopoes. @@ -51,7 +51,7 @@ To make a finding about a CVE to a software version, you need multiple objects: Existing boefjes ================ -The existing boefjes can be viewed via the KATalog in OpenKAT and are on `GitHUB in the boefjes repository. `_ +The existing boefjes can be viewed via the KATalog in OpenKAT and are on `GitHub in the boefjes repository. `_ Object-types, classes and objects. ---------------------------------- @@ -65,7 +65,7 @@ When we talk about objects, we usually mean instance of such a class, or a 'reco Example: the boefje for shodan ------------------------------ -The boefje calling shodan gives a good first impression of its capabilities. The boefje includes the following files. +The boefje calling Shodan gives a good first impression of its capabilities. The boefje includes the following files. - __init.py__, which remains empty - boefje.json, containing the normalizers and object-types in the data model @@ -75,7 +75,7 @@ The boefje calling shodan gives a good first impression of its capabilities. The - normalize.py, the normalizer (whiskers) - normalizer.json, which accepts and supplies the normalizer - requirements.txt, with the requirements for this boefje -- schema.json, settings for the web interface +- schema.json, settings for the web interface formatted as JSON Schema boefje.json *********** @@ -99,7 +99,6 @@ An example: "IPPort", "CVEFindingType" ], - "environment_keys": ["SHODAN_API"], "scan_level": 1 } @@ -111,15 +110,15 @@ Using the template as a base, you can create a boefje.json for your own boefje. NOTE: If your boefje needs object-types that do not exist, you will need to create those. This will be described later in the document. -The boefje also uses variables from the web interface, like the Shodan the API key. There are more possibilities, you can be creative with this and let the end user bring settings from the web interface. Use *environment_keys* for this. The schema.json file defines the metadata for these fields. +The boefje also uses variables from the web interface, like the Shodan the API key. There are more possibilities, you can be creative with this and let the end user bring settings from the web interface. Use environment variables or KATalogus settings for this. The schema.json file defines the metadata for these fields. schema.json *********** -To allow the user to add information through the web interface, add the schema.json file to the folder where your boefje is located. This json is used as the basis for a form for the user. In this case, it can contain an API key, but it can also be something else that your boefje responds to. This Schema must conform to the https://json-schema.org/ standard. - -Currently, however, OpenKAT only understands fairly shallow structures. For example, not all field types are supported, nor does OpenKAT understand references. You can test whether your Schema is neatly understood by checking the settings form in Rocky's KAT catalog for your boefje. +To allow the user to pass information to a boefje runtime, add a schema.json file to the folder where your boefje is located. +This can be used, for example, to add an API key that the script requires. +It must conform to the https://json-schema.org/ standard, see for example the schema.json for Shodan: .. code-block:: json @@ -139,6 +138,24 @@ Currently, however, OpenKAT only understands fairly shallow structures. For exam ] } +This JSON defines which additional environment variables can be set for the boefje. +There are two ways to do this. +Firstly, using the Shodan schema as an example, you could set the ``BOEFJE_SHODAN_API`` environment variable in the boefje runtime. +Prepending the key with ``BOEFJE_`` provides an extra safeguard. +Note that setting an environment variable means this configuration is applied to _all_ organisations. +Secondly, if you want to avoid setting environment variables or configure it for just one organisation, +it is also possible to set the API key through the KAT-alogus. +Navigate to the boefje detail page of Shodan to find the schema as a form. +These values take precedence over the environment variables. +This is also a way to test whether the schema is properly understood for your boefje. +If encryption has been set up for the KATalogus, all keys provided through this form are stored encrypted in the database. + +Although the Shodan boefje defines an API key, the schema could contain anything your boefje needs. +However, OpenKAT currently only officially supports "string" and "integer" properties that are one level deep. +Because keys may be passed through environment variables, +schema validation does not happen right away when settings are added or boefjes enabled. +Schema validation happens right before spawning a boefje, meaning your tasks will fail if is missing a required variable. + main.py ******* @@ -190,8 +207,8 @@ normalizer.json The normalizers translate the output of a boefje into objects that fit the data model. Each normalizer defines what input it accepts and what object-types it provides. -In the case of the shodan normalizer, -it involves the entire output of the shodan boefje (created based on IP address), +In the case of the Shodan normalizer, +it involves the entire output of the Shodan boefje (created based on IP address), where findings and ports come out. The `normalizer.json` defines these: .. code-block:: json @@ -295,7 +312,7 @@ If you want to add an object-type, you need to know with which other object-type Adding object-types to the data model requires an addition in octopus. Here, an object-type can be added if it is connected to other object-types. Visually this is well understood using the `Graph explorer `_. The actual code is `in the Octopoes repo `_. -As with the boefje for shodan, here we again use the example from the functional documentation. A description of an object-type in the data model, in this case an IPPort, looks like this: +As with the boefje for Shodan, here we again use the example from the functional documentation. A description of an object-type in the data model, in this case an IPPort, looks like this: .. code-block:: python @@ -521,4 +538,4 @@ There are a number of ways to add your new boefje to OpenKAT. - Do a commit of your code, after review it can be included - Add an image server in the KAT catalog config file ``*`` -``*`` If you want to add an image server, join the ongoing project to standardize and describe it. The idea is to add an image server in the KAT catalog config file that has artifacts from your boefjes and normalizers as outputted by the Github CI. +``*`` If you want to add an image server, join the ongoing project to standardize and describe it. The idea is to add an image server in the KAT catalog config file that has artifacts from your boefjes and normalizers as outputted by the GitHub CI. diff --git a/mula/scheduler/models/plugin.py b/mula/scheduler/models/plugin.py index f51c4952972..a30908af8a3 100644 --- a/mula/scheduler/models/plugin.py +++ b/mula/scheduler/models/plugin.py @@ -12,7 +12,6 @@ class Plugin(BaseModel): authors: list[str] | None = None created: datetime.datetime | None = None description: str | None = None - environment_keys: list[str] | None = None related: list[str] | None = None scan_level: int | None = None consumes: str | list[str] diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index 9c293a670ba..8bb9f7fc463 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -24,7 +24,6 @@ class Plugin(BaseModel): authors: str | None = None created: str | None = None description: str | None = None - environment_keys: list[str] | None = None related: list[str] = Field(default_factory=list) enabled: bool type: str diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index f5bbb28dfac..d9825e7b14e 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -1775,7 +1775,6 @@ def boefje_dns_records(): authors=None, created=None, description="Fetch the DNS record(s) of a hostname", - environment_keys=None, related=[], enabled=True, type="boefje", diff --git a/rocky/tests/stubs/katalogus_boefjes.json b/rocky/tests/stubs/katalogus_boefjes.json index 40c79a6cb1b..d7d6ba63991 100644 --- a/rocky/tests/stubs/katalogus_boefjes.json +++ b/rocky/tests/stubs/katalogus_boefjes.json @@ -5,9 +5,6 @@ "version": null, "created": null, "description": "Use BinaryEdge to find open ports with vulnerabilities that are found on that port", - "environment_keys": [ - "BINARYEDGE_API" - ], "enabled": true, "type": "boefje", "scan_level": 2, @@ -33,7 +30,6 @@ "version": null, "created": null, "description": "Scan SSL certificates of websites", - "environment_keys": [], "enabled": false, "type": "boefje", "scan_level": 1, @@ -51,7 +47,6 @@ "version": null, "created": null, "description": "Scan SSL/TLS versions of websites", - "environment_keys": [], "enabled": false, "type": "boefje", "scan_level": 2, @@ -70,9 +65,6 @@ "version": null, "created": null, "description": "Scan wordpress sites", - "environment_keys": [ - "WP_SCAN_API" - ], "enabled": false, "type": "boefje", "scan_level": 2, @@ -91,7 +83,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ diff --git a/rocky/tests/stubs/katalogus_normalizers.json b/rocky/tests/stubs/katalogus_normalizers.json index 182b5bbb549..dfbca8cb726 100644 --- a/rocky/tests/stubs/katalogus_normalizers.json +++ b/rocky/tests/stubs/katalogus_normalizers.json @@ -5,7 +5,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ @@ -22,7 +21,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ @@ -42,7 +40,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ @@ -59,7 +56,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ @@ -83,7 +79,6 @@ "version": null, "created": null, "description": null, - "environment_keys": [], "enabled": true, "type": "normalizer", "consumes": [ diff --git a/rocky/tests/test_indemnification.py b/rocky/tests/test_indemnification.py index 785679ca7aa..e6d628b323e 100644 --- a/rocky/tests/test_indemnification.py +++ b/rocky/tests/test_indemnification.py @@ -14,7 +14,6 @@ def test_update_clearance_level(rf, client_member, httpx_mock): "authors": None, "created": None, "description": "Use BinaryEdge to find open ports with vulnerabilities that are found on that port", - "environment_keys": ["BINARYEDGE_API"], "related": None, "enabled": True, "type": "boefje", From 1e273324f94cd10ba404e5d234d6ca790e27a8d7 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Thu, 5 Sep 2024 13:40:26 +0200 Subject: [PATCH 02/82] feat: adds notification styling and icons (#3461) Co-authored-by: Jan Klopper --- rocky/assets/css/components/button-plain.scss | 22 ++++++ .../assets/css/components/notifications.scss | 78 +++++++++++++++++++ rocky/assets/css/main.scss | 1 + .../themes/soft/manon/notification-block.scss | 6 +- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 rocky/assets/css/components/button-plain.scss diff --git a/rocky/assets/css/components/button-plain.scss b/rocky/assets/css/components/button-plain.scss new file mode 100644 index 00000000000..50553d75978 --- /dev/null +++ b/rocky/assets/css/components/button-plain.scss @@ -0,0 +1,22 @@ +button, +a.button, +input[type="button"], +input[type="submit"], +input[type="reset"] { + &.plain { + background-color: transparent; + border: 0; + color: var(--colors-blue-600); + padding: 0; + + &:hover { + color: var(--colors-blue-700); + } + + .icon { + &:hover { + color: var(--colors-blue-700); + } + } + } +} diff --git a/rocky/assets/css/components/notifications.scss b/rocky/assets/css/components/notifications.scss index a6e557fdcb1..83abe718872 100644 --- a/rocky/assets/css/components/notifications.scss +++ b/rocky/assets/css/components/notifications.scss @@ -1,3 +1,25 @@ +/* Block notification */ +div, +section { + &.error, + &.warning, + &.explanation, + &.confirmation, + &.system { + flex-direction: row; + + h1, + h2, + h3, + h4, + h5, + h6 { + font-size: var(--heading-small-font-size); + } + } +} + +/* Help text */ div { &.explanation { &.help-text { @@ -10,3 +32,59 @@ div { margin-top: 0; } } + +/* Inline notification */ +p, +span { + &.error, + &.warning, + &.explanation, + &.confirmation, + &.system { + display: flex; + align-items: center; + } +} + +/* Icons */ +p, +span, +section, +div { + &.error { + &::before { + content: "\eac5"; + color: var(--colors-red-600); + } + } + + &.warning { + &::before { + content: "\ea06"; + color: var(--colors-ochre-500); + } + } + + &.explanation { + &::before { + content: "\eac5"; + color: var(--colors-blue-600); + } + } + + &.confirmation { + &::before { + content: "\ea5e"; + color: var(--colors-green-600); + } + } + + &.system { + background-color: var(--colors-black-05); + + &::before { + content: "\ea06"; + color: var(--colors-blue-600); + } + } +} diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index 0e41f9ea21d..d68d91f47e0 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -29,6 +29,7 @@ /* Components */ @import "components/action-buttons"; @import "components/block-indented"; +@import "components/button-plain"; @import "components/cat-loader"; @import "components/cat-paw-loader"; @import "components/cytoscape"; diff --git a/rocky/assets/css/themes/soft/manon/notification-block.scss b/rocky/assets/css/themes/soft/manon/notification-block.scss index 713d94abde7..45e75d01f6c 100644 --- a/rocky/assets/css/themes/soft/manon/notification-block.scss +++ b/rocky/assets/css/themes/soft/manon/notification-block.scss @@ -1,7 +1,9 @@ /* Notification block - Variables */ :root { - --notification-block-element-padding-right: 0.5rem; - --notification-block-element-padding-left: 0.5rem; + --notification-block-element-padding-top: var(--spacing-grid-300); + --notification-block-element-padding-right: var(--spacing-grid-200); + --notification-block-element-padding-left: var(--spacing-grid-200); + --notification-block-element-padding-bottom: var(--spacing-grid-300); --notification-block-element-gap: 0.5rem; } From 980415375c372e6f32086ce55078e8e5533f456b Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:16:58 +0200 Subject: [PATCH 03/82] Hotfix for normalizer API bug (#3475) Signed-off-by: Donny Peeters --- mula/scheduler/server/handlers/tasks.py | 17 +++++++++++------ mula/tests/integration/test_api.py | 7 +++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mula/scheduler/server/handlers/tasks.py b/mula/scheduler/server/handlers/tasks.py index db3391dc2d6..6912e7023ab 100644 --- a/mula/scheduler/server/handlers/tasks.py +++ b/mula/scheduler/server/handlers/tasks.py @@ -139,12 +139,16 @@ def list( ] } elif task_type == "normalizer": - f_plugin = storage.filters.Filter( - column="data", - field="normalizer__id", - operator="eq", - value=plugin_id, - ) + f_plugin = { + "and": [ + storage.filters.Filter( + column="data", + field="normalizer__id", + operator="eq", + value=plugin_id, + ) + ] + } else: f_plugin = { "or": [ @@ -182,6 +186,7 @@ def list( detail=f"invalid filter(s) [exception: {exc}]", ) from exc except storage.errors.StorageError as exc: + self.logger.exception(exc) raise fastapi.HTTPException( status_code=fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"error occurred while accessing the database [exception: {exc}]", diff --git a/mula/tests/integration/test_api.py b/mula/tests/integration/test_api.py index 0511c200f52..9f6440c5801 100644 --- a/mula/tests/integration/test_api.py +++ b/mula/tests/integration/test_api.py @@ -706,6 +706,13 @@ def test_get_tasks_min_created_at_future(self): self.assertEqual(200, response.status_code) self.assertEqual(0, len(response.json()["results"])) + def test_get_normalizer_filtered(self): + # This used to be a bug where the normalizer filter was missing a nesting on the operator + params = {"task_type": "normalizer", "plugin_id": "kat_nmap_normalize"} + response = self.client.get("/tasks", params=params) + self.assertEqual(200, response.status_code) + self.assertEqual(0, len(response.json()["results"])) + def test_get_tasks_filtered(self): response = self.client.post( "/tasks", From 79bba68f818ee04bec6ee1363ae05a55d8705238 Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Fri, 6 Sep 2024 09:14:58 +0200 Subject: [PATCH 04/82] fix: toggle styling (#3449) Co-authored-by: Jan Klopper --- rocky/assets/css/components/toggle.scss | 70 +++++++++++++++++++ rocky/assets/css/components/toolbar.scss | 1 + rocky/assets/css/main.scss | 1 + .../soft/fundamentals/border-radii.scss | 3 +- .../css/themes/soft/manon/button-icon.scss | 2 + .../assets/css/themes/soft/manon/button.scss | 2 +- .../templates/partials/katalogus_toolbar.html | 6 +- 7 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 rocky/assets/css/components/toggle.scss diff --git a/rocky/assets/css/components/toggle.scss b/rocky/assets/css/components/toggle.scss new file mode 100644 index 00000000000..d2a1dc59717 --- /dev/null +++ b/rocky/assets/css/components/toggle.scss @@ -0,0 +1,70 @@ +button, +a, +input[type="button"], +input[type="submit"], +input[type="reset"] { + $breakpoint: 24rem !default; + + &.toggle-button { + /* Alignment */ + display: flex; + align-items: center; + justify-content: center; + align-self: flex-start; + gap: 0; + margin: 0; + box-sizing: border-box; + + /* Styling */ + border-radius: var(--border-radius-l); + padding: var(--spacing-grid-150); + width: 2.75rem; + height: 2.75rem; + border: 1px solid var(--colors-purrple-300); + + /* Text and icon styling */ + background-color: var(--colors-white); + color: var(--colors-purrple-500); + text-decoration: none; + font-size: 0; + + &::before { + color: var(--colors-purrple-500); + padding: 0; + } + + /* Behaviour */ + cursor: pointer; + overflow-wrap: break-word; + + /* States */ + &[aria-current="page"] { + background-color: var(--colors-purrple-200); + border-color: var(--colors-purrple-200); + + &::before { + color: var(--colors-purrple-700); + } + } + + &:hover, + &:active { + border-color: var(--colors-purrple-500); + } + + &:focus { + outline: 2px solid var(--colors-purrple-500); + outline-offset: 0.125rem; + z-index: 2; + position: relative; + } + } +} + +a { + &.toggle-button { + &:visited { + color: var(--colors-purrple-500); + } + } +} diff --git a/rocky/assets/css/components/toolbar.scss b/rocky/assets/css/components/toolbar.scss index ae148bb349c..f8c3e962c81 100644 --- a/rocky/assets/css/components/toolbar.scss +++ b/rocky/assets/css/components/toolbar.scss @@ -4,6 +4,7 @@ justify-content: flex-end; align-items: center; width: 100%; + overflow: visible; /* Making sure outline is visible on focus */ &.start { justify-content: flex-start; diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index d68d91f47e0..f6171506258 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -65,6 +65,7 @@ @import "components/sticky"; @import "components/state-tags"; @import "components/table"; +@import "components/toggle"; @import "components/toolbar"; @import "components/tree-tables"; @import "components/user-icon"; diff --git a/rocky/assets/css/themes/soft/fundamentals/border-radii.scss b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss index 6ca1b1c20b7..0ac5c9d7060 100644 --- a/rocky/assets/css/themes/soft/fundamentals/border-radii.scss +++ b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss @@ -3,7 +3,8 @@ :root { --border-radius-s: 0.25rem; --border-radius-m: 0.5rem; - --border-radius-l: 1.5rem; + --border-radius-l: 1rem; + --border-radius-xl: 1.5rem; --border-radius-round: 50%; } diff --git a/rocky/assets/css/themes/soft/manon/button-icon.scss b/rocky/assets/css/themes/soft/manon/button-icon.scss index e814863f4a2..d8cff1a5e1e 100644 --- a/rocky/assets/css/themes/soft/manon/button-icon.scss +++ b/rocky/assets/css/themes/soft/manon/button-icon.scss @@ -2,7 +2,9 @@ :root { --button-icon-min-width: 2.75rem; + --button-icon-width: 2.75rem; --button-icon-min-height: 2.75rem; + --button-icon-height: 2.75rem; --button-icon-icon-font-size: 0.8rem; --button-icon-icon-width: 0.75rem; } diff --git a/rocky/assets/css/themes/soft/manon/button.scss b/rocky/assets/css/themes/soft/manon/button.scss index 93c3c716d21..a8260df13ec 100644 --- a/rocky/assets/css/themes/soft/manon/button.scss +++ b/rocky/assets/css/themes/soft/manon/button.scss @@ -4,7 +4,7 @@ /* Button */ --button-base-background-color: var(--branding-color-2-background-color); --button-base-text-color: var(--branding-color-2-text-color); - --button-base-border-radius: 1rem; + --button-base-border-radius: var(--border-radius-l); --button-base-font-family: var(--application-base-font-family); --button-base-padding-top: var(--spacing-grid-150); --button-base-padding-right: var(--spacing-grid-200); diff --git a/rocky/katalogus/templates/partials/katalogus_toolbar.html b/rocky/katalogus/templates/partials/katalogus_toolbar.html index cea35c9210b..96f21fe1c29 100644 --- a/rocky/katalogus/templates/partials/katalogus_toolbar.html +++ b/rocky/katalogus/templates/partials/katalogus_toolbar.html @@ -3,8 +3,10 @@ {% if object_list %}
{% translate "Gridview" %} + class=" icon toggle-button ti-layout-grid" + {% if view_type == "grid" %}aria-current="page"{% endif %}>{% translate "Gridview" %} {% translate "Tableview" %} + class=" icon toggle-button ti-menu-2" + {% if view_type == "table" %}aria-current="page"{% endif %}>{% translate "Tableview" %}
{% endif %} From a7ca00d76b746ae03a2c8328a28793db1611ae5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:54:04 +0200 Subject: [PATCH 05/82] Bump cryptography from 42.0.8 to 43.0.1 in /bytes (#3473) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ammar --- boefjes/poetry.lock | 65 +++++++++++++++++------------------- boefjes/pyproject.toml | 2 +- boefjes/requirements-dev.txt | 61 ++++++++++++++++----------------- boefjes/requirements.txt | 61 ++++++++++++++++----------------- bytes/poetry.lock | 65 +++++++++++++++++------------------- bytes/pyproject.toml | 1 + bytes/requirements-dev.txt | 61 ++++++++++++++++----------------- bytes/requirements.txt | 61 ++++++++++++++++----------------- 8 files changed, 174 insertions(+), 203 deletions(-) diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index fcd021764f5..593f2e7f6d7 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -539,43 +539,38 @@ testing = ["pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "py [[package]] name = "cryptography" -version = "42.0.8" +version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, - {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, - {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, - {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, - {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, - {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, - {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, + {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, + {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, + {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, + {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, + {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, + {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, + {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, ] [package.dependencies] @@ -588,7 +583,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -3190,4 +3185,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "5065bdc0a65dda4d1d607f6f6fa30f8f3a0bfd6ce11afdc410f044c10d7720e3" +content-hash = "4135f17871ab68dcf30970e2716a8551978ed6782db30b8bbd7858c90e99e0f0" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index b1ca215be31..2b1f16ad6f9 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -45,7 +45,7 @@ python-libnmap = "0.7.3" # required by kat_shodan boefje shodan = "1.25.0" # required by kat_ssl_certificates boefje -cryptography = "^42.0.1" +cryptography = "^43.0.1" # required by kat_webpage_analysis forcediphttpsadapter = "1.1.0" python-wappalyzer = {git = "https://github.com/chorsley/python-Wappalyzer.git", rev = "0.4.0"} diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index 3d257eb1585..2338137a316 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -288,39 +288,34 @@ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 -cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ - --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ - --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ - --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ - --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ - --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ - --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ - --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ - --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ - --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ - --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ - --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ - --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ - --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ - --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ - --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ - --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ - --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ - --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ - --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ - --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ - --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ - --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ - --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ - --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ - --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ - --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ - --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ - --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ - --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ - --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ - --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e +cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ + --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ + --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ + --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ + --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ + --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ + --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ + --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ + --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ + --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ + --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ + --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ + --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ + --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ + --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ + --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ + --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ + --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ + --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ + --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ + --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ + --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ + --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ + --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ + --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ + --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ + --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index 4ad7647fb2d..c14689d93c8 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -288,39 +288,34 @@ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 -cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ - --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ - --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ - --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ - --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ - --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ - --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ - --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ - --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ - --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ - --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ - --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ - --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ - --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ - --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ - --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ - --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ - --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ - --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ - --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ - --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ - --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ - --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ - --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ - --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ - --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ - --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ - --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ - --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ - --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ - --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ - --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e +cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ + --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ + --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ + --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ + --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ + --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ + --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ + --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ + --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ + --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ + --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ + --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ + --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ + --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ + --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ + --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ + --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ + --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ + --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ + --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ + --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ + --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ + --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ + --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ + --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ + --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ + --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 diff --git a/bytes/poetry.lock b/bytes/poetry.lock index 03c8c961fe8..f70bba87163 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -321,43 +321,38 @@ files = [ [[package]] name = "cryptography" -version = "42.0.8" +version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, - {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, - {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, - {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, - {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, - {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, - {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, + {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, + {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, + {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, + {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, + {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, + {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, + {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, ] [package.dependencies] @@ -370,7 +365,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -1719,4 +1714,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "3c0e90e2a472d71d04b1507109f9ba59c598f04dc6373d87038bc01a9a9f40a2" +content-hash = "b38550771cc3c4f564889d3c83e98d927e7b0db07f0cdbcb01b6c89a877fa2df" diff --git a/bytes/pyproject.toml b/bytes/pyproject.toml index 40842c56ea6..eb8534de8f3 100644 --- a/bytes/pyproject.toml +++ b/bytes/pyproject.toml @@ -40,6 +40,7 @@ opentelemetry-util-http = "^0.47b0" pyjwt = "^2.8.0" fastapi-slim = "^0.111.0" structlog = "^24.2.0" +cryptography = "^43.0.1" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index c7ef092702d..fa977408c9c 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -194,39 +194,34 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows") \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ - --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ - --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ - --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ - --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ - --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ - --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ - --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ - --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ - --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ - --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ - --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ - --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ - --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ - --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ - --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ - --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ - --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ - --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ - --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ - --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ - --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ - --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ - --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ - --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ - --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ - --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ - --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ - --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ - --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ - --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ - --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e +cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ + --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ + --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ + --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ + --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ + --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ + --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ + --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ + --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ + --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ + --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ + --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ + --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ + --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ + --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ + --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ + --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ + --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ + --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ + --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ + --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ + --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ + --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ + --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ + --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ + --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ + --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 diff --git a/bytes/requirements.txt b/bytes/requirements.txt index d3d077cc7d0..dc6f031361e 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -194,39 +194,34 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -cryptography==42.0.8 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \ - --hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \ - --hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \ - --hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \ - --hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \ - --hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \ - --hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \ - --hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \ - --hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \ - --hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \ - --hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \ - --hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \ - --hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \ - --hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \ - --hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \ - --hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \ - --hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \ - --hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \ - --hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \ - --hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \ - --hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \ - --hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \ - --hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \ - --hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \ - --hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \ - --hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \ - --hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \ - --hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \ - --hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \ - --hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \ - --hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \ - --hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e +cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ + --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ + --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ + --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ + --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ + --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ + --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ + --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ + --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ + --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ + --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ + --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ + --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ + --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ + --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ + --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ + --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ + --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ + --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ + --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ + --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ + --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ + --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ + --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ + --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ + --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ + --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 deprecated==1.2.14 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 From a11a7390612e7a465314e818d848ad8ed9c5c10f Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:23:18 +0200 Subject: [PATCH 06/82] Dont yield all snyk findings when no version was found (#3431) Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> --- .../kat_kat_finding_types/kat_finding_types.json | 5 +++++ boefjes/boefjes/plugins/kat_snyk/normalize.py | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index 23ec1b70da7..00fbbba47a4 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -486,5 +486,10 @@ "source": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers", "impact": "Nonstandard headers may not be supported by all browsers and may not provide the security that is expected.", "recommendation": "Remove the nonstandard headers from the response." + }, + "KAT-SOFTWARE-VERSION-NOT-FOUND": { + "description": "The version of the software is not found.", + "risk": "recommendation", + "recommendation": "There was no version found for this software but there are known vulnerabilities for this software." } } diff --git a/boefjes/boefjes/plugins/kat_snyk/normalize.py b/boefjes/boefjes/plugins/kat_snyk/normalize.py index cd8b5746234..240cc580e0f 100755 --- a/boefjes/boefjes/plugins/kat_snyk/normalize.py +++ b/boefjes/boefjes/plugins/kat_snyk/normalize.py @@ -23,7 +23,7 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: elif not results["table_vulnerabilities"] and not results["cve_vulnerabilities"]: # no vulnerabilities found return - else: + if software_version: for vuln in results["table_vulnerabilities"]: snyk_ft = SnykFindingType(id=vuln.get("Vuln_href")) yield snyk_ft @@ -40,6 +40,15 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]: ooi=pk_ooi, description=vuln.get("Vuln_text"), ) + if not software_version and (results["table_vulnerabilities"] or results["cve_vulnerabilities"]): + kat_ooi = KATFindingType(id="KAT-SOFTWARE-VERSION-NOT-FOUND") + yield kat_ooi + yield Finding( + finding_type=kat_ooi.reference, + ooi=pk_ooi, + description="There was no version found for this software. " + "But there are known vulnerabilities for some versions.", + ) # Check for latest version latest_version = "" From a0c48c8fe2463f18b57bfdf6a092f3ba8b542a5c Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:28:11 +0200 Subject: [PATCH 07/82] Make the "name" field for plugins mandatory (#3471) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- boefjes/boefjes/models.py | 2 +- boefjes/boefjes/plugins/kat_dns_version/normalizer.json | 1 + boefjes/boefjes/plugins/kat_green_hosting/normalizer.json | 1 + .../boefjes/plugins/kat_kat_finding_types/normalizer.json | 1 + .../boefjes/plugins/kat_manual/single_ooi/normalizer.json | 1 + .../kat_test/kat_test_2/kat_test_3/normalizer.json | 1 + .../katalogus/boefjes_test_dir/kat_test/normalizer.json | 1 + .../dummy_bad_normalizer_dict_structure/normalizer.json | 1 + .../dummy_bad_normalizer_return_type/normalizer.json | 1 + boefjes/tests/modules/dummy_normalizer/normalizer.json | 1 + .../modules/dummy_normalizer_import_error/normalizer.json | 1 + boefjes/tests/test_tasks.py | 8 ++++++++ 12 files changed, 19 insertions(+), 1 deletion(-) diff --git a/boefjes/boefjes/models.py b/boefjes/boefjes/models.py index 028d1a1c9a6..58665b8588a 100644 --- a/boefjes/boefjes/models.py +++ b/boefjes/boefjes/models.py @@ -13,7 +13,7 @@ class Organisation(BaseModel): class Plugin(BaseModel): id: str - name: str | None = None + name: str version: str | None = None created: datetime.datetime | None = None description: str | None = None diff --git a/boefjes/boefjes/plugins/kat_dns_version/normalizer.json b/boefjes/boefjes/plugins/kat_dns_version/normalizer.json index 0252c4fe250..4bd2cad202f 100644 --- a/boefjes/boefjes/plugins/kat_dns_version/normalizer.json +++ b/boefjes/boefjes/plugins/kat_dns_version/normalizer.json @@ -1,5 +1,6 @@ { "id": "dns-bind-version-normalize", + "name": "DNS bind version normalizer", "consumes": [ "boefje/dns-bind-version" ], diff --git a/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json b/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json index 92434280db5..714628e5587 100644 --- a/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json +++ b/boefjes/boefjes/plugins/kat_green_hosting/normalizer.json @@ -1,6 +1,7 @@ { "id": "kat_green_hosting_normalize", "description": "Parses the Green Hosting output into findings.", + "name": "Green Hosting", "consumes": [ "boefje/green-hosting" ], diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/normalizer.json b/boefjes/boefjes/plugins/kat_kat_finding_types/normalizer.json index fc0516ed23e..81130efc8f7 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/normalizer.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_kat_finding_types_normalize", + "name": "KAT finding types", "description": "Parses KAT finding types.", "consumes": [ "boefje/kat-finding-types" diff --git a/boefjes/boefjes/plugins/kat_manual/single_ooi/normalizer.json b/boefjes/boefjes/plugins/kat_manual/single_ooi/normalizer.json index 193deac6cda..cda7b5d8b97 100644 --- a/boefjes/boefjes/plugins/kat_manual/single_ooi/normalizer.json +++ b/boefjes/boefjes/plugins/kat_manual/single_ooi/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_manual_ooi", + "name": "Manual OOI normalizer", "consumes": [ "manual/ooi" ], diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json index 0613a485c0a..25d874aa2d0 100644 --- a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json +++ b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_test_normalize_2", + "name": "Test normalizer 2", "description": "Testing KAT 2", "consumes": [ "text/html" diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json index 7b7ddc26ade..20e18b975b6 100644 --- a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json +++ b/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json @@ -1,5 +1,6 @@ { "id": "kat_test_normalize", + "name": "Test normalizer", "description": "Testing KAT", "consumes": [ "text/html" diff --git a/boefjes/tests/modules/dummy_bad_normalizer_dict_structure/normalizer.json b/boefjes/tests/modules/dummy_bad_normalizer_dict_structure/normalizer.json index cbfb74cfd32..fe23b0855ae 100644 --- a/boefjes/tests/modules/dummy_bad_normalizer_dict_structure/normalizer.json +++ b/boefjes/tests/modules/dummy_bad_normalizer_dict_structure/normalizer.json @@ -1,5 +1,6 @@ { "id": "dummy_bad_normalizer_dict_structure", + "name": "dummy_bad_normalizer_dict_structure", "description": "", "consumes": [], "produces": [] diff --git a/boefjes/tests/modules/dummy_bad_normalizer_return_type/normalizer.json b/boefjes/tests/modules/dummy_bad_normalizer_return_type/normalizer.json index f0060d3b12e..8bcee7c4327 100644 --- a/boefjes/tests/modules/dummy_bad_normalizer_return_type/normalizer.json +++ b/boefjes/tests/modules/dummy_bad_normalizer_return_type/normalizer.json @@ -1,5 +1,6 @@ { "id": "dummy_bad_normalizer_return_type", + "name": "dummy_bad_normalizer_return_type", "description": "", "consumes": [], "produces": [] diff --git a/boefjes/tests/modules/dummy_normalizer/normalizer.json b/boefjes/tests/modules/dummy_normalizer/normalizer.json index a6447d09407..4347a7a0b47 100644 --- a/boefjes/tests/modules/dummy_normalizer/normalizer.json +++ b/boefjes/tests/modules/dummy_normalizer/normalizer.json @@ -1,5 +1,6 @@ { "id": "dummy_normalizer", + "name": "dummy_normalizer", "description": "", "consumes": [], "produces": [] diff --git a/boefjes/tests/modules/dummy_normalizer_import_error/normalizer.json b/boefjes/tests/modules/dummy_normalizer_import_error/normalizer.json index a6447d09407..4347a7a0b47 100644 --- a/boefjes/tests/modules/dummy_normalizer_import_error/normalizer.json +++ b/boefjes/tests/modules/dummy_normalizer_import_error/normalizer.json @@ -1,5 +1,6 @@ { "id": "dummy_normalizer", + "name": "dummy_normalizer", "description": "", "consumes": [], "produces": [] diff --git a/boefjes/tests/test_tasks.py b/boefjes/tests/test_tasks.py index f9c319897a1..93b37e382d6 100644 --- a/boefjes/tests/test_tasks.py +++ b/boefjes/tests/test_tasks.py @@ -22,21 +22,25 @@ def setUp(self) -> None: self.boefjes = [ Boefje( id="test-boefje-1", + name="test-boefje-1", consumes={"SomeOOI"}, produces=["test-boef-1", "test/text"], ), Boefje( id="test-boefje-2", + name="test-boefje-2", consumes={"SomeOOI"}, produces=["test-boef-2", "test/text"], ), Boefje( id="test-boefje-3", + name="test-boefje-3", consumes={"SomeOOI"}, produces=["test-boef-3", "test/plain"], ), Boefje( id="test-boefje-4", + name="test-boefje-4", consumes={"SomeOOI"}, produces=["test-boef-4", "test/and-simple"], ), @@ -44,11 +48,13 @@ def setUp(self) -> None: self.normalizers = [ Normalizer( id="test-normalizer-1", + name="test-normalizer-1", consumes=["test-boef-3", "test/text"], produces=["SomeOOI", "OtherOOI"], ), Normalizer( id="test-normalizer-2", + name="test-normalizer-2", consumes=["test/text"], produces=["SomeOtherOOI"], ), @@ -56,12 +62,14 @@ def setUp(self) -> None: self.bits = [ Bit( id="test-bit-1", + name="test-bit-1", consumes="SomeOOI", produces=["SomeOOI"], parameters=[], ), Bit( id="test-bit-2", + name="test-bit-2", consumes="SomeOOI", produces=["SomeOOI", "SomeOtherOOI"], parameters=[], From 9942c9fab60a096f12f61851494476af697ee013 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:05:20 +0200 Subject: [PATCH 08/82] Handle empty normalizer results (#3482) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- boefjes/boefjes/job_handler.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/boefjes/boefjes/job_handler.py b/boefjes/boefjes/job_handler.py index 8b0d979d256..7ad0f7247ad 100644 --- a/boefjes/boefjes/job_handler.py +++ b/boefjes/boefjes/job_handler.py @@ -222,6 +222,23 @@ def handle(self, normalizer_meta: NormalizerMeta) -> None: ) ) + if ( + normalizer_meta.raw_data.boefje_meta.input_ooi # No input OOI means no deletion propagation + and not (results.observations or results.declarations or results.affirmations) + ): + # There were no results found, which we still need to signal to Octopoes for deletion propagation + + connector.save_observation( + Observation( + method=normalizer_meta.normalizer.id, + source=Reference.from_str(normalizer_meta.raw_data.boefje_meta.input_ooi), + source_method=normalizer_meta.raw_data.boefje_meta.boefje.id, + task_id=normalizer_meta.id, + valid_time=normalizer_meta.raw_data.boefje_meta.ended_at, + result=[], + ) + ) + corrected_scan_profiles = [] for profile in results.scan_profiles: profile.level = ScanLevel( From b098d8d2ee2f7bdbb4c7d98e7125ae3c16f43bd7 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:13:48 +0200 Subject: [PATCH 09/82] Fix enabling normalizers from Rocky (#3481) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- rocky/katalogus/client.py | 12 ++--- .../katalogus/views/plugin_enable_disable.py | 49 ++----------------- rocky/katalogus/views/plugin_settings_add.py | 2 +- rocky/rocky/locale/django.pot | 10 +--- 4 files changed, 11 insertions(+), 62 deletions(-) diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index 8bb9f7fc463..ebb614b0b9e 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -169,14 +169,14 @@ def get_normalizers(self) -> list[Plugin]: def get_boefjes(self) -> list[Plugin]: return self.get_plugins(plugin_type="boefje") - def enable_boefje(self, plugin: Plugin) -> None: - self._patch_boefje_state(plugin.id, True) + def enable_plugin(self, plugin: Plugin) -> None: + self._patch_plugin_state(plugin.id, True) def enable_boefje_by_id(self, boefje_id: str) -> None: - self.enable_boefje(self.get_plugin(boefje_id)) + self.enable_plugin(self.get_plugin(boefje_id)) - def disable_boefje(self, plugin: Plugin) -> None: - self._patch_boefje_state(plugin.id, False) + def disable_plugin(self, plugin: Plugin) -> None: + self._patch_plugin_state(plugin.id, False) def get_enabled_boefjes(self) -> list[Plugin]: return [plugin for plugin in self.get_boefjes() if plugin.enabled] @@ -184,7 +184,7 @@ def get_enabled_boefjes(self) -> list[Plugin]: def get_enabled_normalizers(self) -> list[Plugin]: return [plugin for plugin in self.get_normalizers() if plugin.enabled] - def _patch_boefje_state(self, boefje_id: str, enabled: bool) -> None: + def _patch_plugin_state(self, boefje_id: str, enabled: bool) -> None: logger.info("Toggle plugin state", plugin_id=boefje_id, enabled=enabled) response = self.session.patch( diff --git a/rocky/katalogus/views/plugin_enable_disable.py b/rocky/katalogus/views/plugin_enable_disable.py index 36db033e530..81b3d7ce36f 100644 --- a/rocky/katalogus/views/plugin_enable_disable.py +++ b/rocky/katalogus/views/plugin_enable_disable.py @@ -1,24 +1,16 @@ from django.contrib import messages from django.http import HttpResponseRedirect -from django.shortcuts import redirect -from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from httpx import HTTPError from katalogus.views.mixins import SinglePluginView class PluginEnableDisableView(SinglePluginView): - def check_required_settings(self, settings: dict): - if self.plugin_schema is None or "required" not in self.plugin_schema: - return True - - return all([field in settings for field in self.plugin_schema["required"]]) - def post(self, request, *args, **kwargs): plugin_state = kwargs["plugin_state"] + if plugin_state == "True": - self.katalogus_client.disable_boefje(self.plugin) + self.katalogus_client.disable_plugin(self.plugin) messages.add_message( self.request, messages.WARNING, @@ -26,43 +18,8 @@ def post(self, request, *args, **kwargs): ) return HttpResponseRedirect(request.POST.get("current_url")) - try: - plugin_settings = self.katalogus_client.get_plugin_settings(self.plugin.id) - except HTTPError: - messages.add_message( - self.request, - messages.ERROR, - _("Failed fetching settings for {}. Is the Katalogus up?").format(self.plugin.name), - ) - return redirect( - reverse( - "boefje_detail", - kwargs={ - "organization_code": self.organization.code, - "plugin_id": self.plugin.id, - }, - ) - ) - - if not self.check_required_settings(plugin_settings): - messages.add_message( - self.request, - messages.INFO, - _("Before enabling, please set the required settings for '{}'.").format(self.plugin.name), - ) - return redirect( - reverse( - "plugin_settings_add", - kwargs={ - "organization_code": self.organization.code, - "plugin_id": self.plugin.id, - "plugin_type": self.plugin.type, - }, - ) - ) - if self.plugin.can_scan(self.organization_member): - self.katalogus_client.enable_boefje(self.plugin) + self.katalogus_client.enable_plugin(self.plugin) messages.add_message( self.request, messages.SUCCESS, diff --git a/rocky/katalogus/views/plugin_settings_add.py b/rocky/katalogus/views/plugin_settings_add.py index 47842b284a5..f89921025cd 100644 --- a/rocky/katalogus/views/plugin_settings_add.py +++ b/rocky/katalogus/views/plugin_settings_add.py @@ -54,7 +54,7 @@ def form_valid(self, form): if "add-enable" in self.request.POST: try: - self.katalogus_client.enable_boefje(self.plugin) + self.katalogus_client.enable_plugin(self.plugin) except HTTPError: messages.add_message(self.request, messages.ERROR, _("Enabling {} failed").format(self.plugin.name)) return redirect(self.get_success_url()) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 8d7603aad8a..84889204c77 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-09-05 08:44+0000\n" +"POT-Creation-Date: 2024-09-06 08:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1198,14 +1198,6 @@ msgstr "" msgid "{} '{}' disabled." msgstr "" -#: katalogus/views/plugin_enable_disable.py -msgid "Failed fetching settings for {}. Is the Katalogus up?" -msgstr "" - -#: katalogus/views/plugin_enable_disable.py -msgid "Before enabling, please set the required settings for '{}'." -msgstr "" - #: katalogus/views/plugin_enable_disable.py msgid "{} '{}' enabled." msgstr "" From 60283ac02e142055e5ceadb858cf4d3c398e983e Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:13:18 +0200 Subject: [PATCH 10/82] Feature/upload multiple files at once to bytes (#3476) Signed-off-by: Donny Peeters Co-authored-by: ammar92 --- boefjes/boefjes/clients/bytes_client.py | 23 +++-- bytes/bytes/api/models.py | 14 +++- bytes/bytes/api/router.py | 97 +++++++++++++--------- bytes/bytes/models.py | 10 ++- bytes/tests/client.py | 31 +++++-- bytes/tests/integration/test_bytes_api.py | 49 +++++++++-- bytes/tests/integration/test_migrations.py | 6 +- bytes/tests/unit/test_context_mapping.py | 2 +- rocky/rocky/bytes_client.py | 19 ++++- 9 files changed, 179 insertions(+), 72 deletions(-) diff --git a/boefjes/boefjes/clients/bytes_client.py b/boefjes/boefjes/clients/bytes_client.py index c2698523183..b7b66bbc272 100644 --- a/boefjes/boefjes/clients/bytes_client.py +++ b/boefjes/boefjes/clients/bytes_client.py @@ -1,5 +1,6 @@ import typing import uuid +from base64 import b64encode from collections.abc import Callable, Set from functools import wraps from typing import Any @@ -99,17 +100,25 @@ def get_normalizer_meta(self, normalizer_meta_id: uuid.UUID) -> NormalizerMeta: @retry_with_login def save_raw(self, boefje_meta_id: str, raw: str | bytes, mime_types: Set[str] = frozenset()) -> UUID: - headers = {"content-type": "application/octet-stream"} - headers.update(self.headers) + file_name = "raw" # The name provides a key for all ids returned, so this is arbitrary as we only upload 1 file + response = self._session.post( "/bytes/raw", - content=raw, - headers=headers, - params={"mime_types": list(mime_types), "boefje_meta_id": boefje_meta_id}, + json={ + "files": [ + { + "name": file_name, + "content": b64encode(raw if isinstance(raw, bytes) else raw.encode()).decode(), + "tags": list(mime_types), + } + ] + }, + headers=self.headers, + params={"boefje_meta_id": str(boefje_meta_id)}, ) - self._verify_response(response) - return UUID(response.json()["id"]) + + return UUID(response.json()[file_name]) @retry_with_login def get_raw(self, raw_data_id: str) -> bytes: diff --git a/bytes/bytes/api/models.py b/bytes/bytes/api/models.py index af77cb82fc6..fddfc0dc4a3 100644 --- a/bytes/bytes/api/models.py +++ b/bytes/bytes/api/models.py @@ -1,7 +1,17 @@ -from pydantic import BaseModel +from pydantic import BaseModel, Field class RawResponse(BaseModel): status: str message: str - id: str | None = None + ids: list[str] | None = None + + +class File(BaseModel): + name: str + content: str = Field(..., contentEncoding="base64") + tags: list[str] = Field(default_factory=list) + + +class BoefjeOutput(BaseModel): + files: list[File] = Field(default_factory=list) diff --git a/bytes/bytes/api/router.py b/bytes/bytes/api/router.py index e88efc6cc06..394f0e959b4 100644 --- a/bytes/bytes/api/router.py +++ b/bytes/bytes/api/router.py @@ -1,13 +1,14 @@ +from base64 import b64decode from uuid import UUID import structlog -from asgiref.sync import async_to_sync from cachetools import TTLCache, cached -from fastapi import APIRouter, Depends, HTTPException, Query, Request +from fastapi import APIRouter, Depends, HTTPException, Query from fastapi.responses import Response +from httpx import codes from starlette.responses import JSONResponse -from bytes.api.models import RawResponse +from bytes.api.models import BoefjeOutput from bytes.auth import authenticate_token from bytes.config import get_settings from bytes.database.sql_meta_repository import MetaIntegrityError, ObjectNotFoundException, create_meta_data_repository @@ -34,10 +35,11 @@ def create_boefje_meta( meta_repository.save_boefje_meta(boefje_meta) except MetaIntegrityError: return JSONResponse( - {"status": "failed", "message": "Integrity error: object might already exist"}, status_code=400 + {"status": "failed", "message": "Integrity error: object might already exist"}, + status_code=codes.BAD_REQUEST, ) - return JSONResponse({"status": "success"}, status_code=201) + return JSONResponse({"status": "success"}, status_code=codes.CREATED) @router.get("/boefje_meta/{boefje_meta_id}", response_model=BoefjeMeta, tags=[BOEFJE_META_TAG]) @@ -95,10 +97,11 @@ def create_normalizer_meta( meta_repository.save_normalizer_meta(normalizer_meta) except MetaIntegrityError: return JSONResponse( - {"status": "failed", "message": "Integrity error: object might already exist"}, status_code=400 + {"status": "failed", "message": "Integrity error: object might already exist"}, + status_code=codes.BAD_REQUEST, ) - return JSONResponse({"status": "success"}, status_code=201) + return JSONResponse({"status": "success"}, status_code=codes.CREATED) @router.get("/normalizer_meta/{normalizer_meta_id}", response_model=NormalizerMeta, tags=[NORMALIZER_META_TAG]) @@ -109,7 +112,7 @@ def get_normalizer_meta_by_id( try: return meta_repository.get_normalizer_meta_by_id(normalizer_meta_id) except ObjectNotFoundException as error: - raise HTTPException(status_code=404, detail="Normalizer meta not found") from error + raise HTTPException(status_code=codes.NOT_FOUND, detail="Normalizer meta not found") from error @router.get("/normalizer_meta", response_model=list[NormalizerMeta], tags=[NORMALIZER_META_TAG]) @@ -148,42 +151,60 @@ def get_normalizer_meta( @router.post("/raw", tags=[RAW_TAG]) def create_raw( - request: Request, boefje_meta_id: UUID, - mime_types: list[str] | None = Query(None), + boefje_output: BoefjeOutput, meta_repository: MetaDataRepository = Depends(create_meta_data_repository), event_manager: EventManager = Depends(create_event_manager), -) -> RawResponse: - parsed_mime_types = [] if mime_types is None else [MimeType(value=mime_type) for mime_type in mime_types] +) -> dict[str, UUID]: + """Parse all the raw files from the request and return the ids. The ids are ordered according to the order from the + request data, but we assume the `name` field is unique, and hence return a mapping of the file name to the id.""" - try: - meta = meta_repository.get_boefje_meta_by_id(boefje_meta_id) + raw_ids = {} + mime_types_by_id = { + raw.id: set(raw.mime_types) for raw in meta_repository.get_raw(RawDataFilter(boefje_meta_id=boefje_meta_id)) + } + all_parsed_mime_types = list(mime_types_by_id.values()) - if meta_repository.has_raw(meta, parsed_mime_types): - return RawResponse(status="success", message="Raw data already present") + for raw in boefje_output.files: + parsed_mime_types = {MimeType(value=x) for x in raw.tags} - # FastAPI/starlette only has async versions of the Request methods, but - # all our code is sync, so we wrap it in async_to_sync. - data = async_to_sync(request.body)() + if parsed_mime_types in mime_types_by_id.values(): + # Set the id for this file using the precomputed dict that maps existing primary keys to the mime-type set. + raw_ids[raw.name] = list(mime_types_by_id.keys())[list(mime_types_by_id.values()).index(parsed_mime_types)] - raw_data = RawData(value=data, boefje_meta=meta, mime_types=parsed_mime_types) - with meta_repository: - raw_id = meta_repository.save_raw(raw_data) - - event = RawFileReceived( - organization=meta.organization, - raw_data=RawDataMeta( - id=raw_id, - boefje_meta=raw_data.boefje_meta, - mime_types=raw_data.mime_types, - ), - ) - event_manager.publish(event) - except Exception as error: - logger.exception("Error saving raw data") - raise HTTPException(status_code=500, detail="Could not save raw data") from error + continue + + if parsed_mime_types in all_parsed_mime_types: + raise HTTPException( + status_code=codes.BAD_REQUEST, detail="Content types do not define unique sets of mime types." + ) + + try: + meta = meta_repository.get_boefje_meta_by_id(boefje_meta_id) + raw_data = RawData(value=b64decode(raw.content.encode()), boefje_meta=meta, mime_types=parsed_mime_types) + + with meta_repository: + raw_id = meta_repository.save_raw(raw_data) + raw_ids[raw.name] = raw_id + + all_parsed_mime_types.append(parsed_mime_types) + + event = RawFileReceived( + organization=meta.organization, + raw_data=RawDataMeta( + id=raw_id, + boefje_meta=raw_data.boefje_meta, + mime_types=raw_data.mime_types, + ), + ) + event_manager.publish(event) + except Exception as error: + logger.exception("Error saving raw data") + raise HTTPException(status_code=codes.INTERNAL_SERVER_ERROR, detail="Could not save raw data") from error + + all_parsed_mime_types.append(parsed_mime_types) - return RawResponse(status="success", message="Raw data saved", id=raw_id) + return raw_ids @router.get("/raw/{raw_id}", tags=[RAW_TAG]) @@ -194,7 +215,7 @@ def get_raw_by_id( try: raw_data = meta_repository.get_raw_by_id(raw_id) except ObjectNotFoundException as error: - raise HTTPException(status_code=404, detail="No raw data found") from error + raise HTTPException(status_code=codes.NOT_FOUND, detail="No raw data found") from error return Response(raw_data.value, media_type="application/octet-stream") @@ -207,7 +228,7 @@ def get_raw_meta_by_id( try: raw_meta = meta_repository.get_raw_meta_by_id(raw_id) except ObjectNotFoundException as error: - raise HTTPException(status_code=404, detail="No raw data found") from error + raise HTTPException(status_code=codes.NOT_FOUND, detail="No raw data found") from error return raw_meta diff --git a/bytes/bytes/models.py b/bytes/bytes/models.py index ce8cfcd08be..03ae39506aa 100644 --- a/bytes/bytes/models.py +++ b/bytes/bytes/models.py @@ -38,6 +38,12 @@ def _validate_timezone_aware_datetime(value: datetime) -> datetime: class MimeType(BaseModel): value: str + def __hash__(self): + return hash(self.value) + + def __lt__(self, other: MimeType): + return self.value < other.value + class Job(BaseModel): id: UUID @@ -69,7 +75,7 @@ class RawDataMeta(BaseModel): id: UUID boefje_meta: BoefjeMeta - mime_types: list[MimeType] = Field(default_factory=list) + mime_types: set[MimeType] = Field(default_factory=set) # These are set once the raw is saved secure_hash: SecureHash | None = None @@ -80,7 +86,7 @@ class RawDataMeta(BaseModel): class RawData(BaseModel): value: bytes boefje_meta: BoefjeMeta - mime_types: list[MimeType] = Field(default_factory=list) + mime_types: set[MimeType] = Field(default_factory=set) # These are set once the raw is saved secure_hash: SecureHash | None = None diff --git a/bytes/tests/client.py b/bytes/tests/client.py index 6996d1e821b..22405c75ffc 100644 --- a/bytes/tests/client.py +++ b/bytes/tests/client.py @@ -1,4 +1,5 @@ import typing +from base64 import b64encode from collections.abc import Callable from functools import wraps from typing import Any @@ -7,6 +8,7 @@ import httpx from httpx import HTTPError +from bytes.api.models import BoefjeOutput from bytes.models import BoefjeMeta, NormalizerMeta from bytes.repositories.meta_repository import BoefjeMetaFilter, NormalizerMetaFilter, RawDataFilter @@ -126,19 +128,34 @@ def save_raw(self, boefje_meta_id: UUID, raw: bytes, mime_types: list[str] | Non if not mime_types: mime_types = [] - headers = {"content-type": "application/octet-stream"} - + file_name = "raw" # The name provides a key for all ids returned, so this is arbitrary as we only upload 1 file response = self.client.post( "/bytes/raw", - content=raw, - headers=headers, - params={"mime_types": mime_types, "boefje_meta_id": str(boefje_meta_id)}, + json={ + "files": [ + { + "name": file_name, + "content": b64encode(raw).decode(), + "tags": mime_types, + } + ], + }, + params={"boefje_meta_id": str(boefje_meta_id)}, ) + self._verify_response(response) + return response.json()[file_name] + + @retry_with_login + def save_raws(self, boefje_meta_id: UUID, boefje_output: BoefjeOutput) -> dict[str, str]: + response = self.client.post( + "/bytes/raw", + content=boefje_output.model_dump_json(), + params={"boefje_meta_id": str(boefje_meta_id)}, + ) self._verify_response(response) - raw_id = response.json()["id"] - return str(raw_id) + return response.json() @retry_with_login def get_raw(self, raw_id: UUID) -> bytes: diff --git a/bytes/tests/integration/test_bytes_api.py b/bytes/tests/integration/test_bytes_api.py index 95122aaeea0..afc34ec75bd 100644 --- a/bytes/tests/integration/test_bytes_api.py +++ b/bytes/tests/integration/test_bytes_api.py @@ -1,10 +1,12 @@ import uuid +from base64 import b64encode import httpx import pytest from httpx import HTTPError from prometheus_client.parser import text_string_to_metric_families +from bytes.api.models import BoefjeOutput, File from bytes.models import MimeType from bytes.rabbitmq import RabbitMQEventManager from bytes.repositories.meta_repository import BoefjeMetaFilter, NormalizerMetaFilter, RawDataFilter @@ -147,7 +149,10 @@ def test_normalizer_meta(bytes_api_client: BytesAPIClient, event_manager: Rabbit normalizer_meta.raw_data.hash_retrieval_link = retrieved_normalizer_meta.raw_data.hash_retrieval_link normalizer_meta.raw_data.signing_provider_url = retrieved_normalizer_meta.raw_data.signing_provider_url - assert normalizer_meta.dict() == retrieved_normalizer_meta.dict() + normalizer_meta.raw_data.mime_types = sorted(normalizer_meta.raw_data.mime_types) + retrieved_normalizer_meta.raw_data.mime_types = sorted(retrieved_normalizer_meta.raw_data.mime_types) + + assert normalizer_meta.model_dump_json() == retrieved_normalizer_meta.model_dump_json() def test_filtered_normalizer_meta(bytes_api_client: BytesAPIClient) -> None: @@ -255,21 +260,30 @@ def test_save_raw_no_mime_types(bytes_api_client: BytesAPIClient) -> None: boefje_meta = get_boefje_meta(meta_id=uuid.uuid4()) bytes_api_client.save_boefje_meta(boefje_meta) - headers = {"content-type": "application/octet-stream"} bytes_api_client.login() - headers.update(bytes_api_client.client.headers) raw_url = f"{bytes_api_client.client.base_url}/bytes/raw" raw = b"second test 123456" + file_name = "raw" response = httpx.post( - raw_url, content=raw, headers=headers, params={"boefje_meta_id": str(boefje_meta.id)}, timeout=30 + raw_url, + json={ + "files": [ + { + "name": file_name, + "content": b64encode(raw).decode(), + "tags": [], + } + ] + }, + headers=bytes_api_client.client.headers, + params={"boefje_meta_id": str(boefje_meta.id)}, ) - assert response.status_code == 200 get_raw_without_mime_type_response = httpx.get( - f"{raw_url}/{response.json().get('id')}", headers=bytes_api_client.client.headers, timeout=30 + f"{raw_url}/{response.json()[file_name]}", headers=bytes_api_client.client.headers, timeout=30 ) assert get_raw_without_mime_type_response.status_code == 200 @@ -293,13 +307,13 @@ def test_raw_mimes(bytes_api_client: BytesAPIClient) -> None: ) ) assert len(retrieved_raws) == 1 - assert retrieved_raws[0]["mime_types"] == [{"value": value} for value in mime_types] + assert {x["value"] for x in retrieved_raws[0]["mime_types"]} == set(mime_types) retrieved_raws = bytes_api_client.get_raws( RawDataFilter(boefje_meta_id=boefje_meta.id, normalized=False, mime_types=[MimeType(value="text/html")]) ) assert len(retrieved_raws) == 1 - assert retrieved_raws[0]["mime_types"] == [{"value": value} for value in mime_types] + assert {x["value"] for x in retrieved_raws[0]["mime_types"]} == set(mime_types) retrieved_raws = bytes_api_client.get_raws( RawDataFilter(boefje_meta_id=boefje_meta.id, normalized=False, mime_types=[MimeType(value="bad/mime")]) @@ -336,3 +350,22 @@ def test_cannot_overwrite_raw(bytes_api_client: BytesAPIClient) -> None: retrieved_raw = bytes_api_client.get_raw(first_raw_id) assert retrieved_raw == right_raw + + +def test_save_multiple_raw_files(bytes_api_client: BytesAPIClient) -> None: + boefje_meta = get_boefje_meta() + bytes_api_client.save_boefje_meta(boefje_meta) + + first_raw = b"first" + second_raw = b"second" + boefje_output = BoefjeOutput( + files=[ + File(name="first", content=b64encode(first_raw).decode(), tags=[]), + File(name="second", content=b64encode(second_raw).decode(), tags=["mime", "type"]), + ] + ) + + ids = bytes_api_client.save_raws(boefje_meta.id, boefje_output) + + assert bytes_api_client.get_raw(ids["first"]) == first_raw + assert bytes_api_client.get_raw(ids["second"]) == second_raw diff --git a/bytes/tests/integration/test_migrations.py b/bytes/tests/integration/test_migrations.py index eb3a29c0c4f..4967d847470 100644 --- a/bytes/tests/integration/test_migrations.py +++ b/bytes/tests/integration/test_migrations.py @@ -13,15 +13,15 @@ def test_clean_mime_types(meta_repository: SQLMetaDataRepository) -> None: meta_repository.save_boefje_meta(boefje_meta) raw = get_raw_data() - raw.mime_types.append(MimeType(value=raw.boefje_meta.boefje.id)) + raw.mime_types.add(MimeType(value=raw.boefje_meta.boefje.id)) raw_id_1 = meta_repository.save_raw(raw) - raw.mime_types.append( + raw.mime_types.add( MimeType(value=f"boefje/{raw.boefje_meta.boefje.id}-ce293f79fd3c809a300a2837bb1da4f7115fc034a1f78") ) raw_id_2 = meta_repository.save_raw(raw) - raw.mime_types.append( + raw.mime_types.add( MimeType(value=f"boefje/{raw.boefje_meta.boefje.id}-ba293f79fd3c809a300a2837bb1da4f7115fc034a1f78") ) raw_id_3 = meta_repository.save_raw(raw) diff --git a/bytes/tests/unit/test_context_mapping.py b/bytes/tests/unit/test_context_mapping.py index 62f303f2c46..61147f84414 100644 --- a/bytes/tests/unit/test_context_mapping.py +++ b/bytes/tests/unit/test_context_mapping.py @@ -62,7 +62,7 @@ def test_context_mapping_raw() -> None: assert raw_data.hash_retrieval_link == raw_data_in_db.hash_retrieval_link assert raw_data.secure_hash == raw_data_in_db.secure_hash assert raw_data.signing_provider_url is None - assert raw_data.mime_types == [to_mime_type(mime_type) for mime_type in raw_data_in_db.mime_types] + assert raw_data.mime_types == {to_mime_type(mime_type) for mime_type in raw_data_in_db.mime_types} raw_data_new = to_raw_data(raw_data_in_db, raw_data.value) diff --git a/rocky/rocky/bytes_client.py b/rocky/rocky/bytes_client.py index 837d586ebc9..9ddd97ff9d7 100644 --- a/rocky/rocky/bytes_client.py +++ b/rocky/rocky/bytes_client.py @@ -1,4 +1,5 @@ import uuid +from base64 import b64encode from collections.abc import Set from datetime import datetime, timezone @@ -113,15 +114,25 @@ def _save_normalizer_meta(self, normalizer_meta: NormalizerMeta) -> None: response.raise_for_status() def _save_raw(self, boefje_meta_id: uuid.UUID, raw: bytes, mime_types: Set[str] = frozenset()) -> str: + file_name = "raw" # The name provides a key for all ids returned, so this is arbitrary as we only upload 1 file + response = self.session.post( "/bytes/raw", - content=raw, - headers={"content-type": "application/octet-stream"}, - params={"mime_types": list(mime_types), "boefje_meta_id": str(boefje_meta_id)}, + json={ + "files": [ + { + "name": file_name, + "content": b64encode(raw).decode(), + "tags": list(mime_types), + } + ] + }, + params={"boefje_meta_id": str(boefje_meta_id)}, ) response.raise_for_status() - return response.json()["id"] + + return response.json()[file_name] def get_raw(self, raw_id: str) -> bytes: # Note: we assume organization permissions are handled before requesting raw data. From ba809d0ce61c3a0f28940c97bd048582c657481a Mon Sep 17 00:00:00 2001 From: JP Bruins Slot Date: Tue, 10 Sep 2024 14:19:56 +0200 Subject: [PATCH 11/82] Add report scheduler functionality to scheduler (#3352) Co-authored-by: ammar92 Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Co-authored-by: Jan Klopper --- mula/scheduler/app.py | 22 ++- mula/scheduler/models/__init__.py | 2 +- mula/scheduler/models/task.py | 13 +- mula/scheduler/schedulers/__init__.py | 1 + mula/scheduler/schedulers/report.py | 162 ++++++++++++++++++ mula/scheduler/server/handlers/schedules.py | 2 + mula/tests/integration/test_api.py | 11 ++ mula/tests/integration/test_app.py | 22 +-- .../integration/test_report_scheduler.py | 162 ++++++++++++++++++ 9 files changed, 383 insertions(+), 14 deletions(-) create mode 100644 mula/scheduler/schedulers/report.py create mode 100644 mula/tests/integration/test_report_scheduler.py diff --git a/mula/scheduler/app.py b/mula/scheduler/app.py index 4e0836bed12..833cb3ec2f5 100644 --- a/mula/scheduler/app.py +++ b/mula/scheduler/app.py @@ -60,7 +60,10 @@ def __init__(self, ctx: context.AppContext) -> None: self.schedulers: dict[ str, - schedulers.Scheduler | schedulers.BoefjeScheduler | schedulers.NormalizerScheduler, + schedulers.Scheduler + | schedulers.BoefjeScheduler + | schedulers.NormalizerScheduler + | schedulers.ReportScheduler, ] = {} self.server: server.Server | None = None @@ -136,12 +139,21 @@ def monitor_organisations(self) -> None: callback=self.remove_scheduler, ) + scheduler_report = schedulers.ReportScheduler( + ctx=self.ctx, + scheduler_id=f"report-{org.id}", + organisation=org, + callback=self.remove_scheduler, + ) + with self.lock: self.schedulers[scheduler_boefje.scheduler_id] = scheduler_boefje self.schedulers[scheduler_normalizer.scheduler_id] = scheduler_normalizer + self.schedulers[scheduler_report.scheduler_id] = scheduler_report scheduler_normalizer.run() scheduler_boefje.run() + scheduler_report.run() if additions: # Flush katalogus caches when new organisations are added @@ -201,6 +213,14 @@ def start_schedulers(self) -> None: ) self.schedulers[normalizer_scheduler.scheduler_id] = normalizer_scheduler + report_scheduler = schedulers.ReportScheduler( + ctx=self.ctx, + scheduler_id=f"report-{org.id}", + organisation=org, + callback=self.remove_scheduler, + ) + self.schedulers[report_scheduler.scheduler_id] = report_scheduler + # Start schedulers for scheduler in self.schedulers.values(): scheduler.run() diff --git a/mula/scheduler/models/__init__.py b/mula/scheduler/models/__init__.py index ed1a7fa177a..a5390ad6ede 100644 --- a/mula/scheduler/models/__init__.py +++ b/mula/scheduler/models/__init__.py @@ -9,4 +9,4 @@ from .queue import Queue from .schedule import Schedule, ScheduleDB from .scheduler import Scheduler -from .task import BoefjeTask, NormalizerTask, Task, TaskDB, TaskStatus +from .task import BoefjeTask, NormalizerTask, ReportTask, Task, TaskDB, TaskStatus diff --git a/mula/scheduler/models/task.py b/mula/scheduler/models/task.py index cf0c9a95834..76c51ad2e79 100644 --- a/mula/scheduler/models/task.py +++ b/mula/scheduler/models/task.py @@ -59,7 +59,7 @@ class Task(BaseModel): hash: str | None = Field(None, max_length=32) - data: dict | None = None + data: dict = Field(default_factory=dict) created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) @@ -143,3 +143,14 @@ def hash(self) -> str: return mmh3.hash_bytes(f"{self.input_ooi}-{self.boefje.id}-{self.organization}").hex() return mmh3.hash_bytes(f"{self.boefje.id}-{self.organization}").hex() + + +class ReportTask(BaseModel): + type: ClassVar[str] = "report" + + organisation_id: str + report_recipe_id: str + + @property + def hash(self) -> str: + return mmh3.hash_bytes(f"{self.report_recipe_id}-{self.organisation_id}").hex() diff --git a/mula/scheduler/schedulers/__init__.py b/mula/scheduler/schedulers/__init__.py index 5614508b532..4c82914aee5 100644 --- a/mula/scheduler/schedulers/__init__.py +++ b/mula/scheduler/schedulers/__init__.py @@ -1,3 +1,4 @@ from .boefje import BoefjeScheduler from .normalizer import NormalizerScheduler +from .report import ReportScheduler from .scheduler import Scheduler diff --git a/mula/scheduler/schedulers/report.py b/mula/scheduler/schedulers/report.py new file mode 100644 index 00000000000..b76d79a13b7 --- /dev/null +++ b/mula/scheduler/schedulers/report.py @@ -0,0 +1,162 @@ +from collections.abc import Callable +from concurrent import futures +from datetime import datetime, timezone +from typing import Any + +import structlog +from opentelemetry import trace + +from scheduler import context, queues, storage +from scheduler.models import Organisation, ReportTask, Task +from scheduler.storage import filters + +from .scheduler import Scheduler + +tracer = trace.get_tracer(__name__) + + +class ReportScheduler(Scheduler): + ITEM_TYPE: Any = ReportTask + + def __init__( + self, + ctx: context.AppContext, + scheduler_id: str, + organisation: Organisation, + queue: queues.PriorityQueue | None = None, + callback: Callable[..., None] | None = None, + ): + self.logger: structlog.BoundLogger = structlog.get_logger(__name__) + self.organisation = organisation + self.create_schedule = False + + self.queue = queue or queues.PriorityQueue( + pq_id=scheduler_id, + maxsize=ctx.config.pq_maxsize, + item_type=self.ITEM_TYPE, + allow_priority_updates=True, + pq_store=ctx.datastores.pq_store, + ) + + super().__init__( + ctx=ctx, + queue=self.queue, + scheduler_id=scheduler_id, + callback=callback, + ) + + def run(self) -> None: + # Rescheduling + self.run_in_thread( + name=f"scheduler-{self.scheduler_id}-reschedule", + target=self.push_tasks_for_rescheduling, + interval=60.0, + ) + + @tracer.start_as_current_span(name="report_push_tasks_for_rescheduling") + def push_tasks_for_rescheduling(self): + if self.queue.full(): + self.logger.warning( + "Report queue is full, not populating with new tasks", + queue_qsize=self.queue.qsize(), + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + ) + return + + try: + schedules, _ = self.ctx.datastores.schedule_store.get_schedules( + filters=filters.FilterRequest( + filters=[ + filters.Filter( + column="scheduler_id", + operator="eq", + value=self.scheduler_id, + ), + filters.Filter( + column="deadline_at", + operator="lt", + value=datetime.now(timezone.utc), + ), + filters.Filter( + column="enabled", + operator="eq", + value=True, + ), + ] + ) + ) + except storage.errors.StorageError as exc_db: + self.logger.error( + "Could not get schedules for rescheduling %s", + self.scheduler_id, + scheduler_id=self.scheduler_id, + organisation_id=self.organisation.id, + exc_info=exc_db, + ) + raise exc_db + + with futures.ThreadPoolExecutor( + thread_name_prefix=f"ReportScheduler-TPE-{self.scheduler_id}-rescheduling" + ) as executor: + for schedule in schedules: + report_task = ReportTask.model_validate(schedule.data) + executor.submit( + self.push_report_task, + report_task, + self.push_tasks_for_rescheduling.__name__, + ) + + def push_report_task(self, report_task: ReportTask, caller: str = "") -> None: + self.logger.debug( + "Pushing report task", + task_hash=report_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + + if self.is_item_on_queue_by_hash(report_task.hash): + self.logger.debug( + "Report task already on queue", + task_hash=report_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + return + + task = Task( + scheduler_id=self.scheduler_id, + priority=int(datetime.now().timestamp()), + type=self.ITEM_TYPE.type, + hash=report_task.hash, + data=report_task.model_dump(), + ) + + try: + self.push_item_to_queue_with_timeout( + task, + self.max_tries, + ) + except queues.QueueFullError: + self.logger.warning( + "Could not add task %s to queue, queue was full", + report_task.hash, + task_hash=report_task.hash, + queue_qsize=self.queue.qsize(), + queue_maxsize=self.queue.maxsize, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) + return + + self.logger.info( + "Report task pushed to queue", + task_id=task.id, + task_hash=report_task.hash, + organisation_id=self.organisation.id, + scheduler_id=self.scheduler_id, + caller=caller, + ) diff --git a/mula/scheduler/server/handlers/schedules.py b/mula/scheduler/server/handlers/schedules.py index 33bd17b5aa3..23e44c638b3 100644 --- a/mula/scheduler/server/handlers/schedules.py +++ b/mula/scheduler/server/handlers/schedules.py @@ -63,6 +63,7 @@ def __init__( def list( self, request: fastapi.Request, + scheduler_id: str | None = None, schedule_hash: str | None = None, enabled: bool | None = None, offset: int = 0, @@ -86,6 +87,7 @@ def list( try: results, count = self.ctx.datastores.schedule_store.get_schedules( + scheduler_id=scheduler_id, schedule_hash=schedule_hash, enabled=enabled, min_deadline_at=min_deadline_at, diff --git a/mula/tests/integration/test_api.py b/mula/tests/integration/test_api.py index 9f6440c5801..f72c67705c4 100644 --- a/mula/tests/integration/test_api.py +++ b/mula/tests/integration/test_api.py @@ -837,6 +837,17 @@ def test_list_schedules(self): self.assertEqual(2, response.json()["count"]) self.assertEqual(2, len(response.json()["results"])) + def test_list_schedules_scheduler_id(self): + response = self.client.get(f"/schedules?scheduler_id={self.scheduler.scheduler_id}") + self.assertEqual(200, response.status_code) + self.assertEqual(2, response.json()["count"]) + self.assertEqual(2, len(response.json()["results"])) + + response = self.client.get(f"/schedules?scheduler_id={uuid.uuid4()}") + self.assertEqual(200, response.status_code) + self.assertEqual(0, response.json()["count"]) + self.assertEqual(0, len(response.json()["results"])) + def test_list_schedules_enabled(self): response = self.client.get("/schedules?enabled=true") self.assertEqual(200, response.status_code) diff --git a/mula/tests/integration/test_app.py b/mula/tests/integration/test_app.py index 4fd380ca3ee..0c5ae739c76 100644 --- a/mula/tests/integration/test_app.py +++ b/mula/tests/integration/test_app.py @@ -50,9 +50,9 @@ def test_monitor_orgs_add(self): # Act self.app.monitor_organisations() - # Assert: four schedulers should have been created for two organisations - self.assertEqual(4, len(self.app.schedulers.keys())) - self.assertEqual(4, len(self.app.server.schedulers.keys())) + # Assert: six schedulers should have been created for two organisations + self.assertEqual(6, len(self.app.schedulers.keys())) + self.assertEqual(6, len(self.app.server.schedulers.keys())) scheduler_org_ids = {s.organisation.id for s in self.app.schedulers.values()} self.assertEqual({"org-1", "org-2"}, scheduler_org_ids) @@ -68,9 +68,9 @@ def test_monitor_orgs_remove(self): # Act self.app.monitor_organisations() - # Assert: four schedulers should have been created for two organisations - self.assertEqual(4, len(self.app.schedulers.keys())) - self.assertEqual(4, len(self.app.server.schedulers.keys())) + # Assert: six schedulers should have been created for two organisations + self.assertEqual(6, len(self.app.schedulers.keys())) + self.assertEqual(6, len(self.app.server.schedulers.keys())) scheduler_org_ids = {s.organisation.id for s in self.app.schedulers.values()} self.assertEqual({"org-1", "org-2"}, scheduler_org_ids) @@ -100,9 +100,9 @@ def test_monitor_orgs_add_and_remove(self): # Act self.app.monitor_organisations() - # Assert: four schedulers should have been created for two organisations - self.assertEqual(4, len(self.app.schedulers.keys())) - self.assertEqual(4, len(self.app.server.schedulers.keys())) + # Assert: six schedulers should have been created for two organisations + self.assertEqual(6, len(self.app.schedulers.keys())) + self.assertEqual(6, len(self.app.server.schedulers.keys())) scheduler_org_ids = {s.organisation.id for s in self.app.schedulers.values()} self.assertEqual({"org-1", "org-2"}, scheduler_org_ids) @@ -117,8 +117,8 @@ def test_monitor_orgs_add_and_remove(self): self.app.monitor_organisations() # Assert - self.assertEqual(4, len(self.app.schedulers.keys())) - self.assertEqual(4, len(self.app.server.schedulers.keys())) + self.assertEqual(6, len(self.app.schedulers.keys())) + self.assertEqual(6, len(self.app.server.schedulers.keys())) scheduler_org_ids = {s.organisation.id for s in self.app.schedulers.values()} self.assertEqual({"org-1", "org-3"}, scheduler_org_ids) diff --git a/mula/tests/integration/test_report_scheduler.py b/mula/tests/integration/test_report_scheduler.py new file mode 100644 index 00000000000..f0d93232a47 --- /dev/null +++ b/mula/tests/integration/test_report_scheduler.py @@ -0,0 +1,162 @@ +import unittest +from types import SimpleNamespace +from unittest import mock + +from scheduler import config, models, schedulers, storage + +from tests.factories import OrganisationFactory + + +class ReportSchedulerBaseTestCase(unittest.TestCase): + def setUp(self): + # Application Context + self.mock_ctx = mock.patch("scheduler.context.AppContext").start() + self.mock_ctx.config = config.settings.Settings() + + # Database + self.dbconn = storage.DBConn(str(self.mock_ctx.config.db_uri)) + self.dbconn.connect() + models.Base.metadata.drop_all(self.dbconn.engine) + models.Base.metadata.create_all(self.dbconn.engine) + + self.mock_ctx.datastores = SimpleNamespace( + **{ + storage.TaskStore.name: storage.TaskStore(self.dbconn), + storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn), + storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn), + } + ) + + # Scheduler + self.organisation = OrganisationFactory() + self.scheduler = schedulers.ReportScheduler( + ctx=self.mock_ctx, + scheduler_id=self.organisation.id, + organisation=self.organisation, + ) + + def tearDown(self): + self.scheduler.stop() + models.Base.metadata.drop_all(self.dbconn.engine) + self.dbconn.engine.dispose() + + +class ReportSchedulerTestCase(ReportSchedulerBaseTestCase): + def setUp(self): + super().setUp() + + self.mock_get_schedules = mock.patch( + "scheduler.context.AppContext.datastores.schedule_store.get_schedules", + ).start() + + def tearDown(self): + mock.patch.stopall() + + def test_enable_scheduler(self): + # Disable scheduler first + self.scheduler.disable() + + # Threads should be stopped + self.assertEqual(0, len(self.scheduler.threads)) + + # Queue should be empty + self.assertEqual(0, self.scheduler.queue.qsize()) + + # Re-enable scheduler + self.scheduler.enable() + + # Threads should be started + self.assertGreater(len(self.scheduler.threads), 0) + + # Scheduler should be enabled + self.assertTrue(self.scheduler.is_enabled()) + + # Stop the scheduler + self.scheduler.stop() + + def test_disable_scheduler(self): + # Disable scheduler + self.scheduler.disable() + + # Threads should be stopped + self.assertEqual(0, len(self.scheduler.threads)) + + # Queue should be empty + self.assertEqual(0, self.scheduler.queue.qsize()) + + # Scheduler should be disabled + self.assertFalse(self.scheduler.is_enabled()) + + def test_push_tasks_for_rescheduling(self): + """When the deadline of schedules have passed, the resulting task should be added to the queue""" + # Arrange + report_task = models.ReportTask( + organisation_id=self.organisation.id, + report_recipe_id="123", + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=report_task.hash, + data=report_task.dict(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Mocks + self.mock_get_schedules.return_value = ([schedule_db], 1) + + # Act + self.scheduler.push_tasks_for_rescheduling() + + # Assert: new item should be on queue + self.assertEqual(1, self.scheduler.queue.qsize()) + + # Assert: new item is created with a similar task + peek = self.scheduler.queue.peek(0) + self.assertEqual(schedule.hash, peek.hash) + + # Assert: task should be created, and should be the one that is queued + task_db = self.mock_ctx.datastores.task_store.get_task(peek.id) + self.assertIsNotNone(task_db) + self.assertEqual(peek.id, task_db.id) + + def test_push_tasks_for_rescheduling_item_on_queue(self): + """When the deadline of schedules have passed, the resulting task should be added to the queue""" + # Arrange + report_task = models.ReportTask( + organisation_id=self.organisation.id, + report_recipe_id="123", + ) + + schedule = models.Schedule( + scheduler_id=self.scheduler.scheduler_id, + hash=report_task.hash, + data=report_task.dict(), + ) + + schedule_db = self.mock_ctx.datastores.schedule_store.create_schedule(schedule) + + # Mocks + self.mock_get_schedules.return_value = ([schedule_db], 1) + + # Act + self.scheduler.push_tasks_for_rescheduling() + + # Assert: new item should be on queue + self.assertEqual(1, self.scheduler.queue.qsize()) + + # Assert: new item is created with a similar task + peek = self.scheduler.queue.peek(0) + self.assertEqual(schedule.hash, peek.hash) + + # Assert: task should be created, and should be the one that is queued + task_db = self.mock_ctx.datastores.task_store.get_task(peek.id) + self.assertIsNotNone(task_db) + self.assertEqual(peek.id, task_db.id) + + # Act: push again + self.scheduler.push_tasks_for_rescheduling() + + # Should only be one task on queue + self.assertEqual(1, self.scheduler.queue.qsize()) From 4958776f498b2edc9c54df45293315eea0c1da40 Mon Sep 17 00:00:00 2001 From: Rieven Date: Tue, 10 Sep 2024 16:58:50 +0200 Subject: [PATCH 12/82] Fix report types selection not being overriden (#3436) Co-authored-by: Peter-Paul van Gemerden Co-authored-by: ammar92 Co-authored-by: Jan Klopper --- .../templates/partials/report_types_selection.html | 9 +++++---- rocky/reports/views/aggregate_report.py | 4 ++++ rocky/reports/views/generate_report.py | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/rocky/reports/templates/partials/report_types_selection.html b/rocky/reports/templates/partials/report_types_selection.html index 3c401605847..066add7c640 100644 --- a/rocky/reports/templates/partials/report_types_selection.html +++ b/rocky/reports/templates/partials/report_types_selection.html @@ -14,7 +14,7 @@

{% translate "Choose report types" %}

{% endblocktranslate %}

{% if not selected_oois %} - {% include "partials/return_button.html" with btn_text="Go back" %} + {% include "partials/return_button.html" with btn_text="Go back" selected_report_types=None %} {% else %}

@@ -40,7 +40,7 @@

action="{{ previous }}" class="inline layout-wide"> {% csrf_token %} - {% include "forms/report_form_fields.html" %} + {% include "forms/report_form_fields.html" with selected_report_types=None %} + + + + + + +{% endblock content %} diff --git a/rocky/katalogus/templates/boefjes.html b/rocky/katalogus/templates/boefjes.html index 91c55b0eb4b..445f0d7e9dc 100644 --- a/rocky/katalogus/templates/boefjes.html +++ b/rocky/katalogus/templates/boefjes.html @@ -16,14 +16,21 @@

Boefjes

{% blocktranslate trimmed %} - Boefjes gather factual information, such as by calling an - external scanning tool like nmap or using a database like shodan. + Boefjes are used to scan for objects. They detect vulnerabilities, + security issues, and give insight. Each boefje is a separate scan that + can run on a selection of objects. {% endblocktranslate %}

{{ object_list|length }} Boefje{{ object_list|pluralize:"s" }} {% translate "available" %}

+ {% if perms.tools.can_set_katalogus_settings %} + + {% endif %} {% include "partials/katalogus_filter.html" with form=form %} {% include "partials/katalogus_toolbar.html" %} diff --git a/rocky/katalogus/templates/plugin_container_image.html b/rocky/katalogus/templates/plugin_container_image.html new file mode 100644 index 00000000000..674fcd4a7f4 --- /dev/null +++ b/rocky/katalogus/templates/plugin_container_image.html @@ -0,0 +1,85 @@ +{% load static %} +{% load i18n %} + +
+

{% translate "Container image" %}

+

+ {% translate "The container image for this Boefje is:" %} {{ plugin.oci_image }} +

+
+
+

{% translate "Variants" %}

+

+ {% blocktranslate %} + Boefje variants that use the same container image. For more + information about Boefje variants you can read the documentation. + {% endblocktranslate %} +

+
+ {% if variants %} + + {% endif %} +
+ {% if variants %} +
+
    +
  • + +
    + + + + + + + + + + + + + {% for variant in variants %} + + + + + + + + + + + {% endfor %} + +
    {% translate "Overview of variants" %}
    {% translate "Name" %}{% translate "Scan level" %}{% translate "Published by" %}{% translate "Status" %}
    {{ variant.name }}name{{ variant.scan_level }}scan_level{{ variant.published_by }}published_by{{ variant.status }}status + +
    +
    {% translate "Arguments" %}
    +

    {% translate "The following arguments are used for this Boefje variant." %}

    +
    +

    Some code example

    +
    +
    +
    +
  • +
+
+ {% else %} +

+ {% translate "This Boefje has no variants yet." %} + {% blocktranslate trimmed %} + You can make a variant and change the arguments and JSON Schema + to customize it to fit your needs. + {% endblocktranslate %} +

+ {% endif %} +
diff --git a/rocky/katalogus/templates/plugin_settings_list.html b/rocky/katalogus/templates/plugin_settings_list.html index 3ca5ca51dfb..545d88c229e 100644 --- a/rocky/katalogus/templates/plugin_settings_list.html +++ b/rocky/katalogus/templates/plugin_settings_list.html @@ -2,62 +2,56 @@ {% load i18n %} {% if object_list %} -
-
-

{{ plugin.type|title }}{% translate " Details" %}

-

{% translate "Settings" %}

-
- - - +
+
+
+

{% translate "Settings" %}

+

+ {% blocktranslate %} + In the table below the settings for this specific Boefje can be seen. + Set or change the value of the variables by editing the settings. + {% endblocktranslate %} +

+
+ +
+
+
{% translate "Overview of settings" %}
+ + + + + + + + + + {% for setting in object_list %} - - - - - - - - {% for setting in object_list %} - - - - + + - + - + {% elif setting.secret %} + ••••••••••••• {% else %} - + {{ setting.value }} {% endif %} - - {% endfor %} - -
{% translate "Overview of settings" %}
{% translate "Variable" %}{% translate "Value" %}{% translate "Required" %}
{% translate "Name" %}{% translate "Value" %}{% translate "Required" %}{% translate "Action" %}
{{ setting.name }} - {% if setting.value is None %} - {% translate "Unset" %} - {% elif setting.secret %} - ••••••••••••• - {% else %} - {{ setting.value }} - {% endif %} - - {% if setting.required %} - {% translate "Yes" %} - {% else %} - {% translate "No" %} - {% endif %} - {{ setting.name }} {% if setting.value is None %} - - {% translate "Add" %} - - {% translate "Edit" %} -
-
- {% csrf_token %} - -
-
+ + + {% if setting.required %} + {% translate "Yes" %} + {% else %} + {% translate "No" %} + {% endif %} + + + {% endfor %} + +
-
+ {% endif %} diff --git a/rocky/katalogus/urls.py b/rocky/katalogus/urls.py index 7a254ce01da..90fea04b60d 100644 --- a/rocky/katalogus/urls.py +++ b/rocky/katalogus/urls.py @@ -1,5 +1,6 @@ -from django.urls import path +from django.urls import path, re_path +from katalogus.views.boefje_setup import BoefjeSetupView from katalogus.views.change_clearance_level import ChangeClearanceLevel from katalogus.views.katalogus import ( AboutPluginsView, @@ -32,7 +33,12 @@ name="confirm_clone_settings", ), path( - "plugins/boefjes//", + "plugins/boefjes/add/", + BoefjeSetupView.as_view(), + name="boefje_setup", + ), + re_path( + r"^plugins/boefjes/(?P(grid|table))/$", BoefjeListView.as_view(), name="boefjes_list", ), diff --git a/rocky/katalogus/views/boefje_setup.py b/rocky/katalogus/views/boefje_setup.py new file mode 100644 index 00000000000..18e608c0158 --- /dev/null +++ b/rocky/katalogus/views/boefje_setup.py @@ -0,0 +1,61 @@ +import uuid +from datetime import datetime + +from account.mixins import OrganizationPermissionRequiredMixin, OrganizationView +from django.shortcuts import redirect +from django.urls import reverse +from django.views.generic.edit import FormView +from tools.forms.boefje import BoefjeAddForm + +from katalogus.client import Boefje, get_katalogus +from octopoes.models.types import type_by_name + + +class BoefjeSetupView(OrganizationPermissionRequiredMixin, OrganizationView, FormView): + """View where the user can create a new boefje""" + + template_name = "boefje_setup.html" + form_class = BoefjeAddForm + permission_required = "tools.can_set_katalogus_settings" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context["breadcrumbs"] = [ + {"url": reverse("katalogus", kwargs={"organization_code": self.organization.code}), "text": "KAT-alogus"}, + { + "url": reverse("boefje_setup", kwargs={"organization_code": self.organization.code}), + "text": "Boefje setup", + }, + ] + + return context + + def form_valid(self, form): + """If the form is valid, redirect to the supplied URL.""" + form_data = form.cleaned_data + input_object = {type_by_name(form_data["consumes"])} + arguments = form_data["oci_arguments"].split() + produces = form_data["produces"].replace(",", "").split() + boefje_id = str(uuid.uuid4()) + + boefje = Boefje( + id=boefje_id, + name=form_data["name"] or None, + created=str(datetime.now()), + description=form_data["description"] or None, + enabled=False, + type="boefje", + scan_level=form_data["scan_level"], + consumes=input_object, + produces=produces, + schema=form_data["schema"], + oci_image=form_data["oci_image"] or None, + oci_arguments=arguments, + ) + + get_katalogus(self.organization.code).create_plugin(boefje) + + return redirect( + reverse("boefje_detail", kwargs={"organization_code": self.organization.code, "plugin_id": boefje_id}) + ) diff --git a/rocky/katalogus/views/plugin_settings_list.py b/rocky/katalogus/views/plugin_settings_list.py index f27b16f1d43..90c66269254 100644 --- a/rocky/katalogus/views/plugin_settings_list.py +++ b/rocky/katalogus/views/plugin_settings_list.py @@ -24,7 +24,7 @@ def get_plugin_settings(self) -> list[dict[str, Any]]: return [] settings = self.katalogus_client.get_plugin_settings(plugin_id=self.plugin.id) - props = self.plugin_schema["properties"] + props = self.plugin_schema.get("properties", []) return [ { diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 856c78aeee1..3591cc84059 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -27,13 +27,13 @@ msgid "Important dates" msgstr "" #: account/forms/account_setup.py katalogus/templates/katalogus_settings.html -#: katalogus/templates/plugin_settings_list.html +#: katalogus/templates/plugin_container_image.html #: reports/report_types/dns_report/report.html #: reports/report_types/tls_report/report.html #: reports/templates/partials/export_report_settings.html #: reports/templates/report_overview/report_history_table.html #: reports/templates/report_overview/subreports_table.html -#: rocky/templates/organizations/organization_list.html +#: tools/forms/boefje.py rocky/templates/organizations/organization_list.html #: rocky/templates/organizations/organization_settings.html #: rocky/templates/partials/ooi_detail_related_object.html msgid "Name" @@ -647,8 +647,9 @@ msgstr "" #: katalogus/templates/about_plugins.html katalogus/templates/boefjes.html msgid "" -"Boefjes gather factual information, such as by calling an external scanning " -"tool like nmap or using a database like shodan." +"Boefjes are used to scan for objects. They detect vulnerabilities, security " +"issues, and give insight. Each boefje is a separate scan that can run on a " +"selection of objects." msgstr "" #: katalogus/templates/about_plugins.html katalogus/templates/normalizers.html @@ -665,21 +666,10 @@ msgstr "" #: katalogus/templates/boefje_detail.html #: katalogus/templates/partials/plugin_tile_modal.html +#: katalogus/templates/plugin_container_image.html msgid "Scan level" msgstr "" -#: katalogus/templates/boefje_detail.html -#: katalogus/templates/normalizer_detail.html -#: reports/report_types/aggregate_organisation_report/appendix.html -#: reports/report_types/dns_report/report.html -#: reports/report_types/findings_report/report.html -#: reports/report_types/vulnerability_report/report.html -#: reports/templates/summary/report_asset_overview.html -#: tools/forms/finding_type.py rocky/templates/oois/ooi_detail.html -#: rocky/templates/oois/ooi_detail_findings_list.html rocky/templates/scan.html -msgid "Description" -msgstr "" - #: katalogus/templates/boefje_detail.html #: katalogus/templates/normalizer_detail.html msgid "Consumes" @@ -709,10 +699,42 @@ msgstr "" msgid "%(plugin_name)s can produce the following output:" msgstr "" +#: katalogus/templates/boefje_detail.html +#, python-format +msgid "%(plugin_name)s doesn't produce any output mime types." +msgstr "" + +#: katalogus/templates/boefje_setup.html +msgid "Boefje setup" +msgstr "" + +#: katalogus/templates/boefje_setup.html +msgid "" +"\n" +" You can create a new Boefje. If you want more " +"information on this,\n" +" you can check out the documentation.\n" +" " +msgstr "" + +#: katalogus/templates/boefje_setup.html +msgid "Create variant" +msgstr "" + +#: katalogus/templates/boefje_setup.html +msgid "Discard variant" +msgstr "" + #: katalogus/templates/boefjes.html katalogus/templates/normalizers.html msgid "available" msgstr "" +#: katalogus/templates/boefjes.html +msgid "Add Boefje" +msgstr "" + #: katalogus/templates/change_clearance_level.html #: katalogus/templates/partials/objects_to_scan.html #: reports/templates/partials/report_setup_scan.html @@ -753,8 +775,8 @@ msgstr "" #: katalogus/templates/change_clearance_level.html onboarding/forms.py #: reports/templates/partials/report_ooi_list.html -#: reports/templates/summary/ooi_selection.html tools/forms/ooi.py -#: rocky/templates/oois/ooi_page_tabs.html +#: reports/templates/summary/ooi_selection.html tools/forms/boefje.py +#: tools/forms/ooi.py rocky/templates/oois/ooi_page_tabs.html #: rocky/templates/partials/explanations.html msgid "Clearance level" msgstr "" @@ -837,6 +859,17 @@ msgstr "" msgid "Value" msgstr "" +#: katalogus/templates/normalizer_detail.html +#: reports/report_types/aggregate_organisation_report/appendix.html +#: reports/report_types/dns_report/report.html +#: reports/report_types/findings_report/report.html +#: reports/report_types/vulnerability_report/report.html +#: reports/templates/summary/report_asset_overview.html tools/forms/boefje.py +#: tools/forms/finding_type.py rocky/templates/oois/ooi_detail.html +#: rocky/templates/oois/ooi_detail_findings_list.html rocky/templates/scan.html +msgid "Description" +msgstr "" + #: katalogus/templates/normalizer_detail.html #, python-format msgid "%(plugin_name)s is able to process the following mime types:" @@ -990,7 +1023,6 @@ msgid "Required settings" msgstr "" #: katalogus/templates/partials/plugin_settings_required.html -#: katalogus/templates/plugin_settings_list.html #: rocky/templates/findings/finding_add.html #: rocky/templates/partials/ooi_detail_related_object.html #: rocky/templates/partials/ooi_list_toolbar.html @@ -1064,6 +1096,98 @@ msgstr "" msgid "All" msgstr "" +#: katalogus/templates/plugin_container_image.html tools/forms/boefje.py +msgid "Container image" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "The container image for this Boefje is:" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "Variants" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "" +"\n" +" Boefje variants that use the same container image. For " +"more\n" +" information about Boefje variants you can read the " +"documentation.\n" +" " +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "Add variant" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "Overview of variants" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "Published by" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +#: reports/report_types/tls_report/report.html +#: reports/templates/partials/plugin_overview_table.html +#: rocky/templates/organizations/organization_member_list.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "Status" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +#: reports/report_types/dns_report/report.html +#: reports/report_types/findings_report/report.html +#: reports/report_types/vulnerability_report/report.html +#: rocky/templates/crisis_room/crisis_room_findings_block.html +#: rocky/templates/findings/finding_list.html +#: rocky/templates/organizations/organization_crisis_room.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "Close details" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +#: reports/report_types/dns_report/report.html +#: reports/report_types/findings_report/report.html +#: reports/report_types/vulnerability_report/report.html +#: rocky/templates/crisis_room/crisis_room_findings_block.html +#: rocky/templates/findings/finding_list.html +#: rocky/templates/organizations/organization_crisis_room.html +#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html +#: rocky/templates/tasks/ooi_detail_task_list.html +#: rocky/templates/tasks/plugin_detail_task_list.html +msgid "Open details" +msgstr "" + +#: katalogus/templates/plugin_container_image.html tools/forms/boefje.py +msgid "Arguments" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "The following arguments are used for this Boefje variant." +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "no variants explanation" +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "This Boefje has no variants yet." +msgstr "" + +#: katalogus/templates/plugin_container_image.html +msgid "" +"You can make a variant and change the arguments and JSON Schema to customize " +"it to fit your needs." +msgstr "" + #: katalogus/templates/plugin_settings_add.html msgid "" "\n" @@ -1123,30 +1247,35 @@ msgid "" msgstr "" #: katalogus/templates/plugin_settings_delete.html -#: katalogus/templates/plugin_settings_list.html #: katalogus/views/plugin_settings_delete.py #: rocky/templates/admin/delete_confirmation.html rocky/views/ooi_delete.py msgid "Delete" msgstr "" #: katalogus/templates/plugin_settings_list.html -msgid " Details" +msgid "" +"\n" +" In the table below the settings for this specific " +"Boefje can be seen.\n" +" Set or change the value of the variables by editing " +"the settings.\n" +" " msgstr "" #: katalogus/templates/plugin_settings_list.html -msgid "Overview of settings" +msgid "Edit Settings" msgstr "" #: katalogus/templates/plugin_settings_list.html -msgid "Required" +msgid "Overview of settings" msgstr "" #: katalogus/templates/plugin_settings_list.html -msgid "Action" +msgid "Variable" msgstr "" #: katalogus/templates/plugin_settings_list.html -msgid "Unset" +msgid "Required" msgstr "" #: katalogus/templates/plugin_settings_list.html @@ -1159,13 +1288,6 @@ msgstr "" msgid "No" msgstr "" -#: katalogus/templates/plugin_settings_list.html -#: rocky/templates/organizations/organization_member_list.html -#: rocky/templates/organizations/organization_settings.html -#: rocky/views/ooi_edit.py rocky/views/organization_edit.py -msgid "Edit" -msgstr "" - #: katalogus/views/change_clearance_level.py msgid "Session has terminated, please select objects again." msgstr "" @@ -2731,30 +2853,6 @@ msgstr "" msgid "Details" msgstr "" -#: reports/report_types/dns_report/report.html -#: reports/report_types/findings_report/report.html -#: reports/report_types/vulnerability_report/report.html -#: rocky/templates/crisis_room/crisis_room_findings_block.html -#: rocky/templates/findings/finding_list.html -#: rocky/templates/organizations/organization_crisis_room.html -#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html -#: rocky/templates/tasks/ooi_detail_task_list.html -#: rocky/templates/tasks/plugin_detail_task_list.html -msgid "Close details" -msgstr "" - -#: reports/report_types/dns_report/report.html -#: reports/report_types/findings_report/report.html -#: reports/report_types/vulnerability_report/report.html -#: rocky/templates/crisis_room/crisis_room_findings_block.html -#: rocky/templates/findings/finding_list.html -#: rocky/templates/organizations/organization_crisis_room.html -#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html -#: rocky/templates/tasks/ooi_detail_task_list.html -#: rocky/templates/tasks/plugin_detail_task_list.html -msgid "Open details" -msgstr "" - #: reports/report_types/dns_report/report.html msgid "Findings information" msgstr "" @@ -3226,15 +3324,6 @@ msgstr "" msgid "Ciphers" msgstr "" -#: reports/report_types/tls_report/report.html -#: reports/templates/partials/plugin_overview_table.html -#: rocky/templates/organizations/organization_member_list.html -#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html -#: rocky/templates/tasks/ooi_detail_task_list.html -#: rocky/templates/tasks/plugin_detail_task_list.html -msgid "Status" -msgstr "" - #: reports/report_types/tls_report/report.html msgid "Protocol" msgstr "" @@ -4006,6 +4095,18 @@ msgstr "" msgid "The selected date is in the future. Please select a different date." msgstr "" +#: tools/forms/boefje.py +msgid "JSON Schema" +msgstr "" + +#: tools/forms/boefje.py +msgid "Input object type" +msgstr "" + +#: tools/forms/boefje.py +msgid "Output mime types" +msgstr "" + #: tools/forms/finding_type.py msgid "KAT-ID" msgstr "" @@ -4292,6 +4393,47 @@ msgid "" "the view to represent that moment in time." msgstr "" +#: tools/forms/settings.py +msgid "" +"

A description of the boefje explaining in short what it can do. This will " +"both be displayed inside the KAT-alogus and on the Boefje details page.

" +msgstr "" + +#: tools/forms/settings.py +msgid "" +"

If any other settings are needed for your Boefje, add these as a JSON " +"Schema, otherwise, leave the field empty or 'null'.

This JSON is " +"used as the basis for a form for the user. When the user enables this Boefje " +"they can get the option to give extra information. For example, it can " +"contain an API key that the script requires.

More information about " +"what the schema.json file looks like can be found here.

" +msgstr "" + +#: tools/forms/settings.py +msgid "" +"

Select the object type that your Boefje consumes.

This object type " +"triggers the Boefje to run. Whenever this OOI gets added, this Boefje will " +"run with that OOI.

" +msgstr "" + +#: tools/forms/settings.py +msgid "" +"

Add a set of mime types that are produced by this Boefje, separated by " +"commas. For example: 'text/html', 'image/jpeg' or 'boefje/" +"{boefje-id}'

These output mime types will be shown on the Boefje " +"detail page as information for other users.

" +msgstr "" + +#: tools/forms/settings.py +msgid "" +"

Select a clearance level for your Boefje. For more information about the " +"different clearance levels please check the documentation." +"

" +msgstr "" + #: tools/forms/settings.py msgid "Depth of the tree." msgstr "" @@ -5551,6 +5693,12 @@ msgstr "" msgid "Assigned clearance level" msgstr "" +#: rocky/templates/organizations/organization_member_list.html +#: rocky/templates/organizations/organization_settings.html +#: rocky/views/ooi_edit.py rocky/views/organization_edit.py +msgid "Edit" +msgstr "" + #: rocky/templates/organizations/organization_member_list.html msgid "Super user" msgstr "" diff --git a/rocky/rocky/templates/partials/form/field_input.html b/rocky/rocky/templates/partials/form/field_input.html index fcaad77193a..d2d09ec65e7 100644 --- a/rocky/rocky/templates/partials/form/field_input.html +++ b/rocky/rocky/templates/partials/form/field_input.html @@ -1,7 +1,8 @@ {% load i18n %}
- {{ field.label_tag }} +

{{ field.label_tag }}

+

{{ field.field.widget.attrs.description }}

{% if form_view != "vertical" %}
{% if field.field.required %} diff --git a/rocky/rocky/templates/tasks/normalizers.html b/rocky/rocky/templates/tasks/normalizers.html index 340dad142de..90353c04698 100644 --- a/rocky/rocky/templates/tasks/normalizers.html +++ b/rocky/rocky/templates/tasks/normalizers.html @@ -56,7 +56,11 @@

{% translate "Normalizers" %}

{{ task.created_at }} {{ task.modified_at }} - {{ task.data.raw_data.boefje_meta.boefje.id }} + {% if task.data.raw_data.boefje_meta.boefje.name %} + {{ task.data.raw_data.boefje_meta.boefje.name }} + {% else %} + {{ task.data.raw_data.boefje_meta.boefje.id }} + {% endif %} {{ task.data.raw_data.boefje_meta.input_ooi }} diff --git a/rocky/rocky/templates/tasks/plugin_detail_task_list.html b/rocky/rocky/templates/tasks/plugin_detail_task_list.html index 4e0778c4c76..80240a75031 100644 --- a/rocky/rocky/templates/tasks/plugin_detail_task_list.html +++ b/rocky/rocky/templates/tasks/plugin_detail_task_list.html @@ -3,11 +3,9 @@

{% translate "Tasks" %}

{% if not task_list %} -

{% translate "There are no tasks for" %} {{ plugin.name }}

- {% include "tasks/partials/task_filter.html" %} - +

{% translate "There are no tasks for" %} {{ plugin.name }}.

{% else %} -

{% translate "List of tasks for" %} {{ plugin.name }}

+

{% translate "List of tasks for" %} {{ plugin.name }}:

{% include "tasks/partials/task_filter.html" %} diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index e786260e9c8..ac260544261 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -1106,6 +1106,25 @@ def plugin_details(): ) +@pytest.fixture +def plugin_details_with_container(): + return parse_plugin( + { + "id": "test-boefje", + "type": "boefje", + "name": "TestBoefje", + "description": "Meows to the moon", + "scan_level": 1, + "consumes": ["Network"], + "produces": ["Network"], + "enabled": True, + "schema": {}, + "oci_image": "ghcr.io/test/image:123", + "oci_arguments": ["-test", "-arg"], + } + ) + + @pytest.fixture def plugin_schema(): return { diff --git a/rocky/tests/katalogus/test_katalogus_create_boefje.py b/rocky/tests/katalogus/test_katalogus_create_boefje.py new file mode 100644 index 00000000000..8229e375571 --- /dev/null +++ b/rocky/tests/katalogus/test_katalogus_create_boefje.py @@ -0,0 +1,21 @@ +from katalogus.views.boefje_setup import BoefjeSetupView +from pytest_django.asserts import assertContains + +from tests.conftest import setup_request + + +def test_boefje_setup(rf, superuser_member): + request = setup_request(rf.get("boefje_setup"), superuser_member.user) + response = BoefjeSetupView.as_view()(request, organization_code=superuser_member.organization.code) + + assert response.status_code == 200 + assertContains(response, "Boefje setup") + assertContains(response, "Container image") + assertContains(response, "Name") + assertContains(response, "Description") + assertContains(response, "Arguments") + assertContains(response, "JSON Schema") + assertContains(response, "Input object type") + assertContains(response, "Output mime types") + assertContains(response, "Clearance level") + assertContains(response, "Create variant") diff --git a/rocky/tests/katalogus/test_katalogus_plugin_detail.py b/rocky/tests/katalogus/test_katalogus_plugin_detail.py index 1585f32f436..ceeb6d030b4 100644 --- a/rocky/tests/katalogus/test_katalogus_plugin_detail.py +++ b/rocky/tests/katalogus/test_katalogus_plugin_detail.py @@ -1,5 +1,5 @@ from katalogus.views.plugin_detail import BoefjeDetailView -from pytest_django.asserts import assertContains +from pytest_django.asserts import assertContains, assertNotContains from tests.conftest import setup_request @@ -27,6 +27,35 @@ def test_plugin_detail_view( assertContains(response, "Object list") assertContains(response, "Consumes") assertContains(response, plugin_details.description) + assertNotContains(response, "Container image") + assertNotContains(response, "Variants") + + +def test_plugin_detail_view_with_container_image( + rf, + superuser_member, + mock_mixins_katalogus, + plugin_details_with_container, + mock_organization_view_octopoes, + mock_scheduler_client_task_list, +): + mock_mixins_katalogus().get_plugin.return_value = plugin_details_with_container + + request = setup_request(rf.get("boefje_detail"), superuser_member.user) + response = BoefjeDetailView.as_view()( + request, + organization_code=superuser_member.organization.code, + plugin_id="test-plugin", + ) + + assertContains(response, "TestBoefje") + assertContains(response, "Container image") + assertContains(response, "Variants") + assertContains(response, "Produces") + assertContains(response, "Tasks") + assertContains(response, "Object list") + assertContains(response, "Consumes") + assertContains(response, plugin_details_with_container.description) def test_plugin_detail_view_no_consumes( diff --git a/rocky/tools/forms/boefje.py b/rocky/tools/forms/boefje.py new file mode 100644 index 00000000000..e0cdb1ef269 --- /dev/null +++ b/rocky/tools/forms/boefje.py @@ -0,0 +1,67 @@ +from django import forms +from django.utils.translation import gettext_lazy as _ + +from octopoes.models.types import ALL_TYPES +from tools.enums import SCAN_LEVEL +from tools.forms.base import BaseRockyForm +from tools.forms.settings import ( + BOEFJE_CONSUMES_HELP_TEXT, + BOEFJE_DESCRIPTION_HELP_TEXT, + BOEFJE_PRODUCES_HELP_TEXT, + BOEFJE_SCAN_LEVEL_HELP_TEXT, + BOEFJE_SCHEMA_HELP_TEXT, +) + +OOI_TYPE_CHOICES = sorted((ooi_type.get_object_type(), ooi_type.get_object_type()) for ooi_type in ALL_TYPES) + + +class BoefjeAddForm(BaseRockyForm): + oci_image = forms.CharField( + required=True, + label=_("Container image"), + widget=forms.TextInput( + attrs={ + "description": "The name of the Docker image. For example: ghcr.io/minvws/openkat/nmap", + "aria-describedby": "input-description", + } + ), + ) + name = forms.CharField( + required=True, + label=_("Name"), + ) + description = forms.CharField( + required=False, + label=_("Description"), + widget=forms.Textarea(attrs={"rows": 3}), + help_text=BOEFJE_DESCRIPTION_HELP_TEXT, + ) + oci_arguments = forms.CharField( + required=False, + label=_("Arguments"), + widget=forms.TextInput( + attrs={"description": "For example: -sTU --top-ports 1000", "aria-describedby": "input-description"} + ), + ) + schema = forms.JSONField( + required=False, + label=_("JSON Schema"), + help_text=BOEFJE_SCHEMA_HELP_TEXT, + ) + consumes = forms.CharField( + required=False, + label=_("Input object type"), + widget=forms.Select(choices=OOI_TYPE_CHOICES), + help_text=BOEFJE_CONSUMES_HELP_TEXT, + ) + produces = forms.CharField( + required=False, + label=_("Output mime types"), + help_text=BOEFJE_PRODUCES_HELP_TEXT, + ) + scan_level = forms.CharField( + required=False, + label=_("Clearance level"), + widget=forms.Select(choices=SCAN_LEVEL.choices), + help_text=BOEFJE_SCAN_LEVEL_HELP_TEXT, + ) diff --git a/rocky/tools/forms/settings.py b/rocky/tools/forms/settings.py index 3e107731ff7..2bf599a3e98 100644 --- a/rocky/tools/forms/settings.py +++ b/rocky/tools/forms/settings.py @@ -1,5 +1,6 @@ from typing import Any +from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from tools.enums import SCAN_LEVEL @@ -58,6 +59,51 @@ "Select a datetime to change the view to represent that moment in time." ) +BOEFJE_DESCRIPTION_HELP_TEXT = mark_safe( + _( + "

A description of the boefje explaining in short what it can do. " + "This will both be displayed inside the KAT-alogus and on the Boefje details page.

" + ) +) + +BOEFJE_SCHEMA_HELP_TEXT = mark_safe( + _( + "

If any other settings are needed for your Boefje, add these as a JSON Schema, " + "otherwise, leave the field empty or 'null'.

" + "

This JSON is used as the basis for a form for the user. " + "When the user enables this Boefje they can get the option to give extra information. " + "For example, it can contain an API key that the script requires.

" + "

More information about what the schema.json file looks like can be found " + " " + "here.

" + ) +) + +BOEFJE_CONSUMES_HELP_TEXT = mark_safe( + _( + "

Select the object type that your Boefje consumes.

" + "

This object type triggers the Boefje to run. Whenever this OOI gets added, " + "this Boefje will run with that OOI.

" + ) +) + + +BOEFJE_PRODUCES_HELP_TEXT = mark_safe( + _( + "

Add a set of mime types that are produced by this Boefje, separated by commas. " + "For example: 'text/html', 'image/jpeg' or 'boefje/{boefje-id}'

" + "

These output mime types will be shown on the Boefje detail page as information for other users.

" + ) +) +BOEFJE_SCAN_LEVEL_HELP_TEXT = mark_safe( + _( + "

Select a clearance level for your Boefje. For more information about the different " + "clearance levels please check the " + " " + "documentation.

" + ) +) + DEPTH_DEFAULT = 9 DEPTH_MAX = 15 DEPTH_HELP_TEXT = _("Depth of the tree.") diff --git a/rocky/tools/management/commands/setup_dev_account.py b/rocky/tools/management/commands/setup_dev_account.py index ae401e8543b..ff0ea20f036 100644 --- a/rocky/tools/management/commands/setup_dev_account.py +++ b/rocky/tools/management/commands/setup_dev_account.py @@ -39,6 +39,7 @@ def handle(self, *args, **options): redteamer_permissions = [ "can_scan_organization", "can_enable_disable_boefje", + "can_add_boefje", "can_set_clearance_level", "can_delete_oois", "can_mute_findings", diff --git a/rocky/tools/migrations/0042_alter_organization_options.py b/rocky/tools/migrations/0042_alter_organization_options.py new file mode 100644 index 00000000000..6972b7a0ab7 --- /dev/null +++ b/rocky/tools/migrations/0042_alter_organization_options.py @@ -0,0 +1,29 @@ +# Generated by Django 5.0.8 on 2024-08-26 08:52 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("tools", "0001_squashed_0041_merge_20230731_1131"), + ] + + operations = [ + migrations.AlterModelOptions( + name="organization", + options={ + "permissions": ( + ("can_switch_organization", "Can switch organization"), + ("can_scan_organization", "Can scan organization"), + ("can_enable_disable_boefje", "Can enable or disable boefje"), + ("can_add_boefje", "Can add new or duplicated boefje"), + ("can_set_clearance_level", "Can set clearance level"), + ("can_delete_oois", "Can delete oois"), + ("can_mute_findings", "Can mute findings"), + ("can_view_katalogus_settings", "Can view KAT-alogus settings"), + ("can_set_katalogus_settings", "Can set KAT-alogus settings"), + ("can_recalculate_bits", "Can recalculate bits"), + ) + }, + ), + ] diff --git a/rocky/tools/migrations/0043_alter_organization_options.py b/rocky/tools/migrations/0043_alter_organization_options.py new file mode 100644 index 00000000000..2d662f68c64 --- /dev/null +++ b/rocky/tools/migrations/0043_alter_organization_options.py @@ -0,0 +1,29 @@ +# Generated by Django 5.0.8 on 2024-08-27 09:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("tools", "0042_alter_organization_options"), + ] + + operations = [ + migrations.AlterModelOptions( + name="organization", + options={ + "permissions": ( + ("can_switch_organization", "Can switch organization"), + ("can_scan_organization", "Can scan organization"), + ("can_enable_disable_boefje", "Can enable or disable boefje"), + ("can_add_boefje", "Can add new or duplicate boefjes"), + ("can_set_clearance_level", "Can set clearance level"), + ("can_delete_oois", "Can delete oois"), + ("can_mute_findings", "Can mute findings"), + ("can_view_katalogus_settings", "Can view KAT-alogus settings"), + ("can_set_katalogus_settings", "Can set KAT-alogus settings"), + ("can_recalculate_bits", "Can recalculate bits"), + ) + }, + ), + ] diff --git a/rocky/tools/models.py b/rocky/tools/models.py index 5e8cf119958..7cf68230ab8 100644 --- a/rocky/tools/models.py +++ b/rocky/tools/models.py @@ -101,6 +101,7 @@ class Meta: ("can_switch_organization", "Can switch organization"), ("can_scan_organization", "Can scan organization"), ("can_enable_disable_boefje", "Can enable or disable boefje"), + ("can_add_boefje", "Can add new or duplicate boefjes"), ("can_set_clearance_level", "Can set clearance level"), ("can_delete_oois", "Can delete oois"), ("can_mute_findings", "Can mute findings"), From de06d4a7741571f8dc1cdc4b59118e66c33a20af Mon Sep 17 00:00:00 2001 From: HeleenSG Date: Wed, 11 Sep 2024 11:02:59 +0200 Subject: [PATCH 15/82] feat: multi select dropdown (#3446) Co-authored-by: Roelof Korporaal Co-authored-by: Jan Klopper --- rocky/assets/css/components/destructive.scss | 41 +++++++++++ .../assets/css/components/dropdown-form.scss | 72 +++++++++++++++++++ rocky/assets/css/components/dropdown.scss | 4 ++ rocky/assets/css/components/form.scss | 21 ++++++ rocky/assets/css/main.scss | 2 + .../css/themes/soft/manon/checkbox.scss | 1 + rocky/assets/css/themes/soft/manon/form.scss | 1 + .../soft/manon/language-selector-list.scss | 2 +- rocky/assets/css/themes/soft/manon/link.scss | 4 ++ rocky/assets/css/themes/soft/manon/tags.scss | 1 + 10 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 rocky/assets/css/components/destructive.scss create mode 100644 rocky/assets/css/components/dropdown-form.scss diff --git a/rocky/assets/css/components/destructive.scss b/rocky/assets/css/components/destructive.scss new file mode 100644 index 00000000000..52a218ef2ff --- /dev/null +++ b/rocky/assets/css/components/destructive.scss @@ -0,0 +1,41 @@ +@mixin destructive-text-element { + &.destructive { + color: var(--color-alert-negative); + + &:hover { + color: var(--color-alert-negative-darker); + } + } +} + +@mixin destructive-button { + &.destructive { + color: var(--colors-white); + background-color: var(--color-alert-negative); + + &:hover { + background-color: var(--color-alert-negative-darker); + } + + &.ghost { + color: var(--color-alert-negative); + background-color: var(--color-white); + + &:hover { + color: var(--color-alert-negative-darker); + } + } + } +} + +a { + @include destructive-text-element; +} + +button, +a.button, +input[type="button"], +input[type="submit"], +input[type="reset"] { + @include destructive-button; +} diff --git a/rocky/assets/css/components/dropdown-form.scss b/rocky/assets/css/components/dropdown-form.scss new file mode 100644 index 00000000000..8d3b1e91b09 --- /dev/null +++ b/rocky/assets/css/components/dropdown-form.scss @@ -0,0 +1,72 @@ +@use "destructive"; + +.dropdown { + form { + $form-padding-sides: 1rem; + + background-color: transparent; + padding: 0.75rem $form-padding-sides 0 $form-padding-sides; + + .toolbar { + justify-content: space-between; + + a { + font-weight: bold; + text-decoration: none; + + @include destructive.destructive-text-element; + } + + button, + a.button, + input[type="button"], + input[type="submit"], + input[type="reset"] { + background-color: transparent; + color: var(--link-text-color); + border: 0; + padding: 0; + min-width: 0; + margin: 0; + min-height: 0; + border-radius: 0; + + &:hover { + color: var(--colors-blue-700); + } + + @include destructive.destructive-button; + + &.destructive { + color: var(--color-alert-negative); + background-color: transparent; + + &:hover { + color: var(--color-alert-negative-darker); + background-color: transparent; + } + } + } + } + + ul { + padding-left: 0; + + /* Negative margin added to allow li background color to full width of the form */ + margin-left: calc($form-padding-sides * -1); + margin-right: calc($form-padding-sides * -1); + + li { + min-height: var(--collapsing-element-list-item-min-height); + display: flex; + align-items: center; + padding-left: $form-padding-sides; + padding-right: $form-padding-sides; + + &:hover { + background-color: var(--colors-black-05); + } + } + } + } +} diff --git a/rocky/assets/css/components/dropdown.scss b/rocky/assets/css/components/dropdown.scss index e226bbdb21e..dd80fa95389 100644 --- a/rocky/assets/css/components/dropdown.scss +++ b/rocky/assets/css/components/dropdown.scss @@ -25,6 +25,9 @@ margin-block-start: 0; padding-inline-start: 0; gap: 0; + border-radius: var(--border-radius-s); + border: 1px solid var(--colors-grey-200); + background-color: var(--colors-white); &[aria-expanded="true"] { display: flex; @@ -37,6 +40,7 @@ background-color: var(--colors-white); list-style-type: disc; gap: 0; + border-radius: var(--border-radius-s); &:not(:last-child) { border-bottom: 1px solid var(--colors-grey-200); diff --git a/rocky/assets/css/components/form.scss b/rocky/assets/css/components/form.scss index d5a184cd9cb..cb741c63629 100644 --- a/rocky/assets/css/components/form.scss +++ b/rocky/assets/css/components/form.scss @@ -19,6 +19,27 @@ form { } } + .input-icon { + position: relative; + display: flex; + flex-direction: row; + align-items: center; + + input { + padding-right: 2.5rem; + + &:hover { + border-color: var(--colors-grey-700); + } + } + + .icon { + display: block; + margin-left: -1.25rem; + stroke: var(--colors-blue-600); + } + } + @media (min-width: $breakpoint-filter) { .filter-fields-direction { &.row { diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss index f6171506258..541b3d8dd42 100644 --- a/rocky/assets/css/main.scss +++ b/rocky/assets/css/main.scss @@ -33,6 +33,8 @@ @import "components/cat-loader"; @import "components/cat-paw-loader"; @import "components/cytoscape"; +@import "components/destructive"; +@import "components/dropdown-form"; @import "components/dropdown"; @import "components/dropdown-list"; @import "components/filter"; diff --git a/rocky/assets/css/themes/soft/manon/checkbox.scss b/rocky/assets/css/themes/soft/manon/checkbox.scss index 7d58f541dc2..1e198264016 100644 --- a/rocky/assets/css/themes/soft/manon/checkbox.scss +++ b/rocky/assets/css/themes/soft/manon/checkbox.scss @@ -1,3 +1,4 @@ :root { --checkbox-accent-color: var(--branding-color-2, initial); + --form-fieldset-checkbox-margin: 0.75rem 0; } diff --git a/rocky/assets/css/themes/soft/manon/form.scss b/rocky/assets/css/themes/soft/manon/form.scss index cdfbe4649f3..b8f619912fe 100644 --- a/rocky/assets/css/themes/soft/manon/form.scss +++ b/rocky/assets/css/themes/soft/manon/form.scss @@ -12,6 +12,7 @@ --form-input-border-style: solid; --form-input-border-color: var(--colors-grey-200); --form-inline-gap: 1rem; + --form-input-border-radius: var(--border-radius-s); /* Help */ --form-help-button-icon-content: "\ec9d"; diff --git a/rocky/assets/css/themes/soft/manon/language-selector-list.scss b/rocky/assets/css/themes/soft/manon/language-selector-list.scss index 651c607f45b..4ad717484df 100644 --- a/rocky/assets/css/themes/soft/manon/language-selector-list.scss +++ b/rocky/assets/css/themes/soft/manon/language-selector-list.scss @@ -46,7 +46,7 @@ /* List item */ --language-selector-list-item-background-color: transparent; --language-selector-list-item-active-background-color: transparent; - --language-selector-list-item-hover-background-color: var(--colors-grey-100); + --language-selector-list-item-hover-background-color: var(--colors-black-05); /* List item link */ --language-selector-list-item-link-border-width: 0; diff --git a/rocky/assets/css/themes/soft/manon/link.scss b/rocky/assets/css/themes/soft/manon/link.scss index 30a8a69fef0..6238c19d40e 100644 --- a/rocky/assets/css/themes/soft/manon/link.scss +++ b/rocky/assets/css/themes/soft/manon/link.scss @@ -6,4 +6,8 @@ a { text-decoration-thickness: 0.045rem; + + &:hover { + color: var(--colors-blue-700); + } } diff --git a/rocky/assets/css/themes/soft/manon/tags.scss b/rocky/assets/css/themes/soft/manon/tags.scss index 78e97397ca2..a6b2bd95fa9 100644 --- a/rocky/assets/css/themes/soft/manon/tags.scss +++ b/rocky/assets/css/themes/soft/manon/tags.scss @@ -2,4 +2,5 @@ :root { --tag-font-size: var(--body-text-small-font-size); + --tag-font-weight: bold; } From 68eef2c4ae298361a0412a2538dfc6ba3bd6f1c7 Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:47:49 +0200 Subject: [PATCH 16/82] Fix hanging upload of large files (#3489) Co-authored-by: Jeroen Dekkers Co-authored-by: Jan Klopper --- bytes/poetry.lock | 23 ++++++++++++++++++++++- bytes/pyproject.toml | 1 - bytes/requirements-dev.txt | 21 +++++++++++++++++++++ bytes/requirements.txt | 21 +++++++++++++++++++++ bytes/tests/client.py | 4 ++-- bytes/tests/integration/test_bytes_api.py | 17 +++++++++++++++++ 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/bytes/poetry.lock b/bytes/poetry.lock index f70bba87163..62b5b7ad32c 100644 --- a/bytes/poetry.lock +++ b/bytes/poetry.lock @@ -1474,30 +1474,51 @@ description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ + {file = "SQLAlchemy-1.4.51-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678"}, {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072"}, + {file = "SQLAlchemy-1.4.51-cp310-cp310-win32.whl", hash = "sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee"}, + {file = "SQLAlchemy-1.4.51-cp310-cp310-win_amd64.whl", hash = "sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c"}, + {file = "SQLAlchemy-1.4.51-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d"}, {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f"}, {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e"}, + {file = "SQLAlchemy-1.4.51-cp311-cp311-win32.whl", hash = "sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81"}, + {file = "SQLAlchemy-1.4.51-cp311-cp311-win_amd64.whl", hash = "sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171"}, + {file = "SQLAlchemy-1.4.51-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d"}, {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916"}, {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb"}, + {file = "SQLAlchemy-1.4.51-cp312-cp312-win32.whl", hash = "sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87"}, + {file = "SQLAlchemy-1.4.51-cp312-cp312-win_amd64.whl", hash = "sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65"}, + {file = "SQLAlchemy-1.4.51-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c"}, {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894"}, + {file = "SQLAlchemy-1.4.51-cp36-cp36m-win32.whl", hash = "sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054"}, + {file = "SQLAlchemy-1.4.51-cp36-cp36m-win_amd64.whl", hash = "sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1"}, + {file = "SQLAlchemy-1.4.51-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade"}, {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6"}, + {file = "SQLAlchemy-1.4.51-cp37-cp37m-win32.whl", hash = "sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3"}, + {file = "SQLAlchemy-1.4.51-cp37-cp37m-win_amd64.whl", hash = "sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2"}, + {file = "SQLAlchemy-1.4.51-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3"}, {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f"}, + {file = "SQLAlchemy-1.4.51-cp38-cp38-win32.whl", hash = "sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b"}, + {file = "SQLAlchemy-1.4.51-cp38-cp38-win_amd64.whl", hash = "sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff"}, + {file = "SQLAlchemy-1.4.51-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea"}, {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad"}, + {file = "SQLAlchemy-1.4.51-cp39-cp39-win32.whl", hash = "sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee"}, + {file = "SQLAlchemy-1.4.51-cp39-cp39-win_amd64.whl", hash = "sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba"}, {file = "SQLAlchemy-1.4.51.tar.gz", hash = "sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9"}, ] @@ -1714,4 +1735,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "b38550771cc3c4f564889d3c83e98d927e7b0db07f0cdbcb01b6c89a877fa2df" +content-hash = "58cec422be3f5e2e68f57975ffdcc243d64db0cb688abebd817fa9d0a7f3fbe1" diff --git a/bytes/pyproject.toml b/bytes/pyproject.toml index eb8534de8f3..e1bab9ef739 100644 --- a/bytes/pyproject.toml +++ b/bytes/pyproject.toml @@ -18,7 +18,6 @@ pynacl = "^1.5.0" rfc3161ng = "^2.1.3" sqlalchemy = "^1.4.48" uvicorn = "^0.29.0" -asgiref = "^3.8.1" # OpenTelemetry opentelemetry-sdk = "^1.26.0" diff --git a/bytes/requirements-dev.txt b/bytes/requirements-dev.txt index fa977408c9c..07b92536586 100644 --- a/bytes/requirements-dev.txt +++ b/bytes/requirements-dev.txt @@ -652,9 +652,12 @@ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65 \ --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ + --hash=sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0 \ + --hash=sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b \ --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ @@ -662,20 +665,38 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ + --hash=sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff \ + --hash=sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171 \ --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ + --hash=sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b \ + --hash=sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81 \ --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ + --hash=sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2 \ --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ + --hash=sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee \ + --hash=sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298 \ --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ + --hash=sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c \ + --hash=sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87 \ + --hash=sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba \ + --hash=sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d \ + --hash=sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1 \ --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ + --hash=sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee \ + --hash=sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99 \ --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ + --hash=sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b \ + --hash=sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054 \ --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ + --hash=sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d \ --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ + --hash=sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3 \ --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ diff --git a/bytes/requirements.txt b/bytes/requirements.txt index dc6f031361e..b5c65385389 100644 --- a/bytes/requirements.txt +++ b/bytes/requirements.txt @@ -637,9 +637,12 @@ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65 \ --hash=sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678 \ --hash=sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e \ --hash=sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea \ + --hash=sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0 \ + --hash=sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b \ --hash=sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb \ --hash=sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3 \ --hash=sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1 \ @@ -647,20 +650,38 @@ sqlalchemy==1.4.51 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b \ --hash=sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad \ --hash=sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707 \ + --hash=sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff \ + --hash=sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171 \ --hash=sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd \ + --hash=sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b \ + --hash=sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81 \ --hash=sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c \ + --hash=sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2 \ --hash=sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916 \ + --hash=sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee \ + --hash=sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298 \ --hash=sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f \ --hash=sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c \ --hash=sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340 \ + --hash=sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c \ + --hash=sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87 \ + --hash=sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba \ + --hash=sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d \ + --hash=sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1 \ --hash=sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072 \ + --hash=sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee \ + --hash=sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99 \ --hash=sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f \ --hash=sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894 \ + --hash=sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b \ + --hash=sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054 \ --hash=sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4 \ --hash=sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349 \ --hash=sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9 \ --hash=sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6 \ + --hash=sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d \ --hash=sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12 \ + --hash=sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3 \ --hash=sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ diff --git a/bytes/tests/client.py b/bytes/tests/client.py index 22405c75ffc..0fcdb95b8b5 100644 --- a/bytes/tests/client.py +++ b/bytes/tests/client.py @@ -6,7 +6,7 @@ from uuid import UUID import httpx -from httpx import HTTPError +from httpx import HTTPError, HTTPStatusError from bytes.api.models import BoefjeOutput from bytes.models import BoefjeMeta, NormalizerMeta @@ -23,7 +23,7 @@ def wrapper(self, *args, **kwargs): # type: ignore try: return function(self, *args, **kwargs) except HTTPError as error: - if error.response.status_code != 401: + if not isinstance(error, HTTPStatusError) or error.response.status_code != 401: raise self.login() diff --git a/bytes/tests/integration/test_bytes_api.py b/bytes/tests/integration/test_bytes_api.py index afc34ec75bd..0677bf3ce0f 100644 --- a/bytes/tests/integration/test_bytes_api.py +++ b/bytes/tests/integration/test_bytes_api.py @@ -236,6 +236,23 @@ def test_raw(bytes_api_client: BytesAPIClient, event_manager: RabbitMQEventManag assert str(boefje_meta.id) in body.decode() +def test_raw_big(bytes_api_client: BytesAPIClient, event_manager: RabbitMQEventManager) -> None: + boefje_meta = get_boefje_meta() + bytes_api_client.save_boefje_meta(boefje_meta) + + raw = b"test 123" * 100000 + raw_id = bytes_api_client.save_raw(boefje_meta.id, raw) + + retrieved_raw = bytes_api_client.get_raw(raw_id) + + assert retrieved_raw == raw + + method, properties, body = event_manager.connection.channel().basic_get("test__raw_file_received") + event_manager.connection.channel().basic_ack(method.delivery_tag) + + assert str(boefje_meta.id) in body.decode() + + def test_save_raw_with_one_mime_type(bytes_api_client: BytesAPIClient) -> None: boefje_meta = get_boefje_meta(meta_id=uuid.uuid4()) bytes_api_client.save_boefje_meta(boefje_meta) From b85e80ae3dadf8687b46fdb97a61f3c2f561646a Mon Sep 17 00:00:00 2001 From: noamblitz <43830693+noamblitz@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:20:32 +0200 Subject: [PATCH 17/82] Add timezone to valid time (#3429) Co-authored-by: Jan Klopper --- rocky/rocky/views/upload_raw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/rocky/views/upload_raw.py b/rocky/rocky/views/upload_raw.py index 5159b2ad9bc..7e286581b9d 100644 --- a/rocky/rocky/views/upload_raw.py +++ b/rocky/rocky/views/upload_raw.py @@ -62,7 +62,7 @@ def process_raw(self, form): raw_file = form.cleaned_data["raw_file"] mime_types = form.cleaned_data["mime_types"] input_ooi = form.cleaned_data["ooi"] - valid_time = form.cleaned_data["date"] + valid_time = form.cleaned_data["date"].replace(tzinfo=timezone.utc) try: get_bytes_client(self.organization.code).upload_raw( From 1c98a0c1b64650540b2d95e5828ff74375223a08 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:28:35 +0200 Subject: [PATCH 18/82] Check if the task is still running according to the scheduler before changing the status (#3506) Co-authored-by: Jan Klopper --- boefjes/boefjes/app.py | 9 ++- boefjes/boefjes/docker_boefjes_runner.py | 1 - boefjes/tests/conftest.py | 13 +++-- .../scheduler/pop_response_boefje_2.json | 25 +++++++++ .../pop_response_boefje_dispatched.json | 25 +++++++++ boefjes/tests/test_app.py | 55 +++++++++++++------ 6 files changed, 104 insertions(+), 24 deletions(-) create mode 100644 boefjes/tests/examples/scheduler/pop_response_boefje_2.json create mode 100644 boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json diff --git a/boefjes/boefjes/app.py b/boefjes/boefjes/app.py index c12f1e15bc9..2b671f0f642 100644 --- a/boefjes/boefjes/app.py +++ b/boefjes/boefjes/app.py @@ -174,7 +174,7 @@ def _cleanup_pending_worker_task(self, worker: mp.Process) -> None: try: task = self.scheduler_client.get_task(handling_task_id) - if task.status is TaskStatus.DISPATCHED: + if task.status is TaskStatus.DISPATCHED or task.status is TaskStatus.RUNNING: try: self.scheduler_client.patch_task(task.id, TaskStatus.FAILED) logger.warning("Set status to failed in the scheduler for task[id=%s]", handling_task_id) @@ -244,6 +244,7 @@ def _start_working( handling_tasks[os.getpid()] = str(p_item.id) try: + scheduler_client.patch_task(p_item.id, TaskStatus.RUNNING) handler.handle(p_item.data) status = TaskStatus.COMPLETED except Exception: # noqa @@ -253,8 +254,10 @@ def _start_working( raise finally: try: - scheduler_client.patch_task(p_item.id, status) # Note: implicitly, we have p_item.id == task_id - logger.info("Set status to %s in the scheduler for task[id=%s]", status, p_item.data.id) + if scheduler_client.get_task(p_item.id).status == TaskStatus.RUNNING: + # The docker runner could have handled this already + scheduler_client.patch_task(p_item.id, status) # Note that implicitly, we have p_item.id == task_id + logger.info("Set status to %s in the scheduler for task[id=%s]", status, p_item.data.id) except HTTPError: logger.exception("Could not patch scheduler task to %s", status.value) diff --git a/boefjes/boefjes/docker_boefjes_runner.py b/boefjes/boefjes/docker_boefjes_runner.py index f28c64055ae..3efea0c48c9 100644 --- a/boefjes/boefjes/docker_boefjes_runner.py +++ b/boefjes/boefjes/docker_boefjes_runner.py @@ -36,7 +36,6 @@ def run(self) -> None: stderr_mime_types = boefjes.plugins.models._default_mime_types(self.boefje_meta.boefje) task_id = self.boefje_meta.id - self.scheduler_client.patch_task(task_id, TaskStatus.RUNNING) self.boefje_meta.started_at = datetime.now(timezone.utc) try: diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index 079185699ed..da8085d5f39 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -44,11 +44,13 @@ def __init__( log_path: Path, raise_on_empty_queue: Exception = KeyboardInterrupt, iterations_to_wait_for_exception: int = 0, - sleep_time: int = 0.1, + sleep_time: float = 0.1, ): self.queue_response = queue_response self.boefje_responses = boefje_responses self.normalizer_responses = normalizer_responses + + log_path.touch(exist_ok=True) self.log_path = log_path self.raise_on_empty_queue = raise_on_empty_queue self.iterations_to_wait_for_exception = iterations_to_wait_for_exception @@ -76,6 +78,7 @@ def pop_item(self, queue: str) -> Task | None: if WorkerManager.Queue.NORMALIZERS.value in queue: p_item = TypeAdapter(Task).validate_json(self.normalizer_responses.pop(0)) self._popped_items[str(p_item.id)] = p_item + self._tasks[str(p_item.id)] = self._task_from_id(p_item.id) return p_item except IndexError: raise self.raise_on_empty_queue @@ -128,9 +131,11 @@ def item_handler(tmp_path: Path): def manager(item_handler: MockHandler, tmp_path: Path) -> SchedulerWorkerManager: scheduler_client = MockSchedulerClient( queue_response=get_dummy_data("scheduler/queues_response.json"), - boefje_responses=( - 2 * [get_dummy_data("scheduler/pop_response_boefje.json")] + [get_dummy_data("scheduler/should_crash.json")] - ), + boefje_responses=[ + get_dummy_data("scheduler/pop_response_boefje.json"), + get_dummy_data("scheduler/pop_response_boefje_2.json"), + get_dummy_data("scheduler/should_crash.json"), + ], normalizer_responses=[get_dummy_data("scheduler/pop_response_normalizer.json")], log_path=tmp_path / "patch_task_log", ) diff --git a/boefjes/tests/examples/scheduler/pop_response_boefje_2.json b/boefjes/tests/examples/scheduler/pop_response_boefje_2.json new file mode 100644 index 00000000000..762be767cc9 --- /dev/null +++ b/boefjes/tests/examples/scheduler/pop_response_boefje_2.json @@ -0,0 +1,25 @@ +{ + "id": "70da7d4f-f41f-4940-901b-d98a92e9014c", + "priority": 1, + "scheduler_id": "boefje-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "boefje", + "hash": "70da7d4f-f41f-4940-901b-d98a92e9014c", + "data": { + "id": "70da7d4f-f41f-4940-901b-d98a92e9014c", + "boefje": { + "id": "dns-records", + "version": null + }, + "input_ooi": "Hostname|internet|test.test", + "organization": "_dev", + "arguments": {}, + "started_at": null, + "runnable_hash": null, + "environment": null, + "ended_at": null + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" +} diff --git a/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json b/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json new file mode 100644 index 00000000000..29e7d5dfb72 --- /dev/null +++ b/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json @@ -0,0 +1,25 @@ +{ + "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", + "priority": 1, + "scheduler_id": "boefje-_dev", + "schedule_id": null, + "status": "dispatched", + "type": "boefje", + "hash": "70da7d4f-f41f-4940-901b-d98a92e9014b", + "data": { + "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", + "boefje": { + "id": "dns-records", + "version": null + }, + "input_ooi": "Hostname|internet|test.test", + "organization": "_dev", + "arguments": {}, + "started_at": null, + "runnable_hash": null, + "environment": null, + "ended_at": null + }, + "created_at": "2021-06-29T14:00:00", + "modified_at": "2021-06-29T14:00:00" +} diff --git a/boefjes/tests/test_app.py b/boefjes/tests/test_app.py index 05bc10a35d5..70e1523979f 100644 --- a/boefjes/tests/test_app.py +++ b/boefjes/tests/test_app.py @@ -22,10 +22,15 @@ def test_one_process(manager: SchedulerWorkerManager, item_handler: MockHandler) patched_tasks = manager.scheduler_client.get_all_patched_tasks() - assert len(patched_tasks) == 3 - assert patched_tasks[0] == ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed") - assert patched_tasks[1] == ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed") - assert patched_tasks[2] == ("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "failed") + assert len(patched_tasks) == 6 + assert set(patched_tasks) == { + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014c", "running"), + ("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed"), + ("70da7d4f-f41f-4940-901b-d98a92e9014c", "completed"), + ("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "failed"), + } def test_two_processes(manager: SchedulerWorkerManager, item_handler: MockHandler) -> None: @@ -39,9 +44,14 @@ def test_two_processes(manager: SchedulerWorkerManager, item_handler: MockHandle assert len(items) == 2 patched_tasks = manager.scheduler_client.get_all_patched_tasks() - assert len(patched_tasks) == 3 - assert patched_tasks.count(("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed")) == 2 - assert patched_tasks.count(("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "failed")) == 1 + assert set(patched_tasks) == { + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014c", "running"), + ("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed"), + ("70da7d4f-f41f-4940-901b-d98a92e9014c", "completed"), + ("9071c9fd-2b9f-440f-a524-ef1ca4824fd4", "failed"), + } def test_two_processes_exception(manager: SchedulerWorkerManager, item_handler: MockHandler, tmp_path) -> None: @@ -78,7 +88,7 @@ def test_two_processes_handler_exception(manager: SchedulerWorkerManager, item_h patched_tasks = manager.scheduler_client.get_all_patched_tasks() - assert len(patched_tasks) == 3 + assert len(patched_tasks) == 6 # Handler starts raising an Exception from the second call onward, # so we have 2 completed tasks and 4 failed tasks. assert patched_tasks.count(("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed")) == 1 @@ -89,9 +99,11 @@ def test_two_processes_cleanup_unfinished_tasks( manager: SchedulerWorkerManager, item_handler: MockHandler, tmp_path ) -> None: """ - Push 3 slow tasks to 2 workers, - then crash (from popping from an empty queue), - then clean up task on queue and the tasks being handled + We push 2 slow tasks to the Queue, which will be popped by 2 workers, emptying the Queue and stalling the 2 workers. + Because the Queue is now empty, the manager will get 2 new tasks from the scheduler to push to the queue. But only + one will be pushed because we do not have any tasks from the scheduler anymore (triggering a KeyboardInterrupt to + crash the main process). Then the manager should clean up the running tasks by setting the status of the running + tasks to failed and push any tasks still on the Queue back to the scheduler. """ manager.scheduler_client = MockSchedulerClient( @@ -112,10 +124,14 @@ def test_two_processes_cleanup_unfinished_tasks( assert len(items) == 0 patched_tasks = manager.scheduler_client.get_all_patched_tasks() - assert len(patched_tasks) == 1 + assert len(patched_tasks) == 3 # Task was running but main process crashed intentionally and cleaned it up - assert patched_tasks.count(("70da7d4f-f41f-4940-901b-d98a92e9014b", "failed")) == 1 + assert set(patched_tasks) == { + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "failed"), + } # Tasks (one with the same id) was still unhandled the queue and pushed back to the scheduler by the main process assert manager.scheduler_client._pushed_items["70da7d4f-f41f-4940-901b-d98a92e9014b"][0] == "boefje" @@ -140,6 +156,7 @@ def test_null(manager: SchedulerWorkerManager, tmp_path: Path, item_handler: Moc [get_dummy_data("scheduler/pop_response_normalizer.json")], tmp_path / "patch_task_log", iterations_to_wait_for_exception=2, + sleep_time=0.3, ) with pytest.raises(KeyboardInterrupt): @@ -149,9 +166,15 @@ def test_null(manager: SchedulerWorkerManager, tmp_path: Path, item_handler: Moc patched_tasks = manager.scheduler_client.get_all_patched_tasks() assert len(items) == 3 - assert len(patched_tasks) == 3 - assert patched_tasks[0] == ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed") - assert patched_tasks[2] == ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed") + assert len(patched_tasks) == 6 + assert set(patched_tasks) == { + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed"), + ("70da7d4f-f41f-4940-901b-d98a92e9014b", "completed"), + } def test_create_manager(): From ecdf1df6c628c555b9c520834b00ded6b8ceaa7f Mon Sep 17 00:00:00 2001 From: Rieven Date: Thu, 12 Sep 2024 10:20:36 +0200 Subject: [PATCH 19/82] Exclude OOIs creation from the OOI add form by OOI-types (#3490) Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Co-authored-by: Jan Klopper --- rocky/rocky/views/ooi_add.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/rocky/rocky/views/ooi_add.py b/rocky/rocky/views/ooi_add.py index 1840c35ee06..12f451e5f99 100644 --- a/rocky/rocky/views/ooi_add.py +++ b/rocky/rocky/views/ooi_add.py @@ -8,12 +8,20 @@ from tools.view_helpers import existing_ooi_type from octopoes.models import OOI +from octopoes.models.ooi.monitoring import Incident +from octopoes.models.ooi.question import Question +from octopoes.models.ooi.reports import Report, ReportData +from octopoes.models.ooi.web import RESTAPI, ImageMetadata from octopoes.models.types import type_by_name from rocky.views.ooi_view import BaseOOIFormView +EXCLUDE_OOI_TYPES = [ + ooi_type.get_object_type() for ooi_type in [Question, RESTAPI, Incident, ImageMetadata, Report, ReportData] +] + def ooi_type_input_choices(): - ooi_types = OOI_TYPES_WITHOUT_FINDINGS + ooi_types = [ooi_type for ooi_type in OOI_TYPES_WITHOUT_FINDINGS if ooi_type not in EXCLUDE_OOI_TYPES] ooi_types.sort() return [{"value": ooi_type, "text": ooi_type} for ooi_type in ooi_types] @@ -66,9 +74,12 @@ def setup(self, request, *args, **kwargs): def get_ooi_class(self) -> type[OOI]: try: - return type_by_name(self.kwargs["ooi_type"]) + ooi_type = self.kwargs["ooi_type"] + if ooi_type in EXCLUDE_OOI_TYPES: + raise KeyError + return type_by_name(ooi_type) except KeyError: - raise Http404("OOI not found") + raise Http404("OOI-type not found") def get_form_kwargs(self): kwargs = super().get_form_kwargs() From 53d71a33594ce569b6f0d2dbdccc6bb6da0f85b4 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:26:50 +0200 Subject: [PATCH 20/82] Use the right variable name in the template's if-statement (#3519) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- rocky/katalogus/templates/boefje_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/katalogus/templates/boefje_detail.html b/rocky/katalogus/templates/boefje_detail.html index 04d6abcb960..7b59666d1c5 100644 --- a/rocky/katalogus/templates/boefje_detail.html +++ b/rocky/katalogus/templates/boefje_detail.html @@ -32,7 +32,7 @@

{{ plugin.name }}

- {% if perms.tools.can_view_katalogus_settings and object_list %} + {% if perms.tools.can_view_katalogus_settings and plugin_settings %}
{% include "plugin_settings_list.html" with object_list=plugin_settings plugin=plugin %} From 8ec43412faaceaa86105e67772b7e2473ac3bec8 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:23:14 +0200 Subject: [PATCH 21/82] Add regex pattern check to PORTS setting of `nmap-ports` (#3516) Signed-off-by: Donny Peeters Co-authored-by: Jan Klopper --- .../plugins/kat_nmap_ports/schema.json | 1 + boefjes/tests/test_nmap.py | 86 +++++++++++++++---- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_nmap_ports/schema.json b/boefjes/boefjes/plugins/kat_nmap_ports/schema.json index 4b52a8af648..b078f26b0b8 100644 --- a/boefjes/boefjes/plugins/kat_nmap_ports/schema.json +++ b/boefjes/boefjes/plugins/kat_nmap_ports/schema.json @@ -6,6 +6,7 @@ "title": "PORTS", "maxLength": 2048, "type": "string", + "pattern": "^((6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)|(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)-(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d))$|^((6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)|(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)-(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d))(,((6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)|(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)-(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{0,4}|\\d)))+$", "description": "Specify the ports that need to be scanned (nmap format). Single ports are comma separated, port ranges can be specified using the dash symbol. For example: 22,111,137,80-100 will scan ports 22, 111, 137 and the port range 80 up to 100." } }, diff --git a/boefjes/tests/test_nmap.py b/boefjes/tests/test_nmap.py index 9d0de572fdf..f936160f910 100644 --- a/boefjes/tests/test_nmap.py +++ b/boefjes/tests/test_nmap.py @@ -1,21 +1,77 @@ -from unittest import TestCase +import re + +import pytest +from jsonschema.exceptions import ValidationError +from jsonschema.validators import validate from boefjes.plugins.kat_nmap_tcp.normalize import run from octopoes.models.ooi.network import IPAddressV4, Network from tests.loading import get_dummy_data -class NmapTest(TestCase): - def test_normalizer(self): - input_ooi = IPAddressV4(network=Network(name="internet").reference, address="134.209.85.72") - output = list(run(input_ooi.serialize(), get_dummy_data("raw/nmap_mispoes.xml"))) - self.assertEqual(15, len(output)) - for i, out in enumerate(output[:-1]): - if out.object_type == "IPPort" and output[i + 1].object_type == "Service": - if out.port == 80: - self.assertEqual("http", output[i + 1].name) - elif out.port == 443: - self.assertEqual("https", output[i + 1].name) - else: - self.assertNotEqual("http", output[i + 1].name) - self.assertNotEqual("https", output[i + 1].name) +def test_normalizer(): + input_ooi = IPAddressV4(network=Network(name="internet").reference, address="134.209.85.72") + output = list(run(input_ooi.serialize(), get_dummy_data("raw/nmap_mispoes.xml"))) + assert len(output) == 15 + for i, out in enumerate(output[:-1]): + if out.object_type == "IPPort" and output[i + 1].object_type == "Service": + name = output[i + 1].name + if out.port == 80: + assert name == "http" + elif out.port == 443: + assert name == "https" + else: + assert name != "http" + assert name != "https" + + +def get_pattern(): + max_65535 = r"(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{0,4}|\d)" + max_65535_or_port_range = f"({max_65535}|{max_65535}-{max_65535})" + one_or_comma_separated = f"^{max_65535_or_port_range}$|^{max_65535_or_port_range}(,{max_65535_or_port_range})+$" + + return re.compile(one_or_comma_separated) + + +def test_single_port_pattern(local_repo): + schema = local_repo.schema("nmap-ports") + for single_port in ["1", "2", "20", "200", "2000", "20000", "65535"]: + assert get_pattern().search(single_port) is not None + validate(instance={"PORTS": single_port}, schema=schema) + + +def test_bad_single_port_pattern(local_repo): + schema = local_repo.schema("nmap-ports") + for bad_single_port in ["-1", "-2000", "65536", "222222"]: + assert get_pattern().search(bad_single_port) is None + with pytest.raises(ValidationError): + validate(instance={"PORTS": bad_single_port}, schema=schema) + + +def test_multi_ports_pattern(local_repo): + schema = local_repo.schema("nmap-ports") + for multi_port in ["1,2", "2,3,4", "2,3,4,5,6,7", "2,20,200,2000,65535"]: + assert get_pattern().search(multi_port) is not None + validate(instance={"PORTS": multi_port}, schema=schema) + + +def test_port_range_pattern(local_repo): + schema = local_repo.schema("nmap-ports") + for port_range in ["1-2", "2-20000", "65533-65535"]: + assert get_pattern().search(port_range) is not None + validate(instance={"PORTS": port_range}, schema=schema) + + +def test_combined(local_repo): + schema = local_repo.schema("nmap-ports") + for port_range in ["1,1-65000", "1,2,234,4300-5999,1"]: + assert get_pattern().search(port_range) is not None + validate(instance={"PORTS": port_range}, schema=schema) + + +def test_badly_combined(local_repo): + schema = local_repo.schema("nmap-ports") + for port_range in ["1,1-", "1-234-323"]: + assert get_pattern().search(port_range) is None + with pytest.raises(ValidationError): + validate(instance={"PORTS": port_range}, schema=schema) From 93b7faf39237816597c26a6ddc9c06ca25c03c7e Mon Sep 17 00:00:00 2001 From: Jeroen Dekkers Date: Thu, 12 Sep 2024 14:30:18 +0200 Subject: [PATCH 22/82] Update xtdb-http-multinode to the latest version (#3523) --- boefjes/.ci/docker-compose.yml | 2 +- docker-compose.release-example.yml | 2 +- octopoes/.ci/docker-compose.yml | 2 +- rocky/.ci/docker-compose.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/boefjes/.ci/docker-compose.yml b/boefjes/.ci/docker-compose.yml index f3dc4ecc244..bf7ee7aeadd 100644 --- a/boefjes/.ci/docker-compose.yml +++ b/boefjes/.ci/docker-compose.yml @@ -85,7 +85,7 @@ services: - .ci/.env.test ci_xtdb: - image: "ghcr.io/dekkers/xtdb-http-multinode:v1.0.8" + image: "ghcr.io/dekkers/xtdb-http-multinode:v1.1.0" ci_octopoes_api_worker: build: diff --git a/docker-compose.release-example.yml b/docker-compose.release-example.yml index 9469c26bff7..c90b1bf7bdb 100644 --- a/docker-compose.release-example.yml +++ b/docker-compose.release-example.yml @@ -31,7 +31,7 @@ services: APPS: "ROCKY BYTES KATALOGUS SCHEDULER" crux: - image: "ghcr.io/dekkers/xtdb-http-multinode:v1.0.8" + image: "ghcr.io/dekkers/xtdb-http-multinode:v1.1.0" restart: on-failure ports: - "127.0.0.1:3000:3000" diff --git a/octopoes/.ci/docker-compose.yml b/octopoes/.ci/docker-compose.yml index 6b4d0205f6a..d4e33b42e13 100644 --- a/octopoes/.ci/docker-compose.yml +++ b/octopoes/.ci/docker-compose.yml @@ -25,7 +25,7 @@ services: - ".ci/ci.env" xtdb: - image: "ghcr.io/dekkers/xtdb-http-multinode:v1.0.8" + image: "ghcr.io/dekkers/xtdb-http-multinode:v1.1.0" ports: - "127.0.0.1:29002:3000" diff --git a/rocky/.ci/docker-compose.yml b/rocky/.ci/docker-compose.yml index 130d3e59f20..03940ae2236 100644 --- a/rocky/.ci/docker-compose.yml +++ b/rocky/.ci/docker-compose.yml @@ -52,7 +52,7 @@ services: - .env.test xtdb: - image: "ghcr.io/dekkers/xtdb-http-multinode:v1.0.8" + image: "ghcr.io/dekkers/xtdb-http-multinode:v1.1.0" rabbitmq: restart: on-failure From dc0c4dc6a01a774fb0fea5212d45750e644fba4e Mon Sep 17 00:00:00 2001 From: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:32:15 +0200 Subject: [PATCH 23/82] Updated findings in the findings database (#3427) Co-authored-by: Jan Klopper From 822b776904ea9c7358b925f383f971a78694387a Mon Sep 17 00:00:00 2001 From: Jan Klopper Date: Thu, 12 Sep 2024 17:26:25 +0200 Subject: [PATCH 24/82] remove unneeded column from filtered plugin table view (#3515) Co-authored-by: Ammar Co-authored-by: Rieven --- rocky/katalogus/templates/katalogus.html | 2 +- rocky/katalogus/templates/partials/plugins.html | 16 ++++++++++------ rocky/rocky/locale/django.pot | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/rocky/katalogus/templates/katalogus.html b/rocky/katalogus/templates/katalogus.html index 24107431705..3284a9491e3 100644 --- a/rocky/katalogus/templates/katalogus.html +++ b/rocky/katalogus/templates/katalogus.html @@ -32,7 +32,7 @@

{% translate "All plugins" %}

{% include "partials/katalogus_filter.html" with form=form %} {% include "partials/katalogus_toolbar.html" %} - {% include "partials/plugins.html" %} + {% include "partials/plugins.html" with active="all" %}
diff --git a/rocky/katalogus/templates/partials/plugins.html b/rocky/katalogus/templates/partials/plugins.html index 95524ce1d0b..495f8d431cb 100644 --- a/rocky/katalogus/templates/partials/plugins.html +++ b/rocky/katalogus/templates/partials/plugins.html @@ -8,7 +8,9 @@
- + {% if active == "all" %} + + {% endif %} @@ -21,11 +23,13 @@ {{ plugin.name }} - + {% if active == "all" %} + + {% endif %} diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 3591cc84059..553fcdeb553 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-09-05 15:36+0000\n" +"POT-Creation-Date: 2024-09-11 14:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" From ae790c32365482b19cd1917ce3e5d0abaef4f0ef Mon Sep 17 00:00:00 2001 From: originalsouth Date: Mon, 16 Sep 2024 10:17:02 +0200 Subject: [PATCH 25/82] Also delete self-affirming or self-infered objects (#3498) Co-authored-by: ammar92 --- octopoes/octopoes/core/service.py | 9 +- .../tests/integration/test_ooi_deletion.py | 98 ++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/octopoes/octopoes/core/service.py b/octopoes/octopoes/core/service.py index cc7f64e00af..70c89f48f90 100644 --- a/octopoes/octopoes/core/service.py +++ b/octopoes/octopoes/core/service.py @@ -162,7 +162,14 @@ def get_ooi_tree( def _delete_ooi(self, reference: Reference, valid_time: datetime) -> None: referencing_origins = self.origin_repository.list_origins(valid_time, result=reference) - if not referencing_origins: + if not any( + origin + for origin in referencing_origins + if not ( + origin.origin_type == OriginType.AFFIRMATION + or (origin.origin_type == OriginType.INFERENCE and origin.source == reference) + ) + ): self.ooi_repository.delete(reference, valid_time) def save_origin( diff --git a/octopoes/tests/integration/test_ooi_deletion.py b/octopoes/tests/integration/test_ooi_deletion.py index ad52fbe1b98..86e40eda52b 100644 --- a/octopoes/tests/integration/test_ooi_deletion.py +++ b/octopoes/tests/integration/test_ooi_deletion.py @@ -7,7 +7,7 @@ import pytest -from octopoes.api.models import Declaration, Observation +from octopoes.api.models import Affirmation, Declaration, Observation from octopoes.connector.octopoes import OctopoesAPIConnector from octopoes.core.service import OctopoesService from octopoes.events.events import OOIDBEvent, OriginDBEvent @@ -429,3 +429,99 @@ def chain(source, results): assert xtdb_octopoes_service.ooi_repository.list_oois({OOI}, valid_time).count == 0 assert len(list(filter(lambda x: x.operation_type.value == "delete", event_manager.queue))) > 0 + + +def test_affirming_ooi_delete(octopoes_api_connector: OctopoesAPIConnector, valid_time: datetime): + # Make an object A + network = Network(name="internet") + octopoes_api_connector.save_declaration(Declaration(ooi=network, valid_time=valid_time)) + + # Observe an object B "derived" by A + url = "mispo.es" + hostname = Hostname(network=network.reference, name=url) + hostname_origin = Observation( + method="", + source=network.reference, + source_method=None, + result=[hostname], + task_id=uuid.uuid4(), + valid_time=valid_time, + ) + octopoes_api_connector.save_observation(hostname_origin) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 + + # Delete A and validate B is not present + octopoes_api_connector.delete(network.reference, valid_time) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 0 + + # Re-observe an object B "derived" by A + octopoes_api_connector.save_declaration(Declaration(ooi=network, valid_time=valid_time)) + octopoes_api_connector.save_observation(hostname_origin) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 + + # Affirm object B + octopoes_api_connector.save_affirmation( + Affirmation( + ooi=hostname, + source_method=None, + task_id=uuid.uuid4(), + valid_time=valid_time, + ) + ) + time.sleep(1) + + # Delete A and validate B is not present + octopoes_api_connector.delete(network.reference, valid_time) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 0 + + +def test_delecration_ooi_delete(octopoes_api_connector: OctopoesAPIConnector, valid_time: datetime): + # Make an object A + network = Network(name="internet") + octopoes_api_connector.save_declaration(Declaration(ooi=network, valid_time=valid_time)) + + # Observe an object B "derived" by A + url = "mispo.es" + hostname = Hostname(network=network.reference, name=url) + hostname_origin = Observation( + method="", + source=network.reference, + source_method=None, + result=[hostname], + task_id=uuid.uuid4(), + valid_time=valid_time, + ) + octopoes_api_connector.save_observation(hostname_origin) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 + + # Delete A and validate B is not present + octopoes_api_connector.delete(network.reference, valid_time) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 0 + + # Re-observe an object B "derived" by A + octopoes_api_connector.save_declaration(Declaration(ooi=network, valid_time=valid_time)) + octopoes_api_connector.save_observation(hostname_origin) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 + + # Infer object B + octopoes_api_connector.save_declaration( + Declaration( + ooi=hostname, + source_method=None, + task_id=uuid.uuid4(), + valid_time=valid_time, + ) + ) + time.sleep(1) + + # Delete A and validate B is not present + octopoes_api_connector.delete(network.reference, valid_time) + time.sleep(1) + assert octopoes_api_connector.list_objects({Hostname}, valid_time).count == 1 From 8821f3ffb2d334fc1336d43b77d9a3ca23558e8b Mon Sep 17 00:00:00 2001 From: originalsouth Date: Mon, 16 Sep 2024 16:22:47 +0200 Subject: [PATCH 26/82] Support valid_time and the like for queries in xtdb tools (#3430) --- octopoes/tools/xtdb-cli.py | 31 ++++++++++++++++++++----------- octopoes/tools/xtdb_client.py | 18 ++++++++++++++++-- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/octopoes/tools/xtdb-cli.py b/octopoes/tools/xtdb-cli.py index 74aad128407..e9a62d27b81 100755 --- a/octopoes/tools/xtdb-cli.py +++ b/octopoes/tools/xtdb-cli.py @@ -61,15 +61,24 @@ def status(ctx: click.Context): @cli.command(help='EDN Query (default: "{:query {:find [ ?var ] :where [[?var :xt/id ]]}}")') +@click.option("--tx-id", type=int, help="In UTC, defaulting to latest transaction id (integer)") +@click.option("--tx-time", type=click.DateTime(), help="In UTC, defaulting to latest transaction time (date)") +@click.option("--valid-time", type=click.DateTime(), help="In UTC, defaulting to now (date)") @click.argument("edn", required=False) @click.pass_context -def query(ctx: click.Context, edn: str): +def query( + ctx: click.Context, + edn: str, + valid_time: datetime.datetime | None = None, + tx_time: datetime.datetime | None = None, + tx_id: int | None = None, +): client: XTDBClient = ctx.obj["client"] if edn: - click.echo(json.dumps(client.query(edn))) + click.echo(json.dumps(client.query(edn, valid_time, tx_time, tx_id))) else: - click.echo(json.dumps(client.query())) + click.echo(json.dumps(client.query(valid_time=valid_time, tx_time=tx_time, tx_id=tx_id))) @cli.command(help="List all keys in node") @@ -89,9 +98,9 @@ def list_values(ctx: click.Context): @cli.command(help="Returns the document map for a particular entity.") -@click.option("--tx-id", type=int, help="Defaulting to latest transaction id (integer)") -@click.option("--tx-time", type=click.DateTime(), help="Defaulting to latest transaction time (date)") -@click.option("--valid-time", type=click.DateTime(), help="Defaulting to now (date)") +@click.option("--tx-id", type=int, help="In UTC, defaulting to latest transaction id (integer)") +@click.option("--tx-time", type=click.DateTime(), help="In UTC, defaulting to latest transaction time (date)") +@click.option("--valid-time", type=click.DateTime(), help="In UTC, defaulting to now (date)") @click.argument("key") @click.pass_context def entity( @@ -116,7 +125,7 @@ def entity( "--with-corrections", is_flag=True, help="""Includes bitemporal corrections in the response, inline, - sorted by valid-time then tx-id (boolean, default: false)""", + sorted by valid-time (in UTC) then tx-id (boolean, default: false)""", ) @click.argument("key") @click.pass_context @@ -127,9 +136,9 @@ def history(ctx: click.Context, key: str, with_corrections: bool, with_docs: boo @cli.command(help="Returns the transaction details for an entity - returns a map containing the tx-id and tx-time.") -@click.option("--tx-id", type=int, help="Defaulting to the latest transaction id (integer)") -@click.option("--tx-time", type=click.DateTime(), help="Defaulting to the latest transaction time (date)") -@click.option("--valid-time", type=click.DateTime(), help="Defaulting to now (date)") +@click.option("--tx-id", type=int, help="In UTC, defaulting to the latest transaction id (integer)") +@click.option("--tx-time", type=click.DateTime(), help="In UTC, defaulting to the latest transaction time (date)") +@click.option("--valid-time", type=click.DateTime(), help="In UTC, defaulting to now (date)") @click.argument("key") @click.pass_context def entity_tx( @@ -182,7 +191,7 @@ def await_tx(ctx: click.Context, tx_id: int, timeout: int | None): The returned date is the latest index time when this node has caught up as of this call.""" ) @click.option("--timeout", type=int, help="Specified in milliseconds, defaulting to 10 seconds (integer)") -@click.argument("tx-time", type=click.DateTime()) +@click.argument("tx-time", type=click.DateTime(), help="In UTC") @click.pass_context def await_tx_time( ctx: click.Context, diff --git a/octopoes/tools/xtdb_client.py b/octopoes/tools/xtdb_client.py index 70c0530912f..ad58dc2af42 100644 --- a/octopoes/tools/xtdb_client.py +++ b/octopoes/tools/xtdb_client.py @@ -37,8 +37,22 @@ def status(self) -> JsonValue: return res.json() - def query(self, query: str = "{:query {:find [ ?var ] :where [[?var :xt/id ]]}}") -> JsonValue: - res = self._client.post("/query", content=query, headers={"Content-Type": "application/edn"}) + def query( + self, + query: str = "{:query {:find [ ?var ] :where [[?var :xt/id ]]}}", + valid_time: datetime.datetime | None = None, + tx_time: datetime.datetime | None = None, + tx_id: int | None = None, + ) -> JsonValue: + params = {} + if valid_time is not None: + params["valid-time"] = valid_time.isoformat() + if tx_time is not None: + params["tx-time"] = tx_time.isoformat() + if tx_id is not None: + params["tx-id"] = str(tx_id) + + res = self._client.post("/query", params=params, content=query, headers={"Content-Type": "application/edn"}) return res.json() From 32aa48a32833b0c34d53d1d962542af343745e49 Mon Sep 17 00:00:00 2001 From: Donny Peeters <46660228+Donnype@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:48:02 +0200 Subject: [PATCH 27/82] Chore: use only Pytest in the boefjes (#3536) Signed-off-by: Donny Peeters --- ..._introduce_schema_field_to_boefje_model.py | 1 - boefjes/poetry.lock | 1632 +++++++++-------- boefjes/pyproject.toml | 1 + boefjes/requirements-dev.txt | 1556 ++++++++-------- boefjes/requirements.txt | 1541 ++++++++-------- boefjes/tests/conftest.py | 95 +- .../tests/examples/adr-validator-output.json | 17 - boefjes/tests/examples/crt-normalize.json | 13 - boefjes/tests/examples/crt.json | 13 - boefjes/tests/examples/dns-job.json | 20 - boefjes/tests/examples/dns-normalize2.json | 17 - boefjes/tests/examples/dummy.json | 18 - boefjes/tests/examples/ipv6_nameservers.json | 20 - .../examples/ipv6_nameservers_normalize.json | 27 - boefjes/tests/examples/ipv6_webservers.json | 19 - .../examples/ipv6_webservers_normalize.json | 26 - .../tests/examples/nmap-250-normalize.json | 9 - boefjes/tests/examples/nmap-250.json | 13 - boefjes/tests/examples/nmap-normalize.json | 9 - boefjes/tests/examples/nmap.json | 13 - boefjes/tests/examples/raw/wappalizer.json | 41 - .../examples/raw/wappalizer_redirected.json | 47 - .../pop_response_boefje_dispatched.json | 25 - .../tests/examples/ssl-scan-normalize.json | 11 - boefjes/tests/examples/ssl-scan.json | 13 - .../tests/examples/website_similarity.json | 13 - .../website_similarity_normalize.json | 11 - boefjes/tests/examples/whois-job.json | 13 - boefjes/tests/examples/whois-normalize.json | 11 - boefjes/tests/examples/wpscan-job.json | 13 - boefjes/tests/examples/wpscan-normalize.json | 7 - boefjes/tests/integration/test_api.py | 429 +++-- ...test_json_settings_encryption_migration.py | 135 +- .../test_migration_add_schema_field.py | 317 ++-- .../test_remove_repository_migration.py | 126 +- ...est_settings_to_boefje_config_migration.py | 167 +- .../integration/test_sql_repositories.py | 407 ++-- .../tests/katalogus/test_organisation_api.py | 59 +- .../tests/katalogus/test_plugin_service.py | 190 +- boefjes/tests/katalogus/test_plugins_api.py | 247 ++- boefjes/tests/katalogus/test_settings.py | 23 +- .../kat_test}/__init__.py | 0 .../kat_test/boefje.json | 0 .../kat_test/kat_test_2}/__init__.py | 0 .../kat_test/kat_test_2/boefje.json | 0 .../kat_test_2/kat_test_3}/__init__.py | 0 .../kat_test_2/kat_test_3/normalize.py | 0 .../kat_test_2/kat_test_3/normalizer.json | 0 .../kat_test/kat_test_2/main.py | 0 .../kat_test/kat_test_2/schema.json | 0 .../kat_test/kat_test_4}/__init__.py | 0 .../kat_test/kat_test_4/boefje.json | 0 .../kat_test/kat_test_4/schema.json | 0 .../kat_test/main.py | 0 .../kat_test/normalize.py | 0 .../kat_test/normalizer.json | 0 .../kat_test/schema.json | 0 .../kat_test_4 => plugins}/__init__.py | 0 boefjes/tests/plugins/test_adr_validator.py | 49 + boefjes/tests/plugins/test_answer_parser.py | 24 + boefjes/tests/plugins/test_bodyimage.py | 82 + boefjes/tests/plugins/test_calvin.py | 126 ++ boefjes/tests/plugins/test_cve-2023-35078.py | 45 + .../tests/{ => plugins}/test_cve-2024-6387.py | 0 .../tests/plugins/test_cve_finding_types.py | 87 + boefjes/tests/plugins/test_dns.py | 480 +++++ boefjes/tests/{ => plugins}/test_dnssec.py | 0 boefjes/tests/{ => plugins}/test_fierce.py | 0 .../test_generic_finding_normalizer.py | 44 + boefjes/tests/plugins/test_leakix.py | 24 + boefjes/tests/plugins/test_manual.py | 168 ++ boefjes/tests/{ => plugins}/test_nmap.py | 24 +- boefjes/tests/{ => plugins}/test_rdns.py | 0 .../tests/{ => plugins}/test_report_data.py | 9 +- boefjes/tests/plugins/test_scan_profiles.py | 73 + boefjes/tests/plugins/test_security_txt.py | 89 + boefjes/tests/plugins/test_snyk.py | 114 ++ .../test_sslcertificate_normalizer.py | 0 boefjes/tests/plugins/test_testssl_sh.py | 120 ++ .../plugins/test_wappalyzer_normalizer.py | 15 + boefjes/tests/test_adr_validator.py | 57 - boefjes/tests/test_answer_parser.py | 32 - boefjes/tests/test_bodyimage.py | 102 -- boefjes/tests/test_calvin.py | 155 -- boefjes/tests/test_cve-2023-35078.py | 47 - boefjes/tests/test_cve_finding_types.py | 90 - boefjes/tests/test_dns.py | 494 ----- .../tests/test_generic_finding_normalizer.py | 48 - boefjes/tests/test_leakix.py | 27 - boefjes/tests/test_manual.py | 194 -- boefjes/tests/test_scan_profiles.py | 81 - boefjes/tests/test_security_txt.py | 97 - boefjes/tests/test_snyk.py | 136 -- boefjes/tests/test_tasks.py | 373 ++-- boefjes/tests/test_testssl_sh.py | 124 -- boefjes/tests/test_wappalyzer_normalizer.py | 23 - 96 files changed, 5230 insertions(+), 5788 deletions(-) delete mode 100644 boefjes/tests/examples/adr-validator-output.json delete mode 100644 boefjes/tests/examples/crt-normalize.json delete mode 100644 boefjes/tests/examples/crt.json delete mode 100644 boefjes/tests/examples/dns-job.json delete mode 100644 boefjes/tests/examples/dns-normalize2.json delete mode 100644 boefjes/tests/examples/dummy.json delete mode 100644 boefjes/tests/examples/ipv6_nameservers.json delete mode 100644 boefjes/tests/examples/ipv6_nameservers_normalize.json delete mode 100644 boefjes/tests/examples/ipv6_webservers.json delete mode 100644 boefjes/tests/examples/ipv6_webservers_normalize.json delete mode 100644 boefjes/tests/examples/nmap-250-normalize.json delete mode 100644 boefjes/tests/examples/nmap-250.json delete mode 100644 boefjes/tests/examples/nmap-normalize.json delete mode 100644 boefjes/tests/examples/nmap.json delete mode 100644 boefjes/tests/examples/raw/wappalizer.json delete mode 100644 boefjes/tests/examples/raw/wappalizer_redirected.json delete mode 100644 boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json delete mode 100644 boefjes/tests/examples/ssl-scan-normalize.json delete mode 100644 boefjes/tests/examples/ssl-scan.json delete mode 100644 boefjes/tests/examples/website_similarity.json delete mode 100644 boefjes/tests/examples/website_similarity_normalize.json delete mode 100644 boefjes/tests/examples/whois-job.json delete mode 100644 boefjes/tests/examples/whois-normalize.json delete mode 100644 boefjes/tests/examples/wpscan-job.json delete mode 100644 boefjes/tests/examples/wpscan-normalize.json rename boefjes/tests/{katalogus/boefjes_test_dir => modules/kat_test}/__init__.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/boefje.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir/kat_test => modules/kat_test/kat_test_2}/__init__.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_2/boefje.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir/kat_test/kat_test_2 => modules/kat_test/kat_test_2/kat_test_3}/__init__.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_2/kat_test_3/normalize.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_2/kat_test_3/normalizer.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_2/main.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_2/schema.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3 => modules/kat_test/kat_test_4}/__init__.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_4/boefje.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/kat_test_4/schema.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/main.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/normalize.py (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/normalizer.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir => modules}/kat_test/schema.json (100%) rename boefjes/tests/{katalogus/boefjes_test_dir/kat_test/kat_test_4 => plugins}/__init__.py (100%) create mode 100644 boefjes/tests/plugins/test_adr_validator.py create mode 100644 boefjes/tests/plugins/test_answer_parser.py create mode 100644 boefjes/tests/plugins/test_bodyimage.py create mode 100644 boefjes/tests/plugins/test_calvin.py create mode 100644 boefjes/tests/plugins/test_cve-2023-35078.py rename boefjes/tests/{ => plugins}/test_cve-2024-6387.py (100%) create mode 100644 boefjes/tests/plugins/test_cve_finding_types.py create mode 100644 boefjes/tests/plugins/test_dns.py rename boefjes/tests/{ => plugins}/test_dnssec.py (100%) rename boefjes/tests/{ => plugins}/test_fierce.py (100%) create mode 100644 boefjes/tests/plugins/test_generic_finding_normalizer.py create mode 100644 boefjes/tests/plugins/test_leakix.py create mode 100644 boefjes/tests/plugins/test_manual.py rename boefjes/tests/{ => plugins}/test_nmap.py (81%) rename boefjes/tests/{ => plugins}/test_rdns.py (100%) rename boefjes/tests/{ => plugins}/test_report_data.py (63%) create mode 100644 boefjes/tests/plugins/test_scan_profiles.py create mode 100644 boefjes/tests/plugins/test_security_txt.py create mode 100644 boefjes/tests/plugins/test_snyk.py rename boefjes/tests/{ => plugins}/test_sslcertificate_normalizer.py (100%) create mode 100644 boefjes/tests/plugins/test_testssl_sh.py create mode 100644 boefjes/tests/plugins/test_wappalyzer_normalizer.py delete mode 100644 boefjes/tests/test_adr_validator.py delete mode 100644 boefjes/tests/test_answer_parser.py delete mode 100644 boefjes/tests/test_bodyimage.py delete mode 100644 boefjes/tests/test_calvin.py delete mode 100644 boefjes/tests/test_cve-2023-35078.py delete mode 100644 boefjes/tests/test_cve_finding_types.py delete mode 100644 boefjes/tests/test_dns.py delete mode 100644 boefjes/tests/test_generic_finding_normalizer.py delete mode 100644 boefjes/tests/test_leakix.py delete mode 100644 boefjes/tests/test_manual.py delete mode 100644 boefjes/tests/test_scan_profiles.py delete mode 100644 boefjes/tests/test_security_txt.py delete mode 100644 boefjes/tests/test_snyk.py delete mode 100644 boefjes/tests/test_testssl_sh.py delete mode 100644 boefjes/tests/test_wappalyzer_normalizer.py diff --git a/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py b/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py index 2cd63145aa5..219c31be33b 100644 --- a/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py +++ b/boefjes/boefjes/migrations/versions/5be152459a7b_introduce_schema_field_to_boefje_model.py @@ -38,7 +38,6 @@ def upgrade() -> None: for plugin in local_repo.get_all(): schema = local_repo.schema(plugin.id) - if schema: try: # This way we avoid the safeguard that updating static boefjes is not allowed diff --git a/boefjes/poetry.lock b/boefjes/poetry.lock index 593f2e7f6d7..d96b40e2849 100644 --- a/boefjes/poetry.lock +++ b/boefjes/poetry.lock @@ -2,98 +2,113 @@ [[package]] name = "aiohappyeyeballs" -version = "2.3.5" +version = "2.4.0" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "aiohappyeyeballs-2.3.5-py3-none-any.whl", hash = "sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03"}, - {file = "aiohappyeyeballs-2.3.5.tar.gz", hash = "sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105"}, + {file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"}, + {file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"}, ] [[package]] name = "aiohttp" -version = "3.10.3" +version = "3.10.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db"}, - {file = "aiohttp-3.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1"}, - {file = "aiohttp-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb"}, - {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2"}, - {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201"}, - {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8"}, - {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa"}, - {file = "aiohttp-3.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73"}, - {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93"}, - {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7"}, - {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27"}, - {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7"}, - {file = "aiohttp-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9"}, - {file = "aiohttp-3.10.3-cp310-cp310-win32.whl", hash = "sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9"}, - {file = "aiohttp-3.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299"}, - {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b"}, - {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2"}, - {file = "aiohttp-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9"}, - {file = "aiohttp-3.10.3-cp311-cp311-win32.whl", hash = "sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b"}, - {file = "aiohttp-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3"}, - {file = "aiohttp-3.10.3-cp312-cp312-win32.whl", hash = "sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a"}, - {file = "aiohttp-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf"}, - {file = "aiohttp-3.10.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752"}, - {file = "aiohttp-3.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88"}, - {file = "aiohttp-3.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c"}, - {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e"}, - {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4"}, - {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f"}, - {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f"}, - {file = "aiohttp-3.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9"}, - {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f"}, - {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f"}, - {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8"}, - {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7"}, - {file = "aiohttp-3.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f"}, - {file = "aiohttp-3.10.3-cp38-cp38-win32.whl", hash = "sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5"}, - {file = "aiohttp-3.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394"}, - {file = "aiohttp-3.10.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e"}, - {file = "aiohttp-3.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1"}, - {file = "aiohttp-3.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc"}, - {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad"}, - {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a"}, - {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a"}, - {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1"}, - {file = "aiohttp-3.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab"}, - {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844"}, - {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06"}, - {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2"}, - {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f"}, - {file = "aiohttp-3.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21"}, - {file = "aiohttp-3.10.3-cp39-cp39-win32.whl", hash = "sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac"}, - {file = "aiohttp-3.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752"}, - {file = "aiohttp-3.10.3.tar.gz", hash = "sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, + {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, + {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, + {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, + {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, + {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, + {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, + {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, + {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, + {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, + {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, + {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, + {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, + {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, + {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, + {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, + {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, + {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, + {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, + {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, + {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, + {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, + {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, + {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, + {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, + {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, + {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, + {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, + {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, + {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, + {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, + {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, ] [package.dependencies] @@ -293,89 +308,89 @@ rich = ">=10.16.2" [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, - {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, - {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, - {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, - {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, - {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, - {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, - {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -524,18 +539,18 @@ files = [ [[package]] name = "configparser" -version = "7.0.0" +version = "7.1.0" description = "Updated configparser from stdlib for earlier Pythons." optional = false python-versions = ">=3.8" files = [ - {file = "configparser-7.0.0-py3-none-any.whl", hash = "sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017"}, - {file = "configparser-7.0.0.tar.gz", hash = "sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0"}, + {file = "configparser-7.1.0-py3-none-any.whl", hash = "sha256:98e374573c4e10e92399651e3ba1c47a438526d633c44ee96143dec26dad4299"}, + {file = "configparser-7.1.0.tar.gz", hash = "sha256:eb82646c892dbdf773dae19c633044d163c3129971ae09b49410a303b8e0a5f7"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "types-backports"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "types-backports"] [[package]] name = "cryptography" @@ -703,19 +718,19 @@ standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23 [[package]] name = "filelock" -version = "3.15.4" +version = "3.16.0" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609"}, + {file = "filelock-3.16.0.tar.gz", hash = "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.3)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "forcediphttpsadapter" @@ -820,13 +835,13 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.63.2" +version = "1.65.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, - {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, + {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, + {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, ] [package.dependencies] @@ -837,69 +852,77 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "greenlet" -version = "3.0.3" +version = "3.1.0" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, + {file = "greenlet-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8"}, + {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca"}, + {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc"}, + {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d"}, + {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25"}, + {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682"}, + {file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1"}, + {file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99"}, + {file = "greenlet-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54"}, + {file = "greenlet-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345"}, + {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6"}, + {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc"}, + {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6"}, + {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f"}, + {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19"}, + {file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a"}, + {file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b"}, + {file = "greenlet-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9"}, + {file = "greenlet-3.1.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27"}, + {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303"}, + {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf"}, + {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc"}, + {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f"}, + {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a"}, + {file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665"}, + {file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811"}, + {file = "greenlet-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b"}, + {file = "greenlet-3.1.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd"}, + {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca"}, + {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64"}, + {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b"}, + {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989"}, + {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17"}, + {file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5"}, + {file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484"}, + {file = "greenlet-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0"}, + {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0"}, + {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6"}, + {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a"}, + {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df"}, + {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637"}, + {file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954"}, + {file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3"}, + {file = "greenlet-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00"}, + {file = "greenlet-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6"}, + {file = "greenlet-3.1.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33"}, + {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f"}, + {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7"}, + {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09"}, + {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491"}, + {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b"}, + {file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d"}, + {file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0"}, + {file = "greenlet-3.1.0-cp38-cp38-win32.whl", hash = "sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2"}, + {file = "greenlet-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910"}, + {file = "greenlet-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b"}, + {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7"}, + {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501"}, + {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3967dcc1cd2ea61b08b0b276659242cbce5caca39e7cbc02408222fb9e6ff39"}, + {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d45b75b0f3fd8d99f62eb7908cfa6d727b7ed190737dec7fe46d993da550b81a"}, + {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d004db911ed7b6218ec5c5bfe4cf70ae8aa2223dffbb5b3c69e342bb253cb28"}, + {file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9505a0c8579899057cbefd4ec34d865ab99852baf1ff33a9481eb3924e2da0b"}, + {file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fd6e94593f6f9714dbad1aaba734b5ec04593374fa6638df61592055868f8b8"}, + {file = "greenlet-3.1.0-cp39-cp39-win32.whl", hash = "sha256:d0dd943282231480aad5f50f89bdf26690c995e8ff555f26d8a5b9887b559bcc"}, + {file = "greenlet-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:ac0adfdb3a21dc2a24ed728b61e72440d297d0fd3a577389df566651fcd08f97"}, + {file = "greenlet-3.1.0.tar.gz", hash = "sha256:b395121e9bbe8d02a750886f108d540abe66075e61e22f7353d9acb0b81be0f0"}, ] [package.extras] @@ -908,61 +931,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.65.4" +version = "1.66.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.65.4-cp310-cp310-linux_armv7l.whl", hash = "sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c"}, - {file = "grpcio-1.65.4-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a"}, - {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8"}, - {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82"}, - {file = "grpcio-1.65.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e"}, - {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de"}, - {file = "grpcio-1.65.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d"}, - {file = "grpcio-1.65.4-cp310-cp310-win32.whl", hash = "sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1"}, - {file = "grpcio-1.65.4-cp310-cp310-win_amd64.whl", hash = "sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec"}, - {file = "grpcio-1.65.4-cp311-cp311-linux_armv7l.whl", hash = "sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef"}, - {file = "grpcio-1.65.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18"}, - {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8"}, - {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17"}, - {file = "grpcio-1.65.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4"}, - {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e"}, - {file = "grpcio-1.65.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5"}, - {file = "grpcio-1.65.4-cp311-cp311-win32.whl", hash = "sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b"}, - {file = "grpcio-1.65.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558"}, - {file = "grpcio-1.65.4-cp312-cp312-linux_armv7l.whl", hash = "sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56"}, - {file = "grpcio-1.65.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2"}, - {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e"}, - {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74"}, - {file = "grpcio-1.65.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63"}, - {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a"}, - {file = "grpcio-1.65.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28"}, - {file = "grpcio-1.65.4-cp312-cp312-win32.whl", hash = "sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0"}, - {file = "grpcio-1.65.4-cp312-cp312-win_amd64.whl", hash = "sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416"}, - {file = "grpcio-1.65.4-cp38-cp38-linux_armv7l.whl", hash = "sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021"}, - {file = "grpcio-1.65.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52"}, - {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385"}, - {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864"}, - {file = "grpcio-1.65.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816"}, - {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524"}, - {file = "grpcio-1.65.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7"}, - {file = "grpcio-1.65.4-cp38-cp38-win32.whl", hash = "sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a"}, - {file = "grpcio-1.65.4-cp38-cp38-win_amd64.whl", hash = "sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f"}, - {file = "grpcio-1.65.4-cp39-cp39-linux_armv7l.whl", hash = "sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733"}, - {file = "grpcio-1.65.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4"}, - {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe"}, - {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1"}, - {file = "grpcio-1.65.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b"}, - {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2"}, - {file = "grpcio-1.65.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257"}, - {file = "grpcio-1.65.4-cp39-cp39-win32.whl", hash = "sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d"}, - {file = "grpcio-1.65.4-cp39-cp39-win_amd64.whl", hash = "sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9"}, - {file = "grpcio-1.65.4.tar.gz", hash = "sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39"}, + {file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"}, + {file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d"}, + {file = "grpcio-1.66.1-cp310-cp310-win32.whl", hash = "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c"}, + {file = "grpcio-1.66.1-cp310-cp310-win_amd64.whl", hash = "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858"}, + {file = "grpcio-1.66.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a"}, + {file = "grpcio-1.66.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd"}, + {file = "grpcio-1.66.1-cp311-cp311-win32.whl", hash = "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791"}, + {file = "grpcio-1.66.1-cp311-cp311-win_amd64.whl", hash = "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb"}, + {file = "grpcio-1.66.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a"}, + {file = "grpcio-1.66.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524"}, + {file = "grpcio-1.66.1-cp312-cp312-win32.whl", hash = "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759"}, + {file = "grpcio-1.66.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734"}, + {file = "grpcio-1.66.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2"}, + {file = "grpcio-1.66.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d"}, + {file = "grpcio-1.66.1-cp38-cp38-win32.whl", hash = "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3"}, + {file = "grpcio-1.66.1-cp38-cp38-win_amd64.whl", hash = "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce"}, + {file = "grpcio-1.66.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503"}, + {file = "grpcio-1.66.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c"}, + {file = "grpcio-1.66.1-cp39-cp39-win32.whl", hash = "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45"}, + {file = "grpcio-1.66.1-cp39-cp39-win_amd64.whl", hash = "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8"}, + {file = "grpcio-1.66.1.tar.gz", hash = "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.65.4)"] +protobuf = ["grpcio-tools (>=1.66.1)"] [[package]] name = "h11" @@ -1008,13 +1031,13 @@ files = [ [[package]] name = "httpx" -version = "0.27.0" +version = "0.27.2" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, ] [package.dependencies] @@ -1029,18 +1052,22 @@ brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-metadata" version = "8.0.0" @@ -1144,153 +1171,149 @@ test = ["pytest", "pytest-cov"] [[package]] name = "lxml" -version = "5.2.2" +version = "5.3.0" 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.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"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, + {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, + {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, + {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, + {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, + {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, + {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, ] [package.extras] @@ -1298,7 +1321,7 @@ cssselect = ["cssselect (>=0.7)"] html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.10)"] +source = ["Cython (>=3.0.11)"] [[package]] name = "mako" @@ -1606,103 +1629,108 @@ files = [ [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "netaddr" version = "0.9.0" @@ -2114,13 +2142,13 @@ files = [ [[package]] name = "pyasn1" -version = "0.6.0" +version = "0.6.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" files = [ - {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, - {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] [[package]] @@ -2150,18 +2178,18 @@ files = [ [[package]] name = "pydantic" -version = "2.8.2" +version = "2.9.1" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, - {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, + {file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"}, + {file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.20.1" +annotated-types = ">=0.6.0" +pydantic-core = "2.23.3" typing-extensions = [ {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, @@ -2169,103 +2197,104 @@ typing-extensions = [ [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.20.1" +version = "2.23.3" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, - {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, - {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, - {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, - {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, - {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, - {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, - {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, - {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, - {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, - {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, - {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, - {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, - {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"}, + {file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"}, + {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"}, + {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"}, + {file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"}, + {file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"}, + {file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"}, + {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"}, + {file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"}, + {file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"}, + {file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"}, + {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"}, + {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"}, + {file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"}, + {file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"}, + {file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"}, + {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"}, + {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"}, + {file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"}, + {file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"}, + {file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"}, + {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"}, + {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"}, + {file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"}, + {file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"}, + {file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"}, + {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"}, + {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"}, + {file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"}, + {file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"}, + {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"}, + {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"}, + {file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"}, ] [package.dependencies] @@ -2273,13 +2302,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.4.0" +version = "2.5.2" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"}, - {file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"}, + {file = "pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907"}, + {file = "pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0"}, ] [package.dependencies] @@ -2293,17 +2322,21 @@ yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pydicom" -version = "2.4.4" +version = "3.0.0" description = "A pure Python package for reading and writing DICOM data" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "pydicom-2.4.4-py3-none-any.whl", hash = "sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42"}, - {file = "pydicom-2.4.4.tar.gz", hash = "sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a"}, + {file = "pydicom-3.0.0-py3-none-any.whl", hash = "sha256:7b1435dc7427a3d172685a9406ff1a75eb2d7651d236d0d99abd4953a1100922"}, + {file = "pydicom-3.0.0.tar.gz", hash = "sha256:003aeb025bbd20fc029f71eb286cf8772cc924d8de2baaec184c2caa513502df"}, ] [package.extras] -docs = ["matplotlib", "numpy", "numpydoc", "pillow", "sphinx", "sphinx-copybutton", "sphinx-gallery", "sphinx_rtd_theme", "sphinxcontrib-napoleon"] +basic = ["numpy", "types-pydicom"] +dev = ["black (==24.8.0)", "mypy (==1.11.2)", "pre-commit", "pydicom-data", "pytest", "pytest-cov", "ruff (==0.6.3)", "types-requests"] +docs = ["matplotlib", "numpy", "numpydoc", "pillow", "sphinx", "sphinx-copybutton", "sphinx-gallery", "sphinx_rtd_theme", "sphinxcontrib-jquery", "sphinxcontrib-napoleon"] +gpl-license = ["pylibjpeg[libjpeg]"] +pixeldata = ["numpy", "pillow", "pyjpegls", "pylibjpeg[openjpeg]", "pylibjpeg[rle]", "python-gdcm"] [[package]] name = "pygments" @@ -2366,13 +2399,13 @@ tests = ["pyfakefs", "pytest", "sqlalchemy"] [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] @@ -2388,21 +2421,38 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-env" -version = "1.1.3" +version = "1.1.4" description = "pytest plugin that allows you to add environment variables." optional = false python-versions = ">=3.8" files = [ - {file = "pytest_env-1.1.3-py3-none-any.whl", hash = "sha256:aada77e6d09fcfb04540a6e462c58533c37df35fa853da78707b17ec04d17dfc"}, - {file = "pytest_env-1.1.3.tar.gz", hash = "sha256:fcd7dc23bb71efd3d35632bde1bbe5ee8c8dc4489d6617fb010674880d96216b"}, + {file = "pytest_env-1.1.4-py3-none-any.whl", hash = "sha256:a4212056d4d440febef311a98fdca56c31256d58fb453d103cba4e8a532b721d"}, + {file = "pytest_env-1.1.4.tar.gz", hash = "sha256:86653658da8f11c6844975db955746c458a9c09f1e64957603161e2ff93f5133"}, ] [package.dependencies] -pytest = ">=7.4.3" +pytest = ">=8.3.2" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [package.extras] -test = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "pytest-mock (>=3.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "python-dateutil" @@ -2547,13 +2597,13 @@ requests = ">=1.0.0" [[package]] name = "rich" -version = "13.7.1" +version = "13.8.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, + {file = "rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06"}, + {file = "rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a"}, ] [package.dependencies] @@ -2694,19 +2744,23 @@ requests = "*" [[package]] name = "setuptools" -version = "72.1.0" +version = "75.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, - {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, + {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, + {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] [[package]] name = "shodan" @@ -2749,66 +2803,66 @@ files = [ [[package]] name = "soupsieve" -version = "2.5" +version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] name = "sqlalchemy" -version = "1.4.53" +version = "1.4.54" description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.53-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-win32.whl", hash = "sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed"}, - {file = "SQLAlchemy-1.4.53-cp310-cp310-win_amd64.whl", hash = "sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530"}, - {file = "SQLAlchemy-1.4.53-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc"}, - {file = "SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7"}, - {file = "SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c"}, - {file = "SQLAlchemy-1.4.53-cp311-cp311-win32.whl", hash = "sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046"}, - {file = "SQLAlchemy-1.4.53-cp311-cp311-win_amd64.whl", hash = "sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69"}, - {file = "SQLAlchemy-1.4.53-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22"}, - {file = "SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315"}, - {file = "SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330"}, - {file = "SQLAlchemy-1.4.53-cp312-cp312-win32.whl", hash = "sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05"}, - {file = "SQLAlchemy-1.4.53-cp312-cp312-win_amd64.whl", hash = "sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883"}, - {file = "SQLAlchemy-1.4.53-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d"}, - {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3"}, - {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c"}, - {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59"}, - {file = "SQLAlchemy-1.4.53-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-win32.whl", hash = "sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6"}, - {file = "SQLAlchemy-1.4.53-cp37-cp37m-win_amd64.whl", hash = "sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-win32.whl", hash = "sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a"}, - {file = "SQLAlchemy-1.4.53-cp38-cp38-win_amd64.whl", hash = "sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-win32.whl", hash = "sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85"}, - {file = "SQLAlchemy-1.4.53-cp39-cp39-win_amd64.whl", hash = "sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a"}, - {file = "SQLAlchemy-1.4.53.tar.gz", hash = "sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:af00236fe21c4d4f4c227b6ccc19b44c594160cc3ff28d104cdce85855369277"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1183599e25fa38a1a322294b949da02b4f0da13dbc2688ef9dbe746df573f8a6"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1990d5a6a5dc358a0894c8ca02043fb9a5ad9538422001fb2826e91c50f1d539"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:14b3f4783275339170984cadda66e3ec011cce87b405968dc8d51cf0f9997b0d"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b24364150738ce488333b3fb48bfa14c189a66de41cd632796fbcacb26b4585"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win32.whl", hash = "sha256:a8a72259a1652f192c68377be7011eac3c463e9892ef2948828c7d58e4829988"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win_amd64.whl", hash = "sha256:b67589f7955924865344e6eacfdcf70675e64f36800a576aa5e961f0008cde2a"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win32.whl", hash = "sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl", hash = "sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a41611835010ed4ea4c7aed1da5b58aac78ee7e70932a91ed2705a7b38e40f52"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8c1b9ecaf9f2590337d5622189aeb2f0dbc54ba0232fa0856cf390957584a9"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de620f978ca273ce027769dc8db7e6ee72631796187adc8471b3c76091b809e"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a2530400a6e7e68fd1552a55515de6a4559122e495f73554a51cedafc11669"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cf7076c8578b3de4e43a046cc7a1af8466e1c3f5e64167189fe8958a4f9c02"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:f1e1b92ee4ee9ffc68624ace218b89ca5ca667607ccee4541a90cc44999b9aea"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41cffc63c7c83dfc30c4cab5b4308ba74440a9633c4509c51a0c52431fb0f8ab"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5933c45d11cbd9694b1540aa9076816cc7406964c7b16a380fd84d3a5fe3241"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cafe0ba3a96d0845121433cffa2b9232844a2609fce694fcc02f3f31214ece28"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a19f816f4702d7b1951d7576026c7124b9bfb64a9543e571774cf517b7a50b29"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win32.whl", hash = "sha256:76c2ba7b5a09863d0a8166fbc753af96d561818c572dbaf697c52095938e7be4"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win_amd64.whl", hash = "sha256:a86b0e4be775902a5496af4fb1b60d8a2a457d78f531458d294360b8637bb014"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:a49730afb716f3f675755afec109895cab95bc9875db7ffe2e42c1b1c6279482"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e78444bc77d089e62874dc74df05a5c71f01ac598010a327881a48408d0064"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02d2ecb9508f16ab9c5af466dfe5a88e26adf2e1a8d1c56eb616396ccae2c186"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:394b0135900b62dbf63e4809cdc8ac923182af2816d06ea61cd6763943c2cc05"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed3576675c187e3baa80b02c4c9d0edfab78eff4e89dd9da736b921333a2432"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win32.whl", hash = "sha256:fc9ffd9a38e21fad3e8c5a88926d57f94a32546e937e0be46142b2702003eba7"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win_amd64.whl", hash = "sha256:a01bc25eb7a5688656c8770f931d5cb4a44c7de1b3cec69b84cc9745d1e4cc10"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0b76bbb1cbae618d10679be8966f6d66c94f301cfc15cb49e2f2382563fb6efb"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb2886c0be2c6c54d0651d5a61c29ef347e8eec81fd83afebbf7b59b80b7393"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:954816850777ac234a4e32b8c88ac1f7847088a6e90cfb8f0e127a1bf3feddff"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d83cd1cc03c22d922ec94d0d5f7b7c96b1332f5e122e81b1a61fb22da77879a"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1576fba3616f79496e2f067262200dbf4aab1bb727cd7e4e006076686413c80c"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win32.whl", hash = "sha256:3112de9e11ff1957148c6de1df2bc5cc1440ee36783412e5eedc6f53638a577d"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win_amd64.whl", hash = "sha256:6da60fb24577f989535b8fc8b2ddc4212204aaf02e53c4c7ac94ac364150ed08"}, + {file = "sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a"}, ] [package.dependencies] @@ -2910,13 +2964,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -3066,101 +3120,103 @@ files = [ [[package]] name = "yarl" -version = "1.9.4" +version = "1.11.1" description = "Yet another URL library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00"}, + {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d"}, + {file = "yarl-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e"}, + {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc"}, + {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec"}, + {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf"}, + {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49"}, + {file = "yarl-1.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff"}, + {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad"}, + {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145"}, + {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd"}, + {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26"}, + {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46"}, + {file = "yarl-1.11.1-cp310-cp310-win32.whl", hash = "sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91"}, + {file = "yarl-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998"}, + {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68"}, + {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe"}, + {file = "yarl-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675"}, + {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63"}, + {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27"}, + {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5"}, + {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92"}, + {file = "yarl-1.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b"}, + {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a"}, + {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83"}, + {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff"}, + {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c"}, + {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e"}, + {file = "yarl-1.11.1-cp311-cp311-win32.whl", hash = "sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6"}, + {file = "yarl-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b"}, + {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0"}, + {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265"}, + {file = "yarl-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867"}, + {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd"}, + {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef"}, + {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8"}, + {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870"}, + {file = "yarl-1.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2"}, + {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84"}, + {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa"}, + {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff"}, + {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239"}, + {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45"}, + {file = "yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447"}, + {file = "yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639"}, + {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c"}, + {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e"}, + {file = "yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93"}, + {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d"}, + {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7"}, + {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089"}, + {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5"}, + {file = "yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5"}, + {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786"}, + {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318"}, + {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82"}, + {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a"}, + {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da"}, + {file = "yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979"}, + {file = "yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367"}, + {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dae7bd0daeb33aa3e79e72877d3d51052e8b19c9025ecf0374f542ea8ec120e4"}, + {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3ff6b1617aa39279fe18a76c8d165469c48b159931d9b48239065767ee455b2b"}, + {file = "yarl-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3257978c870728a52dcce8c2902bf01f6c53b65094b457bf87b2644ee6238ddc"}, + {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f351fa31234699d6084ff98283cb1e852270fe9e250a3b3bf7804eb493bd937"}, + {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8aef1b64da41d18026632d99a06b3fefe1d08e85dd81d849fa7c96301ed22f1b"}, + {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7175a87ab8f7fbde37160a15e58e138ba3b2b0e05492d7351314a250d61b1591"}, + {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba444bdd4caa2a94456ef67a2f383710928820dd0117aae6650a4d17029fa25e"}, + {file = "yarl-1.11.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ea9682124fc062e3d931c6911934a678cb28453f957ddccf51f568c2f2b5e05"}, + {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8418c053aeb236b20b0ab8fa6bacfc2feaaf7d4683dd96528610989c99723d5f"}, + {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:61a5f2c14d0a1adfdd82258f756b23a550c13ba4c86c84106be4c111a3a4e413"}, + {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f3a6d90cab0bdf07df8f176eae3a07127daafcf7457b997b2bf46776da2c7eb7"}, + {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:077da604852be488c9a05a524068cdae1e972b7dc02438161c32420fb4ec5e14"}, + {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:15439f3c5c72686b6c3ff235279630d08936ace67d0fe5c8d5bbc3ef06f5a420"}, + {file = "yarl-1.11.1-cp38-cp38-win32.whl", hash = "sha256:238a21849dd7554cb4d25a14ffbfa0ef380bb7ba201f45b144a14454a72ffa5a"}, + {file = "yarl-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:67459cf8cf31da0e2cbdb4b040507e535d25cfbb1604ca76396a3a66b8ba37a6"}, + {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:884eab2ce97cbaf89f264372eae58388862c33c4f551c15680dd80f53c89a269"}, + {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a336eaa7ee7e87cdece3cedb395c9657d227bfceb6781295cf56abcd3386a26"}, + {file = "yarl-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87f020d010ba80a247c4abc335fc13421037800ca20b42af5ae40e5fd75e7909"}, + {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:637c7ddb585a62d4469f843dac221f23eec3cbad31693b23abbc2c366ad41ff4"}, + {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48dfd117ab93f0129084577a07287376cc69c08138694396f305636e229caa1a"}, + {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e0ae31fb5ccab6eda09ba1494e87eb226dcbd2372dae96b87800e1dcc98804"}, + {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46f81501160c28d0c0b7333b4f7be8983dbbc161983b6fb814024d1b4952f79"}, + {file = "yarl-1.11.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04293941646647b3bfb1719d1d11ff1028e9c30199509a844da3c0f5919dc520"}, + {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:250e888fa62d73e721f3041e3a9abf427788a1934b426b45e1b92f62c1f68366"}, + {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e8f63904df26d1a66aabc141bfd258bf738b9bc7bc6bdef22713b4f5ef789a4c"}, + {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:aac44097d838dda26526cffb63bdd8737a2dbdf5f2c68efb72ad83aec6673c7e"}, + {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:267b24f891e74eccbdff42241c5fb4f974de2d6271dcc7d7e0c9ae1079a560d9"}, + {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6907daa4b9d7a688063ed098c472f96e8181733c525e03e866fb5db480a424df"}, + {file = "yarl-1.11.1-cp39-cp39-win32.whl", hash = "sha256:14438dfc5015661f75f85bc5adad0743678eefee266ff0c9a8e32969d5d69f74"}, + {file = "yarl-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:94d0caaa912bfcdc702a4204cd5e2bb01eb917fc4f5ea2315aa23962549561b0"}, + {file = "yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38"}, + {file = "yarl-1.11.1.tar.gz", hash = "sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53"}, ] [package.dependencies] @@ -3169,20 +3225,24 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.19.2" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "4135f17871ab68dcf30970e2716a8551978ed6782db30b8bbd7858c90e99e0f0" +content-hash = "a676ac50b0ec9c1af1a96f12ee08db8177dd88005367efd4a2db590a97362b00" diff --git a/boefjes/pyproject.toml b/boefjes/pyproject.toml index 2b1f16ad6f9..e40621a78c7 100644 --- a/boefjes/pyproject.toml +++ b/boefjes/pyproject.toml @@ -77,6 +77,7 @@ maxminddb = "^2.6.2" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" pytest-env = "^1.1.3" +pytest-mock = "^3.14.0" [build-system] requires = ["setuptools>=45", "wheel"] diff --git a/boefjes/requirements-dev.txt b/boefjes/requirements-dev.txt index 2338137a316..26e2c95c2da 100644 --- a/boefjes/requirements-dev.txt +++ b/boefjes/requirements-dev.txt @@ -1,83 +1,98 @@ -aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ - --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 -aiohttp==3.10.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b \ - --hash=sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3 \ - --hash=sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27 \ - --hash=sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844 \ - --hash=sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7 \ - --hash=sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201 \ - --hash=sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee \ - --hash=sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f \ - --hash=sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696 \ - --hash=sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2 \ - --hash=sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f \ - --hash=sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f \ - --hash=sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8 \ - --hash=sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8 \ - --hash=sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68 \ - --hash=sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394 \ - --hash=sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e \ - --hash=sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7 \ - --hash=sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a \ - --hash=sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9 \ - --hash=sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7 \ - --hash=sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4 \ - --hash=sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab \ - --hash=sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec \ - --hash=sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c \ - --hash=sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1 \ - --hash=sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e \ - --hash=sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e \ - --hash=sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7 \ - --hash=sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752 \ - --hash=sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9 \ - --hash=sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5 \ - --hash=sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef \ - --hash=sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806 \ - --hash=sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17 \ - --hash=sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb \ - --hash=sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc \ - --hash=sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a \ - --hash=sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f \ - --hash=sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93 \ - --hash=sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1 \ - --hash=sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09 \ - --hash=sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57 \ - --hash=sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad \ - --hash=sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1 \ - --hash=sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88 \ - --hash=sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9 \ - --hash=sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9 \ - --hash=sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06 \ - --hash=sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1 \ - --hash=sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2 \ - --hash=sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299 \ - --hash=sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac \ - --hash=sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204 \ - --hash=sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5 \ - --hash=sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f \ - --hash=sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f \ - --hash=sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2 \ - --hash=sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f \ - --hash=sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6 \ - --hash=sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272 \ - --hash=sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e \ - --hash=sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db \ - --hash=sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f \ - --hash=sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752 \ - --hash=sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a \ - --hash=sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e \ - --hash=sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c \ - --hash=sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279 \ - --hash=sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc \ - --hash=sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b \ - --hash=sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf \ - --hash=sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa \ - --hash=sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21 \ - --hash=sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73 \ - --hash=sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189 +aiohappyeyeballs==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2 \ + --hash=sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd +aiohttp==3.10.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277 \ + --hash=sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1 \ + --hash=sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe \ + --hash=sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb \ + --hash=sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca \ + --hash=sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91 \ + --hash=sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972 \ + --hash=sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a \ + --hash=sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3 \ + --hash=sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa \ + --hash=sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77 \ + --hash=sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b \ + --hash=sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8 \ + --hash=sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599 \ + --hash=sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc \ + --hash=sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf \ + --hash=sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511 \ + --hash=sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699 \ + --hash=sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487 \ + --hash=sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987 \ + --hash=sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff \ + --hash=sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db \ + --hash=sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022 \ + --hash=sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce \ + --hash=sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a \ + --hash=sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5 \ + --hash=sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7 \ + --hash=sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820 \ + --hash=sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf \ + --hash=sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e \ + --hash=sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf \ + --hash=sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5 \ + --hash=sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6 \ + --hash=sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6 \ + --hash=sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91 \ + --hash=sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3 \ + --hash=sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a \ + --hash=sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d \ + --hash=sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088 \ + --hash=sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc \ + --hash=sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f \ + --hash=sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75 \ + --hash=sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471 \ + --hash=sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e \ + --hash=sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697 \ + --hash=sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092 \ + --hash=sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69 \ + --hash=sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3 \ + --hash=sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32 \ + --hash=sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589 \ + --hash=sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178 \ + --hash=sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92 \ + --hash=sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2 \ + --hash=sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e \ + --hash=sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058 \ + --hash=sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857 \ + --hash=sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1 \ + --hash=sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6 \ + --hash=sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22 \ + --hash=sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0 \ + --hash=sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b \ + --hash=sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57 \ + --hash=sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f \ + --hash=sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e \ + --hash=sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16 \ + --hash=sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1 \ + --hash=sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f \ + --hash=sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6 \ + --hash=sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04 \ + --hash=sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae \ + --hash=sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d \ + --hash=sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b \ + --hash=sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f \ + --hash=sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862 \ + --hash=sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689 \ + --hash=sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c \ + --hash=sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683 \ + --hash=sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef \ + --hash=sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f \ + --hash=sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12 \ + --hash=sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73 \ + --hash=sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061 \ + --hash=sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072 \ + --hash=sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11 \ + --hash=sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691 \ + --hash=sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77 \ + --hash=sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385 \ + --hash=sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172 \ + --hash=sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569 \ + --hash=sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f \ + --hash=sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 @@ -114,77 +129,77 @@ beautifulsoup4==4.11.1 ; python_version >= "3.10" and python_version < "4.0" \ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2ddd6d0ee6df70acf15792328df8bb4d0dd5a76b50883adac62989f1641820c1 \ --hash=sha256:665acf8777a871098832527ab8e0c5b1b9f9a548be928239747a6fcde8b613eb -certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 -cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f \ - --hash=sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab \ - --hash=sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499 \ - --hash=sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058 \ - --hash=sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693 \ - --hash=sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb \ - --hash=sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377 \ - --hash=sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885 \ - --hash=sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2 \ - --hash=sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401 \ - --hash=sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4 \ - --hash=sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b \ - --hash=sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59 \ - --hash=sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f \ - --hash=sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c \ - --hash=sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555 \ - --hash=sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa \ - --hash=sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424 \ - --hash=sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb \ - --hash=sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2 \ - --hash=sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8 \ - --hash=sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e \ - --hash=sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9 \ - --hash=sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82 \ - --hash=sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828 \ - --hash=sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759 \ - --hash=sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc \ - --hash=sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118 \ - --hash=sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf \ - --hash=sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932 \ - --hash=sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a \ - --hash=sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29 \ - --hash=sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206 \ - --hash=sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2 \ - --hash=sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c \ - --hash=sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c \ - --hash=sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0 \ - --hash=sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a \ - --hash=sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195 \ - --hash=sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6 \ - --hash=sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9 \ - --hash=sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc \ - --hash=sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb \ - --hash=sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0 \ - --hash=sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7 \ - --hash=sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb \ - --hash=sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a \ - --hash=sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492 \ - --hash=sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720 \ - --hash=sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42 \ - --hash=sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7 \ - --hash=sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d \ - --hash=sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d \ - --hash=sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb \ - --hash=sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4 \ - --hash=sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2 \ - --hash=sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b \ - --hash=sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8 \ - --hash=sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e \ - --hash=sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204 \ - --hash=sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3 \ - --hash=sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150 \ - --hash=sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4 \ - --hash=sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 \ - --hash=sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e \ - --hash=sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb \ - --hash=sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91 +certifi==2024.8.30 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ + --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ + --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ + --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ + --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ + --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ + --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ + --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ + --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ + --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ + --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ + --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ + --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ + --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ + --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ + --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ + --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ + --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ + --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ + --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ + --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ + --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ + --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ + --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ + --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ + --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ + --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ + --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ + --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ + --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ + --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ + --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ + --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ + --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ + --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ + --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ + --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ + --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ + --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ + --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ + --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ + --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ + --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ + --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ + --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ + --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ + --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ + --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ + --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ + --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ + --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ + --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ + --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ + --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ + --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ + --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ + --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ + --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ + --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ + --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ + --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ + --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ + --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ + --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ + --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ + --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ @@ -285,9 +300,9 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ - --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 +configparser==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:98e374573c4e10e92399651e3ba1c47a438526d633c44ee96143dec26dad4299 \ + --hash=sha256:eb82646c892dbdf773dae19c633044d163c3129971ae09b49410a303b8e0a5f7 cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ @@ -337,9 +352,9 @@ exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -filelock==3.15.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ - --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 +filelock==3.16.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec \ + --hash=sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609 forcediphttpsadapter==1.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d224cf6e8e50eb788c9f5994a7afa6d389bac6dbe540b7dfd77a32590ad0153 \ --hash=sha256:5e7662ece61735585332d09b87d94fffe4752469d5c0d3feff48746e5d70744b @@ -421,115 +436,123 @@ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887 \ --hash=sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced \ --hash=sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74 -googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ - --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 -greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ - --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ - --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ - --hash=sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257 \ - --hash=sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4 \ - --hash=sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676 \ - --hash=sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61 \ - --hash=sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc \ - --hash=sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca \ - --hash=sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7 \ - --hash=sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728 \ - --hash=sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305 \ - --hash=sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6 \ - --hash=sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379 \ - --hash=sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414 \ - --hash=sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04 \ - --hash=sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a \ - --hash=sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf \ - --hash=sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491 \ - --hash=sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559 \ - --hash=sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e \ - --hash=sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274 \ - --hash=sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb \ - --hash=sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b \ - --hash=sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9 \ - --hash=sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b \ - --hash=sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be \ - --hash=sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506 \ - --hash=sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405 \ - --hash=sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113 \ - --hash=sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f \ - --hash=sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5 \ - --hash=sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230 \ - --hash=sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d \ - --hash=sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f \ - --hash=sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a \ - --hash=sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e \ - --hash=sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61 \ - --hash=sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6 \ - --hash=sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d \ - --hash=sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71 \ - --hash=sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22 \ - --hash=sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2 \ - --hash=sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3 \ - --hash=sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067 \ - --hash=sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc \ - --hash=sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881 \ - --hash=sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3 \ - --hash=sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e \ - --hash=sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac \ - --hash=sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53 \ - --hash=sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0 \ - --hash=sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b \ - --hash=sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83 \ - --hash=sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41 \ - --hash=sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c \ - --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ - --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ - --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ - --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ - --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ - --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ - --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ - --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ - --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ - --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ - --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ - --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ - --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ - --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ - --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ - --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ - --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ - --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ - --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ - --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ - --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ - --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ - --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ - --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ - --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ - --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ - --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ - --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ - --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ - --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ - --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ - --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ - --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ - --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ - --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ - --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ - --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ - --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ - --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ - --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ - --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ - --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ - --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ - --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ - --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ - --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ - --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ - --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de +googleapis-common-protos==1.65.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ + --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 +greenlet==3.1.0 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ + --hash=sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9 \ + --hash=sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17 \ + --hash=sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc \ + --hash=sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637 \ + --hash=sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2 \ + --hash=sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3 \ + --hash=sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6 \ + --hash=sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b \ + --hash=sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf \ + --hash=sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27 \ + --hash=sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1 \ + --hash=sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc \ + --hash=sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a \ + --hash=sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b \ + --hash=sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d \ + --hash=sha256:2d004db911ed7b6218ec5c5bfe4cf70ae8aa2223dffbb5b3c69e342bb253cb28 \ + --hash=sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303 \ + --hash=sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99 \ + --hash=sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f \ + --hash=sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7 \ + --hash=sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6 \ + --hash=sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a \ + --hash=sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc \ + --hash=sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0 \ + --hash=sha256:5fd6e94593f6f9714dbad1aaba734b5ec04593374fa6638df61592055868f8b8 \ + --hash=sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a \ + --hash=sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca \ + --hash=sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b \ + --hash=sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989 \ + --hash=sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19 \ + --hash=sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6 \ + --hash=sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484 \ + --hash=sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd \ + --hash=sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25 \ + --hash=sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b \ + --hash=sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910 \ + --hash=sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0 \ + --hash=sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5 \ + --hash=sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345 \ + --hash=sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6 \ + --hash=sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00 \ + --hash=sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df \ + --hash=sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811 \ + --hash=sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca \ + --hash=sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8 \ + --hash=sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33 \ + --hash=sha256:ac0adfdb3a21dc2a24ed728b61e72440d297d0fd3a577389df566651fcd08f97 \ + --hash=sha256:b395121e9bbe8d02a750886f108d540abe66075e61e22f7353d9acb0b81be0f0 \ + --hash=sha256:b9505a0c8579899057cbefd4ec34d865ab99852baf1ff33a9481eb3924e2da0b \ + --hash=sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682 \ + --hash=sha256:c3967dcc1cd2ea61b08b0b276659242cbce5caca39e7cbc02408222fb9e6ff39 \ + --hash=sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64 \ + --hash=sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f \ + --hash=sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665 \ + --hash=sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f \ + --hash=sha256:d0dd943282231480aad5f50f89bdf26690c995e8ff555f26d8a5b9887b559bcc \ + --hash=sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d \ + --hash=sha256:d45b75b0f3fd8d99f62eb7908cfa6d727b7ed190737dec7fe46d993da550b81a \ + --hash=sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0 \ + --hash=sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09 \ + --hash=sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b \ + --hash=sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491 \ + --hash=sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7 \ + --hash=sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954 \ + --hash=sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501 \ + --hash=sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54 +grpcio==1.66.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e \ + --hash=sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce \ + --hash=sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8 \ + --hash=sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d \ + --hash=sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858 \ + --hash=sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0 \ + --hash=sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a \ + --hash=sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45 \ + --hash=sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef \ + --hash=sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2 \ + --hash=sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac \ + --hash=sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd \ + --hash=sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1 \ + --hash=sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce \ + --hash=sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492 \ + --hash=sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e \ + --hash=sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb \ + --hash=sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44 \ + --hash=sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb \ + --hash=sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759 \ + --hash=sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e \ + --hash=sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761 \ + --hash=sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26 \ + --hash=sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791 \ + --hash=sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c \ + --hash=sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60 \ + --hash=sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df \ + --hash=sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a \ + --hash=sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3 \ + --hash=sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734 \ + --hash=sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f \ + --hash=sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083 \ + --hash=sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524 \ + --hash=sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d \ + --hash=sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a \ + --hash=sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0 \ + --hash=sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb \ + --hash=sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503 \ + --hash=sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815 \ + --hash=sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22 \ + --hash=sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2 \ + --hash=sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c \ + --hash=sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d \ + --hash=sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b \ + --hash=sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c \ + --hash=sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9 h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -538,12 +561,12 @@ httpcore==1.0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 httpretty==1.1.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68 -httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 \ - --hash=sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5 -idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +httpx==0.27.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0 \ + --hash=sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2 +idna==3.10 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 @@ -562,149 +585,145 @@ langcodes==3.4.0 ; python_version >= "3.10" and python_version < "4.0" \ language-data==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:77d5cab917f91ee0b2f1aa7018443e911cf8985ef734ca2ba3940770f6a3816b \ --hash=sha256:82a86050bbd677bfde87d97885b17566cfe75dad3ac4f5ce44b52c28f752e773 -lxml==5.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3 \ - --hash=sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a \ - --hash=sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0 \ - --hash=sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b \ - --hash=sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f \ - --hash=sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6 \ - --hash=sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73 \ - --hash=sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d \ - --hash=sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad \ - --hash=sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b \ - --hash=sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a \ - --hash=sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5 \ - --hash=sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab \ - --hash=sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316 \ - --hash=sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6 \ - --hash=sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df \ - --hash=sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca \ - --hash=sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264 \ - --hash=sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8 \ - --hash=sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f \ - --hash=sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b \ - --hash=sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3 \ - --hash=sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5 \ - --hash=sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed \ - --hash=sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab \ - --hash=sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5 \ - --hash=sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726 \ - --hash=sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d \ - --hash=sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632 \ - --hash=sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706 \ - --hash=sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8 \ - --hash=sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472 \ - --hash=sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835 \ - --hash=sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf \ - --hash=sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db \ - --hash=sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d \ - --hash=sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545 \ - --hash=sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9 \ - --hash=sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be \ - --hash=sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe \ - --hash=sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905 \ - --hash=sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438 \ - --hash=sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db \ - --hash=sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776 \ - --hash=sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c \ - --hash=sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed \ - --hash=sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd \ - --hash=sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484 \ - --hash=sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d \ - --hash=sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6 \ - --hash=sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30 \ - --hash=sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182 \ - --hash=sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61 \ - --hash=sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425 \ - --hash=sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb \ - --hash=sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1 \ - --hash=sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511 \ - --hash=sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e \ - --hash=sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207 \ - --hash=sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b \ - --hash=sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585 \ - --hash=sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56 \ - --hash=sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391 \ - --hash=sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85 \ - --hash=sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147 \ - --hash=sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18 \ - --hash=sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1 \ - --hash=sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa \ - --hash=sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48 \ - --hash=sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3 \ - --hash=sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184 \ - --hash=sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67 \ - --hash=sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7 \ - --hash=sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34 \ - --hash=sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706 \ - --hash=sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8 \ - --hash=sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c \ - --hash=sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115 \ - --hash=sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009 \ - --hash=sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466 \ - --hash=sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526 \ - --hash=sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d \ - --hash=sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525 \ - --hash=sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14 \ - --hash=sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3 \ - --hash=sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0 \ - --hash=sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b \ - --hash=sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1 \ - --hash=sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f \ - --hash=sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf \ - --hash=sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf \ - --hash=sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0 \ - --hash=sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b \ - --hash=sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff \ - --hash=sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88 \ - --hash=sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2 \ - --hash=sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40 \ - --hash=sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716 \ - --hash=sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2 \ - --hash=sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2 \ - --hash=sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a \ - --hash=sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734 \ - --hash=sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87 \ - --hash=sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48 \ - --hash=sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36 \ - --hash=sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b \ - --hash=sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07 \ - --hash=sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c \ - --hash=sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573 \ - --hash=sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001 \ - --hash=sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9 \ - --hash=sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3 \ - --hash=sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce \ - --hash=sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3 \ - --hash=sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04 \ - --hash=sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927 \ - --hash=sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083 \ - --hash=sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d \ - --hash=sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32 \ - --hash=sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9 \ - --hash=sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f \ - --hash=sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2 \ - --hash=sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c \ - --hash=sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d \ - --hash=sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393 \ - --hash=sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8 \ - --hash=sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6 \ - --hash=sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66 \ - --hash=sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5 \ - --hash=sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97 \ - --hash=sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196 \ - --hash=sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836 \ - --hash=sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae \ - --hash=sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297 \ - --hash=sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421 \ - --hash=sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6 \ - --hash=sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981 \ - --hash=sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30 \ - --hash=sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30 \ - --hash=sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f \ - --hash=sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324 \ - --hash=sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b +lxml==5.3.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e \ + --hash=sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229 \ + --hash=sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3 \ + --hash=sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5 \ + --hash=sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70 \ + --hash=sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15 \ + --hash=sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002 \ + --hash=sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd \ + --hash=sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22 \ + --hash=sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf \ + --hash=sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22 \ + --hash=sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832 \ + --hash=sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727 \ + --hash=sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e \ + --hash=sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30 \ + --hash=sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f \ + --hash=sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f \ + --hash=sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51 \ + --hash=sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4 \ + --hash=sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de \ + --hash=sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875 \ + --hash=sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42 \ + --hash=sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e \ + --hash=sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6 \ + --hash=sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391 \ + --hash=sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc \ + --hash=sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b \ + --hash=sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237 \ + --hash=sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4 \ + --hash=sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86 \ + --hash=sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f \ + --hash=sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a \ + --hash=sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8 \ + --hash=sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f \ + --hash=sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903 \ + --hash=sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03 \ + --hash=sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e \ + --hash=sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99 \ + --hash=sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7 \ + --hash=sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab \ + --hash=sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d \ + --hash=sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22 \ + --hash=sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492 \ + --hash=sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b \ + --hash=sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3 \ + --hash=sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be \ + --hash=sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469 \ + --hash=sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f \ + --hash=sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a \ + --hash=sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c \ + --hash=sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a \ + --hash=sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4 \ + --hash=sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94 \ + --hash=sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442 \ + --hash=sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b \ + --hash=sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84 \ + --hash=sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c \ + --hash=sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9 \ + --hash=sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1 \ + --hash=sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be \ + --hash=sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367 \ + --hash=sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e \ + --hash=sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21 \ + --hash=sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa \ + --hash=sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16 \ + --hash=sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d \ + --hash=sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe \ + --hash=sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83 \ + --hash=sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba \ + --hash=sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040 \ + --hash=sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763 \ + --hash=sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8 \ + --hash=sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff \ + --hash=sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2 \ + --hash=sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a \ + --hash=sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b \ + --hash=sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce \ + --hash=sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c \ + --hash=sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577 \ + --hash=sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8 \ + --hash=sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71 \ + --hash=sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512 \ + --hash=sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540 \ + --hash=sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f \ + --hash=sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2 \ + --hash=sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a \ + --hash=sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce \ + --hash=sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e \ + --hash=sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2 \ + --hash=sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27 \ + --hash=sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1 \ + --hash=sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d \ + --hash=sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1 \ + --hash=sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330 \ + --hash=sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920 \ + --hash=sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99 \ + --hash=sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff \ + --hash=sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18 \ + --hash=sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff \ + --hash=sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c \ + --hash=sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179 \ + --hash=sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080 \ + --hash=sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19 \ + --hash=sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d \ + --hash=sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70 \ + --hash=sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32 \ + --hash=sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a \ + --hash=sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2 \ + --hash=sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79 \ + --hash=sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3 \ + --hash=sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5 \ + --hash=sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f \ + --hash=sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d \ + --hash=sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3 \ + --hash=sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b \ + --hash=sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753 \ + --hash=sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9 \ + --hash=sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957 \ + --hash=sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033 \ + --hash=sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb \ + --hash=sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656 \ + --hash=sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab \ + --hash=sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b \ + --hash=sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d \ + --hash=sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd \ + --hash=sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859 \ + --hash=sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11 \ + --hash=sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c \ + --hash=sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a \ + --hash=sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005 \ + --hash=sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654 \ + --hash=sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80 \ + --hash=sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e \ + --hash=sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec \ + --hash=sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7 \ + --hash=sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965 \ + --hash=sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945 \ + --hash=sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8 mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc @@ -934,97 +953,99 @@ maxminddb==2.6.2 ; python_version >= "3.10" and python_version < "4.0" \ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556 \ - --hash=sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c \ - --hash=sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29 \ - --hash=sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b \ - --hash=sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8 \ - --hash=sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7 \ - --hash=sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd \ - --hash=sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40 \ - --hash=sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6 \ - --hash=sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3 \ - --hash=sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c \ - --hash=sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9 \ - --hash=sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5 \ - --hash=sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae \ - --hash=sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442 \ - --hash=sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9 \ - --hash=sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc \ - --hash=sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c \ - --hash=sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea \ - --hash=sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5 \ - --hash=sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50 \ - --hash=sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182 \ - --hash=sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453 \ - --hash=sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e \ - --hash=sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600 \ - --hash=sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733 \ - --hash=sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda \ - --hash=sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241 \ - --hash=sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461 \ - --hash=sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e \ - --hash=sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e \ - --hash=sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b \ - --hash=sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e \ - --hash=sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7 \ - --hash=sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386 \ - --hash=sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd \ - --hash=sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9 \ - --hash=sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf \ - --hash=sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee \ - --hash=sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5 \ - --hash=sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a \ - --hash=sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271 \ - --hash=sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54 \ - --hash=sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4 \ - --hash=sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496 \ - --hash=sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb \ - --hash=sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319 \ - --hash=sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3 \ - --hash=sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f \ - --hash=sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527 \ - --hash=sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed \ - --hash=sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604 \ - --hash=sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef \ - --hash=sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8 \ - --hash=sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5 \ - --hash=sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5 \ - --hash=sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626 \ - --hash=sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c \ - --hash=sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d \ - --hash=sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c \ - --hash=sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc \ - --hash=sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc \ - --hash=sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b \ - --hash=sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38 \ - --hash=sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450 \ - --hash=sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1 \ - --hash=sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f \ - --hash=sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3 \ - --hash=sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755 \ - --hash=sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226 \ - --hash=sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a \ - --hash=sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046 \ - --hash=sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf \ - --hash=sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479 \ - --hash=sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e \ - --hash=sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1 \ - --hash=sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a \ - --hash=sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83 \ - --hash=sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929 \ - --hash=sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93 \ - --hash=sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a \ - --hash=sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c \ - --hash=sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44 \ - --hash=sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89 \ - --hash=sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba \ - --hash=sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e \ - --hash=sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da \ - --hash=sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24 \ - --hash=sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423 \ - --hash=sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef +multidict==6.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f \ + --hash=sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056 \ + --hash=sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761 \ + --hash=sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3 \ + --hash=sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b \ + --hash=sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6 \ + --hash=sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748 \ + --hash=sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966 \ + --hash=sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f \ + --hash=sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1 \ + --hash=sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6 \ + --hash=sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada \ + --hash=sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305 \ + --hash=sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2 \ + --hash=sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d \ + --hash=sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a \ + --hash=sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef \ + --hash=sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c \ + --hash=sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb \ + --hash=sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60 \ + --hash=sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6 \ + --hash=sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4 \ + --hash=sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478 \ + --hash=sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81 \ + --hash=sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7 \ + --hash=sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56 \ + --hash=sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3 \ + --hash=sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6 \ + --hash=sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30 \ + --hash=sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb \ + --hash=sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506 \ + --hash=sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0 \ + --hash=sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925 \ + --hash=sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c \ + --hash=sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6 \ + --hash=sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e \ + --hash=sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95 \ + --hash=sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2 \ + --hash=sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133 \ + --hash=sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2 \ + --hash=sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa \ + --hash=sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3 \ + --hash=sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3 \ + --hash=sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436 \ + --hash=sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657 \ + --hash=sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581 \ + --hash=sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492 \ + --hash=sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43 \ + --hash=sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2 \ + --hash=sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2 \ + --hash=sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926 \ + --hash=sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057 \ + --hash=sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc \ + --hash=sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80 \ + --hash=sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255 \ + --hash=sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1 \ + --hash=sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972 \ + --hash=sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53 \ + --hash=sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1 \ + --hash=sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423 \ + --hash=sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a \ + --hash=sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160 \ + --hash=sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c \ + --hash=sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd \ + --hash=sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa \ + --hash=sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5 \ + --hash=sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b \ + --hash=sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa \ + --hash=sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef \ + --hash=sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44 \ + --hash=sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4 \ + --hash=sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156 \ + --hash=sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753 \ + --hash=sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28 \ + --hash=sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d \ + --hash=sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a \ + --hash=sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304 \ + --hash=sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008 \ + --hash=sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429 \ + --hash=sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72 \ + --hash=sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399 \ + --hash=sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3 \ + --hash=sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392 \ + --hash=sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167 \ + --hash=sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c \ + --hash=sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774 \ + --hash=sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351 \ + --hash=sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76 \ + --hash=sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875 \ + --hash=sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd \ + --hash=sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28 \ + --hash=sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 @@ -1182,113 +1203,113 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \ - --hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 +pyasn1==0.6.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00cf2f253aa44c7d6589a56d70c5b820a5060c3a0a2aee018f0b4ed732fe7632 pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc -pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ - --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ - --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ - --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ - --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ - --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ - --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ - --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ - --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ - --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ - --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ - --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ - --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ - --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ - --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ - --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ - --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ - --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ - --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ - --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ - --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ - --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ - --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ - --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ - --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ - --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ - --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ - --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ - --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ - --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ - --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ - --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ - --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ - --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ - --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ - --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ - --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ - --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ - --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ - --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ - --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ - --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ - --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ - --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ - --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ - --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ - --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ - --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ - --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ - --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ - --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ - --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ - --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ - --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ - --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ - --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ - --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ - --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ - --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ - --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ - --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ - --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ - --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ - --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ - --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ - --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ - --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ - --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ - --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ - --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ - --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ - --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ - --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ - --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ - --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ - --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ - --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ - --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ - --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ - --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ - --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ - --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ - --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ - --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ - --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ - --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ - --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ - --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ - --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ - --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 -pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ - --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 -pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ - --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 +pydantic-core==2.23.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801 \ + --hash=sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec \ + --hash=sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295 \ + --hash=sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba \ + --hash=sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e \ + --hash=sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e \ + --hash=sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4 \ + --hash=sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211 \ + --hash=sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea \ + --hash=sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c \ + --hash=sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835 \ + --hash=sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d \ + --hash=sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c \ + --hash=sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c \ + --hash=sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61 \ + --hash=sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83 \ + --hash=sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb \ + --hash=sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1 \ + --hash=sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5 \ + --hash=sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690 \ + --hash=sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b \ + --hash=sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7 \ + --hash=sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70 \ + --hash=sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a \ + --hash=sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8 \ + --hash=sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd \ + --hash=sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee \ + --hash=sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1 \ + --hash=sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab \ + --hash=sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958 \ + --hash=sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5 \ + --hash=sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b \ + --hash=sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961 \ + --hash=sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c \ + --hash=sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25 \ + --hash=sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4 \ + --hash=sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4 \ + --hash=sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f \ + --hash=sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326 \ + --hash=sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab \ + --hash=sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8 \ + --hash=sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b \ + --hash=sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6 \ + --hash=sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8 \ + --hash=sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01 \ + --hash=sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc \ + --hash=sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d \ + --hash=sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e \ + --hash=sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b \ + --hash=sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855 \ + --hash=sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700 \ + --hash=sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a \ + --hash=sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa \ + --hash=sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541 \ + --hash=sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791 \ + --hash=sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162 \ + --hash=sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611 \ + --hash=sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef \ + --hash=sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe \ + --hash=sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5 \ + --hash=sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba \ + --hash=sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28 \ + --hash=sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa \ + --hash=sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27 \ + --hash=sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4 \ + --hash=sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b \ + --hash=sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2 \ + --hash=sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c \ + --hash=sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8 \ + --hash=sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb \ + --hash=sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c \ + --hash=sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e \ + --hash=sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305 \ + --hash=sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8 \ + --hash=sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4 \ + --hash=sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433 \ + --hash=sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45 \ + --hash=sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16 \ + --hash=sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed \ + --hash=sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0 \ + --hash=sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d \ + --hash=sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710 \ + --hash=sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48 \ + --hash=sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423 \ + --hash=sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf \ + --hash=sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9 \ + --hash=sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63 \ + --hash=sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5 \ + --hash=sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb +pydantic-settings==2.5.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907 \ + --hash=sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0 +pydantic==2.9.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2 \ + --hash=sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612 +pydicom==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:003aeb025bbd20fc029f71eb286cf8772cc924d8de2baaec184c2caa513502df \ + --hash=sha256:7b1435dc7427a3d172685a9406ff1a75eb2d7651d236d0d99abd4953a1100922 pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a @@ -1306,12 +1327,15 @@ pynacl==1.5.0 ; python_version >= "3.10" and python_version < "4.0" \ pynetdicom==2.0.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:231212e9b9c5e0debf2af4f17d8afa14ecd1b262a11cdb891b2b2b15f7ab5939 \ --hash=sha256:6726173d25a51f66f2a4557d816c0f93b3b2a8435ce3d319e6cdd8e48bf657d5 -pytest-env==1.1.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:aada77e6d09fcfb04540a6e462c58533c37df35fa853da78707b17ec04d17dfc \ - --hash=sha256:fcd7dc23bb71efd3d35632bde1bbe5ee8c8dc4489d6617fb010674880d96216b -pytest==8.3.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5 \ - --hash=sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce +pytest-env==1.1.4 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:86653658da8f11c6844975db955746c458a9c09f1e64957603161e2ff93f5133 \ + --hash=sha256:a4212056d4d440febef311a98fdca56c31256d58fb453d103cba4e8a532b721d +pytest-mock==3.14.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f \ + --hash=sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0 +pytest==8.3.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181 \ + --hash=sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2 python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 @@ -1345,9 +1369,9 @@ requests-file==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 -rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ - --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rich==13.8.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06 \ + --hash=sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c \ --hash=sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585 \ @@ -1455,9 +1479,9 @@ rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ - --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec +setuptools==75.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \ + --hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538 shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ @@ -1466,54 +1490,54 @@ six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc -soupsieve==2.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \ - --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 -sqlalchemy==1.4.53 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0 \ - --hash=sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11 \ - --hash=sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed \ - --hash=sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d \ - --hash=sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98 \ - --hash=sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05 \ - --hash=sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63 \ - --hash=sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae \ - --hash=sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22 \ - --hash=sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883 \ - --hash=sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9 \ - --hash=sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530 \ - --hash=sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525 \ - --hash=sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf \ - --hash=sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d \ - --hash=sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85 \ - --hash=sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d \ - --hash=sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3 \ - --hash=sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e \ - --hash=sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315 \ - --hash=sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69 \ - --hash=sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499 \ - --hash=sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48 \ - --hash=sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c \ - --hash=sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a \ - --hash=sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380 \ - --hash=sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172 \ - --hash=sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59 \ - --hash=sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c \ - --hash=sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27 \ - --hash=sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a \ - --hash=sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a \ - --hash=sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da \ - --hash=sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7 \ - --hash=sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6 \ - --hash=sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd \ - --hash=sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816 \ - --hash=sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d \ - --hash=sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046 \ - --hash=sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755 \ - --hash=sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330 \ - --hash=sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3 \ - --hash=sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981 \ - --hash=sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc +soupsieve==2.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \ + --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9 +sqlalchemy==1.4.54 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02d2ecb9508f16ab9c5af466dfe5a88e26adf2e1a8d1c56eb616396ccae2c186 \ + --hash=sha256:0b76bbb1cbae618d10679be8966f6d66c94f301cfc15cb49e2f2382563fb6efb \ + --hash=sha256:0de620f978ca273ce027769dc8db7e6ee72631796187adc8471b3c76091b809e \ + --hash=sha256:1183599e25fa38a1a322294b949da02b4f0da13dbc2688ef9dbe746df573f8a6 \ + --hash=sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f \ + --hash=sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc \ + --hash=sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936 \ + --hash=sha256:14b3f4783275339170984cadda66e3ec011cce87b405968dc8d51cf0f9997b0d \ + --hash=sha256:1576fba3616f79496e2f067262200dbf4aab1bb727cd7e4e006076686413c80c \ + --hash=sha256:1990d5a6a5dc358a0894c8ca02043fb9a5ad9538422001fb2826e91c50f1d539 \ + --hash=sha256:1d83cd1cc03c22d922ec94d0d5f7b7c96b1332f5e122e81b1a61fb22da77879a \ + --hash=sha256:1e8c1b9ecaf9f2590337d5622189aeb2f0dbc54ba0232fa0856cf390957584a9 \ + --hash=sha256:26e78444bc77d089e62874dc74df05a5c71f01ac598010a327881a48408d0064 \ + --hash=sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5 \ + --hash=sha256:3112de9e11ff1957148c6de1df2bc5cc1440ee36783412e5eedc6f53638a577d \ + --hash=sha256:394b0135900b62dbf63e4809cdc8ac923182af2816d06ea61cd6763943c2cc05 \ + --hash=sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d \ + --hash=sha256:41cffc63c7c83dfc30c4cab5b4308ba74440a9633c4509c51a0c52431fb0f8ab \ + --hash=sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a \ + --hash=sha256:5ed3576675c187e3baa80b02c4c9d0edfab78eff4e89dd9da736b921333a2432 \ + --hash=sha256:6b24364150738ce488333b3fb48bfa14c189a66de41cd632796fbcacb26b4585 \ + --hash=sha256:6da60fb24577f989535b8fc8b2ddc4212204aaf02e53c4c7ac94ac364150ed08 \ + --hash=sha256:76c2ba7b5a09863d0a8166fbc753af96d561818c572dbaf697c52095938e7be4 \ + --hash=sha256:954816850777ac234a4e32b8c88ac1f7847088a6e90cfb8f0e127a1bf3feddff \ + --hash=sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4 \ + --hash=sha256:a01bc25eb7a5688656c8770f931d5cb4a44c7de1b3cec69b84cc9745d1e4cc10 \ + --hash=sha256:a19f816f4702d7b1951d7576026c7124b9bfb64a9543e571774cf517b7a50b29 \ + --hash=sha256:a41611835010ed4ea4c7aed1da5b58aac78ee7e70932a91ed2705a7b38e40f52 \ + --hash=sha256:a49730afb716f3f675755afec109895cab95bc9875db7ffe2e42c1b1c6279482 \ + --hash=sha256:a86b0e4be775902a5496af4fb1b60d8a2a457d78f531458d294360b8637bb014 \ + --hash=sha256:a8a72259a1652f192c68377be7011eac3c463e9892ef2948828c7d58e4829988 \ + --hash=sha256:af00236fe21c4d4f4c227b6ccc19b44c594160cc3ff28d104cdce85855369277 \ + --hash=sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e \ + --hash=sha256:b5933c45d11cbd9694b1540aa9076816cc7406964c7b16a380fd84d3a5fe3241 \ + --hash=sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c \ + --hash=sha256:b67589f7955924865344e6eacfdcf70675e64f36800a576aa5e961f0008cde2a \ + --hash=sha256:c5a2530400a6e7e68fd1552a55515de6a4559122e495f73554a51cedafc11669 \ + --hash=sha256:cafe0ba3a96d0845121433cffa2b9232844a2609fce694fcc02f3f31214ece28 \ + --hash=sha256:cdb2886c0be2c6c54d0651d5a61c29ef347e8eec81fd83afebbf7b59b80b7393 \ + --hash=sha256:d0cf7076c8578b3de4e43a046cc7a1af8466e1c3f5e64167189fe8958a4f9c02 \ + --hash=sha256:f1e1b92ee4ee9ffc68624ace218b89ca5ca667607ccee4541a90cc44999b9aea \ + --hash=sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88 \ + --hash=sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f \ + --hash=sha256:fc9ffd9a38e21fad3e8c5a88926d57f94a32546e937e0be46142b2702003eba7 starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 @@ -1529,9 +1553,9 @@ tomli==2.0.1 ; python_version >= "3.10" and python_version < "3.11" \ typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 -urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ - --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 +urllib3==2.2.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 uvicorn==0.29.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de \ --hash=sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0 @@ -1614,97 +1638,99 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ xlsxwriter==3.2.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:9977d0c661a72866a61f9f7a809e25ebbb0fb7036baa3b9fe74afcfca6b3cb8c \ --hash=sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e -yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51 \ - --hash=sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce \ - --hash=sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559 \ - --hash=sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0 \ - --hash=sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81 \ - --hash=sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc \ - --hash=sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4 \ - --hash=sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c \ - --hash=sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130 \ - --hash=sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136 \ - --hash=sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e \ - --hash=sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec \ - --hash=sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7 \ - --hash=sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1 \ - --hash=sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455 \ - --hash=sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099 \ - --hash=sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129 \ - --hash=sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10 \ - --hash=sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142 \ - --hash=sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98 \ - --hash=sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa \ - --hash=sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7 \ - --hash=sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525 \ - --hash=sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c \ - --hash=sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9 \ - --hash=sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c \ - --hash=sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8 \ - --hash=sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b \ - --hash=sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf \ - --hash=sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23 \ - --hash=sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd \ - --hash=sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27 \ - --hash=sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f \ - --hash=sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece \ - --hash=sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434 \ - --hash=sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec \ - --hash=sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff \ - --hash=sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78 \ - --hash=sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d \ - --hash=sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863 \ - --hash=sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53 \ - --hash=sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31 \ - --hash=sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15 \ - --hash=sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5 \ - --hash=sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b \ - --hash=sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57 \ - --hash=sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3 \ - --hash=sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1 \ - --hash=sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f \ - --hash=sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad \ - --hash=sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c \ - --hash=sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7 \ - --hash=sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2 \ - --hash=sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b \ - --hash=sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2 \ - --hash=sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b \ - --hash=sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9 \ - --hash=sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be \ - --hash=sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e \ - --hash=sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984 \ - --hash=sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4 \ - --hash=sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074 \ - --hash=sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2 \ - --hash=sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392 \ - --hash=sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91 \ - --hash=sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541 \ - --hash=sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf \ - --hash=sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572 \ - --hash=sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66 \ - --hash=sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575 \ - --hash=sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14 \ - --hash=sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5 \ - --hash=sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1 \ - --hash=sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e \ - --hash=sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551 \ - --hash=sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17 \ - --hash=sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead \ - --hash=sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0 \ - --hash=sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe \ - --hash=sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234 \ - --hash=sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0 \ - --hash=sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7 \ - --hash=sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34 \ - --hash=sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42 \ - --hash=sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385 \ - --hash=sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78 \ - --hash=sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be \ - --hash=sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958 \ - --hash=sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749 \ - --hash=sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec -zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ - --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c +yarl==1.11.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49 \ + --hash=sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867 \ + --hash=sha256:04293941646647b3bfb1719d1d11ff1028e9c30199509a844da3c0f5919dc520 \ + --hash=sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a \ + --hash=sha256:077da604852be488c9a05a524068cdae1e972b7dc02438161c32420fb4ec5e14 \ + --hash=sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a \ + --hash=sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93 \ + --hash=sha256:0ea9682124fc062e3d931c6911934a678cb28453f957ddccf51f568c2f2b5e05 \ + --hash=sha256:0f351fa31234699d6084ff98283cb1e852270fe9e250a3b3bf7804eb493bd937 \ + --hash=sha256:14438dfc5015661f75f85bc5adad0743678eefee266ff0c9a8e32969d5d69f74 \ + --hash=sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b \ + --hash=sha256:15439f3c5c72686b6c3ff235279630d08936ace67d0fe5c8d5bbc3ef06f5a420 \ + --hash=sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639 \ + --hash=sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089 \ + --hash=sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53 \ + --hash=sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e \ + --hash=sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c \ + --hash=sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e \ + --hash=sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe \ + --hash=sha256:238a21849dd7554cb4d25a14ffbfa0ef380bb7ba201f45b144a14454a72ffa5a \ + --hash=sha256:250e888fa62d73e721f3041e3a9abf427788a1934b426b45e1b92f62c1f68366 \ + --hash=sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63 \ + --hash=sha256:267b24f891e74eccbdff42241c5fb4f974de2d6271dcc7d7e0c9ae1079a560d9 \ + --hash=sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145 \ + --hash=sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf \ + --hash=sha256:3257978c870728a52dcce8c2902bf01f6c53b65094b457bf87b2644ee6238ddc \ + --hash=sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5 \ + --hash=sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff \ + --hash=sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d \ + --hash=sha256:3ff6b1617aa39279fe18a76c8d165469c48b159931d9b48239065767ee455b2b \ + --hash=sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00 \ + --hash=sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad \ + --hash=sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92 \ + --hash=sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998 \ + --hash=sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91 \ + --hash=sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b \ + --hash=sha256:48dfd117ab93f0129084577a07287376cc69c08138694396f305636e229caa1a \ + --hash=sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5 \ + --hash=sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff \ + --hash=sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367 \ + --hash=sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa \ + --hash=sha256:61a5f2c14d0a1adfdd82258f756b23a550c13ba4c86c84106be4c111a3a4e413 \ + --hash=sha256:637c7ddb585a62d4469f843dac221f23eec3cbad31693b23abbc2c366ad41ff4 \ + --hash=sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45 \ + --hash=sha256:67459cf8cf31da0e2cbdb4b040507e535d25cfbb1604ca76396a3a66b8ba37a6 \ + --hash=sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5 \ + --hash=sha256:6907daa4b9d7a688063ed098c472f96e8181733c525e03e866fb5db480a424df \ + --hash=sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c \ + --hash=sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318 \ + --hash=sha256:7175a87ab8f7fbde37160a15e58e138ba3b2b0e05492d7351314a250d61b1591 \ + --hash=sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38 \ + --hash=sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8 \ + --hash=sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e \ + --hash=sha256:75e0ae31fb5ccab6eda09ba1494e87eb226dcbd2372dae96b87800e1dcc98804 \ + --hash=sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec \ + --hash=sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6 \ + --hash=sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870 \ + --hash=sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83 \ + --hash=sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d \ + --hash=sha256:8418c053aeb236b20b0ab8fa6bacfc2feaaf7d4683dd96528610989c99723d5f \ + --hash=sha256:87f020d010ba80a247c4abc335fc13421037800ca20b42af5ae40e5fd75e7909 \ + --hash=sha256:884eab2ce97cbaf89f264372eae58388862c33c4f551c15680dd80f53c89a269 \ + --hash=sha256:8a336eaa7ee7e87cdece3cedb395c9657d227bfceb6781295cf56abcd3386a26 \ + --hash=sha256:8aef1b64da41d18026632d99a06b3fefe1d08e85dd81d849fa7c96301ed22f1b \ + --hash=sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2 \ + --hash=sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7 \ + --hash=sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd \ + --hash=sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68 \ + --hash=sha256:94d0caaa912bfcdc702a4204cd5e2bb01eb917fc4f5ea2315aa23962549561b0 \ + --hash=sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786 \ + --hash=sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da \ + --hash=sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc \ + --hash=sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447 \ + --hash=sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239 \ + --hash=sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0 \ + --hash=sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84 \ + --hash=sha256:aac44097d838dda26526cffb63bdd8737a2dbdf5f2c68efb72ad83aec6673c7e \ + --hash=sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef \ + --hash=sha256:ba444bdd4caa2a94456ef67a2f383710928820dd0117aae6650a4d17029fa25e \ + --hash=sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82 \ + --hash=sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675 \ + --hash=sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26 \ + --hash=sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979 \ + --hash=sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46 \ + --hash=sha256:dae7bd0daeb33aa3e79e72877d3d51052e8b19c9025ecf0374f542ea8ec120e4 \ + --hash=sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff \ + --hash=sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27 \ + --hash=sha256:e8f63904df26d1a66aabc141bfd258bf738b9bc7bc6bdef22713b4f5ef789a4c \ + --hash=sha256:f3a6d90cab0bdf07df8f176eae3a07127daafcf7457b997b2bf46776da2c7eb7 \ + --hash=sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265 \ + --hash=sha256:f46f81501160c28d0c0b7333b4f7be8983dbbc161983b6fb814024d1b4952f79 \ + --hash=sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd +zipp==3.20.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ + --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 diff --git a/boefjes/requirements.txt b/boefjes/requirements.txt index c14689d93c8..b529e0af69b 100644 --- a/boefjes/requirements.txt +++ b/boefjes/requirements.txt @@ -1,83 +1,98 @@ -aiohappyeyeballs==2.3.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4d6dea59215537dbc746e93e779caea8178c866856a721c9c660d7a5a7b8be03 \ - --hash=sha256:6fa48b9f1317254f122a07a131a86b71ca6946ca989ce6326fff54a99a920105 -aiohttp==3.10.3 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b \ - --hash=sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3 \ - --hash=sha256:0974f3b5b0132edcec92c3306f858ad4356a63d26b18021d859c9927616ebf27 \ - --hash=sha256:09bc79275737d4dc066e0ae2951866bb36d9c6b460cb7564f111cc0427f14844 \ - --hash=sha256:123e5819bfe1b87204575515cf448ab3bf1489cdeb3b61012bde716cda5853e7 \ - --hash=sha256:13031e7ec1188274bad243255c328cc3019e36a5a907978501256000d57a7201 \ - --hash=sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee \ - --hash=sha256:214277dcb07ab3875f17ee1c777d446dcce75bea85846849cc9d139ab8f5081f \ - --hash=sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696 \ - --hash=sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2 \ - --hash=sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f \ - --hash=sha256:2b0f670502100cdc567188c49415bebba947eb3edaa2028e1a50dd81bd13363f \ - --hash=sha256:2bbc55a964b8eecb341e492ae91c3bd0848324d313e1e71a27e3d96e6ee7e8e8 \ - --hash=sha256:32007fdcaab789689c2ecaaf4b71f8e37bf012a15cd02c0a9db8c4d0e7989fa8 \ - --hash=sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68 \ - --hash=sha256:3731a73ddc26969d65f90471c635abd4e1546a25299b687e654ea6d2fc052394 \ - --hash=sha256:38d91b98b4320ffe66efa56cb0f614a05af53b675ce1b8607cdb2ac826a8d58e \ - --hash=sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7 \ - --hash=sha256:434b3ab75833accd0b931d11874e206e816f6e6626fd69f643d6a8269cd9166a \ - --hash=sha256:43b09f38a67679e32d380fe512189ccb0b25e15afc79b23fbd5b5e48e4fc8fd9 \ - --hash=sha256:44bb159b55926b57812dca1b21c34528e800963ffe130d08b049b2d6b994ada7 \ - --hash=sha256:48665433bb59144aaf502c324694bec25867eb6630fcd831f7a893ca473fcde4 \ - --hash=sha256:50544fe498c81cb98912afabfc4e4d9d85e89f86238348e3712f7ca6a2f01dab \ - --hash=sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec \ - --hash=sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c \ - --hash=sha256:59c489661edbd863edb30a8bd69ecb044bd381d1818022bc698ba1b6f80e5dd1 \ - --hash=sha256:5ba2e838b5e6a8755ac8297275c9460e729dc1522b6454aee1766c6de6d56e5e \ - --hash=sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e \ - --hash=sha256:671efce3a4a0281060edf9a07a2f7e6230dca3a1cbc61d110eee7753d28405f7 \ - --hash=sha256:673bb6e3249dc8825df1105f6ef74e2eab779b7ff78e96c15cadb78b04a83752 \ - --hash=sha256:6ae9ae382d1c9617a91647575255ad55a48bfdde34cc2185dd558ce476bf16e9 \ - --hash=sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5 \ - --hash=sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef \ - --hash=sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806 \ - --hash=sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17 \ - --hash=sha256:71bb1d97bfe7e6726267cea169fdf5df7658831bb68ec02c9c6b9f3511e108bb \ - --hash=sha256:7c126f532caf238031c19d169cfae3c6a59129452c990a6e84d6e7b198a001dc \ - --hash=sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a \ - --hash=sha256:812121a201f0c02491a5db335a737b4113151926a79ae9ed1a9f41ea225c0e3f \ - --hash=sha256:8542c9e5bcb2bd3115acdf5adc41cda394e7360916197805e7e32b93d821ef93 \ - --hash=sha256:85466b5a695c2a7db13eb2c200af552d13e6a9313d7fa92e4ffe04a2c0ea74c1 \ - --hash=sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09 \ - --hash=sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57 \ - --hash=sha256:926e68438f05703e500b06fe7148ef3013dd6f276de65c68558fa9974eeb59ad \ - --hash=sha256:9743fa34a10a36ddd448bba8a3adc2a66a1c575c3c2940301bacd6cc896c6bf1 \ - --hash=sha256:a541414578ff47c0a9b0b8b77381ea86b0c8531ab37fc587572cb662ccd80b88 \ - --hash=sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9 \ - --hash=sha256:aed12a54d4e1ee647376fa541e1b7621505001f9f939debf51397b9329fd88b9 \ - --hash=sha256:af4dbec58e37f5afff4f91cdf235e8e4b0bd0127a2a4fd1040e2cad3369d2f06 \ - --hash=sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1 \ - --hash=sha256:b22cae3c9dd55a6b4c48c63081d31c00fc11fa9db1a20c8a50ee38c1a29539d2 \ - --hash=sha256:b51aef59370baf7444de1572f7830f59ddbabd04e5292fa4218d02f085f8d299 \ - --hash=sha256:b69d832e5f5fa15b1b6b2c8eb6a9fd2c0ec1fd7729cb4322ed27771afc9fc2ac \ - --hash=sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204 \ - --hash=sha256:b97dc9a17a59f350c0caa453a3cb35671a2ffa3a29a6ef3568b523b9113d84e5 \ - --hash=sha256:ba562736d3fbfe9241dad46c1a8994478d4a0e50796d80e29d50cabe8fbfcc3f \ - --hash=sha256:bac352fceed158620ce2d701ad39d4c1c76d114255a7c530e057e2b9f55bdf9f \ - --hash=sha256:baec1eb274f78b2de54471fc4c69ecbea4275965eab4b556ef7a7698dee18bf2 \ - --hash=sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f \ - --hash=sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6 \ - --hash=sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272 \ - --hash=sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e \ - --hash=sha256:cc36cbdedf6f259371dbbbcaae5bb0e95b879bc501668ab6306af867577eb5db \ - --hash=sha256:cd788602e239ace64f257d1c9d39898ca65525583f0fbf0988bcba19418fe93f \ - --hash=sha256:d1100e68e70eb72eadba2b932b185ebf0f28fd2f0dbfe576cfa9d9894ef49752 \ - --hash=sha256:d35235a44ec38109b811c3600d15d8383297a8fab8e3dec6147477ec8636712a \ - --hash=sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e \ - --hash=sha256:d5548444ef60bf4c7b19ace21f032fa42d822e516a6940d36579f7bfa8513f9c \ - --hash=sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279 \ - --hash=sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc \ - --hash=sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b \ - --hash=sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf \ - --hash=sha256:e8cc0564b286b625e673a2615ede60a1704d0cbbf1b24604e28c31ed37dc62aa \ - --hash=sha256:f25d6c4e82d7489be84f2b1c8212fafc021b3731abdb61a563c90e37cced3a21 \ - --hash=sha256:f817a54059a4cfbc385a7f51696359c642088710e731e8df80d0607193ed2b73 \ - --hash=sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189 +aiohappyeyeballs==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2 \ + --hash=sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd +aiohttp==3.10.5 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277 \ + --hash=sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1 \ + --hash=sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe \ + --hash=sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb \ + --hash=sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca \ + --hash=sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91 \ + --hash=sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972 \ + --hash=sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a \ + --hash=sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3 \ + --hash=sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa \ + --hash=sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77 \ + --hash=sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b \ + --hash=sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8 \ + --hash=sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599 \ + --hash=sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc \ + --hash=sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf \ + --hash=sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511 \ + --hash=sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699 \ + --hash=sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487 \ + --hash=sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987 \ + --hash=sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff \ + --hash=sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db \ + --hash=sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022 \ + --hash=sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce \ + --hash=sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a \ + --hash=sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5 \ + --hash=sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7 \ + --hash=sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820 \ + --hash=sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf \ + --hash=sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e \ + --hash=sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf \ + --hash=sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5 \ + --hash=sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6 \ + --hash=sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6 \ + --hash=sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91 \ + --hash=sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3 \ + --hash=sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a \ + --hash=sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d \ + --hash=sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088 \ + --hash=sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc \ + --hash=sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f \ + --hash=sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75 \ + --hash=sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471 \ + --hash=sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e \ + --hash=sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697 \ + --hash=sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092 \ + --hash=sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69 \ + --hash=sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3 \ + --hash=sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32 \ + --hash=sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589 \ + --hash=sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178 \ + --hash=sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92 \ + --hash=sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2 \ + --hash=sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e \ + --hash=sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058 \ + --hash=sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857 \ + --hash=sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1 \ + --hash=sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6 \ + --hash=sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22 \ + --hash=sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0 \ + --hash=sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b \ + --hash=sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57 \ + --hash=sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f \ + --hash=sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e \ + --hash=sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16 \ + --hash=sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1 \ + --hash=sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f \ + --hash=sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6 \ + --hash=sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04 \ + --hash=sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae \ + --hash=sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d \ + --hash=sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b \ + --hash=sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f \ + --hash=sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862 \ + --hash=sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689 \ + --hash=sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c \ + --hash=sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683 \ + --hash=sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef \ + --hash=sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f \ + --hash=sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12 \ + --hash=sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73 \ + --hash=sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061 \ + --hash=sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072 \ + --hash=sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11 \ + --hash=sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691 \ + --hash=sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77 \ + --hash=sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385 \ + --hash=sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172 \ + --hash=sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569 \ + --hash=sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f \ + --hash=sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5 aioresponses==0.7.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7 \ --hash=sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1 @@ -114,77 +129,77 @@ beautifulsoup4==4.11.1 ; python_version >= "3.10" and python_version < "4.0" \ censys==2.1.8 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2ddd6d0ee6df70acf15792328df8bb4d0dd5a76b50883adac62989f1641820c1 \ --hash=sha256:665acf8777a871098832527ab8e0c5b1b9f9a548be928239747a6fcde8b613eb -certifi==2024.7.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 -cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f \ - --hash=sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab \ - --hash=sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499 \ - --hash=sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058 \ - --hash=sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693 \ - --hash=sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb \ - --hash=sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377 \ - --hash=sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885 \ - --hash=sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2 \ - --hash=sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401 \ - --hash=sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4 \ - --hash=sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b \ - --hash=sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59 \ - --hash=sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f \ - --hash=sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c \ - --hash=sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555 \ - --hash=sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa \ - --hash=sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424 \ - --hash=sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb \ - --hash=sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2 \ - --hash=sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8 \ - --hash=sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e \ - --hash=sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9 \ - --hash=sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82 \ - --hash=sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828 \ - --hash=sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759 \ - --hash=sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc \ - --hash=sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118 \ - --hash=sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf \ - --hash=sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932 \ - --hash=sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a \ - --hash=sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29 \ - --hash=sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206 \ - --hash=sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2 \ - --hash=sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c \ - --hash=sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c \ - --hash=sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0 \ - --hash=sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a \ - --hash=sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195 \ - --hash=sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6 \ - --hash=sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9 \ - --hash=sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc \ - --hash=sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb \ - --hash=sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0 \ - --hash=sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7 \ - --hash=sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb \ - --hash=sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a \ - --hash=sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492 \ - --hash=sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720 \ - --hash=sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42 \ - --hash=sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7 \ - --hash=sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d \ - --hash=sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d \ - --hash=sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb \ - --hash=sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4 \ - --hash=sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2 \ - --hash=sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b \ - --hash=sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8 \ - --hash=sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e \ - --hash=sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204 \ - --hash=sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3 \ - --hash=sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150 \ - --hash=sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4 \ - --hash=sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76 \ - --hash=sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e \ - --hash=sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb \ - --hash=sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91 +certifi==2024.8.30 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +cffi==1.17.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ + --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ + --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ + --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ + --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ + --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ + --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ + --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ + --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ + --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ + --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ + --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ + --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ + --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ + --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ + --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ + --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ + --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ + --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ + --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ + --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ + --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ + --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ + --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ + --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ + --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ + --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ + --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ + --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ + --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ + --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ + --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ + --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ + --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ + --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ + --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ + --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ + --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ + --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ + --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ + --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ + --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ + --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ + --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ + --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ + --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ + --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ + --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ + --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ + --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ + --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ + --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ + --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ + --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ + --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ + --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ + --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ + --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ + --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ + --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ + --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ + --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ + --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ + --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ + --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ + --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ @@ -285,9 +300,9 @@ click==8.1.7 ; python_version >= "3.10" and python_version < "4.0" \ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 -configparser==7.0.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:af3c618a67aaaedc4d689fd7317d238f566b9aa03cae50102e92d7f0dfe78ba0 \ - --hash=sha256:f46d52a12811c637104c6bb8eb33693be0038ab6bf01d69aae009c39ec8c2017 +configparser==7.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:98e374573c4e10e92399651e3ba1c47a438526d633c44ee96143dec26dad4299 \ + --hash=sha256:eb82646c892dbdf773dae19c633044d163c3129971ae09b49410a303b8e0a5f7 cryptography==43.0.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ @@ -337,9 +352,9 @@ exceptiongroup==1.2.2 ; python_version >= "3.10" and python_version < "3.11" \ fastapi-slim==0.111.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:ac29948dcbf84cc78d68ed2c4df4e695ac265cf53c339e5794008476e9befbbb \ --hash=sha256:f799a60658f56c49fe3842eb534730fabe1168731c0b407b98a042c8d57be39d -filelock==3.15.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ - --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 +filelock==3.16.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec \ + --hash=sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609 forcediphttpsadapter==1.1.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0d224cf6e8e50eb788c9f5994a7afa6d389bac6dbe540b7dfd77a32590ad0153 \ --hash=sha256:5e7662ece61735585332d09b87d94fffe4752469d5c0d3feff48746e5d70744b @@ -421,115 +436,123 @@ frozenlist==1.4.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887 \ --hash=sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced \ --hash=sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74 -googleapis-common-protos==1.63.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945 \ - --hash=sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87 -greenlet==3.0.3 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ - --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ - --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ - --hash=sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257 \ - --hash=sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4 \ - --hash=sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676 \ - --hash=sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61 \ - --hash=sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc \ - --hash=sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca \ - --hash=sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7 \ - --hash=sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728 \ - --hash=sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305 \ - --hash=sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6 \ - --hash=sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379 \ - --hash=sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414 \ - --hash=sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04 \ - --hash=sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a \ - --hash=sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf \ - --hash=sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491 \ - --hash=sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559 \ - --hash=sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e \ - --hash=sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274 \ - --hash=sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb \ - --hash=sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b \ - --hash=sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9 \ - --hash=sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b \ - --hash=sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be \ - --hash=sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506 \ - --hash=sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405 \ - --hash=sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113 \ - --hash=sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f \ - --hash=sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5 \ - --hash=sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230 \ - --hash=sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d \ - --hash=sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f \ - --hash=sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a \ - --hash=sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e \ - --hash=sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61 \ - --hash=sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6 \ - --hash=sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d \ - --hash=sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71 \ - --hash=sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22 \ - --hash=sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2 \ - --hash=sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3 \ - --hash=sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067 \ - --hash=sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc \ - --hash=sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881 \ - --hash=sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3 \ - --hash=sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e \ - --hash=sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac \ - --hash=sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53 \ - --hash=sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0 \ - --hash=sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b \ - --hash=sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83 \ - --hash=sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41 \ - --hash=sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c \ - --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ - --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ - --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 -grpcio==1.65.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:075f3903bc1749ace93f2b0664f72964ee5f2da5c15d4b47e0ab68e4f442c257 \ - --hash=sha256:0a0720299bdb2cc7306737295d56e41ce8827d5669d4a3cd870af832e3b17c4d \ - --hash=sha256:0cef8c919a3359847c357cb4314e50ed1f0cca070f828ee8f878d362fd744d52 \ - --hash=sha256:0e85c8766cf7f004ab01aff6a0393935a30d84388fa3c58d77849fcf27f3e98c \ - --hash=sha256:17de4fda50967679677712eec0a5c13e8904b76ec90ac845d83386b65da0ae1e \ - --hash=sha256:18c10f0d054d2dce34dd15855fcca7cc44ec3b811139437543226776730c0f28 \ - --hash=sha256:24a2246e80a059b9eb981e4c2a6d8111b1b5e03a44421adbf2736cc1d4988a8a \ - --hash=sha256:280e93356fba6058cbbfc6f91a18e958062ef1bdaf5b1caf46c615ba1ae71b5b \ - --hash=sha256:2a1d4c84d9e657f72bfbab8bedf31bdfc6bfc4a1efb10b8f2d28241efabfaaf2 \ - --hash=sha256:2a4f476209acffec056360d3e647ae0e14ae13dcf3dfb130c227ae1c594cbe39 \ - --hash=sha256:2bd672e005afab8bf0d6aad5ad659e72a06dd713020554182a66d7c0c8f47e18 \ - --hash=sha256:3d1bbf7e1dd1096378bd83c83f554d3b93819b91161deaf63e03b7022a85224a \ - --hash=sha256:3dee50c1b69754a4228e933696408ea87f7e896e8d9797a3ed2aeed8dbd04b74 \ - --hash=sha256:4482a44ce7cf577a1f8082e807a5b909236bce35b3e3897f839f2fbd9ae6982d \ - --hash=sha256:4934077b33aa6fe0b451de8b71dabde96bf2d9b4cb2b3187be86e5adebcba021 \ - --hash=sha256:5764237d751d3031a36fafd57eb7d36fd2c10c658d2b4057c516ccf114849a3e \ - --hash=sha256:626319a156b1f19513156a3b0dbfe977f5f93db63ca673a0703238ebd40670d7 \ - --hash=sha256:644a783ce604a7d7c91412bd51cf9418b942cf71896344b6dc8d55713c71ce82 \ - --hash=sha256:66bb051881c84aa82e4f22d8ebc9d1704b2e35d7867757f0740c6ef7b902f9b1 \ - --hash=sha256:74c34fc7562bdd169b77966068434a93040bfca990e235f7a67cdf26e1bd5c63 \ - --hash=sha256:7656376821fed8c89e68206a522522317787a3d9ed66fb5110b1dff736a5e416 \ - --hash=sha256:85e9c69378af02e483bc626fc19a218451b24a402bdf44c7531e4c9253fb49ef \ - --hash=sha256:870370524eff3144304da4d1bbe901d39bdd24f858ce849b7197e530c8c8f2ec \ - --hash=sha256:874acd010e60a2ec1e30d5e505b0651ab12eb968157cd244f852b27c6dbed733 \ - --hash=sha256:886b45b29f3793b0c2576201947258782d7e54a218fe15d4a0468d9a6e00ce17 \ - --hash=sha256:88fcabc332a4aef8bcefadc34a02e9ab9407ab975d2c7d981a8e12c1aed92aa1 \ - --hash=sha256:8dc9ddc4603ec43f6238a5c95400c9a901b6d079feb824e890623da7194ff11e \ - --hash=sha256:8eb485801957a486bf5de15f2c792d9f9c897a86f2f18db8f3f6795a094b4bb2 \ - --hash=sha256:926a0750a5e6fb002542e80f7fa6cab8b1a2ce5513a1c24641da33e088ca4c56 \ - --hash=sha256:a146bc40fa78769f22e1e9ff4f110ef36ad271b79707577bf2a31e3e931141b9 \ - --hash=sha256:a925446e6aa12ca37114840d8550f308e29026cdc423a73da3043fd1603a6385 \ - --hash=sha256:a99e6dffefd3027b438116f33ed1261c8d360f0dd4f943cb44541a2782eba72f \ - --hash=sha256:abccc5d73f5988e8f512eb29341ed9ced923b586bb72e785f265131c160231d8 \ - --hash=sha256:ade1256c98cba5a333ef54636095f2c09e6882c35f76acb04412f3b1aa3c29a5 \ - --hash=sha256:b07f36faf01fca5427d4aa23645e2d492157d56c91fab7e06fe5697d7e171ad4 \ - --hash=sha256:b81711bf4ec08a3710b534e8054c7dcf90f2edc22bebe11c1775a23f145595fe \ - --hash=sha256:be952436571dacc93ccc7796db06b7daf37b3b56bb97e3420e6503dccfe2f1b4 \ - --hash=sha256:c9ba3e63108a8749994f02c7c0e156afb39ba5bdf755337de8e75eb685be244b \ - --hash=sha256:cdb34278e4ceb224c89704cd23db0d902e5e3c1c9687ec9d7c5bb4c150f86816 \ - --hash=sha256:cf53e6247f1e2af93657e62e240e4f12e11ee0b9cef4ddcb37eab03d501ca864 \ - --hash=sha256:d2b819f9ee27ed4e3e737a4f3920e337e00bc53f9e254377dd26fc7027c4d558 \ - --hash=sha256:d72962788b6c22ddbcdb70b10c11fbb37d60ae598c51eb47ec019db66ccfdff0 \ - --hash=sha256:d7b984a8dd975d949c2042b9b5ebcf297d6d5af57dcd47f946849ee15d3c2fb8 \ - --hash=sha256:e4a795c02405c7dfa8affd98c14d980f4acea16ea3b539e7404c645329460e5a \ - --hash=sha256:e6cbdd107e56bde55c565da5fd16f08e1b4e9b0674851d7749e7f32d8645f524 \ - --hash=sha256:ee40d058cf20e1dd4cacec9c39e9bce13fedd38ce32f9ba00f639464fcb757de +googleapis-common-protos==1.65.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ + --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 +greenlet==3.1.0 ; python_version >= "3.10" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" \ + --hash=sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9 \ + --hash=sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17 \ + --hash=sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc \ + --hash=sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637 \ + --hash=sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2 \ + --hash=sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3 \ + --hash=sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6 \ + --hash=sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b \ + --hash=sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf \ + --hash=sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27 \ + --hash=sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1 \ + --hash=sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc \ + --hash=sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a \ + --hash=sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b \ + --hash=sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d \ + --hash=sha256:2d004db911ed7b6218ec5c5bfe4cf70ae8aa2223dffbb5b3c69e342bb253cb28 \ + --hash=sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303 \ + --hash=sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99 \ + --hash=sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f \ + --hash=sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7 \ + --hash=sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6 \ + --hash=sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a \ + --hash=sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc \ + --hash=sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0 \ + --hash=sha256:5fd6e94593f6f9714dbad1aaba734b5ec04593374fa6638df61592055868f8b8 \ + --hash=sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a \ + --hash=sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca \ + --hash=sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b \ + --hash=sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989 \ + --hash=sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19 \ + --hash=sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6 \ + --hash=sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484 \ + --hash=sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd \ + --hash=sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25 \ + --hash=sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b \ + --hash=sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910 \ + --hash=sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0 \ + --hash=sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5 \ + --hash=sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345 \ + --hash=sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6 \ + --hash=sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00 \ + --hash=sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df \ + --hash=sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811 \ + --hash=sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca \ + --hash=sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8 \ + --hash=sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33 \ + --hash=sha256:ac0adfdb3a21dc2a24ed728b61e72440d297d0fd3a577389df566651fcd08f97 \ + --hash=sha256:b395121e9bbe8d02a750886f108d540abe66075e61e22f7353d9acb0b81be0f0 \ + --hash=sha256:b9505a0c8579899057cbefd4ec34d865ab99852baf1ff33a9481eb3924e2da0b \ + --hash=sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682 \ + --hash=sha256:c3967dcc1cd2ea61b08b0b276659242cbce5caca39e7cbc02408222fb9e6ff39 \ + --hash=sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64 \ + --hash=sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f \ + --hash=sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665 \ + --hash=sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f \ + --hash=sha256:d0dd943282231480aad5f50f89bdf26690c995e8ff555f26d8a5b9887b559bcc \ + --hash=sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d \ + --hash=sha256:d45b75b0f3fd8d99f62eb7908cfa6d727b7ed190737dec7fe46d993da550b81a \ + --hash=sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0 \ + --hash=sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09 \ + --hash=sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b \ + --hash=sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491 \ + --hash=sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7 \ + --hash=sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954 \ + --hash=sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501 \ + --hash=sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54 +grpcio==1.66.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e \ + --hash=sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce \ + --hash=sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8 \ + --hash=sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d \ + --hash=sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858 \ + --hash=sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0 \ + --hash=sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a \ + --hash=sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45 \ + --hash=sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef \ + --hash=sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2 \ + --hash=sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac \ + --hash=sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd \ + --hash=sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1 \ + --hash=sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce \ + --hash=sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492 \ + --hash=sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e \ + --hash=sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb \ + --hash=sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44 \ + --hash=sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb \ + --hash=sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759 \ + --hash=sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e \ + --hash=sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761 \ + --hash=sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26 \ + --hash=sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791 \ + --hash=sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c \ + --hash=sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60 \ + --hash=sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df \ + --hash=sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a \ + --hash=sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3 \ + --hash=sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734 \ + --hash=sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f \ + --hash=sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083 \ + --hash=sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524 \ + --hash=sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d \ + --hash=sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a \ + --hash=sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0 \ + --hash=sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb \ + --hash=sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503 \ + --hash=sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815 \ + --hash=sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22 \ + --hash=sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2 \ + --hash=sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c \ + --hash=sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d \ + --hash=sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b \ + --hash=sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c \ + --hash=sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9 h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -538,12 +561,12 @@ httpcore==1.0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 httpretty==1.1.4 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68 -httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 \ - --hash=sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5 -idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +httpx==0.27.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0 \ + --hash=sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2 +idna==3.10 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 importlib-metadata==8.0.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 @@ -559,149 +582,145 @@ langcodes==3.4.0 ; python_version >= "3.10" and python_version < "4.0" \ language-data==1.2.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:77d5cab917f91ee0b2f1aa7018443e911cf8985ef734ca2ba3940770f6a3816b \ --hash=sha256:82a86050bbd677bfde87d97885b17566cfe75dad3ac4f5ce44b52c28f752e773 -lxml==5.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02437fb7308386867c8b7b0e5bc4cd4b04548b1c5d089ffb8e7b31009b961dc3 \ - --hash=sha256:02f6a8eb6512fdc2fd4ca10a49c341c4e109aa6e9448cc4859af5b949622715a \ - --hash=sha256:05f8757b03208c3f50097761be2dea0aba02e94f0dc7023ed73a7bb14ff11eb0 \ - --hash=sha256:06668e39e1f3c065349c51ac27ae430719d7806c026fec462e5693b08b95696b \ - --hash=sha256:07542787f86112d46d07d4f3c4e7c760282011b354d012dc4141cc12a68cef5f \ - --hash=sha256:08ea0f606808354eb8f2dfaac095963cb25d9d28e27edcc375d7b30ab01abbf6 \ - --hash=sha256:0969e92af09c5687d769731e3f39ed62427cc72176cebb54b7a9d52cc4fa3b73 \ - --hash=sha256:0a028b61a2e357ace98b1615fc03f76eb517cc028993964fe08ad514b1e8892d \ - --hash=sha256:0b3f5016e00ae7630a4b83d0868fca1e3d494c78a75b1c7252606a3a1c5fc2ad \ - --hash=sha256:13e69be35391ce72712184f69000cda04fc89689429179bc4c0ae5f0b7a8c21b \ - --hash=sha256:16a8326e51fcdffc886294c1e70b11ddccec836516a343f9ed0f82aac043c24a \ - --hash=sha256:19b4e485cd07b7d83e3fe3b72132e7df70bfac22b14fe4bf7a23822c3a35bff5 \ - --hash=sha256:1a2569a1f15ae6c8c64108a2cd2b4a858fc1e13d25846be0666fc144715e32ab \ - --hash=sha256:1a7aca7964ac4bb07680d5c9d63b9d7028cace3e2d43175cb50bba8c5ad33316 \ - --hash=sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6 \ - --hash=sha256:1d8a701774dfc42a2f0b8ccdfe7dbc140500d1049e0632a611985d943fcf12df \ - --hash=sha256:1e275ea572389e41e8b039ac076a46cb87ee6b8542df3fff26f5baab43713bca \ - --hash=sha256:2304d3c93f2258ccf2cf7a6ba8c761d76ef84948d87bf9664e14d203da2cd264 \ - --hash=sha256:23441e2b5339bc54dc949e9e675fa35efe858108404ef9aa92f0456929ef6fe8 \ - --hash=sha256:23cfafd56887eaed93d07bc4547abd5e09d837a002b791e9767765492a75883f \ - --hash=sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b \ - --hash=sha256:2eb2227ce1ff998faf0cd7fe85bbf086aa41dfc5af3b1d80867ecfe75fb68df3 \ - --hash=sha256:2fb0ba3e8566548d6c8e7dd82a8229ff47bd8fb8c2da237607ac8e5a1b8312e5 \ - --hash=sha256:303f540ad2dddd35b92415b74b900c749ec2010e703ab3bfd6660979d01fd4ed \ - --hash=sha256:339ee4a4704bc724757cd5dd9dc8cf4d00980f5d3e6e06d5847c1b594ace68ab \ - --hash=sha256:33ce9e786753743159799fdf8e92a5da351158c4bfb6f2db0bf31e7892a1feb5 \ - --hash=sha256:343ab62e9ca78094f2306aefed67dcfad61c4683f87eee48ff2fd74902447726 \ - --hash=sha256:34e17913c431f5ae01d8658dbf792fdc457073dcdfbb31dc0cc6ab256e664a8d \ - --hash=sha256:364d03207f3e603922d0d3932ef363d55bbf48e3647395765f9bfcbdf6d23632 \ - --hash=sha256:38b67afb0a06b8575948641c1d6d68e41b83a3abeae2ca9eed2ac59892b36706 \ - --hash=sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8 \ - --hash=sha256:3b019d4ee84b683342af793b56bb35034bd749e4cbdd3d33f7d1107790f8c472 \ - --hash=sha256:3b6a30a9ab040b3f545b697cb3adbf3696c05a3a68aad172e3fd7ca73ab3c835 \ - --hash=sha256:3d1e35572a56941b32c239774d7e9ad724074d37f90c7a7d499ab98761bd80cf \ - --hash=sha256:3d98de734abee23e61f6b8c2e08a88453ada7d6486dc7cdc82922a03968928db \ - --hash=sha256:453d037e09a5176d92ec0fd282e934ed26d806331a8b70ab431a81e2fbabf56d \ - --hash=sha256:45f9494613160d0405682f9eee781c7e6d1bf45f819654eb249f8f46a2c22545 \ - --hash=sha256:4820c02195d6dfb7b8508ff276752f6b2ff8b64ae5d13ebe02e7667e035000b9 \ - --hash=sha256:49095a38eb333aaf44c06052fd2ec3b8f23e19747ca7ec6f6c954ffea6dbf7be \ - --hash=sha256:4aefd911793b5d2d7a921233a54c90329bf3d4a6817dc465f12ffdfe4fc7b8fe \ - --hash=sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905 \ - --hash=sha256:4c30a2f83677876465f44c018830f608fa3c6a8a466eb223535035fbc16f3438 \ - --hash=sha256:50127c186f191b8917ea2fb8b206fbebe87fd414a6084d15568c27d0a21d60db \ - --hash=sha256:50ccb5d355961c0f12f6cf24b7187dbabd5433f29e15147a67995474f27d1776 \ - --hash=sha256:519895c99c815a1a24a926d5b60627ce5ea48e9f639a5cd328bda0515ea0f10c \ - --hash=sha256:54401c77a63cc7d6dc4b4e173bb484f28a5607f3df71484709fe037c92d4f0ed \ - --hash=sha256:546cf886f6242dff9ec206331209db9c8e1643ae642dea5fdbecae2453cb50fd \ - --hash=sha256:55ce6b6d803890bd3cc89975fca9de1dff39729b43b73cb15ddd933b8bc20484 \ - --hash=sha256:56793b7a1a091a7c286b5f4aa1fe4ae5d1446fe742d00cdf2ffb1077865db10d \ - --hash=sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6 \ - --hash=sha256:5b8c041b6265e08eac8a724b74b655404070b636a8dd6d7a13c3adc07882ef30 \ - --hash=sha256:5e097646944b66207023bc3c634827de858aebc226d5d4d6d16f0b77566ea182 \ - --hash=sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61 \ - --hash=sha256:610b5c77428a50269f38a534057444c249976433f40f53e3b47e68349cca1425 \ - --hash=sha256:625e3ef310e7fa3a761d48ca7ea1f9d8718a32b1542e727d584d82f4453d5eeb \ - --hash=sha256:657a972f46bbefdbba2d4f14413c0d079f9ae243bd68193cb5061b9732fa54c1 \ - --hash=sha256:69ab77a1373f1e7563e0fb5a29a8440367dec051da6c7405333699d07444f511 \ - --hash=sha256:6a520b4f9974b0a0a6ed73c2154de57cdfd0c8800f4f15ab2b73238ffed0b36e \ - --hash=sha256:6d68ce8e7b2075390e8ac1e1d3a99e8b6372c694bbe612632606d1d546794207 \ - --hash=sha256:6dcc3d17eac1df7859ae01202e9bb11ffa8c98949dcbeb1069c8b9a75917e01b \ - --hash=sha256:6dfdc2bfe69e9adf0df4915949c22a25b39d175d599bf98e7ddf620a13678585 \ - --hash=sha256:739e36ef7412b2bd940f75b278749106e6d025e40027c0b94a17ef7968d55d56 \ - --hash=sha256:7429e7faa1a60cad26ae4227f4dd0459efde239e494c7312624ce228e04f6391 \ - --hash=sha256:74da9f97daec6928567b48c90ea2c82a106b2d500f397eeb8941e47d30b1ca85 \ - --hash=sha256:74e4f025ef3db1c6da4460dd27c118d8cd136d0391da4e387a15e48e5c975147 \ - --hash=sha256:75a9632f1d4f698b2e6e2e1ada40e71f369b15d69baddb8968dcc8e683839b18 \ - --hash=sha256:76acba4c66c47d27c8365e7c10b3d8016a7da83d3191d053a58382311a8bf4e1 \ - --hash=sha256:79d1fb9252e7e2cfe4de6e9a6610c7cbb99b9708e2c3e29057f487de5a9eaefa \ - --hash=sha256:7ce7ad8abebe737ad6143d9d3bf94b88b93365ea30a5b81f6877ec9c0dee0a48 \ - --hash=sha256:7ed07b3062b055d7a7f9d6557a251cc655eed0b3152b76de619516621c56f5d3 \ - --hash=sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184 \ - --hash=sha256:8268cbcd48c5375f46e000adb1390572c98879eb4f77910c6053d25cc3ac2c67 \ - --hash=sha256:875a3f90d7eb5c5d77e529080d95140eacb3c6d13ad5b616ee8095447b1d22e7 \ - --hash=sha256:89feb82ca055af0fe797a2323ec9043b26bc371365847dbe83c7fd2e2f181c34 \ - --hash=sha256:8a7e24cb69ee5f32e003f50e016d5fde438010c1022c96738b04fc2423e61706 \ - --hash=sha256:8ab6a358d1286498d80fe67bd3d69fcbc7d1359b45b41e74c4a26964ca99c3f8 \ - --hash=sha256:8b8df03a9e995b6211dafa63b32f9d405881518ff1ddd775db4e7b98fb545e1c \ - --hash=sha256:8cf85a6e40ff1f37fe0f25719aadf443686b1ac7652593dc53c7ef9b8492b115 \ - --hash=sha256:8e8d351ff44c1638cb6e980623d517abd9f580d2e53bfcd18d8941c052a5a009 \ - --hash=sha256:9164361769b6ca7769079f4d426a41df6164879f7f3568be9086e15baca61466 \ - --hash=sha256:96e85aa09274955bb6bd483eaf5b12abadade01010478154b0ec70284c1b1526 \ - --hash=sha256:981a06a3076997adf7c743dcd0d7a0415582661e2517c7d961493572e909aa1d \ - --hash=sha256:9cd5323344d8ebb9fb5e96da5de5ad4ebab993bbf51674259dbe9d7a18049525 \ - --hash=sha256:9d6c6ea6a11ca0ff9cd0390b885984ed31157c168565702959c25e2191674a14 \ - --hash=sha256:a02d3c48f9bb1e10c7788d92c0c7db6f2002d024ab6e74d6f45ae33e3d0288a3 \ - --hash=sha256:a233bb68625a85126ac9f1fc66d24337d6e8a0f9207b688eec2e7c880f012ec0 \ - --hash=sha256:a2f6a1bc2460e643785a2cde17293bd7a8f990884b822f7bca47bee0a82fc66b \ - --hash=sha256:a6d17e0370d2516d5bb9062c7b4cb731cff921fc875644c3d751ad857ba9c5b1 \ - --hash=sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f \ - --hash=sha256:ab67ed772c584b7ef2379797bf14b82df9aa5f7438c5b9a09624dd834c1c1aaf \ - --hash=sha256:ac6540c9fff6e3813d29d0403ee7a81897f1d8ecc09a8ff84d2eea70ede1cdbf \ - --hash=sha256:ae4073a60ab98529ab8a72ebf429f2a8cc612619a8c04e08bed27450d52103c0 \ - --hash=sha256:ae791f6bd43305aade8c0e22f816b34f3b72b6c820477aab4d18473a37e8090b \ - --hash=sha256:aef5474d913d3b05e613906ba4090433c515e13ea49c837aca18bde190853dff \ - --hash=sha256:b0b3f2df149efb242cee2ffdeb6674b7f30d23c9a7af26595099afaf46ef4e88 \ - --hash=sha256:b128092c927eaf485928cec0c28f6b8bead277e28acf56800e972aa2c2abd7a2 \ - --hash=sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40 \ - --hash=sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716 \ - --hash=sha256:b47633251727c8fe279f34025844b3b3a3e40cd1b198356d003aa146258d13a2 \ - --hash=sha256:b537bd04d7ccd7c6350cdaaaad911f6312cbd61e6e6045542f781c7f8b2e99d2 \ - --hash=sha256:b5e4ef22ff25bfd4ede5f8fb30f7b24446345f3e79d9b7455aef2836437bc38a \ - --hash=sha256:b74b9ea10063efb77a965a8d5f4182806fbf59ed068b3c3fd6f30d2ac7bee734 \ - --hash=sha256:bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87 \ - --hash=sha256:bbc4b80af581e18568ff07f6395c02114d05f4865c2812a1f02f2eaecf0bfd48 \ - --hash=sha256:bcc98f911f10278d1daf14b87d65325851a1d29153caaf146877ec37031d5f36 \ - --hash=sha256:be49ad33819d7dcc28a309b86d4ed98e1a65f3075c6acd3cd4fe32103235222b \ - --hash=sha256:bec4bd9133420c5c52d562469c754f27c5c9e36ee06abc169612c959bd7dbb07 \ - --hash=sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c \ - --hash=sha256:c689d0d5381f56de7bd6966a4541bff6e08bf8d3871bbd89a0c6ab18aa699573 \ - --hash=sha256:c7079d5eb1c1315a858bbf180000757db8ad904a89476653232db835c3114001 \ - --hash=sha256:cb3942960f0beb9f46e2a71a3aca220d1ca32feb5a398656be934320804c0df9 \ - --hash=sha256:cd9e78285da6c9ba2d5c769628f43ef66d96ac3085e59b10ad4f3707980710d3 \ - --hash=sha256:cf2a978c795b54c539f47964ec05e35c05bd045db5ca1e8366988c7f2fe6b3ce \ - --hash=sha256:d14a0d029a4e176795cef99c056d58067c06195e0c7e2dbb293bf95c08f772a3 \ - --hash=sha256:d237ba6664b8e60fd90b8549a149a74fcc675272e0e95539a00522e4ca688b04 \ - --hash=sha256:d26a618ae1766279f2660aca0081b2220aca6bd1aa06b2cf73f07383faf48927 \ - --hash=sha256:d28cb356f119a437cc58a13f8135ab8a4c8ece18159eb9194b0d269ec4e28083 \ - --hash=sha256:d4ed0c7cbecde7194cd3228c044e86bf73e30a23505af852857c09c24e77ec5d \ - --hash=sha256:d83e2d94b69bf31ead2fa45f0acdef0757fa0458a129734f59f67f3d2eb7ef32 \ - --hash=sha256:d8bbcd21769594dbba9c37d3c819e2d5847656ca99c747ddb31ac1701d0c0ed9 \ - --hash=sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f \ - --hash=sha256:dc911208b18842a3a57266d8e51fc3cfaccee90a5351b92079beed912a7914c2 \ - --hash=sha256:dfa7c241073d8f2b8e8dbc7803c434f57dbb83ae2a3d7892dd068d99e96efe2c \ - --hash=sha256:e282aedd63c639c07c3857097fc0e236f984ceb4089a8b284da1c526491e3f3d \ - --hash=sha256:e290d79a4107d7d794634ce3e985b9ae4f920380a813717adf61804904dc4393 \ - --hash=sha256:e3d9d13603410b72787579769469af730c38f2f25505573a5888a94b62b920f8 \ - --hash=sha256:e481bba1e11ba585fb06db666bfc23dbe181dbafc7b25776156120bf12e0d5a6 \ - --hash=sha256:e49b052b768bb74f58c7dda4e0bdf7b79d43a9204ca584ffe1fb48a6f3c84c66 \ - --hash=sha256:eb00b549b13bd6d884c863554566095bf6fa9c3cecb2e7b399c4bc7904cb33b5 \ - --hash=sha256:ec87c44f619380878bd49ca109669c9f221d9ae6883a5bcb3616785fa8f94c97 \ - --hash=sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196 \ - --hash=sha256:f11ae142f3a322d44513de1018b50f474f8f736bc3cd91d969f464b5bfef8836 \ - --hash=sha256:f2a09f6184f17a80897172863a655467da2b11151ec98ba8d7af89f17bf63dae \ - --hash=sha256:f5b65529bb2f21ac7861a0e94fdbf5dc0daab41497d18223b46ee8515e5ad297 \ - --hash=sha256:f60fdd125d85bf9c279ffb8e94c78c51b3b6a37711464e1f5f31078b45002421 \ - --hash=sha256:f61efaf4bed1cc0860e567d2ecb2363974d414f7f1f124b1df368bbf183453a6 \ - --hash=sha256:f90e552ecbad426eab352e7b2933091f2be77115bb16f09f78404861c8322981 \ - --hash=sha256:f956196ef61369f1685d14dad80611488d8dc1ef00be57c0c5a03064005b0f30 \ - --hash=sha256:fb91819461b1b56d06fa4bcf86617fac795f6a99d12239fb0c68dbeba41a0a30 \ - --hash=sha256:fbc9d316552f9ef7bba39f4edfad4a734d3d6f93341232a9dddadec4f15d425f \ - --hash=sha256:ff69a9a0b4b17d78170c73abe2ab12084bdf1691550c5629ad1fe7849433f324 \ - --hash=sha256:ffb2be176fed4457e445fe540617f0252a72a8bc56208fd65a690fdb1f57660b +lxml==5.3.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e \ + --hash=sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229 \ + --hash=sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3 \ + --hash=sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5 \ + --hash=sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70 \ + --hash=sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15 \ + --hash=sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002 \ + --hash=sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd \ + --hash=sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22 \ + --hash=sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf \ + --hash=sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22 \ + --hash=sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832 \ + --hash=sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727 \ + --hash=sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e \ + --hash=sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30 \ + --hash=sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f \ + --hash=sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f \ + --hash=sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51 \ + --hash=sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4 \ + --hash=sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de \ + --hash=sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875 \ + --hash=sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42 \ + --hash=sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e \ + --hash=sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6 \ + --hash=sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391 \ + --hash=sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc \ + --hash=sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b \ + --hash=sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237 \ + --hash=sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4 \ + --hash=sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86 \ + --hash=sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f \ + --hash=sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a \ + --hash=sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8 \ + --hash=sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f \ + --hash=sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903 \ + --hash=sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03 \ + --hash=sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e \ + --hash=sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99 \ + --hash=sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7 \ + --hash=sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab \ + --hash=sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d \ + --hash=sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22 \ + --hash=sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492 \ + --hash=sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b \ + --hash=sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3 \ + --hash=sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be \ + --hash=sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469 \ + --hash=sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f \ + --hash=sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a \ + --hash=sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c \ + --hash=sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a \ + --hash=sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4 \ + --hash=sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94 \ + --hash=sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442 \ + --hash=sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b \ + --hash=sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84 \ + --hash=sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c \ + --hash=sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9 \ + --hash=sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1 \ + --hash=sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be \ + --hash=sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367 \ + --hash=sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e \ + --hash=sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21 \ + --hash=sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa \ + --hash=sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16 \ + --hash=sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d \ + --hash=sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe \ + --hash=sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83 \ + --hash=sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba \ + --hash=sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040 \ + --hash=sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763 \ + --hash=sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8 \ + --hash=sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff \ + --hash=sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2 \ + --hash=sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a \ + --hash=sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b \ + --hash=sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce \ + --hash=sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c \ + --hash=sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577 \ + --hash=sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8 \ + --hash=sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71 \ + --hash=sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512 \ + --hash=sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540 \ + --hash=sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f \ + --hash=sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2 \ + --hash=sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a \ + --hash=sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce \ + --hash=sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e \ + --hash=sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2 \ + --hash=sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27 \ + --hash=sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1 \ + --hash=sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d \ + --hash=sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1 \ + --hash=sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330 \ + --hash=sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920 \ + --hash=sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99 \ + --hash=sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff \ + --hash=sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18 \ + --hash=sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff \ + --hash=sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c \ + --hash=sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179 \ + --hash=sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080 \ + --hash=sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19 \ + --hash=sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d \ + --hash=sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70 \ + --hash=sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32 \ + --hash=sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a \ + --hash=sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2 \ + --hash=sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79 \ + --hash=sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3 \ + --hash=sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5 \ + --hash=sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f \ + --hash=sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d \ + --hash=sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3 \ + --hash=sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b \ + --hash=sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753 \ + --hash=sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9 \ + --hash=sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957 \ + --hash=sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033 \ + --hash=sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb \ + --hash=sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656 \ + --hash=sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab \ + --hash=sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b \ + --hash=sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d \ + --hash=sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd \ + --hash=sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859 \ + --hash=sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11 \ + --hash=sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c \ + --hash=sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a \ + --hash=sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005 \ + --hash=sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654 \ + --hash=sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80 \ + --hash=sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e \ + --hash=sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec \ + --hash=sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7 \ + --hash=sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965 \ + --hash=sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945 \ + --hash=sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8 mako==1.3.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a \ --hash=sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc @@ -931,97 +950,99 @@ maxminddb==2.6.2 ; python_version >= "3.10" and python_version < "4.0" \ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -multidict==6.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556 \ - --hash=sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c \ - --hash=sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29 \ - --hash=sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b \ - --hash=sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8 \ - --hash=sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7 \ - --hash=sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd \ - --hash=sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40 \ - --hash=sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6 \ - --hash=sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3 \ - --hash=sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c \ - --hash=sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9 \ - --hash=sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5 \ - --hash=sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae \ - --hash=sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442 \ - --hash=sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9 \ - --hash=sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc \ - --hash=sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c \ - --hash=sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea \ - --hash=sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5 \ - --hash=sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50 \ - --hash=sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182 \ - --hash=sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453 \ - --hash=sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e \ - --hash=sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600 \ - --hash=sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733 \ - --hash=sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda \ - --hash=sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241 \ - --hash=sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461 \ - --hash=sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e \ - --hash=sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e \ - --hash=sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b \ - --hash=sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e \ - --hash=sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7 \ - --hash=sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386 \ - --hash=sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd \ - --hash=sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9 \ - --hash=sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf \ - --hash=sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee \ - --hash=sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5 \ - --hash=sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a \ - --hash=sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271 \ - --hash=sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54 \ - --hash=sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4 \ - --hash=sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496 \ - --hash=sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb \ - --hash=sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319 \ - --hash=sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3 \ - --hash=sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f \ - --hash=sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527 \ - --hash=sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed \ - --hash=sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604 \ - --hash=sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef \ - --hash=sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8 \ - --hash=sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5 \ - --hash=sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5 \ - --hash=sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626 \ - --hash=sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c \ - --hash=sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d \ - --hash=sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c \ - --hash=sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc \ - --hash=sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc \ - --hash=sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b \ - --hash=sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38 \ - --hash=sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450 \ - --hash=sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1 \ - --hash=sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f \ - --hash=sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3 \ - --hash=sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755 \ - --hash=sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226 \ - --hash=sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a \ - --hash=sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046 \ - --hash=sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf \ - --hash=sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479 \ - --hash=sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e \ - --hash=sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1 \ - --hash=sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a \ - --hash=sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83 \ - --hash=sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929 \ - --hash=sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93 \ - --hash=sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a \ - --hash=sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c \ - --hash=sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44 \ - --hash=sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89 \ - --hash=sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba \ - --hash=sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e \ - --hash=sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da \ - --hash=sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24 \ - --hash=sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423 \ - --hash=sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef +multidict==6.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f \ + --hash=sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056 \ + --hash=sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761 \ + --hash=sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3 \ + --hash=sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b \ + --hash=sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6 \ + --hash=sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748 \ + --hash=sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966 \ + --hash=sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f \ + --hash=sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1 \ + --hash=sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6 \ + --hash=sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada \ + --hash=sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305 \ + --hash=sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2 \ + --hash=sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d \ + --hash=sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a \ + --hash=sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef \ + --hash=sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c \ + --hash=sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb \ + --hash=sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60 \ + --hash=sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6 \ + --hash=sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4 \ + --hash=sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478 \ + --hash=sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81 \ + --hash=sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7 \ + --hash=sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56 \ + --hash=sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3 \ + --hash=sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6 \ + --hash=sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30 \ + --hash=sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb \ + --hash=sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506 \ + --hash=sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0 \ + --hash=sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925 \ + --hash=sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c \ + --hash=sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6 \ + --hash=sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e \ + --hash=sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95 \ + --hash=sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2 \ + --hash=sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133 \ + --hash=sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2 \ + --hash=sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa \ + --hash=sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3 \ + --hash=sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3 \ + --hash=sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436 \ + --hash=sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657 \ + --hash=sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581 \ + --hash=sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492 \ + --hash=sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43 \ + --hash=sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2 \ + --hash=sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2 \ + --hash=sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926 \ + --hash=sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057 \ + --hash=sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc \ + --hash=sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80 \ + --hash=sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255 \ + --hash=sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1 \ + --hash=sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972 \ + --hash=sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53 \ + --hash=sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1 \ + --hash=sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423 \ + --hash=sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a \ + --hash=sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160 \ + --hash=sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c \ + --hash=sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd \ + --hash=sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa \ + --hash=sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5 \ + --hash=sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b \ + --hash=sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa \ + --hash=sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef \ + --hash=sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44 \ + --hash=sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4 \ + --hash=sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156 \ + --hash=sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753 \ + --hash=sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28 \ + --hash=sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d \ + --hash=sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a \ + --hash=sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304 \ + --hash=sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008 \ + --hash=sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429 \ + --hash=sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72 \ + --hash=sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399 \ + --hash=sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3 \ + --hash=sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392 \ + --hash=sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167 \ + --hash=sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c \ + --hash=sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774 \ + --hash=sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351 \ + --hash=sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76 \ + --hash=sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875 \ + --hash=sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd \ + --hash=sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28 \ + --hash=sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db netaddr==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1 \ --hash=sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128 @@ -1176,113 +1197,113 @@ psycopg2==2.9.9 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c -pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \ - --hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 +pyasn1==0.6.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 pybinaryedge==0.5 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:00cf2f253aa44c7d6589a56d70c5b820a5060c3a0a2aee018f0b4ed732fe7632 pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc -pydantic-core==2.20.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \ - --hash=sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f \ - --hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \ - --hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \ - --hash=sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006 \ - --hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \ - --hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \ - --hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \ - --hash=sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86 \ - --hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \ - --hash=sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6 \ - --hash=sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a \ - --hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \ - --hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \ - --hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \ - --hash=sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c \ - --hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \ - --hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \ - --hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \ - --hash=sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd \ - --hash=sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1 \ - --hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \ - --hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \ - --hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \ - --hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \ - --hash=sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598 \ - --hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \ - --hash=sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331 \ - --hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \ - --hash=sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a \ - --hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \ - --hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \ - --hash=sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91 \ - --hash=sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa \ - --hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \ - --hash=sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0 \ - --hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \ - --hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \ - --hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \ - --hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \ - --hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \ - --hash=sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1 \ - --hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \ - --hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \ - --hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \ - --hash=sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2 \ - --hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \ - --hash=sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434 \ - --hash=sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab \ - --hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \ - --hash=sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a \ - --hash=sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2 \ - --hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \ - --hash=sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611 \ - --hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \ - --hash=sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e \ - --hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \ - --hash=sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09 \ - --hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \ - --hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \ - --hash=sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7 \ - --hash=sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b \ - --hash=sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987 \ - --hash=sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c \ - --hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \ - --hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \ - --hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \ - --hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \ - --hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \ - --hash=sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b \ - --hash=sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad \ - --hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \ - --hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \ - --hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \ - --hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \ - --hash=sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669 \ - --hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \ - --hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \ - --hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \ - --hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \ - --hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \ - --hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \ - --hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \ - --hash=sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad \ - --hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \ - --hash=sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a \ - --hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \ - --hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \ - --hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27 -pydantic-settings==2.4.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315 \ - --hash=sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88 -pydantic==2.8.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \ - --hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8 -pydicom==2.4.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ - --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 +pydantic-core==2.23.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801 \ + --hash=sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec \ + --hash=sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295 \ + --hash=sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba \ + --hash=sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e \ + --hash=sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e \ + --hash=sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4 \ + --hash=sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211 \ + --hash=sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea \ + --hash=sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c \ + --hash=sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835 \ + --hash=sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d \ + --hash=sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c \ + --hash=sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c \ + --hash=sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61 \ + --hash=sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83 \ + --hash=sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb \ + --hash=sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1 \ + --hash=sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5 \ + --hash=sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690 \ + --hash=sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b \ + --hash=sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7 \ + --hash=sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70 \ + --hash=sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a \ + --hash=sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8 \ + --hash=sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd \ + --hash=sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee \ + --hash=sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1 \ + --hash=sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab \ + --hash=sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958 \ + --hash=sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5 \ + --hash=sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b \ + --hash=sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961 \ + --hash=sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c \ + --hash=sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25 \ + --hash=sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4 \ + --hash=sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4 \ + --hash=sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f \ + --hash=sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326 \ + --hash=sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab \ + --hash=sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8 \ + --hash=sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b \ + --hash=sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6 \ + --hash=sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8 \ + --hash=sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01 \ + --hash=sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc \ + --hash=sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d \ + --hash=sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e \ + --hash=sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b \ + --hash=sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855 \ + --hash=sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700 \ + --hash=sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a \ + --hash=sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa \ + --hash=sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541 \ + --hash=sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791 \ + --hash=sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162 \ + --hash=sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611 \ + --hash=sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef \ + --hash=sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe \ + --hash=sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5 \ + --hash=sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba \ + --hash=sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28 \ + --hash=sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa \ + --hash=sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27 \ + --hash=sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4 \ + --hash=sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b \ + --hash=sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2 \ + --hash=sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c \ + --hash=sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8 \ + --hash=sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb \ + --hash=sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c \ + --hash=sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e \ + --hash=sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305 \ + --hash=sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8 \ + --hash=sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4 \ + --hash=sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433 \ + --hash=sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45 \ + --hash=sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16 \ + --hash=sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed \ + --hash=sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0 \ + --hash=sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d \ + --hash=sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710 \ + --hash=sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48 \ + --hash=sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423 \ + --hash=sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf \ + --hash=sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9 \ + --hash=sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63 \ + --hash=sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5 \ + --hash=sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb +pydantic-settings==2.5.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907 \ + --hash=sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0 +pydantic==2.9.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2 \ + --hash=sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612 +pydicom==3.0.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:003aeb025bbd20fc029f71eb286cf8772cc924d8de2baaec184c2caa513502df \ + --hash=sha256:7b1435dc7427a3d172685a9406ff1a75eb2d7651d236d0d99abd4953a1100922 pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a @@ -1333,9 +1354,9 @@ requests-file==2.1.0 ; python_version >= "3.10" and python_version < "4.0" \ requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 -rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ - --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rich==13.8.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06 \ + --hash=sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c \ --hash=sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585 \ @@ -1443,9 +1464,9 @@ rpds-py==0.20.0 ; python_version >= "3.10" and python_version < "4.0" \ sectxt==0.9.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:c5b113cb37ec5053bf8ea335306a7c68079b53959df2324ffa9991885bec67a8 \ --hash=sha256:c81d874a55b96516d13e2b688f3150a6089e0636122237e4710717beafcb26d7 -setuptools==72.1.0 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1 \ - --hash=sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec +setuptools==75.1.0 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \ + --hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538 shodan==1.25.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:7e2bddbc1b60bf620042d0010f4b762a80b43111dbea9c041d72d4325e260c23 six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ @@ -1454,54 +1475,54 @@ six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc -soupsieve==2.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \ - --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 -sqlalchemy==1.4.53 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0465b8a68f8f4de754c1966c45b187ac784ad97bc9747736f913130f0e1adea0 \ - --hash=sha256:07ba54f09033d387ae9df8d62cbe211ed7304e0bfbece1f8c55e21db9fae5c11 \ - --hash=sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed \ - --hash=sha256:13fc34b35d8ddb3fbe3f8fcfdf6c2546e676187f0fb20f5774da362ddaf8fa2d \ - --hash=sha256:16bb9fa4d00b4581b14d9f0e2224dc7745b854aa4687738279af0f48f7056c98 \ - --hash=sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05 \ - --hash=sha256:1a38834b4c183c33daf58544281395aad2e985f0b47cca1e88ea5ada88344e63 \ - --hash=sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae \ - --hash=sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22 \ - --hash=sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883 \ - --hash=sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9 \ - --hash=sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530 \ - --hash=sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525 \ - --hash=sha256:4fe5168d0249c23f537950b6d75935ff2709365a113e29938a979aec36668ecf \ - --hash=sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d \ - --hash=sha256:5f67b9e9dcac3241781e96575468d55a42332157dee04bdbf781df573dff5f85 \ - --hash=sha256:616492f5315128a847f293a7c552f3561ac7e996d2aa5dc46bef4fb0d3781f1d \ - --hash=sha256:626be971ff89541cfd3e70b54be00b57a7f8557204decb6223ce0428fec058f3 \ - --hash=sha256:670c7769bf5dcae9aff331247b5d82fe635c63731088a46ce68ba2ba519ef36e \ - --hash=sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315 \ - --hash=sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69 \ - --hash=sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499 \ - --hash=sha256:83a9c3514ff19d9d30d8a8d378b24cd1dfa5528d20891481cb5f196117db6a48 \ - --hash=sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c \ - --hash=sha256:89d8ac4158ef68eea8bb0f6dd0583127d9aa8720606964ba8eee20b254f9c83a \ - --hash=sha256:8b8608d162d3bd29d807aab32c3fb6e2f8e225a43d1c54c917fed38513785380 \ - --hash=sha256:93e90aa3e3b2f8e8cbae4d5509f8e0cf82972378d323c740a8df1c1e9f484172 \ - --hash=sha256:95123f3a1e0e8020848fd32ba751db889a01a44e4e4fef7e58c87ddd0b2fca59 \ - --hash=sha256:991e42fdfec561ebc6a4fae7161a86d129d6069fa14210b96b8dd752afa7059c \ - --hash=sha256:9d7368df54d3ed45a18955f6cec38ebe075290594ac0d5c87a8ddaff7e10de27 \ - --hash=sha256:a8c2f2a0b2c4e3b86eb58c9b6bb98548205eea2fba9dae4edfd29dc6aebbe95a \ - --hash=sha256:a9d4d132198844bd6828047135ce7b887687c92925049a2468a605fc775c7a1a \ - --hash=sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da \ - --hash=sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7 \ - --hash=sha256:c05fe05941424c2f3747a8952381b7725e24cba2ca00141380e54789d5b616b6 \ - --hash=sha256:c0cf8c0af9563892c6632f7343bc393dfce6eeef8e4d10c5fadba9c0390520bd \ - --hash=sha256:c15d1f1fcf1f9bec0499ae1d9132b950fcc7730f2d26d10484c8808b4e077816 \ - --hash=sha256:c58e011e9e6373b3a091d83f20601fb335a3b4bace80bfcb914ac168aad3b70d \ - --hash=sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046 \ - --hash=sha256:d021699b9007deb7aa715629078830c99a5fec2753d9bdd5ff33290d363ef755 \ - --hash=sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330 \ - --hash=sha256:eaaeedbceb4dfd688fff2faf25a9a87a391f548811494f7bff7fa701b639abc3 \ - --hash=sha256:edf094a20a386ff2ec73de65ef18014b250259cb860edc61741e240ca22d6981 \ - --hash=sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc +soupsieve==2.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \ + --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9 +sqlalchemy==1.4.54 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:02d2ecb9508f16ab9c5af466dfe5a88e26adf2e1a8d1c56eb616396ccae2c186 \ + --hash=sha256:0b76bbb1cbae618d10679be8966f6d66c94f301cfc15cb49e2f2382563fb6efb \ + --hash=sha256:0de620f978ca273ce027769dc8db7e6ee72631796187adc8471b3c76091b809e \ + --hash=sha256:1183599e25fa38a1a322294b949da02b4f0da13dbc2688ef9dbe746df573f8a6 \ + --hash=sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f \ + --hash=sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc \ + --hash=sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936 \ + --hash=sha256:14b3f4783275339170984cadda66e3ec011cce87b405968dc8d51cf0f9997b0d \ + --hash=sha256:1576fba3616f79496e2f067262200dbf4aab1bb727cd7e4e006076686413c80c \ + --hash=sha256:1990d5a6a5dc358a0894c8ca02043fb9a5ad9538422001fb2826e91c50f1d539 \ + --hash=sha256:1d83cd1cc03c22d922ec94d0d5f7b7c96b1332f5e122e81b1a61fb22da77879a \ + --hash=sha256:1e8c1b9ecaf9f2590337d5622189aeb2f0dbc54ba0232fa0856cf390957584a9 \ + --hash=sha256:26e78444bc77d089e62874dc74df05a5c71f01ac598010a327881a48408d0064 \ + --hash=sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5 \ + --hash=sha256:3112de9e11ff1957148c6de1df2bc5cc1440ee36783412e5eedc6f53638a577d \ + --hash=sha256:394b0135900b62dbf63e4809cdc8ac923182af2816d06ea61cd6763943c2cc05 \ + --hash=sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d \ + --hash=sha256:41cffc63c7c83dfc30c4cab5b4308ba74440a9633c4509c51a0c52431fb0f8ab \ + --hash=sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a \ + --hash=sha256:5ed3576675c187e3baa80b02c4c9d0edfab78eff4e89dd9da736b921333a2432 \ + --hash=sha256:6b24364150738ce488333b3fb48bfa14c189a66de41cd632796fbcacb26b4585 \ + --hash=sha256:6da60fb24577f989535b8fc8b2ddc4212204aaf02e53c4c7ac94ac364150ed08 \ + --hash=sha256:76c2ba7b5a09863d0a8166fbc753af96d561818c572dbaf697c52095938e7be4 \ + --hash=sha256:954816850777ac234a4e32b8c88ac1f7847088a6e90cfb8f0e127a1bf3feddff \ + --hash=sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4 \ + --hash=sha256:a01bc25eb7a5688656c8770f931d5cb4a44c7de1b3cec69b84cc9745d1e4cc10 \ + --hash=sha256:a19f816f4702d7b1951d7576026c7124b9bfb64a9543e571774cf517b7a50b29 \ + --hash=sha256:a41611835010ed4ea4c7aed1da5b58aac78ee7e70932a91ed2705a7b38e40f52 \ + --hash=sha256:a49730afb716f3f675755afec109895cab95bc9875db7ffe2e42c1b1c6279482 \ + --hash=sha256:a86b0e4be775902a5496af4fb1b60d8a2a457d78f531458d294360b8637bb014 \ + --hash=sha256:a8a72259a1652f192c68377be7011eac3c463e9892ef2948828c7d58e4829988 \ + --hash=sha256:af00236fe21c4d4f4c227b6ccc19b44c594160cc3ff28d104cdce85855369277 \ + --hash=sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e \ + --hash=sha256:b5933c45d11cbd9694b1540aa9076816cc7406964c7b16a380fd84d3a5fe3241 \ + --hash=sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c \ + --hash=sha256:b67589f7955924865344e6eacfdcf70675e64f36800a576aa5e961f0008cde2a \ + --hash=sha256:c5a2530400a6e7e68fd1552a55515de6a4559122e495f73554a51cedafc11669 \ + --hash=sha256:cafe0ba3a96d0845121433cffa2b9232844a2609fce694fcc02f3f31214ece28 \ + --hash=sha256:cdb2886c0be2c6c54d0651d5a61c29ef347e8eec81fd83afebbf7b59b80b7393 \ + --hash=sha256:d0cf7076c8578b3de4e43a046cc7a1af8466e1c3f5e64167189fe8958a4f9c02 \ + --hash=sha256:f1e1b92ee4ee9ffc68624ace218b89ca5ca667607ccee4541a90cc44999b9aea \ + --hash=sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88 \ + --hash=sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f \ + --hash=sha256:fc9ffd9a38e21fad3e8c5a88926d57f94a32546e937e0be46142b2702003eba7 starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \ --hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823 @@ -1514,9 +1535,9 @@ tldextract==3.5.0 ; python_version >= "3.10" and python_version < "4.0" \ typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 -urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ - --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 +urllib3==2.2.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 uvicorn==0.29.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de \ --hash=sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0 @@ -1599,97 +1620,99 @@ wrapt==1.16.0 ; python_version >= "3.10" and python_version < "4.0" \ xlsxwriter==3.2.0 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:9977d0c661a72866a61f9f7a809e25ebbb0fb7036baa3b9fe74afcfca6b3cb8c \ --hash=sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e -yarl==1.9.4 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51 \ - --hash=sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce \ - --hash=sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559 \ - --hash=sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0 \ - --hash=sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81 \ - --hash=sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc \ - --hash=sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4 \ - --hash=sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c \ - --hash=sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130 \ - --hash=sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136 \ - --hash=sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e \ - --hash=sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec \ - --hash=sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7 \ - --hash=sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1 \ - --hash=sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455 \ - --hash=sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099 \ - --hash=sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129 \ - --hash=sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10 \ - --hash=sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142 \ - --hash=sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98 \ - --hash=sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa \ - --hash=sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7 \ - --hash=sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525 \ - --hash=sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c \ - --hash=sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9 \ - --hash=sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c \ - --hash=sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8 \ - --hash=sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b \ - --hash=sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf \ - --hash=sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23 \ - --hash=sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd \ - --hash=sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27 \ - --hash=sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f \ - --hash=sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece \ - --hash=sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434 \ - --hash=sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec \ - --hash=sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff \ - --hash=sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78 \ - --hash=sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d \ - --hash=sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863 \ - --hash=sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53 \ - --hash=sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31 \ - --hash=sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15 \ - --hash=sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5 \ - --hash=sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b \ - --hash=sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57 \ - --hash=sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3 \ - --hash=sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1 \ - --hash=sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f \ - --hash=sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad \ - --hash=sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c \ - --hash=sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7 \ - --hash=sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2 \ - --hash=sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b \ - --hash=sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2 \ - --hash=sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b \ - --hash=sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9 \ - --hash=sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be \ - --hash=sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e \ - --hash=sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984 \ - --hash=sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4 \ - --hash=sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074 \ - --hash=sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2 \ - --hash=sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392 \ - --hash=sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91 \ - --hash=sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541 \ - --hash=sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf \ - --hash=sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572 \ - --hash=sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66 \ - --hash=sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575 \ - --hash=sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14 \ - --hash=sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5 \ - --hash=sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1 \ - --hash=sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e \ - --hash=sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551 \ - --hash=sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17 \ - --hash=sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead \ - --hash=sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0 \ - --hash=sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe \ - --hash=sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234 \ - --hash=sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0 \ - --hash=sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7 \ - --hash=sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34 \ - --hash=sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42 \ - --hash=sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385 \ - --hash=sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78 \ - --hash=sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be \ - --hash=sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958 \ - --hash=sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749 \ - --hash=sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec -zipp==3.19.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ - --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c +yarl==1.11.1 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49 \ + --hash=sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867 \ + --hash=sha256:04293941646647b3bfb1719d1d11ff1028e9c30199509a844da3c0f5919dc520 \ + --hash=sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a \ + --hash=sha256:077da604852be488c9a05a524068cdae1e972b7dc02438161c32420fb4ec5e14 \ + --hash=sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a \ + --hash=sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93 \ + --hash=sha256:0ea9682124fc062e3d931c6911934a678cb28453f957ddccf51f568c2f2b5e05 \ + --hash=sha256:0f351fa31234699d6084ff98283cb1e852270fe9e250a3b3bf7804eb493bd937 \ + --hash=sha256:14438dfc5015661f75f85bc5adad0743678eefee266ff0c9a8e32969d5d69f74 \ + --hash=sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b \ + --hash=sha256:15439f3c5c72686b6c3ff235279630d08936ace67d0fe5c8d5bbc3ef06f5a420 \ + --hash=sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639 \ + --hash=sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089 \ + --hash=sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53 \ + --hash=sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e \ + --hash=sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c \ + --hash=sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e \ + --hash=sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe \ + --hash=sha256:238a21849dd7554cb4d25a14ffbfa0ef380bb7ba201f45b144a14454a72ffa5a \ + --hash=sha256:250e888fa62d73e721f3041e3a9abf427788a1934b426b45e1b92f62c1f68366 \ + --hash=sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63 \ + --hash=sha256:267b24f891e74eccbdff42241c5fb4f974de2d6271dcc7d7e0c9ae1079a560d9 \ + --hash=sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145 \ + --hash=sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf \ + --hash=sha256:3257978c870728a52dcce8c2902bf01f6c53b65094b457bf87b2644ee6238ddc \ + --hash=sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5 \ + --hash=sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff \ + --hash=sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d \ + --hash=sha256:3ff6b1617aa39279fe18a76c8d165469c48b159931d9b48239065767ee455b2b \ + --hash=sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00 \ + --hash=sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad \ + --hash=sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92 \ + --hash=sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998 \ + --hash=sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91 \ + --hash=sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b \ + --hash=sha256:48dfd117ab93f0129084577a07287376cc69c08138694396f305636e229caa1a \ + --hash=sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5 \ + --hash=sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff \ + --hash=sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367 \ + --hash=sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa \ + --hash=sha256:61a5f2c14d0a1adfdd82258f756b23a550c13ba4c86c84106be4c111a3a4e413 \ + --hash=sha256:637c7ddb585a62d4469f843dac221f23eec3cbad31693b23abbc2c366ad41ff4 \ + --hash=sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45 \ + --hash=sha256:67459cf8cf31da0e2cbdb4b040507e535d25cfbb1604ca76396a3a66b8ba37a6 \ + --hash=sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5 \ + --hash=sha256:6907daa4b9d7a688063ed098c472f96e8181733c525e03e866fb5db480a424df \ + --hash=sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c \ + --hash=sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318 \ + --hash=sha256:7175a87ab8f7fbde37160a15e58e138ba3b2b0e05492d7351314a250d61b1591 \ + --hash=sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38 \ + --hash=sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8 \ + --hash=sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e \ + --hash=sha256:75e0ae31fb5ccab6eda09ba1494e87eb226dcbd2372dae96b87800e1dcc98804 \ + --hash=sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec \ + --hash=sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6 \ + --hash=sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870 \ + --hash=sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83 \ + --hash=sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d \ + --hash=sha256:8418c053aeb236b20b0ab8fa6bacfc2feaaf7d4683dd96528610989c99723d5f \ + --hash=sha256:87f020d010ba80a247c4abc335fc13421037800ca20b42af5ae40e5fd75e7909 \ + --hash=sha256:884eab2ce97cbaf89f264372eae58388862c33c4f551c15680dd80f53c89a269 \ + --hash=sha256:8a336eaa7ee7e87cdece3cedb395c9657d227bfceb6781295cf56abcd3386a26 \ + --hash=sha256:8aef1b64da41d18026632d99a06b3fefe1d08e85dd81d849fa7c96301ed22f1b \ + --hash=sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2 \ + --hash=sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7 \ + --hash=sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd \ + --hash=sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68 \ + --hash=sha256:94d0caaa912bfcdc702a4204cd5e2bb01eb917fc4f5ea2315aa23962549561b0 \ + --hash=sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786 \ + --hash=sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da \ + --hash=sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc \ + --hash=sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447 \ + --hash=sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239 \ + --hash=sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0 \ + --hash=sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84 \ + --hash=sha256:aac44097d838dda26526cffb63bdd8737a2dbdf5f2c68efb72ad83aec6673c7e \ + --hash=sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef \ + --hash=sha256:ba444bdd4caa2a94456ef67a2f383710928820dd0117aae6650a4d17029fa25e \ + --hash=sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82 \ + --hash=sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675 \ + --hash=sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26 \ + --hash=sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979 \ + --hash=sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46 \ + --hash=sha256:dae7bd0daeb33aa3e79e72877d3d51052e8b19c9025ecf0374f542ea8ec120e4 \ + --hash=sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff \ + --hash=sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27 \ + --hash=sha256:e8f63904df26d1a66aabc141bfd258bf738b9bc7bc6bdef22713b4f5ef789a4c \ + --hash=sha256:f3a6d90cab0bdf07df8f176eae3a07127daafcf7457b997b2bf46776da2c7eb7 \ + --hash=sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265 \ + --hash=sha256:f46f81501160c28d0c0b7333b4f7be8983dbbc161983b6fb814024d1b4952f79 \ + --hash=sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd +zipp==3.20.2 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ + --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index da8085d5f39..1c8fde0c10b 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -7,6 +7,7 @@ from pathlib import Path from uuid import UUID +import alembic.config import pytest from fastapi.testclient import TestClient from pydantic import TypeAdapter @@ -16,16 +17,21 @@ from boefjes.clients.bytes_client import BytesAPIClient from boefjes.clients.scheduler_client import Queue, SchedulerClientInterface, Task, TaskStatus from boefjes.config import Settings, settings -from boefjes.dependencies.plugins import PluginService +from boefjes.dependencies.plugins import PluginService, get_plugin_service from boefjes.job_handler import bytes_api_client from boefjes.job_models import BoefjeMeta, NormalizerMeta -from boefjes.local_repository import get_local_repository +from boefjes.katalogus.organisations import check_organisation_exists +from boefjes.katalogus.root import app +from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository, get_local_repository from boefjes.models import Organisation from boefjes.runtime_interfaces import Handler, WorkerManager from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter from boefjes.sql.db import SQL_BASE, get_engine -from boefjes.sql.organisation_storage import SQLOrganisationStorage +from boefjes.sql.organisation_storage import SQLOrganisationStorage, get_organisations_store from boefjes.sql.plugin_storage import SQLPluginStorage +from boefjes.storage.interfaces import OrganisationNotFound +from boefjes.storage.memory import ConfigStorageMemory, OrganisationStorageMemory, PluginStorageMemory from octopoes.api.models import Declaration, Observation from octopoes.connector.octopoes import OctopoesAPIConnector from octopoes.models import OOI @@ -152,14 +158,14 @@ def api(tmp_path): @pytest.fixture def session(): + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) engine = get_engine() session = sessionmaker(bind=engine)() yield session - session.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) session.commit() - session.close() + engine.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) @pytest.fixture @@ -178,23 +184,88 @@ def plugin_storage(session): @pytest.fixture -def local_repo(): +def local_repository(): return get_local_repository() @pytest.fixture -def plugin_service(plugin_storage, config_storage, local_repo): - return PluginService(plugin_storage, config_storage, local_repo) +def mock_local_repository(): + return LocalPluginRepository(Path(__file__).parent / "modules") @pytest.fixture -def organisation(organisation_storage) -> Organisation: - organisation = Organisation(id="test", name="Test org") +def normalizer_runner(local_repository: LocalPluginRepository): + return LocalNormalizerJobRunner(local_repository) + +@pytest.fixture +def boefje_runner(local_repository: LocalPluginRepository): + return LocalBoefjeJobRunner(local_repository) + + +@pytest.fixture +def mock_normalizer_runner(mock_local_repository: LocalPluginRepository): + return LocalNormalizerJobRunner(mock_local_repository) + + +@pytest.fixture +def mock_boefje_runner(mock_local_repository: LocalPluginRepository): + return LocalBoefjeJobRunner(mock_local_repository) + + +@pytest.fixture +def plugin_service(plugin_storage, config_storage, local_repository): + return PluginService(plugin_storage, config_storage, local_repository) + + +@pytest.fixture +def test_organisation(): + return Organisation(id="test", name="Test org") + + +@pytest.fixture +def mock_plugin_service(mock_local_repository, test_organisation) -> PluginService: + storage = ConfigStorageMemory() + storage.upsert(test_organisation.id, "test_plugin", {"DUMMY_VAR": "123"}) + + return PluginService(PluginStorageMemory(), storage, mock_local_repository) + + +@pytest.fixture +def organisation(organisation_storage, test_organisation) -> Organisation: with organisation_storage as repo: - repo.create(organisation) + repo.create(test_organisation) + + return test_organisation + + +@pytest.fixture +def unit_test_client(mock_plugin_service) -> TestClient: + client = TestClient(app) + _store = OrganisationStorageMemory({"test": Organisation(id="test", name="Test")}) + + services = { + "test": mock_plugin_service, + } - return organisation + def get_service(organisation_id: str): + if organisation_id in services: + return services.get(organisation_id) + + raise OrganisationNotFound(organisation_id) + + app.dependency_overrides[get_organisations_store] = lambda: _store + app.dependency_overrides[get_plugin_service] = get_service + app.dependency_overrides[check_organisation_exists] = lambda: None + + yield client + + app.dependency_overrides = {} + + +@pytest.fixture +def test_client() -> TestClient: + return TestClient(app) @pytest.fixture diff --git a/boefjes/tests/examples/adr-validator-output.json b/boefjes/tests/examples/adr-validator-output.json deleted file mode 100644 index ef83370f3e2..00000000000 --- a/boefjes/tests/examples/adr-validator-output.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "rule": "TEST-01", - "passed": false, - "message": "Error A" - }, - { - "rule": "TEST-02", - "passed": true, - "message": "" - }, - { - "rule": "TEST-03", - "passed": false, - "message": "Error B" - } -] diff --git a/boefjes/tests/examples/crt-normalize.json b/boefjes/tests/examples/crt-normalize.json deleted file mode 100644 index ea41e68844d..00000000000 --- a/boefjes/tests/examples/crt-normalize.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "47de840e-b778-4ca7-8709-4693b05bb455", - "organization": "_dev", - "arguments": { - "fqdn": "fundacionladulce.org.ar." - }, - "started_at": "2021-07-27T11:26:42.679000+00:00", - "ended_at": "2021-07-27T11:26:44.679000+00:00", - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/crt.json b/boefjes/tests/examples/crt.json deleted file mode 100644 index 7e290bc2de5..00000000000 --- a/boefjes/tests/examples/crt.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "875ed573-6edb-4470-b6ac-8693a443bfab", - "organization": "_dev", - "arguments": { - "fqdn": "fundacionladulce.org.ar." - }, - "dispatches": { - "normalizers": [ - "kat_crt_sh.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/dns-job.json b/boefjes/tests/examples/dns-job.json deleted file mode 100644 index 8ba85119326..00000000000 --- a/boefjes/tests/examples/dns-job.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "id": "99c3df04-8960-4059-94ea-2a8db1ca8b1c", - "boefje": { - "id": "dns-records", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|www.example.nl", - "arguments": { - "input": { - "name": "www.example.nl" - } - }, - "dispatches": [ - { - "id": "kat_dns_normalize", - "version": null - } - ] -} diff --git a/boefjes/tests/examples/dns-normalize2.json b/boefjes/tests/examples/dns-normalize2.json deleted file mode 100644 index 486edfee681..00000000000 --- a/boefjes/tests/examples/dns-normalize2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "53b86653-decd-453c-9b04-f5471f6e3ebc", - "organization": "_dev", - "input_ooi": "Hostname|internet|www.example.nl", - "arguments": { - "domain": "www.example.nl", - "input": { - "id": "www.example.nl" - } - }, - "dispatches": { - "normalizers": [ - "kat_dns_normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/dummy.json b/boefjes/tests/examples/dummy.json deleted file mode 100644 index 1ab6259ef7f..00000000000 --- a/boefjes/tests/examples/dummy.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "cd29d8e1-5fd9-4ff2-8252-5ac4fc25122c", - "boefje": { - "id": "kat_test.test", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|rijksoverheid.nl", - "arguments": { - "domain": "domain.com" - }, - "dispatches": [ - { - "id": "kat_test.test_normalize", - "version": null - } - ] -} diff --git a/boefjes/tests/examples/ipv6_nameservers.json b/boefjes/tests/examples/ipv6_nameservers.json deleted file mode 100644 index 575cfdea013..00000000000 --- a/boefjes/tests/examples/ipv6_nameservers.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "id": "2a9aef8a-74bc-449c-8172-5fc9faf9fe7e", - "boefje": { - "id": "IPv6 nameservers", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|rijksoverheid.nl", - "arguments": { - "hostname": "rijksoverheid.nl", - "pk": "Hostname|internet|rijksoverheid.nl", - "dns_records": "[{\"hostname\": \"ns0.rijksoverheidnl.com.\", \"ip\": \"2a06:fb00:1::1:82\"}, {\"hostname\": \"ns1.rijksoverheidnl.nl.\", \"ip\": \"2a00:d00:3:6::130\"}]" - }, - "dispatches": [ - { - "id": "kat_ipv6_nameservers_normalize", - "version": null - } - ] -} diff --git a/boefjes/tests/examples/ipv6_nameservers_normalize.json b/boefjes/tests/examples/ipv6_nameservers_normalize.json deleted file mode 100644 index d1c72f4a316..00000000000 --- a/boefjes/tests/examples/ipv6_nameservers_normalize.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "id": "43891719-f715-45d4-9f2b-295ab4bf17d3", - "boefje_meta": { - "id": "48aeb419-17c8-4f63-80c8-496000f5aa59", - "boefje": { - "id": "IPv6 nameservers", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|rijksoverheid.nl", - "arguments": { - "hostname": "rijksoverheid.nl", - "pk": "Hostname|internet|rijksoverheid.nl", - "dns_records": "[{\"hostname\": \"ns0.rijksoverheidnl.com.\", \"ip\": \"2a06:fb00:1::1:82\"}, {\"hostname\": \"ns1.rijksoverheidnl.nl.\", \"ip\": \"2a00:d00:3:6::130\"}]" - }, - "dispatches": [ - { - "id": "kat_ipv6_nameservers_normalize", - "version": null - } - ] - }, - "normalizer": { - "id": "kat_ipv6_nameservers.normalize", - "version": null - } -} diff --git a/boefjes/tests/examples/ipv6_webservers.json b/boefjes/tests/examples/ipv6_webservers.json deleted file mode 100644 index 520c881e88e..00000000000 --- a/boefjes/tests/examples/ipv6_webservers.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "id": "11a83bfb-d74b-4df5-913f-539285558a71", - "boefje": { - "id": "IPv6 webservers", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|rijksoverheid.nl", - "arguments": { - "pk": "Hostname|internet|rijksoverheid.nl", - "dns_records": "[\"2a00:d00:3:2::3\", \"2a00:d00:3:2::4\", \"2a00:d00:3:2::5\", \"2a00:d00:3:2::6\"]" - }, - "dispatches": [ - { - "id": "kat_ipv6_webservers_normalize", - "version": null - } - ] -} diff --git a/boefjes/tests/examples/ipv6_webservers_normalize.json b/boefjes/tests/examples/ipv6_webservers_normalize.json deleted file mode 100644 index a7111484f2e..00000000000 --- a/boefjes/tests/examples/ipv6_webservers_normalize.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "id": "b87ae0ec-24e7-4c1b-9d43-e8ca6db154e9", - "boefje_meta": { - "id": "ip-v6-webserver-job", - "boefje": { - "id": "IPv6 webservers", - "version": null - }, - "organization": "_dev", - "input_ooi": "Hostname|internet|rijksoverheid.nl", - "arguments": { - "pk": "Hostname|internet|rijksoverheid.nl", - "dns_records": "[\"2a00:d00:3:2::3\", \"2a00:d00:3:2::4\", \"2a00:d00:3:2::5\", \"2a00:d00:3:2::6\"]" - }, - "dispatches": [ - { - "id": "kat_ipv6_webservers_normalize", - "version": null - } - ] - }, - "normalizer": { - "id": "kat_ipv6_webservers.normalize", - "version": null - } -} diff --git a/boefjes/tests/examples/nmap-250-normalize.json b/boefjes/tests/examples/nmap-250-normalize.json deleted file mode 100644 index 5318cf5a9bd..00000000000 --- a/boefjes/tests/examples/nmap-250-normalize.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "id": "645fd349-6d62-43dd-8cfe-d3ab03c9e4b7", - "organization": "_dev", - "arguments": {}, - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/nmap-250.json b/boefjes/tests/examples/nmap-250.json deleted file mode 100644 index d2836fe9448..00000000000 --- a/boefjes/tests/examples/nmap-250.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "05d98a46-0e35-461c-91f9-7e62f1cf32d6", - "organization": "_dev", - "arguments": { - "host": "213.239.154.31" - }, - "dispatches": { - "normalizers": [ - "kat_nmap.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/nmap-normalize.json b/boefjes/tests/examples/nmap-normalize.json deleted file mode 100644 index a35dfc5a930..00000000000 --- a/boefjes/tests/examples/nmap-normalize.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "id": "3eedc431-1402-41a5-85dd-e59172e9fd61", - "organization": "_dev", - "arguments": {}, - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/nmap.json b/boefjes/tests/examples/nmap.json deleted file mode 100644 index 6e44a71eb6f..00000000000 --- a/boefjes/tests/examples/nmap.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "646a3a5e-b3ac-4f23-b679-83662d91c9be", - "organization": "_dev", - "arguments": { - "host": "213.239.154.31" - }, - "dispatches": { - "normalizers": [ - "kat_nmap.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/raw/wappalizer.json b/boefjes/tests/examples/raw/wappalizer.json deleted file mode 100644 index 817c338d212..00000000000 --- a/boefjes/tests/examples/raw/wappalizer.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "urls": { - "https://redirected.url/": { - "status": 200 - } - }, - "technologies": [ - { - "slug": "hugo", - "name": "Hugo", - "confidence": 100, - "version": "0.104.0", - "icon": "Hugo.png", - "website": "http://gohugo.io", - "cpe": null, - "categories": [ - { - "id": 57, - "slug": "static-site-generator", - "name": "Static site generator" - } - ] - }, - { - "slug": "ubuntu", - "name": "Ubuntu", - "confidence": 100, - "version": null, - "icon": "Ubuntu.png", - "website": "http://www.ubuntu.com/server", - "cpe": null, - "categories": [ - { - "id": 28, - "slug": "operating-systems", - "name": "Operating systems" - } - ] - } - ] -} diff --git a/boefjes/tests/examples/raw/wappalizer_redirected.json b/boefjes/tests/examples/raw/wappalizer_redirected.json deleted file mode 100644 index 7b5094d83c3..00000000000 --- a/boefjes/tests/examples/raw/wappalizer_redirected.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "urls": { - "https://web.site/": { - "status": 301 - }, - "https://mid.url/": { - "status": 301 - }, - "https://redirected.url/": { - "status": 200 - } - }, - "technologies": [ - { - "slug": "hugo", - "name": "Hugo", - "confidence": 100, - "version": "0.104.0", - "icon": "Hugo.png", - "website": "http://gohugo.io", - "cpe": null, - "categories": [ - { - "id": 57, - "slug": "static-site-generator", - "name": "Static site generator" - } - ] - }, - { - "slug": "ubuntu", - "name": "Ubuntu", - "confidence": 100, - "version": null, - "icon": "Ubuntu.png", - "website": "http://www.ubuntu.com/server", - "cpe": null, - "categories": [ - { - "id": 28, - "slug": "operating-systems", - "name": "Operating systems" - } - ] - } - ] -} diff --git a/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json b/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json deleted file mode 100644 index 29e7d5dfb72..00000000000 --- a/boefjes/tests/examples/scheduler/pop_response_boefje_dispatched.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", - "priority": 1, - "scheduler_id": "boefje-_dev", - "schedule_id": null, - "status": "dispatched", - "type": "boefje", - "hash": "70da7d4f-f41f-4940-901b-d98a92e9014b", - "data": { - "id": "70da7d4f-f41f-4940-901b-d98a92e9014b", - "boefje": { - "id": "dns-records", - "version": null - }, - "input_ooi": "Hostname|internet|test.test", - "organization": "_dev", - "arguments": {}, - "started_at": null, - "runnable_hash": null, - "environment": null, - "ended_at": null - }, - "created_at": "2021-06-29T14:00:00", - "modified_at": "2021-06-29T14:00:00" -} diff --git a/boefjes/tests/examples/ssl-scan-normalize.json b/boefjes/tests/examples/ssl-scan-normalize.json deleted file mode 100644 index ee2ce117c89..00000000000 --- a/boefjes/tests/examples/ssl-scan-normalize.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "bd455215-93f0-4546-b291-6ad8336f7263", - "organization": "_dev", - "arguments": {}, - "started_at": "2021-07-27T11:26:42.679000+00:00", - "ended_at": "2021-07-27T11:26:44.679000+00:00", - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/ssl-scan.json b/boefjes/tests/examples/ssl-scan.json deleted file mode 100644 index 2d7fb98f2b3..00000000000 --- a/boefjes/tests/examples/ssl-scan.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "a52ff058-7be3-4d81-8675-b6357c9894eb", - "organization": "_dev", - "arguments": { - "domain": "example.nl" - }, - "dispatches": { - "normalizers": [ - "kat_ssl_scan.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/website_similarity.json b/boefjes/tests/examples/website_similarity.json deleted file mode 100644 index 42ba9f6bc48..00000000000 --- a/boefjes/tests/examples/website_similarity.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "645fd349-6d62-43dd-8cfe-d3ab03c9e4b7", - "organization": "_dev", - "arguments": { - "domain": "Hostname|internet|rijksoverheid.nl" - }, - "dispatches": { - "normalizers": [ - "kat-website-similarity.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/website_similarity_normalize.json b/boefjes/tests/examples/website_similarity_normalize.json deleted file mode 100644 index 548029df968..00000000000 --- a/boefjes/tests/examples/website_similarity_normalize.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "2460c0b6-83f5-49da-bcc7-5727e81f7028", - "organization": "_dev", - "arguments": { - "domain": "Hostname|internet|rijksoverheid.nl" - }, - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/whois-job.json b/boefjes/tests/examples/whois-job.json deleted file mode 100644 index 37968d4921d..00000000000 --- a/boefjes/tests/examples/whois-job.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "ce3564e5-b2f8-48fb-ac59-7fd172f71b9e", - "organization": "_dev", - "arguments": { - "domain": "tweakers.net" - }, - "dispatches": { - "normalizers": [ - "kat_whois.whois_normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/whois-normalize.json b/boefjes/tests/examples/whois-normalize.json deleted file mode 100644 index ce22d6983d6..00000000000 --- a/boefjes/tests/examples/whois-normalize.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "1244e5f5-f8ea-4471-a0ce-24657f6907af", - "organization": "_dev", - "arguments": {}, - "started_at": "2021-07-27T11:26:42.679000+00:00", - "ended_at": "2021-07-27T11:26:44.679000+00:00", - "dispatches": { - "normalizers": [], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/wpscan-job.json b/boefjes/tests/examples/wpscan-job.json deleted file mode 100644 index 0d1f64a3b6c..00000000000 --- a/boefjes/tests/examples/wpscan-job.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "1f1edf73-9fcf-4190-b810-1ecbd5926b8f", - "organization": "_dev", - "arguments": { - "url": "https://zorg4ons.nl" - }, - "dispatches": { - "normalizers": [ - "kat_wpscan.normalize" - ], - "boefjes": [] - } -} diff --git a/boefjes/tests/examples/wpscan-normalize.json b/boefjes/tests/examples/wpscan-normalize.json deleted file mode 100644 index 592a525e622..00000000000 --- a/boefjes/tests/examples/wpscan-normalize.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "3a8c8b09-4c8d-415e-a58a-28b317c45ba8", - "organization": "_dev", - "arguments": { - "url": "https://zorg4ons.nl" - } -} diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index d8bf1f8ae13..f005e04ca53 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -1,251 +1,232 @@ import os -from unittest import TestCase, skipIf -import alembic.config -from sqlalchemy.orm import sessionmaker -from starlette.testclient import TestClient +import pytest -from boefjes.config import settings -from boefjes.dependencies.encryption import IdentityMiddleware -from boefjes.katalogus.root import app from boefjes.models import Boefje, Normalizer, Organisation -from boefjes.sql.config_storage import SQLConfigStorage -from boefjes.sql.db import SQL_BASE, get_engine -from boefjes.sql.organisation_storage import SQLOrganisationStorage +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestAPI(TestCase): - def setUp(self) -> None: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - session = sessionmaker(bind=get_engine())() - self.organisation_storage = SQLOrganisationStorage(session, settings) - self.settings_storage = SQLConfigStorage(session, IdentityMiddleware()) +def test_get_local_plugin(test_client, organisation): + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/dns-records") + assert response.status_code == 200 + data = response.json() - self.org = Organisation(id="test", name="Test Organisation") - self.client = TestClient(app) - response = self.client.post("/v1/organisations/", content=self.org.json()) - self.assertEqual(response.status_code, 201) + assert data["id"] == "dns-records" - def tearDown(self) -> None: - session = sessionmaker(bind=get_engine())() - for table in SQL_BASE.metadata.tables: - session.execute(f"TRUNCATE {table} CASCADE") # noqa: S608 +def test_filter_plugins(test_client, organisation): + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/") + assert len(response.json()) == 99 + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins?plugin_type=boefje") + assert len(response.json()) == 44 - session.commit() - session.close() + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins?limit=10") + assert len(response.json()) == 10 - def test_get_local_plugin(self): - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") - self.assertEqual(response.status_code, 200) - data = response.json() +def test_cannot_add_plugin_reserved_id(test_client, organisation): + boefje = Boefje(id="dns-records", name="My test boefje", static=False) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.json()) + assert response.status_code == 400 + assert response.json() == {"message": "Plugin id 'dns-records' is already used"} - self.assertEqual("dns-records", data["id"]) + normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer") + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.json()) + assert response.status_code == 400 + assert response.json() == {"message": "Plugin id 'kat_nmap_normalize' is already used"} - def test_filter_plugins(self): - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/") - self.assertEqual(len(response.json()), 99) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?plugin_type=boefje") - self.assertEqual(len(response.json()), 44) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins?limit=10") - self.assertEqual(len(response.json()), 10) +def test_add_boefje(test_client, organisation): + boefje = Boefje(id="test_plugin", name="My test boefje", static=False) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.json()) + assert response.status_code == 201 - def test_cannot_add_plugin_reserved_id(self): - boefje = Boefje(id="dns-records", name="My test boefje", static=False) - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json(), {"message": "Plugin id 'dns-records' is already used"}) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", json={"a": "b"}) + assert response.status_code == 422 - normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer") - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json(), {"message": "Plugin id 'kat_nmap_normalize' is already used"}) - - def test_add_boefje(self): - boefje = Boefje(id="test_plugin", name="My test boefje", static=False) - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - self.assertEqual(response.status_code, 201) + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/?plugin_type=boefje") + assert len(response.json()) == 45 - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", json={"a": "b"}) - self.assertEqual(response.status_code, 422) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=boefje") - self.assertEqual(len(response.json()), 45) + boefje_dict = boefje.dict() + boefje_dict["consumes"] = list(boefje_dict["consumes"]) + boefje_dict["produces"] = list(boefje_dict["produces"]) - boefje_dict = boefje.dict() - boefje_dict["consumes"] = list(boefje_dict["consumes"]) - boefje_dict["produces"] = list(boefje_dict["produces"]) + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_plugin") + assert response.json() == boefje_dict - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_plugin") - self.assertEqual(response.json(), boefje_dict) - - def test_delete_boefje(self): - boefje = Boefje(id="test_plugin", name="My test boefje", static=False) - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - self.assertEqual(response.status_code, 201) - response = self.client.delete(f"/v1/organisations/{self.org.id}/boefjes/test_plugin") - self.assertEqual(response.status_code, 204) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_plugin") - self.assertEqual(response.status_code, 404) +def test_delete_boefje(test_client, organisation): + boefje = Boefje(id="test_plugin", name="My test boefje", static=False) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.json()) + assert response.status_code == 201 - def test_add_normalizer(self): - normalizer = Normalizer(id="test_normalizer", name="My test normalizer", static=False) - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.assertEqual(response.status_code, 201) + response = test_client.delete(f"/v1/organisations/{organisation.id}/boefjes/test_plugin") + assert response.status_code == 204 + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_plugin") + assert response.status_code == 404 - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/?plugin_type=normalizer") - self.assertEqual(len(response.json()), 56) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_normalizer") - self.assertEqual(response.json(), normalizer.dict()) +def test_add_normalizer(test_client, organisation): + normalizer = Normalizer(id="test_normalizer", name="My test normalizer", static=False) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.json()) + assert response.status_code == 201 - def test_delete_normalizer(self): - normalizer = Normalizer(id="test_normalizer", name="My test normalizer", static=False) - response = self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.assertEqual(response.status_code, 201) + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/?plugin_type=normalizer") + assert len(response.json()) == 56 - response = self.client.delete(f"/v1/organisations/{self.org.id}/normalizers/test_normalizer") - self.assertEqual(response.status_code, 204) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/test_normalizer") - self.assertEqual(response.status_code, 404) - - def test_update_plugins(self): - normalizer = Normalizer(id="norm_id", name="My test normalizer") - boefje = Boefje(id="test_plugin", name="My test boefje", description="123") - - self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"description": "4"}) - self.client.patch(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}", json={"enabled": True}) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}") - self.assertEqual(response.json()["description"], "4") - self.assertTrue(response.json()["enabled"]) - - self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=normalizer.json()) - self.client.patch(f"/v1/organisations/{self.org.id}/normalizers/{normalizer.id}", json={"version": "v1.2"}) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{normalizer.id}") - self.assertEqual(response.json()["version"], "v1.2") - - def test_cannot_create_boefje_with_invalid_schema(self): - boefje = Boefje(id="test_plugin", name="My test boefje", description="123").model_dump(mode="json") - boefje["schema"] = {"$schema": 3} - - r = self.client.post(f"/v1/organisations/{self.org.id}/plugins", json=boefje) - self.assertEqual(r.status_code, 400) - - def test_update_boefje_schema(self): - boefje = Boefje(id="test_plugin", name="My test boefje", description="123") - self.client.post(f"/v1/organisations/{self.org.id}/plugins", content=boefje.json()) - - r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"schema": {"$schema": 3}}) - self.assertEqual(r.status_code, 400) - - valid_schema = { - "title": "Arguments", - "type": "object", - "properties": { - "MY_KEY": { - "title": "MY_KEY", - "type": "integer", - } - }, - "required": [], - } - r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/{boefje.id}", json={"schema": valid_schema}) - self.assertEqual(r.status_code, 204) - - schema = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}/schema.json").json() - assert schema == valid_schema - - api_boefje = self.client.get(f"/v1/organisations/{self.org.id}/plugins/{boefje.id}").json() - assert api_boefje["schema"] == valid_schema - - r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"schema": valid_schema}) - self.assertEqual(r.status_code, 404) - - def test_cannot_update_static_plugins(self): - r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"id": "4", "version": "s"}) - self.assertEqual(r.status_code, 404) - r = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"name": "Overwrite name"}) - self.assertEqual(r.status_code, 404) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") - self.assertEqual(response.json()["name"], "DNS records") - self.assertIsNone(response.json()["version"]) - self.assertEqual(response.json()["id"], "dns-records") - - self.client.patch(f"/v1/organisations/{self.org.id}/plugins/dns-records", json={"enabled": True}) - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") - self.assertTrue(response.json()["enabled"]) - - response = self.client.patch(f"/v1/organisations/{self.org.id}/boefjes/dns-records", json={"version": "v1.2"}) - self.assertEqual(response.status_code, 400) - - response = self.client.get(f"/v1/organisations/{self.org.id}/plugins/dns-records") - self.assertNotEqual(response.json()["version"], "v1.2") - - def test_basic_settings_api(self): - plug = "dns-records" - - self.client.put(f"/v1/organisations/{self.org.id}/{plug}/settings", json={"new": "settings", "with integer": 5}) - response = self.client.get(f"/v1/organisations/{self.org.id}/{plug}/settings") - assert response.json() == {"new": "settings", "with integer": 5} - - self.client.put(f"/v1/organisations/{self.org.id}/{plug}/settings", json={"with integer": 8}) - response = self.client.get(f"/v1/organisations/{self.org.id}/{plug}/settings") - assert response.json() == {"with integer": 8} - - self.client.delete(f"/v1/organisations/{self.org.id}/{plug}/settings") - response = self.client.get(f"/v1/organisations/{self.org.id}/{plug}/settings") - assert response.json() == {} - - def test_clone_settings(self): - plug = "dns-records" - - # Set a setting on the first organisation and enable dns-records - self.client.put( - f"/v1/organisations/{self.org.id}/{plug}/settings", - json={"test_key": "test value", "test_key_2": "test value 2"}, - ) - self.client.patch(f"/v1/organisations/{self.org.id}/plugins/{plug}", json={"enabled": True}) - - assert self.client.get(f"/v1/organisations/{self.org.id}/{plug}/settings").json() == { - "test_key": "test value", - "test_key_2": "test value 2", - } - assert self.client.get(f"/v1/organisations/{self.org.id}/plugins/{plug}").json()["enabled"] is True - - # Add the second organisation - new_org_id = "org2" - org2 = Organisation(id=new_org_id, name="Second test Organisation") - self.client.post("/v1/organisations/", content=org2.json()) - self.client.put(f"/v1/organisations/{new_org_id}/{plug}/settings", json={"test_key": "second value"}) - - # Show that the second organisation has no settings and dns-records is not enabled - assert self.client.get(f"/v1/organisations/{new_org_id}/{plug}/settings").json() == {"test_key": "second value"} - assert self.client.get(f"/v1/organisations/{new_org_id}/plugins/{plug}").json()["enabled"] is False - - # Enable two boefjes that should get disabled by the cloning - self.client.patch(f"/v1/organisations/{new_org_id}/plugins/nmap", json={"enabled": True}) - assert self.client.get(f"/v1/organisations/{new_org_id}/plugins/nmap").json()["enabled"] is True - - # Call the clone endpoint - self.client.post(f"/v1/organisations/{self.org.id}/settings/clone/{new_org_id}") - - # Verify that all settings are copied - response = self.client.get(f"/v1/organisations/{new_org_id}/{plug}/settings") - assert response.json() == {"test_key": "test value", "test_key_2": "test value 2"} - - # And that the enabled boefje from the original organisation got enabled - response = self.client.get(f"/v1/organisations/{new_org_id}/plugins/{plug}") - assert response.json()["enabled"] is True - - # And the originally enabled boefje got disabled - response = self.client.get(f"/v1/organisations/{new_org_id}/plugins/nmap") - assert response.json()["enabled"] is False + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_normalizer") + assert response.json() == normalizer.dict() + + +def test_delete_normalizer(test_client, organisation): + normalizer = Normalizer(id="test_normalizer", name="My test normalizer", static=False) + response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.json()) + assert response.status_code == 201 + + response = test_client.delete(f"/v1/organisations/{organisation.id}/normalizers/test_normalizer") + assert response.status_code == 204 + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_normalizer") + assert response.status_code == 404 + + +def test_update_plugins(test_client, organisation): + normalizer = Normalizer(id="norm_id", name="My test normalizer") + boefje = Boefje(id="test_plugin", name="My test boefje", description="123") + + test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.json()) + test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/{boefje.id}", json={"description": "4"}) + test_client.patch(f"/v1/organisations/{organisation.id}/plugins/{boefje.id}", json={"enabled": True}) + + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/{boefje.id}") + assert response.json()["description"] == "4" + assert response.json()["enabled"] is True + + test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.json()) + test_client.patch(f"/v1/organisations/{organisation.id}/normalizers/{normalizer.id}", json={"version": "v1.2"}) + + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/{normalizer.id}") + assert response.json()["version"] == "v1.2" + + +def test_cannot_create_boefje_with_invalid_schema(test_client, organisation): + boefje = Boefje(id="test_plugin", name="My test boefje", description="123").model_dump(mode="json") + boefje["schema"] = {"$schema": 3} + + r = test_client.post(f"/v1/organisations/{organisation.id}/plugins", json=boefje) + assert r.status_code == 400 + + +def test_update_boefje_schema(test_client, organisation): + boefje = Boefje(id="test_plugin", name="My test boefje", description="123") + test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.json()) + + r = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/{boefje.id}", json={"schema": {"$schema": 3}}) + assert r.status_code == 400 + + valid_schema = { + "title": "Arguments", + "type": "object", + "properties": { + "MY_KEY": { + "title": "MY_KEY", + "type": "integer", + } + }, + "required": [], + } + r = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/{boefje.id}", json={"schema": valid_schema}) + assert r.status_code == 204 + + schema = test_client.get(f"/v1/organisations/{organisation.id}/plugins/{boefje.id}/schema.json").json() + assert schema == valid_schema + + api_boefje = test_client.get(f"/v1/organisations/{organisation.id}/plugins/{boefje.id}").json() + assert api_boefje["schema"] == valid_schema + + r = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/dns-records", json={"schema": valid_schema}) + assert r.status_code == 404 + + +def test_cannot_update_static_plugins(test_client, organisation): + r = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/dns-records", json={"id": "4", "version": "s"}) + assert r.status_code == 404 + r = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/dns-records", json={"name": "Overwrite name"}) + assert r.status_code == 404 + + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/dns-records") + assert response.json()["name"] == "DNS records" + assert response.json()["version"] is None + assert response.json()["id"] == "dns-records" + + test_client.patch(f"/v1/organisations/{organisation.id}/plugins/dns-records", json={"enabled": True}) + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/dns-records") + assert response.json()["enabled"] is True + + response = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/dns-records", json={"version": "v1.2"}) + assert response.status_code == 400 + + response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/dns-records") + assert response.json()["version"] != "v1.2" + + +def test_basic_settings_api(test_client, organisation): + plug = "dns-records" + + test_client.put(f"/v1/organisations/{organisation.id}/{plug}/settings", json={"new": "settings", "with integer": 5}) + response = test_client.get(f"/v1/organisations/{organisation.id}/{plug}/settings") + assert response.json() == {"new": "settings", "with integer": 5} + + test_client.put(f"/v1/organisations/{organisation.id}/{plug}/settings", json={"with integer": 8}) + response = test_client.get(f"/v1/organisations/{organisation.id}/{plug}/settings") + assert response.json() == {"with integer": 8} + + test_client.delete(f"/v1/organisations/{organisation.id}/{plug}/settings") + response = test_client.get(f"/v1/organisations/{organisation.id}/{plug}/settings") + assert response.json() == {} + + +def test_clone_settings(test_client, organisation): + plug = "dns-records" + + # Set a setting on the first organisation and enable dns-records + test_client.put( + f"/v1/organisations/{organisation.id}/{plug}/settings", + json={"test_key": "test value", "test_key_2": "test value 2"}, + ) + test_client.patch(f"/v1/organisations/{organisation.id}/plugins/{plug}", json={"enabled": True}) + + assert test_client.get(f"/v1/organisations/{organisation.id}/{plug}/settings").json() == { + "test_key": "test value", + "test_key_2": "test value 2", + } + assert test_client.get(f"/v1/organisations/{organisation.id}/plugins/{plug}").json()["enabled"] is True + + # Add the second organisation + new_org_id = "org2" + org2 = Organisation(id=new_org_id, name="Second test Organisation") + test_client.post("/v1/organisations/", content=org2.json()) + test_client.put(f"/v1/organisations/{new_org_id}/{plug}/settings", json={"test_key": "second value"}) + + # Show that the second organisation has no settings and dns-records is not enabled + assert test_client.get(f"/v1/organisations/{new_org_id}/{plug}/settings").json() == {"test_key": "second value"} + assert test_client.get(f"/v1/organisations/{new_org_id}/plugins/{plug}").json()["enabled"] is False + + # Enable two boefjes that should get disabled by the cloning + test_client.patch(f"/v1/organisations/{new_org_id}/plugins/nmap", json={"enabled": True}) + assert test_client.get(f"/v1/organisations/{new_org_id}/plugins/nmap").json()["enabled"] is True + + # Call the clone endpoint + test_client.post(f"/v1/organisations/{organisation.id}/settings/clone/{new_org_id}") + + # Verify that all settings are copied + response = test_client.get(f"/v1/organisations/{new_org_id}/{plug}/settings") + assert response.json() == {"test_key": "test value", "test_key_2": "test value 2"} + + # And that the enabled boefje from the original organisation got enabled + response = test_client.get(f"/v1/organisations/{new_org_id}/plugins/{plug}") + assert response.json()["enabled"] is True + + # And the originally enabled boefje got disabled + response = test_client.get(f"/v1/organisations/{new_org_id}/plugins/nmap") + assert response.json()["enabled"] is False diff --git a/boefjes/tests/integration/test_json_settings_encryption_migration.py b/boefjes/tests/integration/test_json_settings_encryption_migration.py index a3bb9a336bd..1792fccdb9d 100644 --- a/boefjes/tests/integration/test_json_settings_encryption_migration.py +++ b/boefjes/tests/integration/test_json_settings_encryption_migration.py @@ -1,9 +1,9 @@ import os -from unittest import TestCase, skipIf import alembic.config +import pytest from sqlalchemy import text -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import Session, sessionmaker from boefjes.config import settings from boefjes.dependencies.encryption import NaclBoxMiddleware @@ -12,71 +12,68 @@ from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestJsonSecretsMigration(TestCase): - def setUp(self) -> None: - self.engine = get_engine() - - # To reset autoincrement ids - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) - # Set state to revision 197672984df0 - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "197672984df0"]) - - def test_setting_to_settings_json(self): - session = sessionmaker(bind=self.engine)() - - with SQLOrganisationStorage(session, settings) as storage: - storage.create(Organisation(id="dev1", name="Test 1 ")) - storage.create(Organisation(id="dev2", name="Test 2 ")) - storage.create(Organisation(id="dev3", name="Test 3 ")) - - encrypter = create_encrypter() - entries = self._collect_entries(encrypter) - query = f"INSERT INTO setting (key, value, organisation_pk, plugin_id) values {','.join(map(str, entries))}" # noqa: S608 - self.engine.execute(text(query)) - - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "cd34fdfafdaf"]) - - all_settings = list(self.engine.execute(text("select * from settings")).fetchall()) - self.assertSetEqual( - {(encrypter.decode(x[1]), x[2], x[3]) for x in all_settings}, - { - ('{"key2": "val2"}', "dns-records", 2), - ('{"key5": "val5", "key7": "val7"}', "nmap", 1), - ('{"key4": "val4", "key6": "val6"}', "nmap", 2), - ('{"key1": "val1", "key3": "val3"}', "dns-records", 1), - }, - ) - - session.close() - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) - - results = [x[1:] for x in self.engine.execute(text("SELECT * FROM setting")).fetchall()] # ignore pk's - decoded_results = [(x[0], encrypter.decode(x[1]), x[2], x[3]) for x in results] # compare decoded, since - decoded_entries = [(x[0], encrypter.decode(x[1]), x[2], x[3]) for x in entries] # encoding changes every time. - - assert set(decoded_entries) == set(decoded_results) - - def tearDown(self) -> None: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - - session = sessionmaker(bind=get_engine())() - - for table in SQL_BASE.metadata.tables: - session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 - - session.commit() - session.close() - - @staticmethod - def _collect_entries(encrypter: NaclBoxMiddleware): - return [ - ("key1", encrypter.encode("val1"), 1, "dns-records"), - ("key2", encrypter.encode("val2"), 2, "dns-records"), - ("key3", encrypter.encode("val3"), 1, "dns-records"), - ("key4", encrypter.encode("val4"), 2, "nmap"), - ("key5", encrypter.encode("val5"), 1, "nmap"), - ("key6", encrypter.encode("val6"), 2, "nmap"), - ("key7", encrypter.encode("val7"), 1, "nmap"), - ] + +@pytest.fixture +def migration_197672984df0() -> Session: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision 197672984df0 + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "197672984df0"]) + + engine = get_engine() + session = sessionmaker(bind=engine)() + + yield session + session.commit() + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + + engine.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) + + +def test_setting_to_settings_json(migration_197672984df0): + session = migration_197672984df0 + + with SQLOrganisationStorage(session, settings) as storage: + storage.create(Organisation(id="dev1", name="Test 1 ")) + storage.create(Organisation(id="dev2", name="Test 2 ")) + storage.create(Organisation(id="dev3", name="Test 3 ")) + + encrypter = create_encrypter() + entries = _collect_entries(encrypter) + query = f"INSERT INTO setting (key, value, organisation_pk, plugin_id) values {','.join(map(str, entries))}" # noqa: S608 + session.get_bind().execute(text(query)) + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "cd34fdfafdaf"]) + + all_settings = list(session.execute(text("select * from settings")).fetchall()) + assert {(encrypter.decode(x[1]), x[2], x[3]) for x in all_settings} == { + ('{"key2": "val2"}', "dns-records", 2), + ('{"key5": "val5", "key7": "val7"}', "nmap", 1), + ('{"key4": "val4", "key6": "val6"}', "nmap", 2), + ('{"key1": "val1", "key3": "val3"}', "dns-records", 1), + } + + session.close() + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) + + results = [x[1:] for x in session.execute(text("SELECT * FROM setting")).fetchall()] # ignore pk's + decoded_results = [(x[0], encrypter.decode(x[1]), x[2], x[3]) for x in results] # compare decoded, since + decoded_entries = [(x[0], encrypter.decode(x[1]), x[2], x[3]) for x in entries] # encoding changes every time. + + assert set(decoded_entries) == set(decoded_results) + + +def _collect_entries(encrypter: NaclBoxMiddleware): + return [ + ("key1", encrypter.encode("val1"), 1, "dns-records"), + ("key2", encrypter.encode("val2"), 2, "dns-records"), + ("key3", encrypter.encode("val3"), 1, "dns-records"), + ("key4", encrypter.encode("val4"), 2, "nmap"), + ("key5", encrypter.encode("val5"), 1, "nmap"), + ("key6", encrypter.encode("val6"), 2, "nmap"), + ("key7", encrypter.encode("val7"), 1, "nmap"), + ] diff --git a/boefjes/tests/integration/test_migration_add_schema_field.py b/boefjes/tests/integration/test_migration_add_schema_field.py index 158e99cce34..b2a607bde9d 100644 --- a/boefjes/tests/integration/test_migration_add_schema_field.py +++ b/boefjes/tests/integration/test_migration_add_schema_field.py @@ -1,166 +1,169 @@ import os -from unittest import TestCase, skipIf import alembic.config +import pytest from psycopg2.extras import execute_values -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import Session, sessionmaker -from boefjes.local_repository import get_local_repository from boefjes.sql.db import SQL_BASE, get_engine - -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestSettingsToBoefjeConfig(TestCase): - def setUp(self) -> None: - self.engine = get_engine() - - # To reset autoincrement ids - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) - # Set state to revision 6f99834a4a5a - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) - - dns_records = get_local_repository().by_id("dns-records") - nmap_udp = get_local_repository().by_id("nmap-udp") - - entries = [ - ( - boefje.id, - boefje.name, - boefje.description, - str(boefje.scan_level), - list(sorted(boefje.consumes)), - list(sorted(boefje.produces)), - ["RECORD_TYPES", "REMOTE_NS"], - boefje.oci_image, - boefje.oci_arguments, - boefje.version, - ) - for boefje in [dns_records, nmap_udp] - ] - - connection = self.engine.connect() - query = """INSERT INTO boefje (plugin_id, name, description, scan_level, consumes, produces, environment_keys, - oci_image, oci_arguments, version) values %s""" - - with connection.begin(): - execute_values(connection.connection.cursor(), query, entries) - - def test_fail_on_wrong_plugin_ids(self): - assert self.engine.execute("SELECT * from boefje").fetchall() == [ - ( - 1, - "dns-records", - None, - "DNS records", - "Fetch the DNS record(s) of a hostname.", - "1", - ["Hostname"], - ["boefje/dns-records"], - ["RECORD_TYPES", "REMOTE_NS"], - None, - [], - None, - False, - ), - ( - 2, - "nmap-udp", - None, - "Nmap UDP", - "Defaults to top 250 UDP ports. Includes service detection.", - "2", - ["IPAddressV4", "IPAddressV6"], - ["boefje/nmap-udp"], - ["RECORD_TYPES", "REMOTE_NS"], - "ghcr.io/minvws/openkat/nmap:latest", - ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], - None, - False, - ), - ] - - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "5be152459a7b"]) - - schema_dns = { - "title": "Arguments", - "type": "object", - "properties": { - "RECORD_TYPES": { - "title": "RECORD_TYPES", - "type": "string", - "description": "List of comma separated DNS record types to query for.", - "default": "A,AAAA,CAA,CERT,RP,SRV,TXT,MX,NS,CNAME,DNAME", - }, - "REMOTE_NS": { - "title": "REMOTE_NS", - "maxLength": 45, - "type": "string", - "description": "The IP address of the DNS resolver you want to use.", - "default": "1.1.1.1", - }, +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") + + +@pytest.fixture +def migration_f9de6eb7824b(local_repository) -> Session: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision f9de6eb7824b + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + engine = get_engine() + session = sessionmaker(bind=engine)() + + dns_records = local_repository.by_id("dns-records") + nmap_udp = local_repository.by_id("nmap-udp") + entries = [ + ( + boefje.id, + boefje.name, + boefje.description, + str(boefje.scan_level), + list(sorted(boefje.consumes)), + list(sorted(boefje.produces)), + ["RECORD_TYPES", "REMOTE_NS"], + boefje.oci_image, + boefje.oci_arguments, + boefje.version, + ) + for boefje in [dns_records, nmap_udp] + ] + + query = """INSERT INTO boefje (plugin_id, name, description, scan_level, consumes, produces, environment_keys, + oci_image, oci_arguments, version) values %s""" + + connection = session.connection() + with connection.begin(): + execute_values(connection.connection.cursor(), query, entries) + + session.commit() + + yield session + session.commit() + session.close() + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + + session.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) + session.commit() + session.close() + + +def test_fail_on_wrong_plugin_ids(migration_f9de6eb7824b): + session = migration_f9de6eb7824b + assert session.execute("SELECT * from boefje").fetchall() == [ + ( + 1, + "dns-records", + None, + "DNS records", + "Fetch the DNS record(s) of a hostname.", + "1", + ["Hostname"], + ["boefje/dns-records"], + ["RECORD_TYPES", "REMOTE_NS"], + None, + [], + None, + False, + ), + ( + 2, + "nmap-udp", + None, + "Nmap UDP", + "Defaults to top 250 UDP ports. Includes service detection.", + "2", + ["IPAddressV4", "IPAddressV6"], + ["boefje/nmap-udp"], + ["RECORD_TYPES", "REMOTE_NS"], + "ghcr.io/minvws/openkat/nmap:latest", + ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], + None, + False, + ), + ] + + session.close() + + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "5be152459a7b"]) + + schema_dns = { + "title": "Arguments", + "type": "object", + "properties": { + "RECORD_TYPES": { + "title": "RECORD_TYPES", + "type": "string", + "description": "List of comma separated DNS record types to query for.", + "default": "A,AAAA,CAA,CERT,RP,SRV,TXT,MX,NS,CNAME,DNAME", }, - } - - schema_udp = { - "title": "Arguments", - "type": "object", - "properties": { - "TOP_PORTS_UDP": { - "title": "TOP_PORTS_UDP", - "type": "integer", - "minimum": 1, - "maximum": 65535, - "description": "Scan TOP_PORTS_UDP most common ports. Defaults to 250.", - } + "REMOTE_NS": { + "title": "REMOTE_NS", + "maxLength": 45, + "type": "string", + "description": "The IP address of the DNS resolver you want to use.", + "default": "1.1.1.1", }, - "required": [], - } - - self.assertListEqual( - self.engine.execute("SELECT * from boefje").fetchall(), - [ - ( - 1, - "dns-records", - None, - "DNS records", - "Fetch the DNS record(s) of a hostname.", - "1", - ["Hostname"], - ["boefje/dns-records"], - ["RECORD_TYPES", "REMOTE_NS"], - None, - [], - None, - False, - schema_dns, - ), - ( - 2, - "nmap-udp", - None, - "Nmap UDP", - "Defaults to top 250 UDP ports. Includes service detection.", - "2", - ["IPAddressV4", "IPAddressV6"], - ["boefje/nmap-udp"], - ["RECORD_TYPES", "REMOTE_NS"], - "ghcr.io/minvws/openkat/nmap:latest", - ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], - None, - False, - schema_udp, - ), - ], - ) - - def tearDown(self) -> None: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - - session = sessionmaker(bind=get_engine())() - - for table in SQL_BASE.metadata.tables: - session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 - - session.commit() - session.close() + }, + } + + schema_udp = { + "title": "Arguments", + "type": "object", + "properties": { + "TOP_PORTS_UDP": { + "title": "TOP_PORTS_UDP", + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Scan TOP_PORTS_UDP most common ports. Defaults to 250.", + } + }, + "required": [], + } + + assert session.execute("SELECT * from boefje").fetchall() == [ + ( + 1, + "dns-records", + None, + "DNS records", + "Fetch the DNS record(s) of a hostname.", + "1", + ["Hostname"], + ["boefje/dns-records"], + ["RECORD_TYPES", "REMOTE_NS"], + None, + [], + None, + False, + schema_dns, + ), + ( + 2, + "nmap-udp", + None, + "Nmap UDP", + "Defaults to top 250 UDP ports. Includes service detection.", + "2", + ["IPAddressV4", "IPAddressV6"], + ["boefje/nmap-udp"], + ["RECORD_TYPES", "REMOTE_NS"], + "ghcr.io/minvws/openkat/nmap:latest", + ["--open", "-T4", "-Pn", "-r", "-v10", "-sV", "-sU"], + None, + False, + schema_udp, + ), + ] diff --git a/boefjes/tests/integration/test_remove_repository_migration.py b/boefjes/tests/integration/test_remove_repository_migration.py index 33379d42714..e95ee054299 100644 --- a/boefjes/tests/integration/test_remove_repository_migration.py +++ b/boefjes/tests/integration/test_remove_repository_migration.py @@ -1,101 +1,97 @@ import os -from unittest import TestCase, skipIf import alembic.config +import pytest from sqlalchemy import text -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import Session, sessionmaker from boefjes.config import settings from boefjes.models import Organisation from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestRemoveRepositories(TestCase): - def setUp(self) -> None: - self.engine = get_engine() - # To reset autoincrement ids - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) - # Set state to revision cd34fdfafdaf - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "cd34fdfafdaf"]) +@pytest.fixture +def migration_cd34fdfafdaf() -> Session: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision cd34fdfafdaf + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "cd34fdfafdaf"]) - session = sessionmaker(bind=self.engine)() + engine = get_engine() + session = sessionmaker(bind=engine)() - with SQLOrganisationStorage(session, settings) as storage: - storage.create(Organisation(id="dev1", name="Test 1 ")) - storage.create(Organisation(id="dev2", name="Test 2 ")) + with SQLOrganisationStorage(session, settings) as storage: + storage.create(Organisation(id="dev1", name="Test 1 ")) + storage.create(Organisation(id="dev2", name="Test 2 ")) - session.close() + entries = [(1, "LOCAL", "Repository Local", "https://local.com/")] + query = f"INSERT INTO repository (pk, id, name, base_url) values {','.join(map(str, entries))}" # noqa: S608 - entries = [(1, "LOCAL", "Repository Local", "https://local.com/")] - query = f"INSERT INTO repository (pk, id, name, base_url) values {','.join(map(str, entries))}" # noqa: S608 - self.engine.execute(text(query)) + engine.execute(text(query)) - entries = [(1, "test_plugin_id", True, 1, 1)] # New unique constraint fails - query = ( - f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk, repository_pk)" - f"values {','.join(map(str, entries))}" - ) # noqa: S608 + entries = [(1, "test_plugin_id", True, 1, 1)] # New unique constraint fails + query = ( + f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk, repository_pk)" + f"values {','.join(map(str, entries))}" + ) # noqa: S608 - self.engine.execute(text(query)) + engine.execute(text(query)) - entries = [(1, 1)] - query = ( - f"INSERT INTO organisation_repository (repository_pk, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 - ) - self.engine.execute(text(query)) + entries = [(1, 1)] + query = f"INSERT INTO organisation_repository (repository_pk, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + engine.execute(text(query)) - def test_fail_on_non_unique(self): - session = sessionmaker(bind=self.engine)() + yield session + session.commit() - entries = [(2, "test", "test", "https://test.co/")] # Another non-local repository - query = f"INSERT INTO repository (pk, id, name, base_url) values {','.join(map(str, entries))}" # noqa: S608 - self.engine.execute(text(query)) + engine.execute(text("DELETE FROM plugin_state")) - entries = [(2, "test_plugin_id", True, 1, 2)] # New unique constraint fails - query = ( - f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk, repository_pk)" - f"values {','.join(map(str, entries))}" - ) # noqa: S608 - self.engine.execute(text(query)) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - with self.assertRaises(Exception) as ctx: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) + engine.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) - assert "remove plugin_states that refer to nonlocal repositories first" in str(ctx.exception) - self.engine.execute(text("DELETE FROM plugin_state WHERE id = 2")) # Fix unique constraint fails - self.engine.execute(text("DELETE FROM repository WHERE pk = 2")) # Fix unique constraint fails +def test_fail_on_non_unique(migration_cd34fdfafdaf): + session = migration_cd34fdfafdaf + entries = [(2, "test", "test", "https://test.co/")] # Another non-local repository + query = f"INSERT INTO repository (pk, id, name, base_url) values {','.join(map(str, entries))}" # noqa: S608 + session.get_bind().execute(text(query)) + entries = [(2, "test_plugin_id", True, 1, 2)] # New unique constraint fails + query = ( + f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk, repository_pk)" + f"values {','.join(map(str, entries))}" + ) # noqa: S608 + session.get_bind().execute(text(query)) + + with pytest.raises(Exception) as ctx: alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) - all_plugin_states = [x[1:] for x in self.engine.execute(text("SELECT * FROM plugin_state")).fetchall()] - assert all_plugin_states == [("test_plugin_id", True, 1)] + assert "remove plugin_states that refer to nonlocal repositories first" in str(ctx.value) - session.close() + # Fix unique constraint failures + session.get_bind().execute(text("DELETE FROM plugin_state WHERE id = 2; DELETE FROM repository WHERE pk = 2")) - def test_downgrade(self): - self.engine.execute(text("DELETE FROM plugin_state WHERE id = 2")) # Fix unique constraint fails - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) - all_plugin_states = [x[1:] for x in self.engine.execute(text("SELECT * FROM plugin_state")).fetchall()] - assert all_plugin_states == [("test_plugin_id", True, 1, 1)] - assert self.engine.execute(text("SELECT * from repository")).fetchall() == [ - (1, "LOCAL", "Local Plugin Repository", "http://dev/null") - ] + all_plugin_states = [x[1:] for x in session.get_bind().execute(text("SELECT * FROM plugin_state")).fetchall()] + assert all_plugin_states == [("test_plugin_id", True, 1)] - def tearDown(self) -> None: - self.engine.execute(text("DELETE FROM plugin_state")) # Fix unique constraint fails - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) +def test_downgrade(migration_cd34fdfafdaf): + session = migration_cd34fdfafdaf + session.get_bind().execute(text("DELETE FROM plugin_state WHERE id = 2")) # Fix unique constraint fails - session = sessionmaker(bind=get_engine())() + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "7c88b9cd96aa"]) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) - for table in SQL_BASE.metadata.tables: - session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 + all_plugin_states = [x[1:] for x in session.get_bind().execute(text("SELECT * FROM plugin_state")).fetchall()] - session.commit() - session.close() + assert all_plugin_states == [("test_plugin_id", True, 1, 1)] + assert session.get_bind().execute(text("SELECT * from repository")).fetchall() == [ + (1, "LOCAL", "Local Plugin Repository", "http://dev/null") + ] diff --git a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py index 261a965240c..cd8fad90ef9 100644 --- a/boefjes/tests/integration/test_settings_to_boefje_config_migration.py +++ b/boefjes/tests/integration/test_settings_to_boefje_config_migration.py @@ -1,9 +1,9 @@ import os -from unittest import TestCase, skipIf import alembic.config +import pytest from sqlalchemy import text -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import Session, sessionmaker from boefjes.config import settings from boefjes.models import Organisation @@ -11,104 +11,109 @@ from boefjes.sql.db import SQL_BASE, get_engine from boefjes.sql.organisation_storage import SQLOrganisationStorage +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestSettingsToBoefjeConfig(TestCase): - def setUp(self) -> None: - self.engine = get_engine() - # To reset autoincrement ids - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) - # Set state to revision 6f99834a4a5a - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "6f99834a4a5a"]) +@pytest.fixture +def migration_6f99834a4a5a() -> Session: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) + # To reset autoincrement ids + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "base"]) + # Set state to revision 6f99834a4a5a + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "6f99834a4a5a"]) - session = sessionmaker(bind=self.engine)() + engine = get_engine() + session = sessionmaker(bind=engine)() - with SQLOrganisationStorage(session, settings) as storage: - storage.create(Organisation(id="dev1", name="Test 1 ")) - storage.create(Organisation(id="dev2", name="Test 2 ")) + with SQLOrganisationStorage(session, settings) as storage: + storage.create(Organisation(id="dev1", name="Test 1 ")) + storage.create(Organisation(id="dev2", name="Test 2 ")) - session.close() + encrypter = create_encrypter() + entries = [ + (1, encrypter.encode('{"key1": "val1"}'), "dns-records", 1), + (2, encrypter.encode('{"key1": "val1", "key2": "val2"}'), "dns-records", 2), + (3, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "nmap", 1), + ] + query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 - encrypter = create_encrypter() - entries = [ - (1, encrypter.encode('{"key1": "val1"}'), "dns-records", 1), - (2, encrypter.encode('{"key1": "val1", "key2": "val2"}'), "dns-records", 2), - (3, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "nmap", 1), - ] - query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 - self.engine.execute(text(query)) + engine.execute(text(query)) - entries = [(1, "dns-records", True, 1), (2, "nmap-udp", True, 1)] - query = ( - f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 - ) - self.engine.execute(text(query)) + entries = [(1, "dns-records", True, 1), (2, "nmap-udp", True, 1)] + query = f"INSERT INTO plugin_state (id, plugin_id, enabled, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + engine.execute(text(query)) - def test_fail_on_wrong_plugin_ids(self): - session = sessionmaker(bind=self.engine)() + yield session + session.commit() - encrypter = create_encrypter() - entries = [ - (4, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "test-unknown-plugin-id", 1), - (5, encrypter.encode('{"key1": "val1"}'), "kat_nmap_normalize", 2), - ] - query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 - self.engine.execute(text(query)) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - with self.assertRaises(Exception) as ctx: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + engine.execute(";".join([f"TRUNCATE TABLE {t} CASCADE" for t in SQL_BASE.metadata.tables])) - assert "Settings for normalizer or bit found: kat_nmap_normalize" in str(ctx.exception) - self.engine.execute(text("DELETE FROM settings WHERE id = 5")) # Fix normalizer setting +def test_fail_on_wrong_plugin_ids(migration_6f99834a4a5a): + session = migration_6f99834a4a5a - with self.assertRaises(Exception) as ctx: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + encrypter = create_encrypter() + entries = [ + (4, encrypter.encode('{"key2": "val2", "key3": "val3"}'), "test-unknown-plugin-id", 1), + (5, encrypter.encode('{"key1": "val1"}'), "kat_nmap_normalize", 2), + ] + query = f"INSERT INTO settings (id, values, plugin_id, organisation_pk) values {','.join(map(str, entries))}" # noqa: S608 + session.execute(text(query)) + session.commit() + session.close() - assert "Invalid plugin id found: test-unknown-plugin-id" in str(ctx.exception) + with pytest.raises(Exception) as ctx: + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + + assert "Settings for normalizer or bit found: kat_nmap_normalize" in str(ctx.value) - self.engine.execute(text("DELETE FROM settings WHERE id = 4")) # Fix unknown plugin + session.execute(text("DELETE FROM settings WHERE id = 5")) # Fix normalizer setting + session.commit() + session.close() + with pytest.raises(Exception) as ctx: alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) - assert self.engine.execute(text("SELECT id FROM boefje WHERE plugin_id = 'dns-records'")).fetchall() == [(2,)] + assert "Invalid plugin id found: test-unknown-plugin-id" in str(ctx.value) - config_storage = SQLConfigStorage(session, encrypter) - assert config_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} - assert config_storage.get_all_settings("dev1", "nmap-udp") == {} - assert config_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} + session.execute(text("DELETE FROM settings WHERE id = 4")) # Fix unknown plugin + session.commit() + session.close() - assert config_storage.is_enabled_by_id("dns-records", "dev1") - assert config_storage.is_enabled_by_id("nmap-udp", "dev1") + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) - session.commit() - session.close() + assert session.execute(text("SELECT id FROM boefje WHERE plugin_id = 'dns-records'")).fetchall() == [(2,)] + session.commit() + session.close() - def test_downgrade(self): - # No need to also create a Boefje entry, the seeded settings and migrations take care of that and - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) - - encrypter = create_encrypter() - all_settings = list(self.engine.execute(text("select * from settings")).fetchall()) - self.assertSetEqual( - {(encrypter.decode(x[1]) if x[1] != "{}" else "{}", x[2], x[3]) for x in all_settings}, - { - ('{"key1": "val1"}', "dns-records", 1), - ('{"key1": "val1", "key2": "val2"}', "dns-records", 2), - ('{"key2": "val2", "key3": "val3"}', "nmap", 1), - ("{}", "nmap-udp", 1), - }, - ) - - def tearDown(self) -> None: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - - session = sessionmaker(bind=get_engine())() - - for table in SQL_BASE.metadata.tables: - session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 - - session.commit() - session.close() + config_storage = SQLConfigStorage(session, encrypter) + assert config_storage.get_all_settings("dev1", "dns-records") == {"key1": "val1"} + assert config_storage.get_all_settings("dev1", "nmap-udp") == {} + assert config_storage.get_all_settings("dev2", "dns-records") == {"key1": "val1", "key2": "val2"} + + assert config_storage.is_enabled_by_id("dns-records", "dev1") + assert config_storage.is_enabled_by_id("nmap-udp", "dev1") + + session.commit() + session.close() + + +def test_downgrade(migration_6f99834a4a5a): + session = migration_6f99834a4a5a + + # No need to also create a Boefje entry, the seeded settings and migrations take care of that and + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "f9de6eb7824b"]) + alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "downgrade", "-1"]) + + encrypter = create_encrypter() + all_settings = list(session.execute(text("select * from settings")).fetchall()) + session.commit() + session.close() + assert {(encrypter.decode(x[1]) if x[1] != "{}" else "{}", x[2], x[3]) for x in all_settings} == { + ('{"key1": "val1"}', "dns-records", 1), + ('{"key1": "val1", "key2": "val2"}', "dns-records", 2), + ('{"key2": "val2", "key3": "val3"}', "nmap", 1), + ("{}", "nmap-udp", 1), + } diff --git a/boefjes/tests/integration/test_sql_repositories.py b/boefjes/tests/integration/test_sql_repositories.py index 4dbe5d5c991..268aa76653c 100644 --- a/boefjes/tests/integration/test_sql_repositories.py +++ b/boefjes/tests/integration/test_sql_repositories.py @@ -1,121 +1,86 @@ import datetime import os -from unittest import TestCase, skipIf -import alembic.config -from sqlalchemy.orm import sessionmaker +import pytest -from boefjes.config import settings from boefjes.models import Boefje, Normalizer, Organisation -from boefjes.sql.config_storage import SQLConfigStorage, create_encrypter -from boefjes.sql.db import SQL_BASE, get_engine -from boefjes.sql.organisation_storage import SQLOrganisationStorage -from boefjes.sql.plugin_storage import SQLPluginStorage from boefjes.storage.interfaces import ConfigNotFound, OrganisationNotFound, PluginNotFound, StorageError +pytestmark = pytest.mark.skipif(os.environ.get("CI") != "1", reason="Needs a CI database.") -@skipIf(os.environ.get("CI") != "1", "Needs a CI database.") -class TestRepositories(TestCase): - def setUp(self) -> None: - alembic.config.main(argv=["--config", "/app/boefjes/boefjes/alembic.ini", "upgrade", "head"]) - session = sessionmaker(bind=get_engine())() - self.organisation_storage = SQLOrganisationStorage(session, settings) - self.config_storage = SQLConfigStorage(session, create_encrypter()) - self.plugin_storage = SQLPluginStorage(session, settings) +def test_organisation_storage(organisation_storage): + organisation_id = "test" - def tearDown(self) -> None: - session = sessionmaker(bind=get_engine())() + org = Organisation(id=organisation_id, name="Test") + with organisation_storage as storage: + storage.create(org) - for table in SQL_BASE.metadata.tables: - session.execute(f"DELETE FROM {table} CASCADE") # noqa: S608 + returned_org = storage.get_by_id(organisation_id) + assert org == returned_org - session.commit() - session.close() + all_organisations = storage.get_all() + assert org == all_organisations[organisation_id] - def test_organisation_storage(self): - organisation_id = "test" + with organisation_storage as storage: + storage.delete_by_id(organisation_id) - org = Organisation(id=organisation_id, name="Test") - with self.organisation_storage as storage: - storage.create(org) + with pytest.raises(OrganisationNotFound): + storage.get_by_id(organisation_id) - returned_org = storage.get_by_id(organisation_id) - self.assertEqual(org, returned_org) - all_organisations = storage.get_all() - self.assertEqual(org, all_organisations[organisation_id]) +def test_settings_storage(plugin_storage, organisation_storage, config_storage): + organisation_id = "test" + plugin_id = 64 * "a" - with self.organisation_storage as storage: - storage.delete_by_id(organisation_id) + with plugin_storage as storage: + storage.create_boefje(Boefje(id=plugin_id, name="Test")) - with self.assertRaises(OrganisationNotFound): - storage.get_by_id(organisation_id) + org = Organisation(id=organisation_id, name="Test") + with organisation_storage as storage: + storage.create(org) - def test_settings_storage(self): - organisation_id = "test" - plugin_id = 64 * "a" + with config_storage as settings_storage: + settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 12}) - with self.plugin_storage as storage: - storage.create_boefje(Boefje(id=plugin_id, name="Test")) + with config_storage as settings_storage: + settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 13}) - org = Organisation(id=organisation_id, name="Test") - with self.organisation_storage as storage: - storage.create(org) + returned_settings = settings_storage.get_all_settings(organisation_id, plugin_id) + assert returned_settings["TEST_SETTING"] == "123.9" + assert returned_settings["TEST_SETTING2"] == 13 - with self.config_storage as settings_storage: - settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 12}) + with pytest.raises(ConfigNotFound): + config_storage.delete("no organisation!", plugin_id) - with self.config_storage as settings_storage: - settings_storage.upsert(organisation_id, plugin_id, {"TEST_SETTING": "123.9", "TEST_SETTING2": 13}) + assert {"TEST_SETTING": "123.9", "TEST_SETTING2": 13} == settings_storage.get_all_settings(org.id, plugin_id) + assert config_storage.get_all_settings(org.id, "wrong") == {} + assert config_storage.get_all_settings("wrong", plugin_id) == {} - returned_settings = settings_storage.get_all_settings(organisation_id, plugin_id) - self.assertEqual("123.9", returned_settings["TEST_SETTING"]) - self.assertEqual(13, returned_settings["TEST_SETTING2"]) + with config_storage as settings_storage: + settings_storage.delete(org.id, plugin_id) - with self.assertRaises(ConfigNotFound): - settings_storage.delete("no organisation!", plugin_id) + assert settings_storage.get_all_settings(org.id, plugin_id) == {} - self.assertEqual( - {"TEST_SETTING": "123.9", "TEST_SETTING2": 13}, settings_storage.get_all_settings(org.id, plugin_id) - ) - self.assertEqual(dict(), settings_storage.get_all_settings(org.id, "wrong")) - self.assertEqual(dict(), settings_storage.get_all_settings("wrong", plugin_id)) - - with self.config_storage as settings_storage: - settings_storage.delete(org.id, plugin_id) - - self.assertEqual(dict(), settings_storage.get_all_settings(org.id, plugin_id)) - - with self.assertRaises(StorageError), self.config_storage as settings_storage: - settings_storage.upsert(organisation_id, 65 * "a", {"TEST_SETTING": "123.9"}) - - def test_settings_storage_values_field_limits(self): - organisation_id = "test" - plugin_id = 64 * "a" - - with self.plugin_storage as storage: - storage.create_boefje(Boefje(id=plugin_id, name="Test")) - - org = Organisation(id=organisation_id, name="Test") - with self.organisation_storage as storage: - storage.create(org) - - with self.config_storage as settings_storage: - settings_storage.upsert( - organisation_id, - plugin_id, - { - "TEST_SETTING": 12 * "123.9", - "TEST_SETTING2": 12000, - "TEST_SETTING3": 30 * "b", - "TEST_SETTING4": 30 * "b", - "TEST_SETTING5": 10 * "b", - "TEST_SETTING6": 123456789, - }, - ) - - self.assertEqual( + with pytest.raises(StorageError), config_storage as settings_storage: + settings_storage.upsert(organisation_id, 65 * "a", {"TEST_SETTING": "123.9"}) + + +def test_settings_storage_values_field_limits(plugin_storage, organisation_storage, config_storage): + organisation_id = "test" + plugin_id = 64 * "a" + + with plugin_storage as storage: + storage.create_boefje(Boefje(id=plugin_id, name="Test")) + + org = Organisation(id=organisation_id, name="Test") + with organisation_storage as storage: + storage.create(org) + + with config_storage as settings_storage: + settings_storage.upsert( + organisation_id, + plugin_id, { "TEST_SETTING": 12 * "123.9", "TEST_SETTING2": 12000, @@ -124,149 +89,163 @@ def test_settings_storage_values_field_limits(self): "TEST_SETTING5": 10 * "b", "TEST_SETTING6": 123456789, }, - settings_storage.get_all_settings(org.id, plugin_id), ) - def test_plugin_enabled_storage(self): - with self.organisation_storage as storage: - org = Organisation(id="test", name="Test") - storage.create(org) - - plugin = Boefje( - id="test-boefje-1", - name="Test Boefje 1", - version="0.1", - consumes={"WebPage"}, - produces=["text/html"], - enabled=True, - ) + assert { + "TEST_SETTING": 12 * "123.9", + "TEST_SETTING2": 12000, + "TEST_SETTING3": 30 * "b", + "TEST_SETTING4": 30 * "b", + "TEST_SETTING5": 10 * "b", + "TEST_SETTING6": 123456789, + } == settings_storage.get_all_settings(org.id, plugin_id) - with self.plugin_storage as storage: - storage.create_boefje(plugin) - with self.config_storage as storage: - storage.upsert(org.id, plugin.id, enabled=plugin.enabled) +def test_plugin_enabled_storage(organisation_storage, plugin_storage, config_storage): + with organisation_storage as storage: + org = Organisation(id="test", name="Test") + storage.create(org) - returned_state = storage.is_enabled_by_id(plugin.id, org.id) - self.assertTrue(returned_state) + plugin = Boefje( + id="test-boefje-1", + name="Test Boefje 1", + version="0.1", + consumes={"WebPage"}, + produces=["text/html"], + enabled=True, + ) - with self.config_storage as storage: - storage.upsert(org.id, plugin.id, enabled=False) + with plugin_storage as storage: + storage.create_boefje(plugin) - returned_state = storage.is_enabled_by_id(plugin.id, org.id) - self.assertFalse(returned_state) + with config_storage as storage: + storage.upsert(org.id, plugin.id, enabled=plugin.enabled) - with self.assertRaises(ConfigNotFound): - storage.is_enabled_by_id("wrong", org.id) + returned_state = storage.is_enabled_by_id(plugin.id, org.id) + assert returned_state is True - with self.assertRaises(ConfigNotFound): - storage.is_enabled_by_id("wrong", org.id) + with config_storage as storage: + storage.upsert(org.id, plugin.id, enabled=False) - with self.assertRaises(ConfigNotFound): - storage.is_enabled_by_id(plugin.id, "wrong") + returned_state = storage.is_enabled_by_id(plugin.id, org.id) + assert returned_state is False + + with pytest.raises(ConfigNotFound): + storage.is_enabled_by_id("wrong", org.id) - def test_bare_boefje_storage(self): - boefje = Boefje(id="test_boefje", name="Test", static=False) + with pytest.raises(ConfigNotFound): + storage.is_enabled_by_id("wrong", org.id) - with self.plugin_storage as storage: - storage.create_boefje(boefje) + with pytest.raises(ConfigNotFound): + storage.is_enabled_by_id(plugin.id, "wrong") - returned_boefje = storage.boefje_by_id(boefje.id) - self.assertEqual(boefje, returned_boefje) - storage.update_boefje(boefje.id, {"description": "4"}) - self.assertEqual(storage.boefje_by_id(boefje.id).description, "4") - boefje.description = "4" +def test_bare_boefje_storage(plugin_storage): + boefje = Boefje(id="test_boefje", name="Test", static=False) - all_plugins = storage.get_all() - self.assertEqual(all_plugins, [boefje]) + with plugin_storage as storage: + storage.create_boefje(boefje) - with self.plugin_storage as storage: - storage.delete_boefje_by_id(boefje.id) + returned_boefje = storage.boefje_by_id(boefje.id) + assert boefje == returned_boefje - with self.assertRaises(PluginNotFound): - storage.boefje_by_id(boefje.id) + storage.update_boefje(boefje.id, {"description": "4"}) + assert storage.boefje_by_id(boefje.id).description == "4" + boefje.description = "4" - def test_rich_boefje_storage(self): - boefje = Boefje( - id="test_boefje", - name="Test", - version="v1.09", - created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), - description="My Boefje", - scan_level=4, - consumes=["Internet"], - produces=[ - "image/png", - "application/zip+json", - "application/har+json", - "application/json", - "application/localstorage+json", - ], - oci_image="ghcr.io/test/image:123", - oci_arguments=["host", "-n", "123123123123123123123"], - static=False, - ) + all_plugins = storage.get_all() + assert all_plugins == [boefje] + + with plugin_storage as storage: + storage.delete_boefje_by_id(boefje.id) + + with pytest.raises(PluginNotFound): + storage.boefje_by_id(boefje.id) + + +def test_rich_boefje_storage(plugin_storage): + boefje = Boefje( + id="test_boefje", + name="Test", + version="v1.09", + created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), + description="My Boefje", + scan_level=4, + consumes=["Internet"], + produces=[ + "image/png", + "application/zip+json", + "application/har+json", + "application/json", + "application/localstorage+json", + ], + oci_image="ghcr.io/test/image:123", + oci_arguments=["host", "-n", "123123123123123123123"], + static=False, + ) + + with plugin_storage as storage: + storage.create_boefje(boefje) + + returned_boefje = storage.boefje_by_id(boefje.id) + assert boefje == returned_boefje + + +def test_bare_normalizer_storage(plugin_storage): + normalizer = Normalizer(id="test_boefje", name="Test", static=False) + + with plugin_storage as storage: + storage.create_normalizer(normalizer) + + returned_normalizer = storage.normalizer_by_id(normalizer.id) + assert normalizer == returned_normalizer + + storage.update_normalizer(normalizer.id, {"version": "v4"}) + assert storage.normalizer_by_id(normalizer.id).version == "v4" + normalizer.version = "v4" + + all_plugins = storage.get_all() + assert all_plugins == [normalizer] + + with plugin_storage as storage: + storage.delete_normalizer_by_id(normalizer.id) + + with pytest.raises(PluginNotFound): + storage.normalizer_by_id(normalizer.id) - with self.plugin_storage as storage: - storage.create_boefje(boefje) - - returned_boefje = storage.boefje_by_id(boefje.id) - self.assertEqual(boefje, returned_boefje) - - def test_bare_normalizer_storage(self): - normalizer = Normalizer(id="test_boefje", name="Test", static=False) - - with self.plugin_storage as storage: - storage.create_normalizer(normalizer) - - returned_normalizer = storage.normalizer_by_id(normalizer.id) - self.assertEqual(normalizer, returned_normalizer) - - storage.update_normalizer(normalizer.id, {"version": "v4"}) - self.assertEqual(storage.normalizer_by_id(normalizer.id).version, "v4") - normalizer.version = "v4" - - all_plugins = storage.get_all() - self.assertEqual(all_plugins, [normalizer]) - - with self.plugin_storage as storage: - storage.delete_normalizer_by_id(normalizer.id) - - with self.assertRaises(PluginNotFound): - storage.normalizer_by_id(normalizer.id) - - def test_rich_normalizer_storage(self): - normalizer = Normalizer( - id="test_normalizer", - name="Test", - version="v1.19", - created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), - description="My Normalizer", - scan_level=4, - consumes=["Internet"], - produces=[ - "image/png", - "application/zip+json", - "application/har+json", - "application/json", - "application/localstorage+json", - ], - static=False, - ) - with self.plugin_storage as storage: - storage.create_normalizer(normalizer) +def test_rich_normalizer_storage(plugin_storage): + normalizer = Normalizer( + id="test_normalizer", + name="Test", + version="v1.19", + created=datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=datetime.UTC), + description="My Normalizer", + scan_level=4, + consumes=["Internet"], + produces=[ + "image/png", + "application/zip+json", + "application/har+json", + "application/json", + "application/localstorage+json", + ], + static=False, + ) - returned_normalizer = storage.normalizer_by_id(normalizer.id) - self.assertEqual(normalizer, returned_normalizer) + with plugin_storage as storage: + storage.create_normalizer(normalizer) - def test_plugin_storage(self): - boefje = Boefje(id="test_boefje", name="Test", static=False) - normalizer = Normalizer(id="test_boefje", name="Test", static=False) + returned_normalizer = storage.normalizer_by_id(normalizer.id) + assert normalizer == returned_normalizer - with self.plugin_storage as storage: - storage.create_boefje(boefje) - storage.create_normalizer(normalizer) - self.assertEqual(storage.get_all(), [boefje, normalizer]) +def test_plugin_storage(plugin_storage): + boefje = Boefje(id="test_boefje", name="Test", static=False) + normalizer = Normalizer(id="test_boefje", name="Test", static=False) + + with plugin_storage as storage: + storage.create_boefje(boefje) + storage.create_normalizer(normalizer) + + assert storage.get_all() == [boefje, normalizer] diff --git a/boefjes/tests/katalogus/test_organisation_api.py b/boefjes/tests/katalogus/test_organisation_api.py index 4f2c7364aa9..914012e3688 100644 --- a/boefjes/tests/katalogus/test_organisation_api.py +++ b/boefjes/tests/katalogus/test_organisation_api.py @@ -1,50 +1,35 @@ import json -from unittest import TestCase -from fastapi.testclient import TestClient -from boefjes.katalogus.root import app -from boefjes.models import Organisation -from boefjes.sql.organisation_storage import get_organisations_store -from boefjes.storage.memory import OrganisationStorageMemory +def test_list(unit_test_client): + res = unit_test_client.get("/v1/organisations") + assert res.status_code == 200 -class TestOrganisations(TestCase): - def setUp(self) -> None: - self.client = TestClient(app) +def test_get_organisation(unit_test_client): + res = unit_test_client.get("/v1/organisations/test") + assert res.status_code == 200 - self._store = OrganisationStorageMemory({"test": Organisation(id="test", name="Test")}) - app.dependency_overrides[get_organisations_store] = lambda: self._store +def test_non_existing_organisation(unit_test_client): + res = unit_test_client.get("/v1/organisations/future-organisation") + assert res.status_code == 404 + assert "unknown organisation" in res.text.lower() - def tearDown(self) -> None: - app.dependency_overrides = {} - def test_list(self): - res = self.client.get("/v1/organisations") - self.assertEqual(200, res.status_code) +def test_add_organisation(unit_test_client): + res = unit_test_client.post("/v1/organisations/", content=json.dumps({"id": "new", "name": "New"})) + assert res.status_code == 201 - def test_get_organisation(self): - res = self.client.get("/v1/organisations/test") - self.assertEqual(200, res.status_code) + res = unit_test_client.get("/v1/organisations") + assert res.status_code == 200 + assert len(res.json()) == 2 - def test_non_existing_organisation(self): - res = self.client.get("/v1/organisations/future-organisation") - self.assertEqual(404, res.status_code) - self.assertIn("unknown organisation", res.text.lower()) - def test_add_organisation(self): - res = self.client.post("/v1/organisations/", data=json.dumps({"id": "new", "name": "New"})) - self.assertEqual(201, res.status_code) +def test_delete_organisation(unit_test_client): + res = unit_test_client.delete("/v1/organisations/test") + assert res.status_code == 200 - res = self.client.get("/v1/organisations") - self.assertEqual(200, res.status_code) - self.assertEqual(2, len(res.json())) - - def test_delete_organisation(self): - res = self.client.delete("/v1/organisations/test") - self.assertEqual(200, res.status_code) - - res = self.client.get("/v1/organisations") - self.assertEqual(200, res.status_code) - self.assertEqual(0, len(res.json())) + res = unit_test_client.get("/v1/organisations") + assert res.status_code == 200 + assert len(res.json()) == 0 diff --git a/boefjes/tests/katalogus/test_plugin_service.py b/boefjes/tests/katalogus/test_plugin_service.py index acb892eedee..4f1806f176a 100644 --- a/boefjes/tests/katalogus/test_plugin_service.py +++ b/boefjes/tests/katalogus/test_plugin_service.py @@ -1,145 +1,127 @@ -from unittest import TestCase +import pytest -from boefjes.config import BASE_DIR -from boefjes.dependencies.plugins import PluginService -from boefjes.local_repository import LocalPluginRepository from boefjes.storage.interfaces import SettingsNotConformingToSchema -from boefjes.storage.memory import ConfigStorageMemory, PluginStorageMemory -def mock_plugin_service(organisation_id: str) -> PluginService: - storage = ConfigStorageMemory() - storage.upsert("test", "test_plugin", {"DUMMY_VAR": "123"}) +def test_get_plugins(mock_plugin_service, test_organisation): + plugins = mock_plugin_service.get_all(test_organisation.id) + assert len(plugins) == 14 - test_boefjes_dir = BASE_DIR.parent / "tests" / "katalogus" / "boefjes_test_dir" + kat_test = list(filter(lambda x: x.id == "kat_test", plugins)).pop() + assert kat_test.id == "kat_test" + assert kat_test.name == "Kat test name" + assert kat_test.consumes == {"DNSZone"} + assert set(kat_test.produces) == {"boefje/kat_test"} - return PluginService( - PluginStorageMemory(), - storage, - LocalPluginRepository(test_boefjes_dir), - ) + kat_test_norm = list(filter(lambda x: x.id == "kat_test_normalize", plugins)).pop() + assert "kat_test_normalize" in kat_test_norm.id + assert kat_test_norm.consumes == ["text/html", "normalizer/kat_test_normalize"] + assert kat_test_norm.produces == [] -class TestPluginsService(TestCase): - def setUp(self) -> None: - self.organisation = "test" - self.service = mock_plugin_service(self.organisation) +def test_get_plugin_by_id(mock_plugin_service, test_organisation): + plugin = mock_plugin_service.by_plugin_id("kat_test_normalize", test_organisation.id) - def test_get_plugins(self): - plugins = self.service.get_all(self.organisation) + assert plugin.id == "kat_test_normalize" + assert plugin.enabled is True - self.assertEqual(len(plugins), 5) - kat_test = list(filter(lambda x: x.id == "kat_test", plugins)).pop() - self.assertEqual("kat_test", kat_test.id) - self.assertEqual("Kat test name", kat_test.name) - self.assertEqual({"DNSZone"}, kat_test.consumes) - self.assertSetEqual({"boefje/kat_test"}, set(kat_test.produces)) +def test_update_by_id(mock_plugin_service, test_organisation): + mock_plugin_service.set_enabled_by_id("kat_test_normalize", test_organisation.id, False) + plugin = mock_plugin_service.by_plugin_id("kat_test_normalize", test_organisation.id) + assert plugin.enabled is False - kat_test_norm = list(filter(lambda x: x.id == "kat_test_normalize", plugins)).pop() - self.assertIn("kat_test_normalize", kat_test_norm.id) - self.assertListEqual(["text/html", "normalizer/kat_test_normalize"], kat_test_norm.consumes) - self.assertListEqual([], kat_test_norm.produces) - def test_get_plugin_by_id(self): - plugin = self.service.by_plugin_id("kat_test_normalize", self.organisation) +def test_update_by_id_bad_schema(mock_plugin_service, test_organisation): + plugin_id = "kat_test" - self.assertEqual(plugin.id, "kat_test_normalize") - self.assertTrue(plugin.enabled) + mock_plugin_service.config_storage.upsert(test_organisation.id, plugin_id, {"api_key": 128 * "a"}) + mock_plugin_service.set_enabled_by_id(plugin_id, test_organisation.id, True) - def test_update_by_id(self): - self.service.set_enabled_by_id("kat_test_normalize", self.organisation, False) - plugin = self.service.by_plugin_id("kat_test_normalize", self.organisation) - self.assertFalse(plugin.enabled) + with pytest.raises(SettingsNotConformingToSchema) as ctx: + mock_plugin_service.upsert_settings({"api_key": 129 * "a"}, test_organisation.id, plugin_id) - def test_update_by_id_bad_schema(self): - plugin_id = "kat_test" + msg = f"Settings for plugin kat_test are not conform the plugin schema: '{129 * 'a'}' is too long" + assert ctx.value.message == msg - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) - self.service.set_enabled_by_id(plugin_id, self.organisation, True) - with self.assertRaises(SettingsNotConformingToSchema) as ctx: - self.service.upsert_settings({"api_key": 129 * "a"}, self.organisation, plugin_id) +def test_get_schema(mock_plugin_service): + schema = mock_plugin_service.schema("kat_test") + assert { + "title": "Arguments", + "type": "object", + "properties": {"api_key": {"title": "Api Key", "maxLength": 128, "type": "string"}}, + "required": ["api_key"], + } == schema - msg = f"Settings for plugin kat_test are not conform the plugin schema: '{129 * 'a'}' is too long" - self.assertEqual(ctx.exception.message, msg) + schema = mock_plugin_service.schema("kat_test_normalize") + assert schema is None - def test_get_schema(self): - schema = self.service.schema("kat_test") - self.assertDictEqual( - { - "title": "Arguments", - "type": "object", - "properties": {"api_key": {"title": "Api Key", "maxLength": 128, "type": "string"}}, - "required": ["api_key"], - }, - schema, - ) - schema = self.service.schema("kat_test_normalize") - self.assertIsNone(schema) +def test_removing_mandatory_setting_does_not_disable_plugin_anymore(mock_plugin_service, test_organisation): + plugin_id = "kat_test" - def test_removing_mandatory_setting_does_not_disable_plugin_anymore(self): - plugin_id = "kat_test" + mock_plugin_service.config_storage.upsert(test_organisation.id, plugin_id, {"api_key": 128 * "a"}) + mock_plugin_service.set_enabled_by_id(plugin_id, test_organisation.id, True) - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": 128 * "a"}) - self.service.set_enabled_by_id(plugin_id, self.organisation, True) + plugin = mock_plugin_service.by_plugin_id(plugin_id, test_organisation.id) + assert plugin.enabled is True - plugin = self.service.by_plugin_id(plugin_id, self.organisation) - self.assertTrue(plugin.enabled) + mock_plugin_service.delete_settings(test_organisation.id, plugin_id) - self.service.delete_settings(self.organisation, plugin_id) + plugin = mock_plugin_service.by_plugin_id(plugin_id, test_organisation.id) + assert plugin.enabled is True - plugin = self.service.by_plugin_id(plugin_id, self.organisation) - self.assertTrue(plugin.enabled) - def test_adding_integer_settings_within_given_constraints(self): - plugin_id = "kat_test_2" +def test_adding_integer_settings_within_given_constraints(mock_plugin_service, test_organisation): + plugin_id = "kat_test_2" - with self.assertRaises(SettingsNotConformingToSchema) as ctx: - self.service.upsert_settings({"api_key": "24"}, self.organisation, plugin_id) + with pytest.raises(SettingsNotConformingToSchema) as ctx: + mock_plugin_service.upsert_settings({"api_key": "24"}, test_organisation.id, plugin_id) - self.assertIn("'24' is not of type 'integer'", ctx.exception.message) + assert "'24' is not of type 'integer'" in ctx.value.message - self.service.upsert_settings({"api_key": 24}, self.organisation, plugin_id) - self.service.set_enabled_by_id(plugin_id, self.organisation, True) + mock_plugin_service.upsert_settings({"api_key": 24}, test_organisation.id, plugin_id) + mock_plugin_service.set_enabled_by_id(plugin_id, test_organisation.id, True) - plugin = self.service.by_plugin_id(plugin_id, self.organisation) - self.assertTrue(plugin.enabled) - self.service.set_enabled_by_id(plugin_id, self.organisation, False) + plugin = mock_plugin_service.by_plugin_id(plugin_id, test_organisation.id) + assert plugin.enabled is True + mock_plugin_service.set_enabled_by_id(plugin_id, test_organisation.id, False) - def test_clone_one_setting(self): - new_org_id = "org2" - plugin_id = "kat_test" - self.service.config_storage.upsert(self.organisation, plugin_id, {"api_key": "24"}) - assert self.service.get_all_settings(self.organisation, plugin_id) == {"api_key": "24"} - self.service.set_enabled_by_id(plugin_id, self.organisation, True) +def test_clone_one_setting(mock_plugin_service, test_organisation): + new_org_id = "org2" + plugin_id = "kat_test" + mock_plugin_service.config_storage.upsert(test_organisation.id, plugin_id, {"api_key": "24"}) + assert mock_plugin_service.get_all_settings(test_organisation.id, plugin_id) == {"api_key": "24"} - assert "api_key" not in self.service.get_all_settings(new_org_id, plugin_id) + mock_plugin_service.set_enabled_by_id(plugin_id, test_organisation.id, True) - new_org_plugins = self.service.get_all(new_org_id) - assert len(new_org_plugins) == 5 - assert len([x for x in new_org_plugins if x.enabled]) == 2 # 2 Normalizers - assert plugin_id not in [x.id for x in new_org_plugins if x.enabled] + assert "api_key" not in mock_plugin_service.get_all_settings(new_org_id, plugin_id) - self.service.clone_settings_to_organisation(self.organisation, new_org_id) + new_org_plugins = mock_plugin_service.get_all(new_org_id) + assert len(new_org_plugins) == 14 + assert len([x for x in new_org_plugins if x.enabled]) == 5 # 2 Normalizers + assert plugin_id not in [x.id for x in new_org_plugins if x.enabled] - assert self.service.get_all_settings(self.organisation, plugin_id) == {"api_key": "24"} - assert self.service.get_all_settings(new_org_id, plugin_id) == {"api_key": "24"} + mock_plugin_service.clone_settings_to_organisation(test_organisation.id, new_org_id) - new_org_plugins = self.service.get_all(new_org_id) - assert len(new_org_plugins) == 5 - assert len([x for x in new_org_plugins if x.enabled]) == 3 # 2 Normalizers, 1 boefje - assert plugin_id in [x.id for x in new_org_plugins if x.enabled] + assert mock_plugin_service.get_all_settings(test_organisation.id, plugin_id) == {"api_key": "24"} + assert mock_plugin_service.get_all_settings(new_org_id, plugin_id) == {"api_key": "24"} - def test_clone_many_settings(self): - plugin_id_1 = "kat_test" + new_org_plugins = mock_plugin_service.get_all(new_org_id) + assert len(new_org_plugins) == 14 + assert len([x for x in new_org_plugins if x.enabled]) == 6 # 2 Normalizers, 1 boefje + assert plugin_id in [x.id for x in new_org_plugins if x.enabled] - all_settings_1 = {"api_key": "123"} - self.service.upsert_settings(all_settings_1, self.organisation, plugin_id_1) - self.service.clone_settings_to_organisation(self.organisation, "org2") - all_settings_for_new_org = self.service.get_all_settings("org2", plugin_id_1) - assert len(all_settings_for_new_org) == 1 - assert all_settings_for_new_org == {"api_key": "123"} +def test_clone_many_settings(mock_plugin_service, test_organisation): + plugin_id_1 = "kat_test" + + all_settings_1 = {"api_key": "123"} + mock_plugin_service.upsert_settings(all_settings_1, test_organisation.id, plugin_id_1) + mock_plugin_service.clone_settings_to_organisation(test_organisation.id, "org2") + + all_settings_for_new_org = mock_plugin_service.get_all_settings("org2", plugin_id_1) + assert len(all_settings_for_new_org) == 1 + assert all_settings_for_new_org == {"api_key": "123"} diff --git a/boefjes/tests/katalogus/test_plugins_api.py b/boefjes/tests/katalogus/test_plugins_api.py index 537e0ac81f2..e41ab2daf1a 100644 --- a/boefjes/tests/katalogus/test_plugins_api.py +++ b/boefjes/tests/katalogus/test_plugins_api.py @@ -1,145 +1,114 @@ -from unittest import TestCase +def test_list(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + { + "kat_test", + "kat_test_2", + "kat_test_4", + "kat_test_normalize", + "kat_test_normalize_2", + } + ) + + +def test_list_filter_by_type(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins?plugin_type=boefje") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + { + "kat_test", + "kat_test_2", + "kat_test_4", + } + ) -from fastapi.testclient import TestClient -from boefjes.dependencies.plugins import get_plugin_service -from boefjes.katalogus.organisations import check_organisation_exists -from boefjes.katalogus.root import app -from boefjes.storage.interfaces import OrganisationNotFound -from tests.katalogus.test_plugin_service import mock_plugin_service +def test_list_filter_by_state(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins?state=true") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + { + "kat_test_normalize", + "kat_test_normalize_2", + } + ) + assert all([x["enabled"] for x in res.json()]) is True -class TestPlugins(TestCase): - def setUp(self) -> None: - services = { - "test-org": mock_plugin_service("test-org"), +def test_list_filter_by_id(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins?q=norm") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + { + "kat_test_normalize", + "kat_test_normalize_2", } + ) + + +def test_list_pagination(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins?offset=2&limit=2&q=kat_") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + { + "kat_test_4", + "kat_test_normalize", + } + ) + + +def test_list_plugins(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins") + assert res.status_code == 200 + assert {x["id"] for x in res.json()}.issuperset( + {"kat_test", "kat_test_2", "kat_test_4", "kat_test_normalize", "kat_test_normalize_2"} + ) + + +def test_get_plugin(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins/kat_test") + assert res.status_code == 200 + assert "produces" in res.json() + assert res.json()["produces"] == ["boefje/kat_test"] + + +def test_non_existing_plugin(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins/future-plugin") + assert res.status_code == 404 + + +def test_default_enabled_property_list(unit_test_client): + res = unit_test_client.get("/v1/organisations/test/plugins?plugin_type=boefje") + assert res.status_code == 200 + assert any([plugin["enabled"] for plugin in res.json()]) is False + + +def test_patching_enabled_state(unit_test_client): + res = unit_test_client.patch( + "/v1/organisations/test/plugins/kat_test_normalize", + json={"enabled": False}, + ) + assert res.status_code == 204 + + res = unit_test_client.get("/v1/organisations/test/plugins") + assert res.status_code == 200 + assert {plugin["id"]: plugin["enabled"] for plugin in res.json() if "kat_" in plugin["id"]} == { + "kat_test": False, + "kat_test_4": False, + "kat_test_2": False, + "kat_test_normalize": False, + "kat_test_normalize_2": True, + } + + +def test_patching_enabled_state_non_existing_org(unit_test_client): + res = unit_test_client.patch( + "/v1/organisations/non-existing-org/plugins/kat_test_normalize", + json={"enabled": False}, + ) + + assert res.status_code == 404 - def get_service(organisation_id: str): - if organisation_id in services: - return services.get(organisation_id) - - raise OrganisationNotFound(organisation_id) - - app.dependency_overrides[get_plugin_service] = get_service - app.dependency_overrides[check_organisation_exists] = lambda: None - - self.client = TestClient(app) - - def tearDown(self) -> None: - app.dependency_overrides = {} - - def test_list(self): - res = self.client.get("/v1/organisations/test-org/plugins") - self.assertEqual(200, res.status_code) - self.assertSetEqual( - { - "kat_test", - "kat_test_2", - "kat_test_4", - "kat_test_normalize", - "kat_test_normalize_2", - }, - {x["id"] for x in res.json()}, - ) - - def test_list_filter_by_type(self): - res = self.client.get("/v1/organisations/test-org/plugins?plugin_type=boefje") - self.assertEqual(200, res.status_code) - self.assertSetEqual( - { - "kat_test", - "kat_test_2", - "kat_test_4", - }, - {x["id"] for x in res.json()}, - ) - - def test_list_filter_by_state(self): - res = self.client.get("/v1/organisations/test-org/plugins?state=true") - self.assertEqual(200, res.status_code) - plugins = res.json() - self.assertSetEqual( - { - "kat_test_normalize", - "kat_test_normalize_2", - }, - {x["id"] for x in plugins}, - ) - self.assertTrue(all([x["enabled"] for x in plugins])) - - def test_list_filter_by_id(self): - res = self.client.get("/v1/organisations/test-org/plugins?q=norm") - self.assertEqual(200, res.status_code) - self.assertSetEqual( - { - "kat_test_normalize", - "kat_test_normalize_2", - }, - {x["id"] for x in (res.json())}, - ) - - def test_list_pagination(self): - res = self.client.get("/v1/organisations/test-org/plugins?offset=2&limit=2") - self.assertEqual(200, res.status_code) - self.assertSetEqual( - { - "kat_test_4", - "kat_test_normalize", - }, - {x["id"] for x in (res.json())}, - ) - - def test_list_plugins(self): - res = self.client.get("/v1/organisations/test-org/plugins") - self.assertEqual(200, res.status_code) - self.assertListEqual( - ["kat_test", "kat_test_2", "kat_test_4", "kat_test_normalize", "kat_test_normalize_2"], - [x["id"] for x in res.json()], - ) - - def test_get_plugin(self): - res = self.client.get("/v1/organisations/test-org/plugins/kat_test") - self.assertEqual(200, res.status_code) - assert "produces" in res.json() - assert res.json()["produces"] == ["boefje/kat_test"] - - def test_non_existing_plugin(self): - res = self.client.get("/v1/organisations/test-org/plugins/future-plugin") - self.assertEqual(404, res.status_code) - - def test_default_enabled_property_list(self): - res = self.client.get("/v1/organisations/test-org/plugins?plugin_type=boefje") - self.assertEqual(200, res.status_code) - self.assertFalse(any([plugin["enabled"] for plugin in res.json()])) - - def test_patching_enabled_state(self): - res = self.client.patch( - "/v1/organisations/test-org/plugins/kat_test_normalize", - json={"enabled": False}, - ) - self.assertEqual(204, res.status_code) - - res = self.client.get("/v1/organisations/test-org/plugins") - self.assertEqual(200, res.status_code) - self.assertEqual( - { - "kat_test": False, - "kat_test_4": False, - "kat_test_2": False, - "kat_test_normalize": False, - "kat_test_normalize_2": True, - }, - {plugin["id"]: plugin["enabled"] for plugin in res.json()}, - ) - - def test_patching_enabled_state_non_existing_org(self): - res = self.client.patch( - "/v1/organisations/non-existing-org/plugins/kat_test_normalize", - json={"enabled": False}, - ) - - self.assertEqual(404, res.status_code) - - res = self.client.get("/v1/organisations/non-existing-org/plugins") - self.assertEqual(404, res.status_code) + res = unit_test_client.get("/v1/organisations/non-existing-org/plugins") + assert res.status_code == 404 diff --git a/boefjes/tests/katalogus/test_settings.py b/boefjes/tests/katalogus/test_settings.py index 603f6e88958..56cd442af3f 100644 --- a/boefjes/tests/katalogus/test_settings.py +++ b/boefjes/tests/katalogus/test_settings.py @@ -1,23 +1,20 @@ import base64 -from unittest import TestCase from nacl.public import PrivateKey from boefjes.dependencies.encryption import NaclBoxMiddleware -class TestSettingsEncryption(TestCase): - def setUp(self) -> None: - sk = PrivateKey.generate() - sk_b64 = base64.b64encode(bytes(sk)).decode() - pub_b64 = base64.b64encode(bytes(sk.public_key)).decode() - self.encryption = NaclBoxMiddleware(private_key=sk_b64, public_key=pub_b64) +def test_encode_decode(): + sk = PrivateKey.generate() + sk_b64 = base64.b64encode(bytes(sk)).decode() + pub_b64 = base64.b64encode(bytes(sk.public_key)).decode() + nacl_box_middleware = NaclBoxMiddleware(private_key=sk_b64, public_key=pub_b64) - def test_encode_decode(self): - msg = "The president is taking the underpass" + msg = "The president is taking the underpass" - encrypted = self.encryption.encode(msg) - decrypted = self.encryption.decode(encrypted) + encrypted = nacl_box_middleware.encode(msg) + decrypted = nacl_box_middleware.decode(encrypted) - self.assertNotEqual(encrypted, msg) - self.assertEqual(msg, decrypted) + assert encrypted != msg + assert decrypted == msg diff --git a/boefjes/tests/katalogus/boefjes_test_dir/__init__.py b/boefjes/tests/modules/kat_test/__init__.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/__init__.py rename to boefjes/tests/modules/kat_test/__init__.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json b/boefjes/tests/modules/kat_test/boefje.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/boefje.json rename to boefjes/tests/modules/kat_test/boefje.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/__init__.py b/boefjes/tests/modules/kat_test/kat_test_2/__init__.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/__init__.py rename to boefjes/tests/modules/kat_test/kat_test_2/__init__.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json b/boefjes/tests/modules/kat_test/kat_test_2/boefje.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/boefje.json rename to boefjes/tests/modules/kat_test/kat_test_2/boefje.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/__init__.py b/boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/__init__.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/__init__.py rename to boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/__init__.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py b/boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/normalize.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalize.py rename to boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/normalize.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json b/boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/normalizer.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/normalizer.json rename to boefjes/tests/modules/kat_test/kat_test_2/kat_test_3/normalizer.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/main.py b/boefjes/tests/modules/kat_test/kat_test_2/main.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/main.py rename to boefjes/tests/modules/kat_test/kat_test_2/main.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/schema.json b/boefjes/tests/modules/kat_test/kat_test_2/schema.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/schema.json rename to boefjes/tests/modules/kat_test/kat_test_2/schema.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py b/boefjes/tests/modules/kat_test/kat_test_4/__init__.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_2/kat_test_3/__init__.py rename to boefjes/tests/modules/kat_test/kat_test_4/__init__.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json b/boefjes/tests/modules/kat_test/kat_test_4/boefje.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/boefje.json rename to boefjes/tests/modules/kat_test/kat_test_4/boefje.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/schema.json b/boefjes/tests/modules/kat_test/kat_test_4/schema.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/schema.json rename to boefjes/tests/modules/kat_test/kat_test_4/schema.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/main.py b/boefjes/tests/modules/kat_test/main.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/main.py rename to boefjes/tests/modules/kat_test/main.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalize.py b/boefjes/tests/modules/kat_test/normalize.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalize.py rename to boefjes/tests/modules/kat_test/normalize.py diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json b/boefjes/tests/modules/kat_test/normalizer.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/normalizer.json rename to boefjes/tests/modules/kat_test/normalizer.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/schema.json b/boefjes/tests/modules/kat_test/schema.json similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/schema.json rename to boefjes/tests/modules/kat_test/schema.json diff --git a/boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/__init__.py b/boefjes/tests/plugins/__init__.py similarity index 100% rename from boefjes/tests/katalogus/boefjes_test_dir/kat_test/kat_test_4/__init__.py rename to boefjes/tests/plugins/__init__.py diff --git a/boefjes/tests/plugins/test_adr_validator.py b/boefjes/tests/plugins/test_adr_validator.py new file mode 100644 index 00000000000..2bc6da84b8b --- /dev/null +++ b/boefjes/tests/plugins/test_adr_validator.py @@ -0,0 +1,49 @@ +from boefjes.job_models import NormalizerMeta +from tests.loading import get_dummy_data + + +def test_no_findings(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("adr-validator-normalize.json")) + + raw = """[{"rule": "TEST-01", "passed": true, "message": ""}]""" + output = normalizer_runner.run(meta, bytes(raw, "UTF-8")) + + assert len(output.observations) == 1 + + observation = output.observations[0] + + assert len(observation.results) == 2 + + assert observation.results[0].object_type == "APIDesignRule" + assert observation.results[0].name == "TEST-01" + assert observation.results[1].object_type == "APIDesignRuleResult" + assert observation.results[1].message == "" + assert observation.results[1].passed is True + + +def test_with_findings(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("adr-validator-normalize.json")) + + raw = """[ + {"rule": "TEST-01", "passed": true, "message": ""}, + {"rule": "TEST-02", "passed": false, "message": "An error"}, + {"rule": "TEST-02", "passed": true, "message": ""} + ]""" + output = normalizer_runner.run(meta, bytes(raw, "UTF-8")) + + assert len(output.observations) == 1 + + observation = output.observations[0] + assert len(observation.results) == 8 + + assert observation.results[2].object_type == "APIDesignRule" + assert observation.results[2].name == "TEST-02" + assert observation.results[3].object_type == "APIDesignRuleResult" + assert observation.results[3].message == "An error" + assert observation.results[3].passed is False + + assert observation.results[4].object_type == "ADRFindingType" + assert observation.results[4].id == "TEST-02" + assert observation.results[5].object_type == "Finding" + assert observation.results[5].description == "An error" + assert str(observation.results[5].finding_type) == "ADRFindingType|TEST-02" diff --git a/boefjes/tests/plugins/test_answer_parser.py b/boefjes/tests/plugins/test_answer_parser.py new file mode 100644 index 00000000000..9762a2683ad --- /dev/null +++ b/boefjes/tests/plugins/test_answer_parser.py @@ -0,0 +1,24 @@ +import pytest +from pydantic import ValidationError + +from boefjes.job_models import NormalizerMeta +from tests.loading import get_dummy_data + + +def test_config_yielded(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("answer-normalize.json")) + + with pytest.raises(TypeError): + raw = '[{"key": "test"}]' + normalizer_runner.run(meta, bytes(raw, "UTF-8")) + + with pytest.raises(ValidationError): + raw = '{"schema": "/bit/port-classification-ip", "answer": [{"key": "test"}]}' + normalizer_runner.run(meta, bytes(raw, "UTF-8")) + + raw = '{"schema": "/bit/port-classification-ip", "answer": {"key": "test"}}' + output = normalizer_runner.run(meta, bytes(raw, "UTF-8")) + + assert len(output.observations) == 1 + assert len(output.observations[0].results) == 1 + assert output.observations[0].results[0].object_type == "Config" diff --git a/boefjes/tests/plugins/test_bodyimage.py b/boefjes/tests/plugins/test_bodyimage.py new file mode 100644 index 00000000000..241c3cdb927 --- /dev/null +++ b/boefjes/tests/plugins/test_bodyimage.py @@ -0,0 +1,82 @@ +import json + +from requests.models import CaseInsensitiveDict, PreparedRequest, Response + +from boefjes.job_models import BoefjeMeta, NormalizerMeta +from tests.loading import get_dummy_data + + +def test_website_analysis(boefje_runner, mocker): + do_request_mock = mocker.patch("boefjes.plugins.kat_webpage_analysis.main.do_request", spec=Response) + meta = BoefjeMeta.model_validate_json(get_dummy_data("webpage-analysis.json")) + + mock_response = Response() + mock_response._content = bytes(get_dummy_data("download_body")) + mock_response.request = mocker.MagicMock(spec=PreparedRequest()) + mock_response.request.url = "" + mock_response.request.method = "GET" + mock_response.headers = CaseInsensitiveDict(json.loads(get_dummy_data("download_headers.json"))) + + do_request_mock.return_value = mock_response + + output = boefje_runner.run(meta, {}) + + assert "openkat-http/response" in output[0][0] + assert "openkat-http/headers" in output[1][0] + assert "openkat-http/body" in output[2][0] + + +def test_website_analysis_for_image(boefje_runner, mocker): + do_request_mock = mocker.patch("boefjes.plugins.kat_webpage_analysis.main.do_request", spec=Response) + meta = BoefjeMeta.model_validate_json(get_dummy_data("webpage-analysis.json")) + + mock_response = Response() + mock_response._content = bytes(get_dummy_data("cat_image")) + mock_response.request = mocker.MagicMock(spec=PreparedRequest()) + mock_response.request.url = "" + mock_response.request.method = "GET" + mock_response.headers = CaseInsensitiveDict(json.loads(get_dummy_data("download_image_headers.json"))) + + do_request_mock.return_value = mock_response + + output = boefje_runner.run(meta, {}) + assert "image/jpeg" in output[2][0] + + +def test_body_image_normalizer(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("bodyimage-normalize.json")) + output = normalizer_runner.run(meta, get_dummy_data("cat_image")).observations[0].results + + assert len(output) == 1 + assert { + "object_type": "ImageMetadata", + "primary_key": "ImageMetadata|internet|134.209.85.72|tcp|443|https|internet" + "|mispo.es|https|internet|mispo.es|443|/", + "resource": "HTTPResource|internet|134.209.85.72|tcp|443|https|internet" + "|mispo.es|https|internet|mispo.es|443|/", + "scan_profile": None, + "user_id": None, + "image_info": { + "format": "JPEG", + "frames": 1, + "height": 600, + "is_animated": False, + "mode": "RGB", + "size": (600, 600), + "width": 600, + }, + } == output[0].dict() + + +def test_body_normalizer(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("body-normalize.json")) + output = normalizer_runner.run(meta, get_dummy_data("download_body")).observations[0].results + + assert len(output) == 4 + + output_dicts = sorted([o.dict() for o in output], key=lambda x: x["primary_key"]) + + assert output_dicts[0]["primary_key"] == "URL|internet|http://placekitten.com/600/600" + assert output_dicts[1]["primary_key"] == "URL|internet|http://placekitten.com/600/600.webp" + assert output_dicts[2]["primary_key"] == "URL|internet|https://mispo.es/600/600" + assert output_dicts[3]["primary_key"] == "URL|internet|https://mispo.es/600/600.webp" diff --git a/boefjes/tests/plugins/test_calvin.py b/boefjes/tests/plugins/test_calvin.py new file mode 100644 index 00000000000..46d07957702 --- /dev/null +++ b/boefjes/tests/plugins/test_calvin.py @@ -0,0 +1,126 @@ +from boefjes.job_models import NormalizerMeta +from octopoes.models.ooi.monitoring import Application +from tests.loading import get_dummy_data + + +def test_parse_user_changed(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) + output = normalizer_runner.run(meta, get_dummy_data("user-changed.json")) + + assert len(output.declarations) == 8 + assert { + "application": Application(name="organisation/env/app").reference, + "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1655979300000', + "event_title": "UC: User privilege monitoring", + "event_type": "ksql-usecase", + "meta_data": { + "_id": "62b43a6e69c14474a3773f8b", + "log_action_code": "U", + "log_count": 9.0, + "log_routing_key": "test_app.account_change", + "log_user_user_id": 1234.0, + "outbox_sent": None, + "windowKey": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1655979300000', + "window_emit": 1655978930000.0, + "window_end": 1655979300000.0, + "window_start": 1655975700000.0, + }, + "object_type": "Incident", + "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' + '"log_user_user_id":1234}-1655979300000', + "scan_profile": None, + "user_id": None, + "severity": "MEDIUM", + } == output.declarations[1].ooi.dict() + + assert { + "application": Application(name="organisation/env/app").reference, + "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658825100000', + "event_title": "UC: User privilege monitoring", + "event_type": "ksql-usecase", + "meta_data": { + "_id": "62df9e499dd2b029d842576d", + "log_action_code": "U", + "log_count": 4.0, + "log_routing_key": "test_app.account_change", + "log_user_user_id": 1234.0, + "outbox_sent": None, + "windowKey": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658825100000', + "window_emit": 1658822215000.0, + "window_end": 1658825100000.0, + "window_start": 1658821500000.0, + }, + "object_type": "Incident", + "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' + '"log_user_user_id":1234}-1658825100000', + "scan_profile": None, + "user_id": None, + "severity": "MEDIUM", + } == output.declarations[-1].ooi.dict() + + +def test_parse_admin_login_failure(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) + output = normalizer_runner.run(meta, get_dummy_data("user-login-admin-failure.json")) + + assert len(output.declarations) == 8 + assert { + "application": Application(name="organisation/env/app").reference, + "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1659618600000', + "event_title": "UC: Detect brute force login attempts for an admin account", + "event_type": "ksql-usecase", + "meta_data": { + "_id": "62ebc44c9dd2b029d84ac32a", + "log_action_code": "E", + "log_count": 3.0, + "log_object_result": 0.0, + "log_routing_key": "test_app.user_login", + "log_user_roles": "ADMIN,REGISTRATOR,SHIFT_MANAGER,CSV,KVTB_ADMIN,STATS", + "log_user_user_id": 1234.0, + "outbox_sent": True, + "windowKey": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1659618600000', + "window_emit": 1659618378000.0, + "window_end": 1659618600000.0, + "window_start": 1659617700000.0, + }, + "object_type": "Incident", + "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' + '"log_user_user_id":1234}-1659618600000', + "scan_profile": None, + "user_id": None, + "severity": "MEDIUM", + } == output.declarations[1].ooi.dict() + + +def test_parse_user_login_failure(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) + output = normalizer_runner.run(meta, get_dummy_data("user-login-failure.json")) + + assert len(output.declarations) == 8 + assert { + "application": Application(name="organisation/env/app").reference, + "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658998200000', + "event_title": "UC: Detects attempts to guess passwords", + "event_type": "ksql-usecase", + "meta_data": { + "_id": "62e24d509dd2b029d84391fb", + "log_action_code": "E", + "log_count": 10.0, + "log_object_result": 0.0, + "log_object_user_id": None, + "log_result": None, + "log_routing_key": "test_app.user_login", + "log_user_user_id": 1234.0, + "outbox_sent": None, + "windowKey": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658998200000', + "window_emit": 1658998093000.0, + "window_end": 1658998200000.0, + "window_start": 1658996400000.0, + }, + "object_type": "Incident", + "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' + '"log_user_user_id":1234}-1658998200000', + "scan_profile": None, + "user_id": None, + "severity": "MEDIUM", + } == output.declarations[1].ooi.dict() diff --git a/boefjes/tests/plugins/test_cve-2023-35078.py b/boefjes/tests/plugins/test_cve-2023-35078.py new file mode 100644 index 00000000000..589b1e81339 --- /dev/null +++ b/boefjes/tests/plugins/test_cve-2023-35078.py @@ -0,0 +1,45 @@ +from boefjes.plugins.kat_cve_2023_35078.normalize import VULNERABLE_RANGES, is_vulnerable_version, run +from packaging import version +from tests.loading import get_dummy_data + + +def test_vulnerable_version_11_8(): + detected_version = version.parse("11.8.0.0") + vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] + assert is_vulnerable_version(vulnerable_ranges, detected_version) is True + + +def test_vulnerable_version_11_9(): + detected_version = version.parse("11.9.1.0") + vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] + assert is_vulnerable_version(vulnerable_ranges, detected_version) is True + + +def test_vulnerable_version_11_10(): + detected_version = version.parse("11.10.0.1") + vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] + assert is_vulnerable_version(vulnerable_ranges, detected_version) is True + + +def test_patched_version_11_9(): + detected_version = version.parse("11.9.2.0") + vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] + assert is_vulnerable_version(vulnerable_ranges, detected_version) is False + + +def test_equal_to_patched_version_11_9(): + detected_version = version.parse("11.9.1.1") + vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] + assert is_vulnerable_version(vulnerable_ranges, detected_version) is False + + +def test_cve_2023_35078_vulnerable(mocker): + oois = set(run(mocker.MagicMock(), get_dummy_data("cve_2023_35078_vulnerable.html"))) + + assert any(ooi.object_type == "Finding" for ooi in oois) + + +def test_cve_2023_35078_not_vulnerable(mocker): + oois = set(run(mocker.MagicMock(), get_dummy_data("cve_2023_35078_not_vulnerable.html"))) + + assert not any(ooi.object_type == "Finding" for ooi in oois) diff --git a/boefjes/tests/test_cve-2024-6387.py b/boefjes/tests/plugins/test_cve-2024-6387.py similarity index 100% rename from boefjes/tests/test_cve-2024-6387.py rename to boefjes/tests/plugins/test_cve-2024-6387.py diff --git a/boefjes/tests/plugins/test_cve_finding_types.py b/boefjes/tests/plugins/test_cve_finding_types.py new file mode 100644 index 00000000000..c6a53152193 --- /dev/null +++ b/boefjes/tests/plugins/test_cve_finding_types.py @@ -0,0 +1,87 @@ +from boefjes.job_models import NormalizerAffirmation +from boefjes.plugins.kat_cve_finding_types.normalize import run +from octopoes.models.ooi.findings import RiskLevelSeverity +from octopoes.models.types import CVEFindingType +from tests.loading import get_dummy_data + + +def test_cve_with_cvss(): + input_ooi = {"id": "CVE-2021-46882"} + + oois = list( + run( + input_ooi, + get_dummy_data("inputs/cve-result-with-cvss.json"), + ) + ) + + expected = [ + NormalizerAffirmation( + ooi=CVEFindingType( + id="CVE-2021-46882", + description="The video framework has memory overwriting caused by addition overflow. " + "Successful exploitation of this vulnerability may affect availability.", + source="https://cve.circl.lu/cve/CVE-2021-46882", + risk_severity=RiskLevelSeverity.HIGH, + risk_score=7.5, + ) + ) + ] + + assert expected == oois + + +def test_cve_with_cvss2(): + input_ooi = {"id": "CVE-2016-0616"} + + oois = list( + run( + input_ooi, + get_dummy_data("inputs/cve-result-with-cvss2.json"), + ) + ) + + expected = [ + NormalizerAffirmation( + ooi=CVEFindingType( + id="CVE-2016-0616", + description="Unspecified vulnerability in Oracle MySQL 5.5.46 and earlier and MariaDB before " + "5.5.47, 10.0.x before 10.0.23, and 10.1.x before 10.1.10 allows remote authenticated users " + "to affect availability via unknown vectors related to Optimizer.", + source="https://cve.circl.lu/cve/CVE-2016-0616", + risk_severity=RiskLevelSeverity.MEDIUM, + risk_score=4.0, + ) + ) + ] + + assert expected == oois + + +def test_cve_without_cvss(): + input_ooi = {"id": "CVE-2021-46882"} + + oois = list( + run( + input_ooi, + get_dummy_data("inputs/cve-result-without-cvss.json"), + ) + ) + + expected = [ + NormalizerAffirmation( + ooi=CVEFindingType( + id="CVE-2021-46882", + description="The Nested Pages plugin for WordPress is vulnerable to unauthorized loss of " + "data due to a missing capability check on the 'reset' function in versions up to, and including, " + "3.2.3. This makes it possible for authenticated attackers, " + "with editor-level permissions and above, " + "to reset plugin settings.", + source="https://cve.circl.lu/cve/CVE-2021-46882", + risk_severity=RiskLevelSeverity.UNKNOWN, + risk_score=None, + ), + ) + ] + + assert expected == oois diff --git a/boefjes/tests/plugins/test_dns.py b/boefjes/tests/plugins/test_dns.py new file mode 100644 index 00000000000..063b666664d --- /dev/null +++ b/boefjes/tests/plugins/test_dns.py @@ -0,0 +1,480 @@ +import uuid +from ipaddress import IPv4Address, IPv6Address + +import pytest +from pydantic import BaseModel + +from boefjes.job_models import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, ObservationsWithoutInputOOI, RawDataMeta +from octopoes.models import Reference +from octopoes.models.ooi.dns.records import ( + DNSAAAARecord, + DNSARecord, + DNSCNAMERecord, + DNSMXRecord, + DNSNSRecord, + DNSSOARecord, + DNSTXTRecord, +) +from octopoes.models.ooi.dns.zone import DNSZone, Hostname +from octopoes.models.ooi.network import IPAddressV4, IPAddressV6, Network +from tests.loading import get_dummy_data + + +def test_dns_normalizer(normalizer_runner): + internet = Network(name="internet") + + zone_hostname = Hostname(name="example.nl", network=internet.reference) + zone = DNSZone(hostname=zone_hostname.reference) + zone_hostname.dns_zone = zone.reference + + ip_v4_addresses = [ + IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")), + IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.36")), + ] + dns_a_records = [ + DNSARecord( + hostname=zone_hostname.reference, + value=str(ip.address), + address=ip.reference, + ttl=14364, + ) + for ip in ip_v4_addresses + ] + ip_v6_addresses = [ + IPAddressV6( + network=internet.reference, + address=IPv6Address("2a00:d78:0:712:94:198:159:35"), + ), + IPAddressV6( + network=internet.reference, + address=IPv6Address("2a00:d78:0:712:94:198:159:36"), + ), + ] + dns_aaaa_records = [ + DNSAAAARecord( + hostname=zone_hostname.reference, + value=str(ip.address), + address=ip.reference, + ttl=14400, + ) + for ip in ip_v6_addresses + ] + dns_txt_records = [ + DNSTXTRecord( + hostname=zone_hostname.reference, + value="v=spf1 redirect=spf-a.example.nl", + ttl=14400, + ) + ] + + mx_hostnames = [ + Hostname( + network=internet.reference, + name="mail.example.nl", + ), + Hostname( + network=internet.reference, + name="mail2.example.nl", + ), + ] + dns_mx_records = [ + DNSMXRecord( + hostname=zone_hostname.reference, + value=f"10 {mx_rec.name}.", + ttl=14400, + mail_hostname=mx_rec.reference, + preference=10, + ) + for mx_rec in mx_hostnames + ] + + ns_hostnames = [ + Hostname(name=value, network=internet.reference) + for value in [ + "ns3.examplenl.org", + "ns1.examplenl.nl", + "ns2.examplenl.eu", + "ns0.examplenl.com", + ] + ] + + ns_records = [ + DNSNSRecord( + hostname=zone_hostname.reference, + value=ns_hostname.name + ".", + name_server_hostname=ns_hostname.reference, + ttl=2634, + ) + for ns_hostname in ns_hostnames + ] + + soa_hostname = Hostname( + network=internet.reference, + name="ns1.examplenl.nl", + dns_zone=zone.reference, + ) + soa_record = DNSSOARecord( + hostname=zone_hostname.reference, + value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", + soa_hostname=soa_hostname.reference, + ttl=14340, + serial=2021111101, + retry=7200, + refresh=14400, + expire=1209600, + minimum=86400, + ) + + # noinspection PyTypeChecker + expected = ( + [zone_hostname, zone] + + ip_v4_addresses + + dns_a_records + + ip_v6_addresses + + dns_aaaa_records + + dns_txt_records + + mx_hostnames + + dns_mx_records + + ns_hostnames + + ns_records + + [soa_record] + ) + + meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) + results = normalizer_runner.run(meta, get_dummy_data("inputs/dns-result-example.nl.json")) + + assert len(results.observations) == 1 + assert len(list(map(BaseModel.model_dump, expected))) == len( + list(map(BaseModel.model_dump, results.observations[0].results)) + ) + + +def test_dns_normalizer_cname(normalizer_runner): + internet = Network(name="internet") + + zone_hostname = Hostname( + network=internet.reference, + name="example.nl", + ) + zone = DNSZone( + hostname=zone_hostname.reference, + ) + zone_hostname.dns_zone = zone.reference + + input_hostname = Hostname( + network=internet.reference, + name="www.example.nl", + dns_zone=zone.reference, + ) + cname_target = Hostname( + network=internet.reference, + name="webredir.examplenl.nl", + ) + + soa_hostname = Hostname(network=internet.reference, name="ns1.examplenl.nl") + soa_record = DNSSOARecord( + hostname=zone_hostname.reference, + value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", + ttl=14340, + soa_hostname=soa_hostname.reference, + serial=2021111101, + refresh=14400, + retry=7200, + expire=1209600, + minimum=86400, + ) + + cname_record = DNSCNAMERecord( + hostname=input_hostname.reference, + value=cname_target.name + ".", + ttl=10800, + target_hostname=cname_target.reference, + ) + + ip_address = IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")) + dns_a_record = DNSARecord( + hostname=cname_target.reference, + address=ip_address.reference, + value=str(ip_address.address), + ttl=10800, + ) + + expected = [ + zone, + zone_hostname, + soa_hostname, + soa_record, + cname_target, + cname_record, + ip_address, + dns_a_record, + input_hostname, + ] + + meta = NormalizerMeta( + id=uuid.UUID("72c7d302-0d6f-407a-aaec-9ffcad0ee7c6"), + normalizer=Normalizer(id="kat_dns_normalize"), + raw_data=RawDataMeta( + id=uuid.UUID("3b8397ba-50e4-476e-834a-2fa2595a43a5"), + boefje_meta=BoefjeMeta( + id=uuid.UUID("10535bba-2715-42f9-be47-ccd985b59eea"), + boefje=Boefje(id="dns-records"), + organization="_dev", + input_ooi="Hostname|internet|www.example.nl", + arguments={ + "domain": "www.example.nl.", + "input": {"name": "www.example.nl."}, + }, + ), + mime_types=[{"value": "boefje/dns-records"}], + ), + ) + + results = normalizer_runner.run(meta, get_dummy_data("inputs/dns-result-www.example.nl.json")) + assert len(list(map(BaseModel.model_dump, expected))) == len( + list(map(BaseModel.model_dump, results.observations[0].results)) + ) + + +def test_parse_record_null_mx_record(normalizer_runner): + meta = NormalizerMeta( + id=uuid.UUID("d7d65462-5ced-4a57-a1d7-c6d2edf38354"), + normalizer=Normalizer(id="kat_dns_normalize"), + raw_data=RawDataMeta( + id=uuid.UUID("94fe3b47-fb41-4ad7-b2de-1bfe63460c98"), + boefje_meta=BoefjeMeta( + id=uuid.UUID("f1e72e47-c11f-47e9-953a-52e3b6833eaf"), + boefje=Boefje(id="dns-records"), + organization="_dev", + input_ooi="Hostname|internet|english.example.nl", + arguments={ + "domain": "english.example.nl", + "input": {"name": "english.example.nl"}, + }, + ), + mime_types=[{"value": "boefje/dns-records"}], + ), + ) + + answer = get_dummy_data("inputs/dns-result-mx-example.nl.json") + + internet = Network(name="internet") + input_hostname = Hostname( + network=internet.reference, + name="english.example.nl", + ) + + cname_target = Hostname(network=internet.reference, name="redir.example.nl") + cname_record = DNSCNAMERecord( + hostname=input_hostname.reference, + value="redir.example.nl.", + ttl=60, + target_hostname=cname_target.reference, + ) + mx_record = DNSMXRecord( + hostname=cname_target.reference, + value="0 .", + ttl=14400, + preference=0, + ) + + results = normalizer_runner.run(meta, answer) + + expected = [cname_target, cname_record, mx_record, input_hostname] + assert len(list(map(BaseModel.model_dump, expected))) == len( + list(map(BaseModel.model_dump, results.observations[0].results)) + ) + + +def test_parse_cname_soa(normalizer_runner): + internet = Network(name="internet") + + zone_hostname = Hostname( + network=internet.reference, + name="example.com", + ) + zone = DNSZone( + hostname=zone_hostname.reference, + ) + zone_hostname.dns_zone = zone.reference + + input_hostname = Hostname( + network=internet.reference, + name="www.example.com", + dns_zone=zone.reference, + ) + + cname_record = DNSCNAMERecord( + hostname=input_hostname.reference, + value="example.com.", + ttl=60, + target_hostname=zone_hostname.reference, + ) + ip_address = IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")) + a_record = DNSARecord( + hostname=zone_hostname.reference, + address=ip_address.reference, + value=str(ip_address.address), + ttl=60, + ) + soa_hostname = Hostname(network=internet.reference, name="ns.icann.org") + ns_hostnames = [ + Hostname(name=value, network=internet.reference) + for value in [ + "a.iana-servers.net", + "b.iana-servers.net", + ] + ] + ns_records = [ + DNSNSRecord( + hostname=zone_hostname.reference, + value=ns_hostname.name + ".", + name_server_hostname=ns_hostname.reference, + ttl=60, + ) + for ns_hostname in ns_hostnames + ] + soa_record = DNSSOARecord( + hostname=zone_hostname.reference, + value="ns.icann.org. noc.dns.icann.org. 2022040432 7200 3600 1209600 3600", + ttl=21, + soa_hostname=soa_hostname.reference, + serial=2022040432, + retry=3600, + refresh=7200, + expire=1209600, + minimum=3600, + ) + txt_record = DNSTXTRecord( + hostname=zone_hostname.reference, + value="v=spf1 -all", + ttl=60, + ) + mx_record = DNSMXRecord( + hostname=zone_hostname.reference, + value="0 example.com.", + ttl=60, + mail_hostname=zone_hostname.reference, + preference=0, + ) + + meta = NormalizerMeta( + id=uuid.UUID("a2a85d54-a6ce-495d-b7a5-23c1a79f4cec"), + normalizer=Normalizer(id="kat_dns_normalize"), + raw_data=RawDataMeta( + id=uuid.UUID("ac481bc2-a524-4dcc-91a4-28ed9c2c142b"), + boefje_meta=BoefjeMeta( + id=uuid.UUID("0671b9ac-1624-4c09-a94a-4f9edbc40064"), + boefje=Boefje(id="dns-records"), + organization="_dev", + input_ooi="Hostname|internet|www.example.com", + arguments={ + "domain": "www.example.com", + "input": {"name": "www.example.com"}, + }, + ), + mime_types=[{"value": "boefje/dns-records"}], + ), + ) + + results = normalizer_runner.run(meta, get_dummy_data("inputs/dns-result-example.com-cnames.json")) + + expected = ( + [ + zone, + zone_hostname, + cname_record, + ip_address, + a_record, + soa_record, + txt_record, + mx_record, + input_hostname, + soa_hostname, + ] + + ns_hostnames + + ns_records + ) + assert len(list(map(BaseModel.model_dump, expected))) == len( + list(map(BaseModel.model_dump, results.observations[0].results)) + ) + + +def test_find_parent_dns_zone(normalizer_runner): + internet = Network(name="internet") + + requested_zone = DNSZone( + hostname=Hostname( + network=internet.reference, + name="sub.example.nl", + ).reference + ) + parent_zone_hostname = Hostname( + network=internet.reference, + name="example.nl", + ) + parent_zone = DNSZone(hostname=parent_zone_hostname.reference) + parent_zone_hostname.dns_zone = parent_zone.reference + + requested_zone.parent = parent_zone.reference + + name_server_hostname = Hostname( + network=internet.reference, + name="ns1.examplenl.nl", + ) + + soa_record = DNSSOARecord( + hostname=parent_zone_hostname.reference, + value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", + ttl=14340, + soa_hostname=name_server_hostname.reference, + serial=2021111101, + retry=7200, + refresh=14400, + expire=1209600, + minimum=86400, + ) + + input_ = DNSZone( + hostname=Hostname( + network=Reference.from_str("Network|internet"), + name="sub.example.nl", + ).reference + ).serialize() + + meta = NormalizerMeta( + id=uuid.UUID("ee8374bb-e79f-4083-9ce9-add4f96006f2"), + normalizer=Normalizer(id="kat_dns_zone_normalize"), + raw_data=RawDataMeta( + id=uuid.UUID("2147da2a-921c-4c51-aef3-fa82d8d6e089"), + boefje_meta=BoefjeMeta( + id=uuid.UUID("ff1f0d62-a2e0-480f-8b11-5fb24974edce"), + boefje=Boefje(id="dns-records"), + organization="_dev", + input_ooi="DnsZone|internet|sub.example.nl", + arguments={"input": input_}, + ), + mime_types=[{"value": "boefje/dns-records"}], + ), + ) + + results = normalizer_runner.run(meta, get_dummy_data("inputs/dns-zone-result-sub.example.nl.txt")) + + expected = [ + requested_zone, + parent_zone, + parent_zone_hostname, + name_server_hostname, + soa_record, + ] + assert len(list(map(BaseModel.model_dump, expected))) == len( + list(map(BaseModel.model_dump, results.observations[0].results)) + ) + + +def test_exception_raised_no_input_ooi(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) + meta.raw_data.boefje_meta.input_ooi = None + + with pytest.raises(ObservationsWithoutInputOOI): + normalizer_runner.run(meta, get_dummy_data("inputs/dns-result-example.nl.json")) diff --git a/boefjes/tests/test_dnssec.py b/boefjes/tests/plugins/test_dnssec.py similarity index 100% rename from boefjes/tests/test_dnssec.py rename to boefjes/tests/plugins/test_dnssec.py diff --git a/boefjes/tests/test_fierce.py b/boefjes/tests/plugins/test_fierce.py similarity index 100% rename from boefjes/tests/test_fierce.py rename to boefjes/tests/plugins/test_fierce.py diff --git a/boefjes/tests/plugins/test_generic_finding_normalizer.py b/boefjes/tests/plugins/test_generic_finding_normalizer.py new file mode 100644 index 00000000000..28fbbf7e51c --- /dev/null +++ b/boefjes/tests/plugins/test_generic_finding_normalizer.py @@ -0,0 +1,44 @@ +from boefjes.plugins.kat_finding_normalizer.normalize import run +from octopoes.models import Reference +from octopoes.models.ooi.findings import KATFindingType +from octopoes.models.types import CVEFindingType, Finding + + +def test_single(): + input_ooi = {"primary_key": "Network|internet"} + + oois = list(run(input_ooi, b"CVE-2021-00000")) + + expected = [ + CVEFindingType(id="CVE-2021-00000"), + Finding( + finding_type=CVEFindingType(id="CVE-2021-00000").reference, + ooi=Reference.from_str("Network|internet"), + description="CVE-2021-00000 is found on this OOI", + ), + ] + + assert expected == oois + + +def test_multiple(): + input_ooi = {"primary_key": "Network|internet"} + + oois = list(run(input_ooi, b"CVE-2021-00000, KAT-MOCK-FINDING")) + + expected = [ + CVEFindingType(id="CVE-2021-00000"), + Finding( + finding_type=CVEFindingType(id="CVE-2021-00000").reference, + ooi=Reference.from_str("Network|internet"), + description="CVE-2021-00000 is found on this OOI", + ), + KATFindingType(id="KAT-MOCK-FINDING"), + Finding( + finding_type=KATFindingType(id="KAT-MOCK-FINDING").reference, + ooi=Reference.from_str("Network|internet"), + description="KAT-MOCK-FINDING is found on this OOI", + ), + ] + + assert expected == oois diff --git a/boefjes/tests/plugins/test_leakix.py b/boefjes/tests/plugins/test_leakix.py new file mode 100644 index 00000000000..2d964069bbf --- /dev/null +++ b/boefjes/tests/plugins/test_leakix.py @@ -0,0 +1,24 @@ +from pydantic import parse_obj_as + +from boefjes.plugins.kat_leakix.normalize import run +from octopoes.models.types import OOIType +from tests.loading import get_dummy_data + + +def test_output(): + input_ooi = parse_obj_as( + OOIType, + { + "object_type": "HostnameHTTPURL", + "network": "Network|internet", + "scheme": "https", + "port": 443, + "path": "/", + "netloc": "Hostname|internet|example.com", + }, + ) + + output = [x for x in run(input_ooi.serialize(), get_dummy_data("raw/leakix-example.com.json"))] + + assert len(output) == 170 + assert str(output) == get_dummy_data("raw/leakix-example.com-output.txt").decode().strip() diff --git a/boefjes/tests/plugins/test_manual.py b/boefjes/tests/plugins/test_manual.py new file mode 100644 index 00000000000..4efe64e577d --- /dev/null +++ b/boefjes/tests/plugins/test_manual.py @@ -0,0 +1,168 @@ +from pathlib import Path + +from pydantic_core import Url + +from boefjes.job_models import NormalizerMeta, NormalizerResults +from boefjes.local import LocalNormalizerJobRunner +from boefjes.local_repository import LocalPluginRepository +from octopoes.models import Reference +from tests.loading import get_dummy_data + +TEST_DECLARATIONS_DATA = ( + b"[" + b'{"ooi": {"object_type": "Network", "scan_profile": null, "user_id": null\ + , "primary_key": "Network|net1", "name": "net1"}},' + b'{"ooi": {"object_type": "Network", "scan_profile": null, "user_id": null\ + , "primary_key": "Network|net2", "name": "net2"}}' + b"]" +) +CSV_EXAMPLES = [ + # hostname + b"name,network\nexample.com,internet", + # hostname without network + b"name\nexample.net", + # ipv4s + b"""address,network +1.1.1.1,internet +2.2.2.2,internet +3.3.3.3,darknet""", + # ipv6s + b"""address,network +FE80:CD00:0000:0CDE:1257:0000:211E:729C,internet +FE80:CD00:0000:0CDE:1257:0000:211E:729D,darknet""", + # urls + b"""network,raw +internet,https://example.com/ +darknet,https://openkat.nl/""", + # url without network + b"raw\nhttps://example.com/", +] + + +def test_parse_manual_declarations(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("manual-ooi.json")) + output = normalizer_runner.run(meta, TEST_DECLARATIONS_DATA) + + assert len(output.declarations) == 2 + assert len(output.observations) == 0 + + assert { + "name": "net1", + "object_type": "Network", + "primary_key": "Network|net1", + "scan_profile": None, + "user_id": None, + } == output.declarations[0].ooi.dict() + assert { + "name": "net2", + "object_type": "Network", + "primary_key": "Network|net2", + "scan_profile": None, + "user_id": None, + } == output.declarations[1].ooi.dict() + + +def test_parse_manual_hostname_csv(normalizer_runner): + meta, output, runner = check_network_created(normalizer_runner, 0) + + assert len(output.declarations) == 2 + assert { + "dns_zone": None, + "name": "example.com", + "network": Reference("Network|internet"), + "object_type": "Hostname", + "primary_key": "Hostname|internet|example.com", + "registered_domain": None, + "scan_profile": None, + "user_id": None, + } == output.declarations[1].ooi.dict() + + meta, output, runner = check_network_created(normalizer_runner, 1) + + assert len(output.declarations) == 2 + assert { + "dns_zone": None, + "name": "example.net", + "network": Reference("Network|internet"), + "object_type": "Hostname", + "primary_key": "Hostname|internet|example.net", + "registered_domain": None, + "scan_profile": None, + "user_id": None, + } == output.declarations[1].ooi.dict() + + +def test_parse_manual_ip_csv(normalizer_runner): + meta, output, runner = check_network_created(normalizer_runner, 2) + assert len(output.declarations) == 6 + assert { + "address": "1.1.1.1", + "netblock": None, + "network": Reference("Network|internet"), + "object_type": "IPAddressV4", + "primary_key": "IPAddressV4|internet|1.1.1.1", + "scan_profile": None, + "user_id": None, + } == output.declarations[1].ooi.dict() + + meta, output, runner = check_network_created(normalizer_runner, 3) + assert { + "address": "fe80:cd00:0:cde:1257:0:211e:729c", + "netblock": None, + "network": Reference("Network|internet"), + "object_type": "IPAddressV6", + "primary_key": "IPAddressV6|internet|fe80:cd00:0:cde:1257:0:211e:729c", + "scan_profile": None, + "user_id": None, + } == output.declarations[1].ooi.dict() + + +def test_parse_url_csv(normalizer_runner): + meta, output, runner = check_network_created(normalizer_runner, 4) + assert len(output.declarations) == 4 + + assert { + "network": Reference("Network|internet"), + "object_type": "URL", + "primary_key": "URL|internet|https://example.com/", + "raw": Url( + "https://example.com/", + ), + "scan_profile": None, + "user_id": None, + "web_url": None, + } == output.declarations[1].ooi.model_dump() + + meta, output, runner = check_network_created(normalizer_runner, 5) + assert len(output.declarations) == 2 + assert { + "network": Reference("Network|internet"), + "object_type": "URL", + "primary_key": "URL|internet|https://example.com/", + "raw": Url( + "https://example.com/", + ), + "scan_profile": None, + "user_id": None, + "web_url": None, + } == output.declarations[1].ooi.dict() + + +def check_network_created( + normalizer_runner, csv_idx: int +) -> tuple[NormalizerMeta, NormalizerResults, LocalNormalizerJobRunner]: + meta = NormalizerMeta.model_validate_json(get_dummy_data("manual-csv.json")) + local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") + runner = LocalNormalizerJobRunner(local_repository) + output = normalizer_runner.run(meta, CSV_EXAMPLES[csv_idx]) + + assert len(output.observations) == 0 + assert { + "name": "internet", + "object_type": "Network", + "primary_key": "Network|internet", + "scan_profile": None, + "user_id": None, + } == output.declarations[0].ooi.dict() + + return meta, output, runner diff --git a/boefjes/tests/test_nmap.py b/boefjes/tests/plugins/test_nmap.py similarity index 81% rename from boefjes/tests/test_nmap.py rename to boefjes/tests/plugins/test_nmap.py index f936160f910..76e6c8159ca 100644 --- a/boefjes/tests/test_nmap.py +++ b/boefjes/tests/plugins/test_nmap.py @@ -33,44 +33,44 @@ def get_pattern(): return re.compile(one_or_comma_separated) -def test_single_port_pattern(local_repo): - schema = local_repo.schema("nmap-ports") +def test_single_port_pattern(local_repository): + schema = local_repository.schema("nmap-ports") for single_port in ["1", "2", "20", "200", "2000", "20000", "65535"]: assert get_pattern().search(single_port) is not None validate(instance={"PORTS": single_port}, schema=schema) -def test_bad_single_port_pattern(local_repo): - schema = local_repo.schema("nmap-ports") +def test_bad_single_port_pattern(local_repository): + schema = local_repository.schema("nmap-ports") for bad_single_port in ["-1", "-2000", "65536", "222222"]: assert get_pattern().search(bad_single_port) is None with pytest.raises(ValidationError): validate(instance={"PORTS": bad_single_port}, schema=schema) -def test_multi_ports_pattern(local_repo): - schema = local_repo.schema("nmap-ports") +def test_multi_ports_pattern(local_repository): + schema = local_repository.schema("nmap-ports") for multi_port in ["1,2", "2,3,4", "2,3,4,5,6,7", "2,20,200,2000,65535"]: assert get_pattern().search(multi_port) is not None validate(instance={"PORTS": multi_port}, schema=schema) -def test_port_range_pattern(local_repo): - schema = local_repo.schema("nmap-ports") +def test_port_range_pattern(local_repository): + schema = local_repository.schema("nmap-ports") for port_range in ["1-2", "2-20000", "65533-65535"]: assert get_pattern().search(port_range) is not None validate(instance={"PORTS": port_range}, schema=schema) -def test_combined(local_repo): - schema = local_repo.schema("nmap-ports") +def test_combined(local_repository): + schema = local_repository.schema("nmap-ports") for port_range in ["1,1-65000", "1,2,234,4300-5999,1"]: assert get_pattern().search(port_range) is not None validate(instance={"PORTS": port_range}, schema=schema) -def test_badly_combined(local_repo): - schema = local_repo.schema("nmap-ports") +def test_badly_combined(local_repository): + schema = local_repository.schema("nmap-ports") for port_range in ["1,1-", "1-234-323"]: assert get_pattern().search(port_range) is None with pytest.raises(ValidationError): diff --git a/boefjes/tests/test_rdns.py b/boefjes/tests/plugins/test_rdns.py similarity index 100% rename from boefjes/tests/test_rdns.py rename to boefjes/tests/plugins/test_rdns.py diff --git a/boefjes/tests/test_report_data.py b/boefjes/tests/plugins/test_report_data.py similarity index 63% rename from boefjes/tests/test_report_data.py rename to boefjes/tests/plugins/test_report_data.py index d8a8ed591ed..beda0a2f069 100644 --- a/boefjes/tests/test_report_data.py +++ b/boefjes/tests/plugins/test_report_data.py @@ -1,19 +1,14 @@ import json -from pathlib import Path from boefjes.job_models import NormalizerDeclaration, NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository from tests.loading import get_dummy_data -def test_report_data(): - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) +def test_report_data(normalizer_runner): meta = NormalizerMeta.model_validate_json(get_dummy_data("report-data-normalize.json")) raw = get_dummy_data("report-data.json") - output = runner.run(meta, raw) + output = normalizer_runner.run(meta, raw) ooi_dict = json.loads(raw) declaration = NormalizerDeclaration( diff --git a/boefjes/tests/plugins/test_scan_profiles.py b/boefjes/tests/plugins/test_scan_profiles.py new file mode 100644 index 00000000000..2c52709f2e0 --- /dev/null +++ b/boefjes/tests/plugins/test_scan_profiles.py @@ -0,0 +1,73 @@ +import json +import os + +import pytest +from pydantic import ValidationError + +from boefjes.config import Settings +from boefjes.job_handler import NormalizerHandler +from boefjes.job_models import NormalizerMeta +from octopoes.models import DeclaredScanProfile +from tests.loading import get_dummy_data + +RAW_DATA = json.dumps( + {"ip_addresses": [{"address": "127.0.0.1"}, {"address": "10.0.0.0"}], "domains": [{"name": "example.com"}]} +) + + +def test_normalizer_can_yield_scan_profiles(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("external_db.json")) + output = normalizer_runner.run(meta, bytes(RAW_DATA, "UTF-8")) + + assert len(output.observations) == 1 + assert len(output.observations[0].results) == 3 + assert len(output.scan_profiles) == 3 + + profile = output.scan_profiles[0] + assert isinstance(profile, DeclaredScanProfile) + assert profile.reference == "IPAddressV4|internet|127.0.0.1" + assert profile.level == 3 + + profile = output.scan_profiles[1] + assert isinstance(profile, DeclaredScanProfile) + assert profile.reference == "IPAddressV4|internet|10.0.0.0" + assert profile.level == 3 + + profile = output.scan_profiles[2] + assert isinstance(profile, DeclaredScanProfile) + assert profile.reference == "Hostname|internet|example.com" + assert profile.level == 3 + + +def test_job_handler_respects_whitelist(normalizer_runner, mocker): + bytes_mock = mocker.Mock() + bytes_mock.get_raw.return_value = RAW_DATA + octopoes = mocker.Mock() + + meta = NormalizerMeta.model_validate_json(get_dummy_data("external_db.json")) + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": 5}' + with pytest.raises(ValidationError): + Settings() + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": -1}' + with pytest.raises(ValidationError): + Settings() + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": 3}' + NormalizerHandler(normalizer_runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) + assert octopoes.save_many_scan_profiles.call_count == 0 + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 2}' + NormalizerHandler(normalizer_runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) + assert octopoes.save_many_scan_profiles.call_count == 1 + assert octopoes.save_many_scan_profiles.call_args[0][0][0].level == 2 + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 3}' + NormalizerHandler(normalizer_runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) + assert octopoes.save_many_scan_profiles.call_count == 2 + assert octopoes.save_many_scan_profiles.call_args[0][0][0].level == 3 + + os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 4, "abc": 0}' + NormalizerHandler(normalizer_runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) + assert octopoes.save_many_scan_profiles.call_count == 3 diff --git a/boefjes/tests/plugins/test_security_txt.py b/boefjes/tests/plugins/test_security_txt.py new file mode 100644 index 00000000000..f6be6bd8623 --- /dev/null +++ b/boefjes/tests/plugins/test_security_txt.py @@ -0,0 +1,89 @@ +from boefjes.plugins.kat_security_txt_downloader.normalize import run +from octopoes.models import Reference +from octopoes.models.ooi.dns.zone import Hostname +from octopoes.models.ooi.network import IPAddressV4, IPPort, Network +from octopoes.models.ooi.service import IPService, Service +from octopoes.models.ooi.web import URL, SecurityTXT, Website +from tests.loading import get_dummy_data + +input_ooi = { + "object_type": "Website", + "scan_profile": "scan_profile_type='declared' " + "reference=Reference('Website|internet|192.0.2.0|tcp|443|https|internet|example.com') level=", + "primary_key": "Website|internet|192.0.2.0|tcp|443|https|internet|example.com", + "ip_service": { + "ip_port": { + "address": {"network": {"name": "internet"}, "address": "192.0.2.0"}, + "protocol": "tcp", + "port": "443", + }, + "service": {"name": "https"}, + }, + "hostname": {"network": {"name": "internet"}, "name": "example.com"}, + "certificate": "None", +} + + +def test_security_txt_same_website(): + oois = list( + run( + input_ooi, + get_dummy_data("inputs/security_txt_result_same_website.json"), + ) + ) + + expected = [] + expected.append(URL(raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference)) + url = URL(raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference) + expected.append(url) + expected.append( + SecurityTXT( + website=Reference.from_str("Website|internet|192.0.2.0|tcp|443|https|internet|example.com"), + url=url.reference, + security_txt="This is the content", + redirects_to=None, + ) + ) + + assert expected == oois + + +def test_security_txt_different_website(): + oois = list( + run( + input_ooi, + get_dummy_data("inputs/security_txt_result_different_website.json"), + ) + ) + + expected = [] + url_original = URL(raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference) + expected.append(url_original) + url = URL(raw="https://www.example.com/.well-known/security.txt", network=Network(name="internet").reference) + expected.append(url) + expected.append(Hostname(name="www.example.com", network=Network(name="internet").reference)) + ip = IPAddressV4(address="192.0.2.1", network=Network(name="internet").reference) + expected.append(ip) + expected.append(Service(name="https")) + port = IPPort(address=ip.reference, port=443, protocol="tcp") + expected.append(port) + ip_service = IPService(ip_port=port.reference, service=Service(name="https").reference) + expected.append(ip_service) + website = Website( + ip_service=ip_service.reference, + hostname=Hostname(name="www.example.com", network=Network(name="internet").reference).reference, + ) + expected.append(website) + security_txt = SecurityTXT( + website=website.reference, url=url.reference, security_txt="This is the content", redirects_to=None + ) + expected.append(security_txt) + expected.append( + SecurityTXT( + website=Reference.from_str("Website|internet|192.0.2.0|tcp|443|https|internet|example.com"), + url=url_original.reference, + security_txt=None, + redirects_to=security_txt.reference, + ) + ) + assert expected == oois diff --git a/boefjes/tests/plugins/test_snyk.py b/boefjes/tests/plugins/test_snyk.py new file mode 100644 index 00000000000..3a2fa504195 --- /dev/null +++ b/boefjes/tests/plugins/test_snyk.py @@ -0,0 +1,114 @@ +import json +from unittest import mock + +from boefjes.job_models import BoefjeMeta +from boefjes.plugins.kat_snyk.main import run as run_boefje +from boefjes.plugins.kat_snyk.normalize import run +from octopoes.models.ooi.findings import SnykFindingType +from octopoes.models.types import CVEFindingType, Finding, Software +from tests.loading import get_dummy_data + +input_ooi = { + "primary_key": "Software|lodash|1.1.0|", + "software": { + "name": "lodash", + "version": "1.1.0", + }, +} + + +def test_snyk_no_findings(): + assert not list(run(input_ooi, get_dummy_data("inputs/snyk-result-no-findings.json"))) + + +def test_snyk_findings(): + oois = list(run(input_ooi, get_dummy_data("inputs/snyk-result-findings.json"))) + software = Software(name="lodash", version="1.1.0") + + snyk_finding_data = [ + ("SNYK-JS-LODASH-590103", "Prototype Pollution"), + ("SNYK-JS-LODASH-608086", "Prototype Pollution"), + ] + cve_finding_data = [ + ("CVE-2018-16487", "Prototype Pollution"), + ("CVE-2018-3721", "Prototype Pollution"), + ("CVE-2019-1010266", "Regular Expression Denial of Service (ReDoS)"), + ("CVE-2019-10744", "Prototype Pollution"), + ("CVE-2020-28500", "Regular Expression Denial of Service (ReDoS)"), + ("CVE-2020-8203", "Prototype Pollution"), + ("CVE-2021-23337", "Command Injection"), + ] + + snyk_findingtypes = [] + snyk_findings = [] + cve_findingtypes = [] + cve_findings = [] + + for finding in snyk_finding_data: + snyk_ft = SnykFindingType(id=finding[0]) + snyk_findingtypes.append(snyk_ft) + snyk_findings.append( + Finding( + finding_type=snyk_ft.reference, + ooi=software.reference, + description=finding[1], + ) + ) + + for finding in cve_finding_data: + cve_ft = CVEFindingType(id=finding[0]) + cve_findingtypes.append(cve_ft) + cve_findings.append( + Finding( + finding_type=cve_ft.reference, + ooi=software.reference, + description=finding[1], + ) + ) + + # noinspection PyTypeChecker + expected = snyk_findingtypes + snyk_findings + cve_findingtypes + cve_findings + + assert len(expected) == len(oois) + + +def test_snyk_html_parser(mocker): + mock_get = mocker.patch("boefjes.plugins.kat_snyk.main.requests.get") + boefje_meta = BoefjeMeta.model_validate_json(get_dummy_data("snyk-job.json")) + + # Mock the first GET request + mock_first_get = mock.Mock() + mock_first_get.content = get_dummy_data("snyk-vuln.html") + + # Mock the next GET request + mock_second_get = mock.Mock() + mock_second_get.content = get_dummy_data("snyk-vuln2.html") + + # Mock the next 7 GET requests + mock_third_get = mock.Mock() + mock_third_get.content = get_dummy_data("snyk-vuln3.html") + + mock_get.side_effect = [mock_first_get] + [mock_second_get] + [mock_third_get] * 7 + + mime_types, result = run_boefje(boefje_meta)[0] + + output = json.loads(result) + + assert output["table_versions"] == [] + assert output["table_vulnerabilities"] == [ + { + "Vuln_href": "SNYK-JS-LODASH-1018905", + "Vuln_text": "Regular Expression Denial of Service (ReDoS)", + "Vuln_versions": "<4.17.21", + }, + {"Vuln_href": "SNYK-JS-LODASH-608086", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.17"}, + {"Vuln_href": "SNYK-JS-LODASH-450202", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.12"}, + { + "Vuln_href": "SNYK-JS-LODASH-73639", + "Vuln_text": "Regular Expression Denial of Service (ReDoS)", + "Vuln_versions": "<4.17.11", + }, + {"Vuln_href": "SNYK-JS-LODASH-73638", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.11"}, + {"Vuln_href": "npm:lodash:20180130", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.5"}, + ] + assert output["cve_vulnerabilities"] == [{"cve_code": "CVE-2021-23337", "Vuln_text": "Command Injection"}] diff --git a/boefjes/tests/test_sslcertificate_normalizer.py b/boefjes/tests/plugins/test_sslcertificate_normalizer.py similarity index 100% rename from boefjes/tests/test_sslcertificate_normalizer.py rename to boefjes/tests/plugins/test_sslcertificate_normalizer.py diff --git a/boefjes/tests/plugins/test_testssl_sh.py b/boefjes/tests/plugins/test_testssl_sh.py new file mode 100644 index 00000000000..397b5d3884d --- /dev/null +++ b/boefjes/tests/plugins/test_testssl_sh.py @@ -0,0 +1,120 @@ +from boefjes.plugins.kat_testssl_sh_ciphers.normalize import run +from tests.loading import get_dummy_data + +input_ooi = { + "object_type": "IPService", + "scan_profile": "scan_profile_type='declared' " + "reference=Reference('IPService|internet|134.209.85.72|tcp|80|http') level=", + "primary_key": "IPService|internet|134.209.85.72|tcp|80|http", + "ip_port": { + "address": {"network": {"name": "internet"}, "address": "134.209.85.72"}, + "protocol": "tcp", + "port": "80", + }, + "service": {"name": "http"}, +} + + +def test_cipherless_service(): + oois = list( + run( + input_ooi, + get_dummy_data("inputs/testssl-sh-cipherless.json"), + ) + ) + + # noinspection PyTypeChecker + expected = [] + + assert expected == oois + + +def test_ciphered_service(): + oois = list( + run( + input_ooi, + get_dummy_data("inputs/testssl-sh-ciphered.json"), + ) + ) + + # noinspection PyTypeChecker + expected_suites = { + "TLSv1.3": [ + { + "cipher_suite_alias": "TLS_AES_256_GCM_SHA384", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "TLS_AES_256_GCM_SHA384", + "key_size": 253, + "bits": 256, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "x1302", + }, + { + "cipher_suite_alias": "TLS_CHACHA20_POLY1305_SHA256", + "encryption_algorithm": "ChaCha20", + "cipher_suite_name": "TLS_CHACHA20_POLY1305_SHA256", + "key_size": 253, + "bits": 256, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "x1303", + }, + { + "cipher_suite_alias": "TLS_AES_128_GCM_SHA256", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "TLS_AES_128_GCM_SHA256", + "key_size": 253, + "bits": 128, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "x1301", + }, + ], + "TLSv1.2": [ + { + "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "ECDHE-RSA-AES256-GCM-SHA384", + "key_size": 521, + "bits": 256, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "xc030", + }, + { + "cipher_suite_alias": "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "DHE-RSA-AES256-GCM-SHA384", + "key_size": 2048, + "bits": 256, + "key_exchange_algorithm": "DH", + "cipher_suite_code": "x9f", + }, + { + "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "encryption_algorithm": "ChaCha20", + "cipher_suite_name": "ECDHE-RSA-CHACHA20-POLY1305", + "key_size": 521, + "bits": 256, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "xcca8", + }, + { + "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "ECDHE-RSA-AES128-GCM-SHA256", + "key_size": 521, + "bits": 128, + "key_exchange_algorithm": "ECDH", + "cipher_suite_code": "xc02f", + }, + { + "cipher_suite_alias": "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "encryption_algorithm": "AESGCM", + "cipher_suite_name": "DHE-RSA-AES128-GCM-SHA256", + "key_size": 2048, + "bits": 128, + "key_exchange_algorithm": "DH", + "cipher_suite_code": "x9e", + }, + ], + } + assert len(oois) == 1 + assert oois[0].suites == expected_suites diff --git a/boefjes/tests/plugins/test_wappalyzer_normalizer.py b/boefjes/tests/plugins/test_wappalyzer_normalizer.py new file mode 100644 index 00000000000..c89fc63cc49 --- /dev/null +++ b/boefjes/tests/plugins/test_wappalyzer_normalizer.py @@ -0,0 +1,15 @@ +from boefjes.job_models import NormalizerMeta +from tests.loading import get_dummy_data + + +def test_page_analyzer_normalizer(normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("body-page-analysis-normalize.json")) + output = normalizer_runner.run(meta, get_dummy_data("download_page_analysis.raw")) + + results = output.observations[0].results + assert len(results) == 6 + assert {o.primary_key for o in results if o.object_type == "Software"} == { + "Software|jQuery Migrate|1.0.0|", + "Software|jQuery|3.6.0|", + "Software|Bootstrap|3.3.7|", + } diff --git a/boefjes/tests/test_adr_validator.py b/boefjes/tests/test_adr_validator.py deleted file mode 100644 index 1a60197127c..00000000000 --- a/boefjes/tests/test_adr_validator.py +++ /dev/null @@ -1,57 +0,0 @@ -from pathlib import Path -from unittest import TestCase - -from boefjes.job_models import NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from tests.loading import get_dummy_data - - -class ADRValidatorNormalizerTest(TestCase): - def test_no_findings(self): - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - meta = NormalizerMeta.model_validate_json(get_dummy_data("adr-validator-normalize.json")) - - raw = """[{"rule": "TEST-01", "passed": true, "message": ""}]""" - output = runner.run(meta, bytes(raw, "UTF-8")) - - self.assertEqual(1, len(output.observations)) - - observation = output.observations[0] - self.assertEqual(2, len(observation.results)) - - self.assertEqual("APIDesignRule", observation.results[0].object_type) - self.assertEqual("TEST-01", observation.results[0].name) - self.assertEqual("APIDesignRuleResult", observation.results[1].object_type) - self.assertEqual("", observation.results[1].message) - self.assertTrue(observation.results[1].passed) - - def test_with_findings(self): - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - meta = NormalizerMeta.model_validate_json(get_dummy_data("adr-validator-normalize.json")) - - raw = """[ - {"rule": "TEST-01", "passed": true, "message": ""}, - {"rule": "TEST-02", "passed": false, "message": "An error"}, - {"rule": "TEST-02", "passed": true, "message": ""} - ]""" - output = runner.run(meta, bytes(raw, "UTF-8")) - - self.assertEqual(1, len(output.observations)) - - observation = output.observations[0] - self.assertEqual(8, len(observation.results)) - - self.assertEqual("APIDesignRule", observation.results[2].object_type) - self.assertEqual("TEST-02", observation.results[2].name) - self.assertEqual("APIDesignRuleResult", observation.results[3].object_type) - self.assertEqual("An error", observation.results[3].message) - self.assertFalse(observation.results[3].passed) - - self.assertEqual("ADRFindingType", observation.results[4].object_type) - self.assertEqual("TEST-02", observation.results[4].id) - self.assertEqual("Finding", observation.results[5].object_type) - self.assertEqual("An error", observation.results[5].description) - self.assertEqual("ADRFindingType|TEST-02", str(observation.results[5].finding_type)) diff --git a/boefjes/tests/test_answer_parser.py b/boefjes/tests/test_answer_parser.py deleted file mode 100644 index ff4114116a9..00000000000 --- a/boefjes/tests/test_answer_parser.py +++ /dev/null @@ -1,32 +0,0 @@ -from pathlib import Path -from unittest import TestCase - -import pytest -from pydantic import ValidationError - -from boefjes.job_models import NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from tests.loading import get_dummy_data - - -class AnswerParserNormalizerTest(TestCase): - def test_config_yielded(self): - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - meta = NormalizerMeta.model_validate_json(get_dummy_data("answer-normalize.json")) - - with pytest.raises(TypeError): - raw = '[{"key": "test"}]' - runner.run(meta, bytes(raw, "UTF-8")) - - with pytest.raises(ValidationError): - raw = '{"schema": "/bit/port-classification-ip", "answer": [{"key": "test"}]}' - runner.run(meta, bytes(raw, "UTF-8")) - - raw = '{"schema": "/bit/port-classification-ip", "answer": {"key": "test"}}' - output = runner.run(meta, bytes(raw, "UTF-8")) - - self.assertEqual(1, len(output.observations)) - self.assertEqual(1, len(output.observations[0].results)) - self.assertEqual("Config", output.observations[0].results[0].object_type) diff --git a/boefjes/tests/test_bodyimage.py b/boefjes/tests/test_bodyimage.py deleted file mode 100644 index 52e646c5d33..00000000000 --- a/boefjes/tests/test_bodyimage.py +++ /dev/null @@ -1,102 +0,0 @@ -import json -from pathlib import Path -from unittest import TestCase, mock -from unittest.mock import MagicMock - -from requests.models import CaseInsensitiveDict, PreparedRequest, Response - -from boefjes.job_models import BoefjeMeta, NormalizerMeta -from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from tests.loading import get_dummy_data - - -class WebsiteAnalysisTest(TestCase): - maxDiff = None - - @mock.patch("boefjes.plugins.kat_webpage_analysis.main.do_request", spec=Response) - def test_website_analysis(self, do_request_mock: MagicMock): - meta = BoefjeMeta.model_validate_json(get_dummy_data("webpage-analysis.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalBoefjeJobRunner(local_repository) - - mock_response = Response() - mock_response._content = bytes(get_dummy_data("download_body")) - mock_response.request = MagicMock(spec=PreparedRequest()) - mock_response.request.url = "" - mock_response.request.method = "GET" - mock_response.headers = CaseInsensitiveDict(json.loads(get_dummy_data("download_headers.json"))) - - do_request_mock.return_value = mock_response - - output = runner.run(meta, {}) - - self.assertIn("openkat-http/response", output[0][0]) - self.assertIn("openkat-http/headers", output[1][0]) - self.assertIn("openkat-http/body", output[2][0]) - - @mock.patch("boefjes.plugins.kat_webpage_analysis.main.do_request") - def test_website_analysis_for_image(self, do_request_mock: MagicMock): - meta = BoefjeMeta.model_validate_json(get_dummy_data("webpage-analysis.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalBoefjeJobRunner(local_repository) - - mock_response = Response() - mock_response._content = bytes(get_dummy_data("cat_image")) - mock_response.request = MagicMock(spec=PreparedRequest()) - mock_response.request.url = "" - mock_response.request.method = "GET" - mock_response.headers = CaseInsensitiveDict(json.loads(get_dummy_data("download_image_headers.json"))) - - do_request_mock.return_value = mock_response - - output = runner.run(meta, {}) - self.assertIn("image/jpeg", output[2][0]) - - def test_body_image_normalizer(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("bodyimage-normalize.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("cat_image")).observations[0].results - - self.assertEqual(1, len(output)) - self.assertEqual( - { - "object_type": "ImageMetadata", - "primary_key": "ImageMetadata|internet|134.209.85.72|tcp|443|https|internet" - "|mispo.es|https|internet|mispo.es|443|/", - "resource": "HTTPResource|internet|134.209.85.72|tcp|443|https|internet" - "|mispo.es|https|internet|mispo.es|443|/", - "scan_profile": None, - "user_id": None, - "image_info": { - "format": "JPEG", - "frames": 1, - "height": 600, - "is_animated": False, - "mode": "RGB", - "size": (600, 600), - "width": 600, - }, - }, - output[0].dict(), - ) - - def test_body_normalizer(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("body-normalize.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("download_body")).observations[0].results - - self.assertEqual(4, len(output)) - - output_dicts = sorted([o.dict() for o in output], key=lambda x: x["primary_key"]) - - self.assertEqual("URL|internet|http://placekitten.com/600/600", output_dicts[0]["primary_key"]) - self.assertEqual("URL|internet|http://placekitten.com/600/600.webp", output_dicts[1]["primary_key"]) - self.assertEqual("URL|internet|https://mispo.es/600/600", output_dicts[2]["primary_key"]) - self.assertEqual("URL|internet|https://mispo.es/600/600.webp", output_dicts[3]["primary_key"]) diff --git a/boefjes/tests/test_calvin.py b/boefjes/tests/test_calvin.py deleted file mode 100644 index 35fe48f771d..00000000000 --- a/boefjes/tests/test_calvin.py +++ /dev/null @@ -1,155 +0,0 @@ -from pathlib import Path -from unittest import TestCase - -from boefjes.job_models import NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from octopoes.models.ooi.monitoring import Application -from tests.loading import get_dummy_data - - -class CalvinTest(TestCase): - def test_parse_user_changed(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("user-changed.json")) - - self.assertEqual(8, len(output.declarations)) - self.assertEqual( - { - "application": Application(name="organisation/env/app").reference, - "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1655979300000', - "event_title": "UC: User privilege monitoring", - "event_type": "ksql-usecase", - "meta_data": { - "_id": "62b43a6e69c14474a3773f8b", - "log_action_code": "U", - "log_count": 9.0, - "log_routing_key": "test_app.account_change", - "log_user_user_id": 1234.0, - "outbox_sent": None, - "windowKey": '{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1655979300000', - "window_emit": 1655978930000.0, - "window_end": 1655979300000.0, - "window_start": 1655975700000.0, - }, - "object_type": "Incident", - "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1655979300000', - "scan_profile": None, - "user_id": None, - "severity": "MEDIUM", - }, - output.declarations[1].ooi.dict(), - ) - - self.assertEqual( - { - "application": Application(name="organisation/env/app").reference, - "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658825100000', - "event_title": "UC: User privilege monitoring", - "event_type": "ksql-usecase", - "meta_data": { - "_id": "62df9e499dd2b029d842576d", - "log_action_code": "U", - "log_count": 4.0, - "log_routing_key": "test_app.account_change", - "log_user_user_id": 1234.0, - "outbox_sent": None, - "windowKey": '{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1658825100000', - "window_emit": 1658822215000.0, - "window_end": 1658825100000.0, - "window_start": 1658821500000.0, - }, - "object_type": "Incident", - "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1658825100000', - "scan_profile": None, - "user_id": None, - "severity": "MEDIUM", - }, - output.declarations[-1].ooi.dict(), - ) - - def test_parse_admin_login_failure(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("user-login-admin-failure.json")) - - self.assertEqual(8, len(output.declarations)) - self.assertEqual( - { - "application": Application(name="organisation/env/app").reference, - "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1659618600000', - "event_title": "UC: Detect brute force login attempts for an admin account", - "event_type": "ksql-usecase", - "meta_data": { - "_id": "62ebc44c9dd2b029d84ac32a", - "log_action_code": "E", - "log_count": 3.0, - "log_object_result": 0.0, - "log_routing_key": "test_app.user_login", - "log_user_roles": "ADMIN,REGISTRATOR,SHIFT_MANAGER,CSV,KVTB_ADMIN,STATS", - "log_user_user_id": 1234.0, - "outbox_sent": True, - "windowKey": '{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1659618600000', - "window_emit": 1659618378000.0, - "window_end": 1659618600000.0, - "window_start": 1659617700000.0, - }, - "object_type": "Incident", - "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1659618600000', - "scan_profile": None, - "user_id": None, - "severity": "MEDIUM", - }, - output.declarations[1].ooi.dict(), - ) - - def test_parse_user_login_failure(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("calvin-normalizer.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("user-login-failure.json")) - - self.assertEqual(8, len(output.declarations)) - self.assertEqual( - { - "application": Application(name="organisation/env/app").reference, - "event_id": '{"client_environment_app":"organisation/env/app","log_user_user_id":1234}-1658998200000', - "event_title": "UC: Detects attempts to guess passwords", - "event_type": "ksql-usecase", - "meta_data": { - "_id": "62e24d509dd2b029d84391fb", - "log_action_code": "E", - "log_count": 10.0, - "log_object_result": 0.0, - "log_object_user_id": None, - "log_result": None, - "log_routing_key": "test_app.user_login", - "log_user_user_id": 1234.0, - "outbox_sent": None, - "windowKey": '{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1658998200000', - "window_emit": 1658998093000.0, - "window_end": 1658998200000.0, - "window_start": 1658996400000.0, - }, - "object_type": "Incident", - "primary_key": 'Incident|organisation/env/app|{"client_environment_app":"organisation/env/app",' - '"log_user_user_id":1234}-1658998200000', - "scan_profile": None, - "user_id": None, - "severity": "MEDIUM", - }, - output.declarations[1].ooi.dict(), - ) diff --git a/boefjes/tests/test_cve-2023-35078.py b/boefjes/tests/test_cve-2023-35078.py deleted file mode 100644 index 8d7d4d97339..00000000000 --- a/boefjes/tests/test_cve-2023-35078.py +++ /dev/null @@ -1,47 +0,0 @@ -from unittest import TestCase -from unittest.mock import MagicMock - -from boefjes.plugins.kat_cve_2023_35078.normalize import VULNERABLE_RANGES, is_vulnerable_version, run -from packaging import version -from tests.loading import get_dummy_data - - -class CVE_2023_35078Test(TestCase): - maxDiff = None - - def test_vulnerable_version_11_8(self): - detected_version = version.parse("11.8.0.0") - vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] - self.assertTrue(is_vulnerable_version(vulnerable_ranges, detected_version)) - - def test_vulnerable_version_11_9(self): - detected_version = version.parse("11.9.1.0") - vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] - self.assertTrue(is_vulnerable_version(vulnerable_ranges, detected_version)) - - def test_vulnerable_version_11_10(self): - detected_version = version.parse("11.10.0.1") - vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] - self.assertTrue(is_vulnerable_version(vulnerable_ranges, detected_version)) - - def test_patched_version_11_9(self): - detected_version = version.parse("11.9.2.0") - vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] - self.assertFalse(is_vulnerable_version(vulnerable_ranges, detected_version)) - - def test_equal_to_patched_version_11_9(self): - detected_version = version.parse("11.9.1.1") - vulnerable_ranges = [(version.parse(start), version.parse(end)) for start, end in VULNERABLE_RANGES] - self.assertFalse(is_vulnerable_version(vulnerable_ranges, detected_version)) - - -def test_cve_2023_35078_vulnerable(): - oois = set(run(MagicMock(), get_dummy_data("cve_2023_35078_vulnerable.html"))) - - assert any(ooi.object_type == "Finding" for ooi in oois) - - -def test_cve_2023_35078_not_vulnerable(): - oois = set(run(MagicMock(), get_dummy_data("cve_2023_35078_not_vulnerable.html"))) - - assert not any(ooi.object_type == "Finding" for ooi in oois) diff --git a/boefjes/tests/test_cve_finding_types.py b/boefjes/tests/test_cve_finding_types.py deleted file mode 100644 index a67ac217e20..00000000000 --- a/boefjes/tests/test_cve_finding_types.py +++ /dev/null @@ -1,90 +0,0 @@ -from unittest import TestCase - -from boefjes.job_models import NormalizerAffirmation -from boefjes.plugins.kat_cve_finding_types.normalize import run -from octopoes.models.ooi.findings import RiskLevelSeverity -from octopoes.models.types import CVEFindingType -from tests.loading import get_dummy_data - - -class CVETest(TestCase): - maxDiff = None - - def test_cve_with_cvss(self): - input_ooi = {"id": "CVE-2021-46882"} - - oois = list( - run( - input_ooi, - get_dummy_data("inputs/cve-result-with-cvss.json"), - ) - ) - - expected = [ - NormalizerAffirmation( - ooi=CVEFindingType( - id="CVE-2021-46882", - description="The video framework has memory overwriting caused by addition overflow. " - "Successful exploitation of this vulnerability may affect availability.", - source="https://cve.circl.lu/cve/CVE-2021-46882", - risk_severity=RiskLevelSeverity.HIGH, - risk_score=7.5, - ) - ) - ] - - self.assertEqual(expected, oois) - - def test_cve_with_cvss2(self): - input_ooi = {"id": "CVE-2016-0616"} - - oois = list( - run( - input_ooi, - get_dummy_data("inputs/cve-result-with-cvss2.json"), - ) - ) - - expected = [ - NormalizerAffirmation( - ooi=CVEFindingType( - id="CVE-2016-0616", - description="Unspecified vulnerability in Oracle MySQL 5.5.46 and earlier and MariaDB before " - "5.5.47, 10.0.x before 10.0.23, and 10.1.x before 10.1.10 allows remote authenticated users " - "to affect availability via unknown vectors related to Optimizer.", - source="https://cve.circl.lu/cve/CVE-2016-0616", - risk_severity=RiskLevelSeverity.MEDIUM, - risk_score=4.0, - ) - ) - ] - - self.assertEqual(expected, oois) - - def test_cve_without_cvss(self): - input_ooi = {"id": "CVE-2021-46882"} - - oois = list( - run( - input_ooi, - get_dummy_data("inputs/cve-result-without-cvss.json"), - ) - ) - - expected = [ - NormalizerAffirmation( - ooi=CVEFindingType( - id="CVE-2021-46882", - description="The Nested Pages plugin for WordPress is vulnerable to unauthorized loss of " - "data due to a missing capability check on the 'reset' function in versions up to, and including, " - "3.2.3. This makes it possible for authenticated attackers, " - "with editor-level permissions and above, " - "to reset plugin settings.", - source="https://cve.circl.lu/cve/CVE-2021-46882", - risk_severity=RiskLevelSeverity.UNKNOWN, - risk_score=None, - ), - ) - ] - - self.assertEqual(expected, oois) diff --git a/boefjes/tests/test_dns.py b/boefjes/tests/test_dns.py deleted file mode 100644 index 0ae1124b0f8..00000000000 --- a/boefjes/tests/test_dns.py +++ /dev/null @@ -1,494 +0,0 @@ -import uuid -from ipaddress import IPv4Address, IPv6Address -from pathlib import Path -from unittest import TestCase - -from pydantic import BaseModel - -from boefjes.job_models import Boefje, BoefjeMeta, Normalizer, NormalizerMeta, ObservationsWithoutInputOOI, RawDataMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from octopoes.models import Reference -from octopoes.models.ooi.dns.records import ( - DNSAAAARecord, - DNSARecord, - DNSCNAMERecord, - DNSMXRecord, - DNSNSRecord, - DNSSOARecord, - DNSTXTRecord, -) -from octopoes.models.ooi.dns.zone import DNSZone, Hostname -from octopoes.models.ooi.network import IPAddressV4, IPAddressV6, Network -from tests.loading import get_dummy_data - - -class DnsTest(TestCase): - maxDiff = None - - def test_dns_normalizer(self): - internet = Network(name="internet") - - zone_hostname = Hostname(name="example.nl", network=internet.reference) - zone = DNSZone(hostname=zone_hostname.reference) - zone_hostname.dns_zone = zone.reference - - ip_v4_addresses = [ - IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")), - IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.36")), - ] - dns_a_records = [ - DNSARecord( - hostname=zone_hostname.reference, - value=str(ip.address), - address=ip.reference, - ttl=14364, - ) - for ip in ip_v4_addresses - ] - ip_v6_addresses = [ - IPAddressV6( - network=internet.reference, - address=IPv6Address("2a00:d78:0:712:94:198:159:35"), - ), - IPAddressV6( - network=internet.reference, - address=IPv6Address("2a00:d78:0:712:94:198:159:36"), - ), - ] - dns_aaaa_records = [ - DNSAAAARecord( - hostname=zone_hostname.reference, - value=str(ip.address), - address=ip.reference, - ttl=14400, - ) - for ip in ip_v6_addresses - ] - dns_txt_records = [ - DNSTXTRecord( - hostname=zone_hostname.reference, - value="v=spf1 redirect=spf-a.example.nl", - ttl=14400, - ) - ] - - mx_hostnames = [ - Hostname( - network=internet.reference, - name="mail.example.nl", - ), - Hostname( - network=internet.reference, - name="mail2.example.nl", - ), - ] - dns_mx_records = [ - DNSMXRecord( - hostname=zone_hostname.reference, - value=f"10 {mx_rec.name}.", - ttl=14400, - mail_hostname=mx_rec.reference, - preference=10, - ) - for mx_rec in mx_hostnames - ] - - ns_hostnames = [ - Hostname(name=value, network=internet.reference) - for value in [ - "ns3.examplenl.org", - "ns1.examplenl.nl", - "ns2.examplenl.eu", - "ns0.examplenl.com", - ] - ] - - ns_records = [ - DNSNSRecord( - hostname=zone_hostname.reference, - value=ns_hostname.name + ".", - name_server_hostname=ns_hostname.reference, - ttl=2634, - ) - for ns_hostname in ns_hostnames - ] - - soa_hostname = Hostname( - network=internet.reference, - name="ns1.examplenl.nl", - dns_zone=zone.reference, - ) - soa_record = DNSSOARecord( - hostname=zone_hostname.reference, - value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", - soa_hostname=soa_hostname.reference, - ttl=14340, - serial=2021111101, - retry=7200, - refresh=14400, - expire=1209600, - minimum=86400, - ) - - # noinspection PyTypeChecker - expected = ( - [zone_hostname, zone] - + ip_v4_addresses - + dns_a_records - + ip_v6_addresses - + dns_aaaa_records - + dns_txt_records - + mx_hostnames - + dns_mx_records - + ns_hostnames - + ns_records - + [soa_record] - ) - - meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - results = runner.run(meta, get_dummy_data("inputs/dns-result-example.nl.json")) - - self.assertEqual(1, len(results.observations)) - self.assertCountEqual( - map(BaseModel.model_dump, expected), map(BaseModel.model_dump, results.observations[0].results) - ) - - def test_dns_normalizer_cname(self): - internet = Network(name="internet") - - zone_hostname = Hostname( - network=internet.reference, - name="example.nl", - ) - zone = DNSZone( - hostname=zone_hostname.reference, - ) - zone_hostname.dns_zone = zone.reference - - input_hostname = Hostname( - network=internet.reference, - name="www.example.nl", - dns_zone=zone.reference, - ) - cname_target = Hostname( - network=internet.reference, - name="webredir.examplenl.nl", - ) - - soa_hostname = Hostname(network=internet.reference, name="ns1.examplenl.nl") - soa_record = DNSSOARecord( - hostname=zone_hostname.reference, - value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", - ttl=14340, - soa_hostname=soa_hostname.reference, - serial=2021111101, - refresh=14400, - retry=7200, - expire=1209600, - minimum=86400, - ) - - cname_record = DNSCNAMERecord( - hostname=input_hostname.reference, - value=cname_target.name + ".", - ttl=10800, - target_hostname=cname_target.reference, - ) - - ip_address = IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")) - dns_a_record = DNSARecord( - hostname=cname_target.reference, - address=ip_address.reference, - value=str(ip_address.address), - ttl=10800, - ) - - expected = [ - zone, - zone_hostname, - soa_hostname, - soa_record, - cname_target, - cname_record, - ip_address, - dns_a_record, - input_hostname, - ] - - meta = NormalizerMeta( - id=uuid.UUID("72c7d302-0d6f-407a-aaec-9ffcad0ee7c6"), - normalizer=Normalizer(id="kat_dns_normalize"), - raw_data=RawDataMeta( - id=uuid.UUID("3b8397ba-50e4-476e-834a-2fa2595a43a5"), - boefje_meta=BoefjeMeta( - id=uuid.UUID("10535bba-2715-42f9-be47-ccd985b59eea"), - boefje=Boefje(id="dns-records"), - organization="_dev", - input_ooi="Hostname|internet|www.example.nl", - arguments={ - "domain": "www.example.nl.", - "input": {"name": "www.example.nl."}, - }, - ), - mime_types=[{"value": "boefje/dns-records"}], - ), - ) - - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - results = runner.run(meta, get_dummy_data("inputs/dns-result-www.example.nl.json")) - - self.assertCountEqual( - map(BaseModel.model_dump, expected), map(BaseModel.model_dump, results.observations[0].results) - ) - - def test_parse_record_null_mx_record(self): - meta = NormalizerMeta( - id=uuid.UUID("d7d65462-5ced-4a57-a1d7-c6d2edf38354"), - normalizer=Normalizer(id="kat_dns_normalize"), - raw_data=RawDataMeta( - id=uuid.UUID("94fe3b47-fb41-4ad7-b2de-1bfe63460c98"), - boefje_meta=BoefjeMeta( - id=uuid.UUID("f1e72e47-c11f-47e9-953a-52e3b6833eaf"), - boefje=Boefje(id="dns-records"), - organization="_dev", - input_ooi="Hostname|internet|english.example.nl", - arguments={ - "domain": "english.example.nl", - "input": {"name": "english.example.nl"}, - }, - ), - mime_types=[{"value": "boefje/dns-records"}], - ), - ) - - answer = get_dummy_data("inputs/dns-result-mx-example.nl.json") - - internet = Network(name="internet") - input_hostname = Hostname( - network=internet.reference, - name="english.example.nl", - ) - - cname_target = Hostname(network=internet.reference, name="redir.example.nl") - cname_record = DNSCNAMERecord( - hostname=input_hostname.reference, - value="redir.example.nl.", - ttl=60, - target_hostname=cname_target.reference, - ) - mx_record = DNSMXRecord( - hostname=cname_target.reference, - value="0 .", - ttl=14400, - preference=0, - ) - - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - results = runner.run(meta, answer) - - expected = [cname_target, cname_record, mx_record, input_hostname] - self.assertCountEqual( - map(BaseModel.model_dump, expected), map(BaseModel.model_dump, results.observations[0].results) - ) - - def test_parse_cname_soa(self): - internet = Network(name="internet") - - zone_hostname = Hostname( - network=internet.reference, - name="example.com", - ) - zone = DNSZone( - hostname=zone_hostname.reference, - ) - zone_hostname.dns_zone = zone.reference - - input_hostname = Hostname( - network=internet.reference, - name="www.example.com", - dns_zone=zone.reference, - ) - - cname_record = DNSCNAMERecord( - hostname=input_hostname.reference, - value="example.com.", - ttl=60, - target_hostname=zone_hostname.reference, - ) - ip_address = IPAddressV4(network=internet.reference, address=IPv4Address("94.198.159.35")) - a_record = DNSARecord( - hostname=zone_hostname.reference, - address=ip_address.reference, - value=str(ip_address.address), - ttl=60, - ) - soa_hostname = Hostname(network=internet.reference, name="ns.icann.org") - ns_hostnames = [ - Hostname(name=value, network=internet.reference) - for value in [ - "a.iana-servers.net", - "b.iana-servers.net", - ] - ] - ns_records = [ - DNSNSRecord( - hostname=zone_hostname.reference, - value=ns_hostname.name + ".", - name_server_hostname=ns_hostname.reference, - ttl=60, - ) - for ns_hostname in ns_hostnames - ] - soa_record = DNSSOARecord( - hostname=zone_hostname.reference, - value="ns.icann.org. noc.dns.icann.org. 2022040432 7200 3600 1209600 3600", - ttl=21, - soa_hostname=soa_hostname.reference, - serial=2022040432, - retry=3600, - refresh=7200, - expire=1209600, - minimum=3600, - ) - txt_record = DNSTXTRecord( - hostname=zone_hostname.reference, - value="v=spf1 -all", - ttl=60, - ) - mx_record = DNSMXRecord( - hostname=zone_hostname.reference, - value="0 example.com.", - ttl=60, - mail_hostname=zone_hostname.reference, - preference=0, - ) - - meta = NormalizerMeta( - id=uuid.UUID("a2a85d54-a6ce-495d-b7a5-23c1a79f4cec"), - normalizer=Normalizer(id="kat_dns_normalize"), - raw_data=RawDataMeta( - id=uuid.UUID("ac481bc2-a524-4dcc-91a4-28ed9c2c142b"), - boefje_meta=BoefjeMeta( - id=uuid.UUID("0671b9ac-1624-4c09-a94a-4f9edbc40064"), - boefje=Boefje(id="dns-records"), - organization="_dev", - input_ooi="Hostname|internet|www.example.com", - arguments={ - "domain": "www.example.com", - "input": {"name": "www.example.com"}, - }, - ), - mime_types=[{"value": "boefje/dns-records"}], - ), - ) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - results = runner.run(meta, get_dummy_data("inputs/dns-result-example.com-cnames.json")) - - expected = ( - [ - zone, - zone_hostname, - cname_record, - ip_address, - a_record, - soa_record, - txt_record, - mx_record, - input_hostname, - soa_hostname, - ] - + ns_hostnames - + ns_records - ) - self.assertCountEqual( - map(BaseModel.model_dump, expected), map(BaseModel.model_dump, results.observations[0].results) - ) - - def test_find_parent_dns_zone(self): - internet = Network(name="internet") - - requested_zone = DNSZone( - hostname=Hostname( - network=internet.reference, - name="sub.example.nl", - ).reference - ) - parent_zone_hostname = Hostname( - network=internet.reference, - name="example.nl", - ) - parent_zone = DNSZone(hostname=parent_zone_hostname.reference) - parent_zone_hostname.dns_zone = parent_zone.reference - - requested_zone.parent = parent_zone.reference - - name_server_hostname = Hostname( - network=internet.reference, - name="ns1.examplenl.nl", - ) - - soa_record = DNSSOARecord( - hostname=parent_zone_hostname.reference, - value="ns1.examplenl.nl. hostmaster.sidn.nl. 2021111101 14400 7200 1209600 86400", - ttl=14340, - soa_hostname=name_server_hostname.reference, - serial=2021111101, - retry=7200, - refresh=14400, - expire=1209600, - minimum=86400, - ) - - input_ = DNSZone( - hostname=Hostname( - network=Reference.from_str("Network|internet"), - name="sub.example.nl", - ).reference - ).serialize() - - meta = NormalizerMeta( - id=uuid.UUID("ee8374bb-e79f-4083-9ce9-add4f96006f2"), - normalizer=Normalizer(id="kat_dns_zone_normalize"), - raw_data=RawDataMeta( - id=uuid.UUID("2147da2a-921c-4c51-aef3-fa82d8d6e089"), - boefje_meta=BoefjeMeta( - id=uuid.UUID("ff1f0d62-a2e0-480f-8b11-5fb24974edce"), - boefje=Boefje(id="dns-records"), - organization="_dev", - input_ooi="DnsZone|internet|sub.example.nl", - arguments={"input": input_}, - ), - mime_types=[{"value": "boefje/dns-records"}], - ), - ) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - results = runner.run(meta, get_dummy_data("inputs/dns-zone-result-sub.example.nl.txt")) - - expected = [ - requested_zone, - parent_zone, - parent_zone_hostname, - name_server_hostname, - soa_record, - ] - self.assertCountEqual( - map(BaseModel.model_dump, expected), map(BaseModel.model_dump, results.observations[0].results) - ) - - def test_exception_raised_no_input_ooi(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) - meta.raw_data.boefje_meta.input_ooi = None - - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - - with self.assertRaises(ObservationsWithoutInputOOI): - runner.run(meta, get_dummy_data("inputs/dns-result-example.nl.json")) diff --git a/boefjes/tests/test_generic_finding_normalizer.py b/boefjes/tests/test_generic_finding_normalizer.py deleted file mode 100644 index 9e8da108984..00000000000 --- a/boefjes/tests/test_generic_finding_normalizer.py +++ /dev/null @@ -1,48 +0,0 @@ -from unittest import TestCase - -from boefjes.plugins.kat_finding_normalizer.normalize import run -from octopoes.models import Reference -from octopoes.models.ooi.findings import KATFindingType -from octopoes.models.types import CVEFindingType, Finding - - -class CVETest(TestCase): - maxDiff = None - - def test_single(self): - input_ooi = {"primary_key": "Network|internet"} - - oois = list(run(input_ooi, b"CVE-2021-00000")) - - expected = [ - CVEFindingType(id="CVE-2021-00000"), - Finding( - finding_type=CVEFindingType(id="CVE-2021-00000").reference, - ooi=Reference.from_str("Network|internet"), - description="CVE-2021-00000 is found on this OOI", - ), - ] - - self.assertEqual(expected, oois) - - def test_multiple(self): - input_ooi = {"primary_key": "Network|internet"} - - oois = list(run(input_ooi, b"CVE-2021-00000, KAT-MOCK-FINDING")) - - expected = [ - CVEFindingType(id="CVE-2021-00000"), - Finding( - finding_type=CVEFindingType(id="CVE-2021-00000").reference, - ooi=Reference.from_str("Network|internet"), - description="CVE-2021-00000 is found on this OOI", - ), - KATFindingType(id="KAT-MOCK-FINDING"), - Finding( - finding_type=KATFindingType(id="KAT-MOCK-FINDING").reference, - ooi=Reference.from_str("Network|internet"), - description="KAT-MOCK-FINDING is found on this OOI", - ), - ] - - self.assertEqual(expected, oois) diff --git a/boefjes/tests/test_leakix.py b/boefjes/tests/test_leakix.py deleted file mode 100644 index 5f3658aa550..00000000000 --- a/boefjes/tests/test_leakix.py +++ /dev/null @@ -1,27 +0,0 @@ -from unittest import TestCase - -from pydantic import parse_obj_as - -from boefjes.plugins.kat_leakix.normalize import run -from octopoes.models.types import OOIType -from tests.loading import get_dummy_data - - -class LeakIxNormalizerTest(TestCase): - def test_output(self): - input_ooi = parse_obj_as( - OOIType, - { - "object_type": "HostnameHTTPURL", - "network": "Network|internet", - "scheme": "https", - "port": 443, - "path": "/", - "netloc": "Hostname|internet|example.com", - }, - ) - - output = [x for x in run(input_ooi.serialize(), get_dummy_data("raw/leakix-example.com.json"))] - - self.assertEqual(170, len(output)) - self.assertEqual(get_dummy_data("raw/leakix-example.com-output.txt").decode().strip(), str(output)) diff --git a/boefjes/tests/test_manual.py b/boefjes/tests/test_manual.py deleted file mode 100644 index 70e71d4fe2c..00000000000 --- a/boefjes/tests/test_manual.py +++ /dev/null @@ -1,194 +0,0 @@ -from ipaddress import IPv4Address, IPv6Address -from pathlib import Path -from unittest import TestCase - -from pydantic_core import Url - -from boefjes.job_models import NormalizerMeta, NormalizerResults -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from octopoes.models import Reference -from tests.loading import get_dummy_data - - -class ManualTest(TestCase): - TEST_DECLARATIONS_DATA = ( - b"[" - b'{"ooi": {"object_type": "Network", "scan_profile": null, "user_id": null\ - , "primary_key": "Network|net1", "name": "net1"}},' - b'{"ooi": {"object_type": "Network", "scan_profile": null, "user_id": null\ - , "primary_key": "Network|net2", "name": "net2"}}' - b"]" - ) - CSV_EXAMPLES = [ - # hostname - b"name,network\nexample.com,internet", - # hostname without network - b"name\nexample.net", - # ipv4s - b"""address,network -1.1.1.1,internet -2.2.2.2,internet -3.3.3.3,darknet""", - # ipv6s - b"""address,network -FE80:CD00:0000:0CDE:1257:0000:211E:729C,internet -FE80:CD00:0000:0CDE:1257:0000:211E:729D,darknet""", - # urls - b"""network,raw -internet,https://example.com/ -darknet,https://openkat.nl/""", - # url without network - b"raw\nhttps://example.com/", - ] - - def test_parse_manual_declarations(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("manual-ooi.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, self.TEST_DECLARATIONS_DATA) - - self.assertEqual(2, len(output.declarations)) - self.assertEqual(0, len(output.observations)) - - self.assertEqual( - { - "name": "net1", - "object_type": "Network", - "primary_key": "Network|net1", - "scan_profile": None, - "user_id": None, - }, - output.declarations[0].ooi.dict(), - ) - self.assertEqual( - { - "name": "net2", - "object_type": "Network", - "primary_key": "Network|net2", - "scan_profile": None, - "user_id": None, - }, - output.declarations[1].ooi.dict(), - ) - - def test_parse_manual_hostname_csv(self): - meta, output, runner = self.check_network_created(0) - - self.assertEqual(2, len(output.declarations)) - self.assertEqual( - { - "dns_zone": None, - "name": "example.com", - "network": Reference("Network|internet"), - "object_type": "Hostname", - "primary_key": "Hostname|internet|example.com", - "registered_domain": None, - "scan_profile": None, - "user_id": None, - }, - output.declarations[1].ooi.dict(), - ) - - meta, output, runner = self.check_network_created(1) - - self.assertEqual(2, len(output.declarations)) - self.assertEqual( - { - "dns_zone": None, - "name": "example.net", - "network": Reference("Network|internet"), - "object_type": "Hostname", - "primary_key": "Hostname|internet|example.net", - "registered_domain": None, - "scan_profile": None, - "user_id": None, - }, - output.declarations[1].ooi.dict(), - ) - - def test_parse_manual_ip_csv(self): - meta, output, runner = self.check_network_created(2) - self.assertEqual(6, len(output.declarations)) - self.assertEqual( - { - "address": IPv4Address("1.1.1.1"), - "netblock": None, - "network": Reference("Network|internet"), - "object_type": "IPAddressV4", - "primary_key": "IPAddressV4|internet|1.1.1.1", - "scan_profile": None, - "user_id": None, - }, - output.declarations[1].ooi.dict(), - ) - - meta, output, runner = self.check_network_created(3) - self.assertEqual( - { - "address": IPv6Address("fe80:cd00:0:cde:1257:0:211e:729c"), - "netblock": None, - "network": Reference("Network|internet"), - "object_type": "IPAddressV6", - "primary_key": "IPAddressV6|internet|fe80:cd00:0:cde:1257:0:211e:729c", - "scan_profile": None, - "user_id": None, - }, - output.declarations[1].ooi.dict(), - ) - - def test_parse_url_csv(self): - meta, output, runner = self.check_network_created(4) - self.assertEqual(4, len(output.declarations)) - - self.assertEqual( - { - "network": Reference("Network|internet"), - "object_type": "URL", - "primary_key": "URL|internet|https://example.com/", - "raw": Url( - "https://example.com/", - ), - "scan_profile": None, - "user_id": None, - "web_url": None, - }, - output.declarations[1].ooi.model_dump(), - ) - - meta, output, runner = self.check_network_created(5) - self.assertEqual(2, len(output.declarations)) - self.assertEqual( - { - "network": Reference("Network|internet"), - "object_type": "URL", - "primary_key": "URL|internet|https://example.com/", - "raw": Url( - "https://example.com/", - ), - "scan_profile": None, - "user_id": None, - "web_url": None, - }, - output.declarations[1].ooi.dict(), - ) - - def check_network_created(self, csv_idx: int) -> tuple[NormalizerMeta, NormalizerResults, LocalNormalizerJobRunner]: - meta = NormalizerMeta.model_validate_json(get_dummy_data("manual-csv.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, self.CSV_EXAMPLES[csv_idx]) - - self.assertEqual(0, len(output.observations)) - self.assertEqual( - { - "name": "internet", - "object_type": "Network", - "primary_key": "Network|internet", - "scan_profile": None, - "user_id": None, - }, - output.declarations[0].ooi.dict(), - ) - return meta, output, runner diff --git a/boefjes/tests/test_scan_profiles.py b/boefjes/tests/test_scan_profiles.py deleted file mode 100644 index e233a278cf5..00000000000 --- a/boefjes/tests/test_scan_profiles.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -import os -from pathlib import Path -from unittest import TestCase, mock - -import pytest -from pydantic import ValidationError - -from boefjes.config import Settings -from boefjes.job_handler import NormalizerHandler -from boefjes.job_models import NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from octopoes.models import DeclaredScanProfile -from tests.loading import get_dummy_data - -RAW_DATA = json.dumps( - {"ip_addresses": [{"address": "127.0.0.1"}, {"address": "10.0.0.0"}], "domains": [{"name": "example.com"}]} -) - - -class ScanProfileTest(TestCase): - def test_normalizer_can_yield_scan_profiles(self): - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - meta = NormalizerMeta.model_validate_json(get_dummy_data("external_db.json")) - output = runner.run(meta, bytes(RAW_DATA, "UTF-8")) - - self.assertEqual(1, len(output.observations)) - self.assertEqual(3, len(output.observations[0].results)) - self.assertEqual(3, len(output.scan_profiles)) - - profile = output.scan_profiles[0] - self.assertIsInstance(profile, DeclaredScanProfile) - self.assertEqual("IPAddressV4|internet|127.0.0.1", profile.reference) - self.assertEqual(3, profile.level) - - profile = output.scan_profiles[1] - self.assertIsInstance(profile, DeclaredScanProfile) - self.assertEqual("IPAddressV4|internet|10.0.0.0", profile.reference) - self.assertEqual(3, profile.level) - - profile = output.scan_profiles[2] - self.assertIsInstance(profile, DeclaredScanProfile) - self.assertEqual("Hostname|internet|example.com", profile.reference) - self.assertEqual(3, profile.level) - - def test_job_handler_respects_whitelist(self): - bytes_mock = mock.Mock() - bytes_mock.get_raw.return_value = RAW_DATA - octopoes = mock.Mock() - - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - runner = LocalNormalizerJobRunner(local_repository) - meta = NormalizerMeta.model_validate_json(get_dummy_data("external_db.json")) - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": 5}' - with pytest.raises(ValidationError): - Settings() - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": -1}' - with pytest.raises(ValidationError): - Settings() - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"x": 3}' - NormalizerHandler(runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) - assert octopoes.save_many_scan_profiles.call_count == 0 - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 2}' - NormalizerHandler(runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) - assert octopoes.save_many_scan_profiles.call_count == 1 - assert octopoes.save_many_scan_profiles.call_args[0][0][0].level == 2 - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 3}' - NormalizerHandler(runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) - assert octopoes.save_many_scan_profiles.call_count == 2 - assert octopoes.save_many_scan_profiles.call_args[0][0][0].level == 3 - - os.environ["BOEFJES_SCAN_PROFILE_WHITELIST"] = '{"kat_external_db_normalize": 4, "abc": 0}' - NormalizerHandler(runner, bytes_mock, Settings().scan_profile_whitelist, lambda x: octopoes).handle(meta) - assert octopoes.save_many_scan_profiles.call_count == 3 diff --git a/boefjes/tests/test_security_txt.py b/boefjes/tests/test_security_txt.py deleted file mode 100644 index 8241c8656db..00000000000 --- a/boefjes/tests/test_security_txt.py +++ /dev/null @@ -1,97 +0,0 @@ -from unittest import TestCase - -from boefjes.plugins.kat_security_txt_downloader.normalize import run -from octopoes.models import Reference -from octopoes.models.ooi.dns.zone import Hostname -from octopoes.models.ooi.network import IPAddressV4, IPPort, Network -from octopoes.models.ooi.service import IPService, Service -from octopoes.models.ooi.web import URL, SecurityTXT, Website -from tests.loading import get_dummy_data - -input_ooi = { - "object_type": "Website", - "scan_profile": "scan_profile_type='declared' " - "reference=Reference('Website|internet|192.0.2.0|tcp|443|https|internet|example.com') level=", - "primary_key": "Website|internet|192.0.2.0|tcp|443|https|internet|example.com", - "ip_service": { - "ip_port": { - "address": {"network": {"name": "internet"}, "address": "192.0.2.0"}, - "protocol": "tcp", - "port": "443", - }, - "service": {"name": "https"}, - }, - "hostname": {"network": {"name": "internet"}, "name": "example.com"}, - "certificate": "None", -} - - -class SecurityTXTTest(TestCase): - maxDiff = None - - def test_security_txt_same_website(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/security_txt_result_same_website.json"), - ) - ) - - expected = [] - expected.append( - URL(raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference) - ) - url = URL(raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference) - expected.append(url) - expected.append( - SecurityTXT( - website=Reference.from_str("Website|internet|192.0.2.0|tcp|443|https|internet|example.com"), - url=url.reference, - security_txt="This is the content", - redirects_to=None, - ) - ) - - self.assertEqual(expected, oois) - - def test_security_txt_different_website(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/security_txt_result_different_website.json"), - ) - ) - - expected = [] - url_original = URL( - raw="https://example.com/.well-known/security.txt", network=Network(name="internet").reference - ) - expected.append(url_original) - url = URL(raw="https://www.example.com/.well-known/security.txt", network=Network(name="internet").reference) - expected.append(url) - expected.append(Hostname(name="www.example.com", network=Network(name="internet").reference)) - ip = IPAddressV4(address="192.0.2.1", network=Network(name="internet").reference) - expected.append(ip) - expected.append(Service(name="https")) - port = IPPort(address=ip.reference, port=443, protocol="tcp") - expected.append(port) - ip_service = IPService(ip_port=port.reference, service=Service(name="https").reference) - expected.append(ip_service) - website = Website( - ip_service=ip_service.reference, - hostname=Hostname(name="www.example.com", network=Network(name="internet").reference).reference, - ) - expected.append(website) - security_txt = SecurityTXT( - website=website.reference, url=url.reference, security_txt="This is the content", redirects_to=None - ) - expected.append(security_txt) - expected.append( - SecurityTXT( - website=Reference.from_str("Website|internet|192.0.2.0|tcp|443|https|internet|example.com"), - url=url_original.reference, - security_txt=None, - redirects_to=security_txt.reference, - ) - ) - self.assertEqual(expected, oois) diff --git a/boefjes/tests/test_snyk.py b/boefjes/tests/test_snyk.py deleted file mode 100644 index 6de75179347..00000000000 --- a/boefjes/tests/test_snyk.py +++ /dev/null @@ -1,136 +0,0 @@ -import json -from unittest import TestCase, mock - -from boefjes.job_models import BoefjeMeta -from boefjes.plugins.kat_snyk.main import run as run_boefje -from boefjes.plugins.kat_snyk.normalize import run -from octopoes.models.ooi.findings import SnykFindingType -from octopoes.models.types import CVEFindingType, Finding, Software -from tests.loading import get_dummy_data - -input_ooi = { - "primary_key": "Software|lodash|1.1.0|", - "software": { - "name": "lodash", - "version": "1.1.0", - }, -} - - -class SnykTest(TestCase): - maxDiff = None - - def test_snyk_no_findings(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/snyk-result-no-findings.json"), - ) - ) - - # noinspection PyTypeChecker - expected = () - - self.assertCountEqual(expected, oois) - - def test_snyk_findings(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/snyk-result-findings.json"), - ) - ) - - software = Software(name="lodash", version="1.1.0") - - snyk_finding_data = [ - ("SNYK-JS-LODASH-590103", "Prototype Pollution"), - ("SNYK-JS-LODASH-608086", "Prototype Pollution"), - ] - cve_finding_data = [ - ("CVE-2018-16487", "Prototype Pollution"), - ("CVE-2018-3721", "Prototype Pollution"), - ("CVE-2019-1010266", "Regular Expression Denial of Service (ReDoS)"), - ("CVE-2019-10744", "Prototype Pollution"), - ("CVE-2020-28500", "Regular Expression Denial of Service (ReDoS)"), - ("CVE-2020-8203", "Prototype Pollution"), - ("CVE-2021-23337", "Command Injection"), - ] - - snyk_findingtypes = [] - snyk_findings = [] - cve_findingtypes = [] - cve_findings = [] - - for finding in snyk_finding_data: - snyk_ft = SnykFindingType(id=finding[0]) - snyk_findingtypes.append(snyk_ft) - snyk_findings.append( - Finding( - finding_type=snyk_ft.reference, - ooi=software.reference, - description=finding[1], - ) - ) - - for finding in cve_finding_data: - cve_ft = CVEFindingType(id=finding[0]) - cve_findingtypes.append(cve_ft) - cve_findings.append( - Finding( - finding_type=cve_ft.reference, - ooi=software.reference, - description=finding[1], - ) - ) - - # noinspection PyTypeChecker - expected = snyk_findingtypes + snyk_findings + cve_findingtypes + cve_findings - - self.assertCountEqual(expected, oois) - - @mock.patch("boefjes.plugins.kat_snyk.main.requests.get") - def test_snyk_html_parser(self, mock_get): - boefje_meta = BoefjeMeta.model_validate_json(get_dummy_data("snyk-job.json")) - - # Mock the first GET request - mock_first_get = mock.Mock() - mock_first_get.content = get_dummy_data("snyk-vuln.html") - - # Mock the next GET request - mock_second_get = mock.Mock() - mock_second_get.content = get_dummy_data("snyk-vuln2.html") - - # Mock the next 7 GET requests - mock_third_get = mock.Mock() - mock_third_get.content = get_dummy_data("snyk-vuln3.html") - - mock_get.side_effect = [mock_first_get] + [mock_second_get] + [mock_third_get] * 7 - - mime_types, result = run_boefje(boefje_meta)[0] - - output = json.loads(result) - - self.assertListEqual(output["table_versions"], []) - self.assertListEqual( - output["table_vulnerabilities"], - [ - { - "Vuln_href": "SNYK-JS-LODASH-1018905", - "Vuln_text": "Regular Expression Denial of Service (ReDoS)", - "Vuln_versions": "<4.17.21", - }, - {"Vuln_href": "SNYK-JS-LODASH-608086", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.17"}, - {"Vuln_href": "SNYK-JS-LODASH-450202", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.12"}, - { - "Vuln_href": "SNYK-JS-LODASH-73639", - "Vuln_text": "Regular Expression Denial of Service (ReDoS)", - "Vuln_versions": "<4.17.11", - }, - {"Vuln_href": "SNYK-JS-LODASH-73638", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.11"}, - {"Vuln_href": "npm:lodash:20180130", "Vuln_text": "Prototype Pollution", "Vuln_versions": "<4.17.5"}, - ], - ) - self.assertListEqual( - output["cve_vulnerabilities"], [{"cve_code": "CVE-2021-23337", "Vuln_text": "Command Injection"}] - ) diff --git a/boefjes/tests/test_tasks.py b/boefjes/tests/test_tasks.py index c311b25de76..763c89938bf 100644 --- a/boefjes/tests/test_tasks.py +++ b/boefjes/tests/test_tasks.py @@ -3,7 +3,7 @@ import sys from datetime import datetime, timezone from pathlib import Path -from unittest import TestCase, mock +from unittest import mock from uuid import UUID import pytest @@ -11,7 +11,7 @@ from boefjes.dependencies.plugins import PluginService from boefjes.job_handler import BoefjeHandler from boefjes.job_models import BoefjeMeta, InvalidReturnValueNormalizer, NormalizerMeta -from boefjes.local import LocalBoefjeJobRunner, LocalNormalizerJobRunner +from boefjes.local import LocalBoefjeJobRunner from boefjes.local_repository import LocalPluginRepository from boefjes.models import Bit, Boefje, Normalizer, PluginType from boefjes.runtime_interfaces import JobRuntimeError @@ -19,204 +19,183 @@ from boefjes.sql.plugin_storage import create_plugin_storage from tests.loading import get_dummy_data +boefjes = [ + Boefje( + id="test-boefje-1", + name="test-boefje-1", + consumes={"SomeOOI"}, + produces=["test-boef-1", "test/text"], + ), + Boefje( + id="test-boefje-2", + name="test-boefje-2", + consumes={"SomeOOI"}, + produces=["test-boef-2", "test/text"], + ), + Boefje( + id="test-boefje-3", + name="test-boefje-3", + consumes={"SomeOOI"}, + produces=["test-boef-3", "test/plain"], + ), + Boefje( + id="test-boefje-4", + name="test-boefje-4", + consumes={"SomeOOI"}, + produces=["test-boef-4", "test/and-simple"], + ), +] +normalizers = [ + Normalizer( + id="test-normalizer-1", + name="test-normalizer-1", + consumes=["test-boef-3", "test/text"], + produces=["SomeOOI", "OtherOOI"], + ), + Normalizer( + id="test-normalizer-2", + name="test-normalizer-2", + consumes=["test/text"], + produces=["SomeOtherOOI"], + ), +] +bits = [ + Bit( + id="test-bit-1", + name="test-bit-1", + consumes="SomeOOI", + produces=["SomeOOI"], + parameters=[], + ), + Bit( + id="test-bit-2", + name="test-bit-2", + consumes="SomeOOI", + produces=["SomeOOI", "SomeOtherOOI"], + parameters=[], + ), +] +plugins: list[PluginType] = boefjes + normalizers + bits +sys.path.append(str(Path(__file__).parent)) + + +def test_parse_normalizer_meta_to_json(): + meta = NormalizerMeta.model_validate_json(get_dummy_data("snyk-normalizer.json")) + meta.started_at = datetime(10, 10, 10, 10, tzinfo=timezone.utc) + meta.ended_at = datetime(10, 10, 10, 12, tzinfo=timezone.utc) + + assert "0010-10-10T10:00:00Z" in meta.model_dump_json() + assert "0010-10-10T12:00:00Z" in meta.model_dump_json() + + +def test_handle_boefje_with_exception(mocker): + mocker.patch("boefjes.job_handler.get_environment_settings", return_value={}) + mock_bytes_api_client = mocker.patch("boefjes.job_handler.bytes_api_client") + mocker.patch("boefjes.job_handler.get_octopoes_api_connector") + + meta = BoefjeMeta( + id="0dca59db-b339-47c4-bcc9-896fc18e2386", + boefje={"id": "dummy_boefje_runtime_exception"}, + input_ooi="Network|internet", + arguments={}, + organization="_dev", + ) + local_repository = LocalPluginRepository(Path(__file__).parent / "modules") + + mock_session = mock.MagicMock() + mock_session.query.all.return_value = [] + + plugin_service = PluginService( + create_plugin_storage(mock_session), + create_config_storage(mock_session), + local_repository, + ) + + with pytest.raises(RuntimeError): # Bytes still saves exceptions before they are reraised + BoefjeHandler(LocalBoefjeJobRunner(local_repository), plugin_service, mock_bytes_api_client).handle(meta) + + mock_bytes_api_client.save_boefje_meta.assert_called_once_with(meta) + mock_bytes_api_client.save_raw.assert_called_once() + raw_call_args = mock_bytes_api_client.save_raw.call_args + + assert raw_call_args[0][0] == UUID("0dca59db-b339-47c4-bcc9-896fc18e2386") + assert "Traceback (most recent call last)" in raw_call_args[0][1] + assert "JobRuntimeError: Boefje failed" in raw_call_args[0][1] + assert raw_call_args[0][2] == { + "error/boefje", + "boefje/dummy_boefje_runtime_exception", + } + + +def test_exception_raised_unsupported_return_type_normalizer(mock_normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) + meta.raw_data.boefje_meta.input_ooi = None + meta.normalizer.id = "dummy_bad_normalizer_return_type" + + with pytest.raises(InvalidReturnValueNormalizer): + mock_normalizer_runner.run(meta, b"123") + + +def test_exception_raised_invalid_return_value(mock_normalizer_runner): + meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) + meta.raw_data.boefje_meta.input_ooi = None + meta.normalizer.id = "dummy_bad_normalizer_dict_structure" + + with pytest.raises(InvalidReturnValueNormalizer): + mock_normalizer_runner.run(meta, b"123") + + +def test_cleared_boefje_env(mock_boefje_runner) -> None: + """This test checks if un-containerized (local) boefjes can only access their explicitly set env vars""" + + arguments = {"ARG1": "value1", "ARG2": "value2"} + + meta = BoefjeMeta( + id="b49cd6f5-4d92-4a13-9d21-232993826cd9", + boefje={"id": "dummy_boefje_environment"}, + input_ooi="Network|internet", + arguments=arguments, + organization="_dev", + ) + + current_env = os.environ.copy() + output = mock_boefje_runner.run(meta, arguments) + output_dict = ast.literal_eval(output[0][1].decode()) + + # Assert that there are no overlapping environment keys + assert not set(current_env.keys()) & set(output_dict.keys()) + + # Assert that the original environment has been restored correctly + assert current_env == os.environ + -class TaskTest(TestCase): - def setUp(self) -> None: - self.boefjes = [ - Boefje( - id="test-boefje-1", - name="test-boefje-1", - consumes={"SomeOOI"}, - produces=["test-boef-1", "test/text"], - ), - Boefje( - id="test-boefje-2", - name="test-boefje-2", - consumes={"SomeOOI"}, - produces=["test-boef-2", "test/text"], - ), - Boefje( - id="test-boefje-3", - name="test-boefje-3", - consumes={"SomeOOI"}, - produces=["test-boef-3", "test/plain"], - ), - Boefje( - id="test-boefje-4", - name="test-boefje-4", - consumes={"SomeOOI"}, - produces=["test-boef-4", "test/and-simple"], - ), - ] - self.normalizers = [ - Normalizer( - id="test-normalizer-1", - name="test-normalizer-1", - consumes=["test-boef-3", "test/text"], - produces=["SomeOOI", "OtherOOI"], - ), - Normalizer( - id="test-normalizer-2", - name="test-normalizer-2", - consumes=["test/text"], - produces=["SomeOtherOOI"], - ), - ] - self.bits = [ - Bit( - id="test-bit-1", - name="test-bit-1", - consumes="SomeOOI", - produces=["SomeOOI"], - parameters=[], - ), - Bit( - id="test-bit-2", - name="test-bit-2", - consumes="SomeOOI", - produces=["SomeOOI", "SomeOtherOOI"], - parameters=[], - ), - ] - self.plugins: list[PluginType] = self.boefjes + self.normalizers + self.bits - sys.path.append(str(Path(__file__).parent)) - - def _get_boefje_meta(self): - return BoefjeMeta( - id="c188ef6b-b756-4cb0-9cb2-0db776e3cce3", - boefje={"id": "test-boefje-1", "version": "9"}, - input_ooi="Hostname|internet|example.com", - arguments={}, - organization="_dev", - ).copy() - - def test_parse_normalizer_meta_to_json(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("snyk-normalizer.json")) - meta.started_at = datetime(10, 10, 10, 10, tzinfo=timezone.utc) - meta.ended_at = datetime(10, 10, 10, 12, tzinfo=timezone.utc) - - assert "0010-10-10T10:00:00Z" in meta.model_dump_json() - assert "0010-10-10T12:00:00Z" in meta.model_dump_json() - - @mock.patch("boefjes.job_handler.get_environment_settings", return_value={}) - @mock.patch("boefjes.job_handler.bytes_api_client") - @mock.patch("boefjes.job_handler.get_octopoes_api_connector") - def test_handle_boefje_with_exception(self, mock_get_octopoes_api_connector, mock_bytes_api_client, mock_get_env): - meta = BoefjeMeta( - id="0dca59db-b339-47c4-bcc9-896fc18e2386", - boefje={"id": "dummy_boefje_runtime_exception"}, - input_ooi="Network|internet", - arguments={}, - organization="_dev", - ) - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - - mock_session = mock.MagicMock() - mock_session.query.all.return_value = [] - - plugin_service = PluginService( - create_plugin_storage(mock_session), - create_config_storage(mock_session), - local_repository, - ) - - with pytest.raises(RuntimeError): # Bytes still saves exceptions before they are reraised - BoefjeHandler(LocalBoefjeJobRunner(local_repository), plugin_service, mock_bytes_api_client).handle(meta) - - mock_bytes_api_client.save_boefje_meta.assert_called_once_with(meta) - mock_bytes_api_client.save_raw.assert_called_once() - raw_call_args = mock_bytes_api_client.save_raw.call_args - - assert raw_call_args[0][0] == UUID("0dca59db-b339-47c4-bcc9-896fc18e2386") - assert "Traceback (most recent call last)" in raw_call_args[0][1] - assert "JobRuntimeError: Boefje failed" in raw_call_args[0][1] - assert raw_call_args[0][2] == { - "error/boefje", - "boefje/dummy_boefje_runtime_exception", - } - - def test_exception_raised_unsupported_return_type_normalizer(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) - meta.raw_data.boefje_meta.input_ooi = None - meta.normalizer.id = "dummy_bad_normalizer_return_type" - - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - runner = LocalNormalizerJobRunner(local_repository) - - with self.assertRaises(InvalidReturnValueNormalizer): - runner.run(meta, b"123") - - def test_exception_raised_invalid_return_value(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("dns-normalize.json")) - meta.raw_data.boefje_meta.input_ooi = None - meta.normalizer.id = "dummy_bad_normalizer_dict_structure" - - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - runner = LocalNormalizerJobRunner(local_repository) - - with self.assertRaises(InvalidReturnValueNormalizer): - runner.run(meta, b"123") - - def test_cleared_boefje_env(self) -> None: - """This test checks if un-containerized (local) boefjes can only access their explicitly set env vars""" - - arguments = {"ARG1": "value1", "ARG2": "value2"} - - meta = BoefjeMeta( - id="b49cd6f5-4d92-4a13-9d21-232993826cd9", - boefje={"id": "dummy_boefje_environment"}, - input_ooi="Network|internet", - arguments=arguments, - organization="_dev", - ) - - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - - runner = LocalBoefjeJobRunner(local_repository) - - current_env = os.environ.copy() - - output = runner.run(meta, arguments) - - output_dict = ast.literal_eval(output[0][1].decode()) - - # Assert that there are no overlapping environment keys - assert not set(current_env.keys()) & set(output_dict.keys()) - - # Assert that the original environment has been restored correctly - assert current_env == os.environ - - def test_cannot_run_local_oci_boefje(self) -> None: - meta = BoefjeMeta( - id="b49cd6f5-4d92-4a13-9d21-232993826cd9", - boefje={"id": "dummy_oci_boefje_no_main"}, - input_ooi="Network|internet", - organization="_dev", - ) +def test_cannot_run_local_oci_boefje(mock_boefje_runner) -> None: + meta = BoefjeMeta( + id="b49cd6f5-4d92-4a13-9d21-232993826cd9", + boefje={"id": "dummy_oci_boefje_no_main"}, + input_ooi="Network|internet", + organization="_dev", + ) - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - runner = LocalBoefjeJobRunner(local_repository) - - with self.assertRaises(JobRuntimeError): - runner.run(meta, {}) - - def test_correct_local_runner_hash(self) -> None: - """This test checks if calculating the hash of local boefjes returns the correct result""" + with pytest.raises(JobRuntimeError): + mock_boefje_runner.run(meta, {}) - local_repository = LocalPluginRepository(Path(__file__).parent / "modules") - boefje_resource_1 = local_repository.by_id("dummy_boefje_environment") - boefje_resource_2 = local_repository.by_id("dummy") - # This boefje has a __pycache__ folder with *.pyc files, which should be ignored - boefje_resource_3 = local_repository.by_id("dummy_boefje_environment_with_pycache") +def test_correct_local_runner_hash(mock_local_repository) -> None: + """This test checks if calculating the hash of local boefjes returns the correct result""" + boefje_resource_1 = mock_local_repository.by_id("dummy_boefje_environment") + boefje_resource_2 = mock_local_repository.by_id("dummy") - # Sanity check to make sure the .pyc files are actually there - path = Path(__file__).parent / "modules" / "dummy_boefje_environment_with_pycache" - assert Path(path / "some_subdir/cache.pyc").is_file() - assert Path(path / "some_subdir/__init__.py").is_file() - assert Path(path / "__pycache__/pytest__init__.cpython-311.pyc").is_file() - assert Path(path / "__pycache__/pytest_main.cpython-311.pyc").is_file() + # This boefje has a __pycache__ folder with *.pyc files, which should be ignored + boefje_resource_3 = mock_local_repository.by_id("dummy_boefje_environment_with_pycache") - assert boefje_resource_1.runnable_hash == "7450ebc13f6856df925e90cd57f2769468a39723f18ba835749982b484564ec9" - assert boefje_resource_2.runnable_hash == "874e154b572a0315cfe4329bd3b756bf9cad77f6a87bb9b9b9bb6296f1d4b520" - assert boefje_resource_3.runnable_hash == "70c0b0ad3b2e70fd79e52dcf043096a50ed69db1359df0011499e66ab1510bbe" + # Sanity check to make sure the .pyc files are actually there + path = Path(__file__).parent / "modules" / "dummy_boefje_environment_with_pycache" + assert Path(path / "some_subdir/cache.pyc").is_file() + assert Path(path / "some_subdir/__init__.py").is_file() + assert Path(path / "__pycache__/pytest__init__.cpython-311.pyc").is_file() + assert Path(path / "__pycache__/pytest_main.cpython-311.pyc").is_file() + + assert boefje_resource_1.runnable_hash == "7450ebc13f6856df925e90cd57f2769468a39723f18ba835749982b484564ec9" + assert boefje_resource_2.runnable_hash == "874e154b572a0315cfe4329bd3b756bf9cad77f6a87bb9b9b9bb6296f1d4b520" + assert boefje_resource_3.runnable_hash == "70c0b0ad3b2e70fd79e52dcf043096a50ed69db1359df0011499e66ab1510bbe" diff --git a/boefjes/tests/test_testssl_sh.py b/boefjes/tests/test_testssl_sh.py deleted file mode 100644 index 67debdb735d..00000000000 --- a/boefjes/tests/test_testssl_sh.py +++ /dev/null @@ -1,124 +0,0 @@ -from unittest import TestCase - -from boefjes.plugins.kat_testssl_sh_ciphers.normalize import run -from tests.loading import get_dummy_data - -input_ooi = { - "object_type": "IPService", - "scan_profile": "scan_profile_type='declared' " - "reference=Reference('IPService|internet|134.209.85.72|tcp|80|http') level=", - "primary_key": "IPService|internet|134.209.85.72|tcp|80|http", - "ip_port": { - "address": {"network": {"name": "internet"}, "address": "134.209.85.72"}, - "protocol": "tcp", - "port": "80", - }, - "service": {"name": "http"}, -} - - -class TestsslSh(TestCase): - maxDiff = None - - def test_cipherless_service(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/testssl-sh-cipherless.json"), - ) - ) - - # noinspection PyTypeChecker - expected = [] - - self.assertEqual(expected, oois) - - def test_ciphered_service(self): - oois = list( - run( - input_ooi, - get_dummy_data("inputs/testssl-sh-ciphered.json"), - ) - ) - - # noinspection PyTypeChecker - expected_suites = { - "TLSv1.3": [ - { - "cipher_suite_alias": "TLS_AES_256_GCM_SHA384", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "TLS_AES_256_GCM_SHA384", - "key_size": 253, - "bits": 256, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "x1302", - }, - { - "cipher_suite_alias": "TLS_CHACHA20_POLY1305_SHA256", - "encryption_algorithm": "ChaCha20", - "cipher_suite_name": "TLS_CHACHA20_POLY1305_SHA256", - "key_size": 253, - "bits": 256, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "x1303", - }, - { - "cipher_suite_alias": "TLS_AES_128_GCM_SHA256", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "TLS_AES_128_GCM_SHA256", - "key_size": 253, - "bits": 128, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "x1301", - }, - ], - "TLSv1.2": [ - { - "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "ECDHE-RSA-AES256-GCM-SHA384", - "key_size": 521, - "bits": 256, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "xc030", - }, - { - "cipher_suite_alias": "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "DHE-RSA-AES256-GCM-SHA384", - "key_size": 2048, - "bits": 256, - "key_exchange_algorithm": "DH", - "cipher_suite_code": "x9f", - }, - { - "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "encryption_algorithm": "ChaCha20", - "cipher_suite_name": "ECDHE-RSA-CHACHA20-POLY1305", - "key_size": 521, - "bits": 256, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "xcca8", - }, - { - "cipher_suite_alias": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "ECDHE-RSA-AES128-GCM-SHA256", - "key_size": 521, - "bits": 128, - "key_exchange_algorithm": "ECDH", - "cipher_suite_code": "xc02f", - }, - { - "cipher_suite_alias": "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", - "encryption_algorithm": "AESGCM", - "cipher_suite_name": "DHE-RSA-AES128-GCM-SHA256", - "key_size": 2048, - "bits": 128, - "key_exchange_algorithm": "DH", - "cipher_suite_code": "x9e", - }, - ], - } - self.assertEqual(1, len(oois)) - self.assertEqual(expected_suites, oois[0].suites) diff --git a/boefjes/tests/test_wappalyzer_normalizer.py b/boefjes/tests/test_wappalyzer_normalizer.py deleted file mode 100644 index cf70b60bd4d..00000000000 --- a/boefjes/tests/test_wappalyzer_normalizer.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path -from unittest import TestCase - -from boefjes.job_models import NormalizerMeta -from boefjes.local import LocalNormalizerJobRunner -from boefjes.local_repository import LocalPluginRepository -from tests.loading import get_dummy_data - - -class WappalyzerNormalizerTest(TestCase): - def test_page_analyzer_normalizer(self): - meta = NormalizerMeta.model_validate_json(get_dummy_data("body-page-analysis-normalize.json")) - local_repository = LocalPluginRepository(Path(__file__).parent.parent / "boefjes" / "plugins") - - runner = LocalNormalizerJobRunner(local_repository) - output = runner.run(meta, get_dummy_data("download_page_analysis.raw")) - - results = output.observations[0].results - self.assertEqual(6, len(results)) - self.assertCountEqual( - ["Software|jQuery Migrate|1.0.0|", "Software|jQuery|3.6.0|", "Software|Bootstrap|3.3.7|"], - [o.primary_key for o in results if o.object_type == "Software"], - ) From daa78446b565e325cc4ccbdc3a7b5caf01eec630 Mon Sep 17 00:00:00 2001 From: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:56:47 +0200 Subject: [PATCH 28/82] Invert findings, add source URLs. (#3538) Co-authored-by: Jan Klopper --- .../kat_kat_finding_types/kat_finding_types.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json index 00fbbba47a4..f8e35c52111 100644 --- a/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json +++ b/boefjes/boefjes/plugins/kat_kat_finding_types/kat_finding_types.json @@ -13,14 +13,14 @@ "impact": "The usage possibility of JavaScript is not limited by the website. If the website contains a cross-site scripting vulnerability, then JavaScript code can be injected into the web page. This code is then executed by the browser of the victim. If a well-established Content Security Policy is active, the attacker can inject JavaScript code into the browser of the victim, but then the code will not get executed by the browser. A good configured Content Security Policy is a strong protection against cross-site scripting vulnerabilities.", "recommendation": "1. Set the Content-Security-Policy HTTP header in all HTTP answers. 2. Make sure that when the Content Security Policy is violated by a browser, that this violation is logged and monitored. Point the content security violation variable report-uri to a server-side log script. 3. Implement a process that periodically analyses these logs for programming errors and hack attacks." }, - "KAT-NO-X-PERMITTED-CROSS-DOMAIN-POLICIES": { + "KAT-X-PERMITTED-CROSS-DOMAIN-POLICIES": { "description": "The HTTP header X-Permitted-Cross-Domain- Policies is missing in HTTP responses. This header is not officially supported by Mozilla MDN.", "source": "https://owasp.org/www-project-secure-headers/#div-headers", "risk": "recommendation", "impact": "When the value of this header is not set to master- only, Adobe Flash or Adobe Acrobat (and possibly other software) can also look at cross-domain configuration files hosted at the web server.", "recommendation": "This header is not supported by default by Mozilla. If this header is required for your environment: Set the HTTP header X-Permitted-Cross- Domain-Policies: none in all HTTP responses. Use value master-only if a Flash or Acrobat cross- domain configuration file is used that is placed in the root of the web server" }, - "KAT-NO-EXPLICIT-XSS-PROTECTION": { + "KAT-EXPLICIT-XSS-PROTECTION": { "description": "The 'X-XSS-Protection' header is a deprecated header previously used to prevent against Cross-Site-Scripting attacks. Support in modern browsers could introduce XSS attacks again.", "source": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection", "risk": "recommendation", @@ -34,14 +34,14 @@ "impact": "There is a change that clickjacking is possible. This is an attack technique in which the website is invisibly loaded. On top of the original website, another malicious website is loaded that contains specially placed buttons or links. When the victim clicks on those buttons or links, the mouse click and thus its corresponding action is performed on the original website (which is made invisible). If the victim is logged in, then this click can perform an unauthorized action.", "recommendation": "1. Set the HTTP header X-Frame- Options with value deny (safest) or sameorigin in every HTTP answer for older browsers. 2. Set the frame-ancestors variable in the Content-Security-Policy header for modern browsers. 3. Add JavaScript code to all pages to ensure that these web pages may not be loaded within an
{% translate "Plugin name" %}{% translate "Plugin type" %}{% translate "Plugin type" %}{% translate "Plugin description" %} {% translate "Actions" %}
-

- {{ plugin.type|title }} -

-
+

+ {{ plugin.type|title }} +

+
{% if plugin.description %}{{ plugin.description }}{% endif %}