From d7cb42b78b1cfa0e7ed9ae39f335b0de14dd8c19 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:16:19 +0100 Subject: [PATCH 01/32] fix: removed unused import --- requirements.txt | 27 +------------------- shadowmere/{settings.py => settings/base.py} | 23 +++++------------ 2 files changed, 7 insertions(+), 43 deletions(-) rename shadowmere/{settings.py => settings/base.py} (94%) diff --git a/requirements.txt b/requirements.txt index bd3b53e..8b13789 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1 @@ -botocore==1.34.144 -Django==5.0.7 -django-admin-rangefilter==0.13.0 -django-filter==24.2 -django-import-export==4.1.1 -django-minio-storage==0.5.7 -django-prometheus==2.3.1 -django-ratelimit==4.1.0 -django-storages==1.14.4 -djangorestframework==3.15.2 -emoji-country-flag==2.0.1 -gevent==24.2.1 -gunicorn==22.0.0 -huey==2.5.1 -humanfriendly==10.0 -prometheus-client==0.20.0 -prompt-toolkit==3.0.47 -psycopg2-binary==2.9.9 -Pillow==10.4.0 -python-json-logger==2.0.7 -qrcode==7.4.2 -redis==5.0.7 -requests==2.32.3 -sentry-sdk==2.9.0 -sqlparse>=0.5.0 # not directly required, pinned by Snyk to avoid a vulnerability -zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability + diff --git a/shadowmere/settings.py b/shadowmere/settings/base.py similarity index 94% rename from shadowmere/settings.py rename to shadowmere/settings/base.py index bded46b..1d64bf5 100644 --- a/shadowmere/settings.py +++ b/shadowmere/settings/base.py @@ -11,6 +11,7 @@ """ import os +import environ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -18,6 +19,10 @@ from django.utils.translation import gettext_lazy as _ from pythonjsonlogger import jsonlogger +env = environ.Env( + DEBUG=(bool, False) +) + BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production @@ -100,23 +105,7 @@ # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases -if DEBUG: - DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - } - } -else: - DATABASES = { - "default": { - "ENGINE": "django_prometheus.db.backends.postgresql", - "NAME": "shadowmere", - "USER": "shadowmere", - "PASSWORD": os.getenv("POSTGRES_PASSWORD"), - "HOST": "db", - } - } +DATABASES = {"default": env.db()} # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators From c79ded3e0720d410e6cd1eba3db09b86600ba9d1 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:16:45 +0100 Subject: [PATCH 02/32] feat: splitted settings --- shadowmere/settings/__init__.py | 0 shadowmere/settings/base.py | 131 +++++++++++--------------------- shadowmere/settings/dev.py | 1 + shadowmere/settings/prod.py | 47 ++++++++++++ 4 files changed, 94 insertions(+), 85 deletions(-) create mode 100644 shadowmere/settings/__init__.py create mode 100644 shadowmere/settings/dev.py create mode 100644 shadowmere/settings/prod.py diff --git a/shadowmere/settings/__init__.py b/shadowmere/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shadowmere/settings/base.py b/shadowmere/settings/base.py index 1d64bf5..54c86b0 100644 --- a/shadowmere/settings/base.py +++ b/shadowmere/settings/base.py @@ -9,57 +9,52 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.2/ref/settings/ """ - import os import environ from pathlib import Path +from datetime import date # Build paths inside the project like this: BASE_DIR / 'subdir'. +from celery.schedules import crontab from django.contrib.admin import AdminSite from django.utils.translation import gettext_lazy as _ -from pythonjsonlogger import jsonlogger env = environ.Env( - DEBUG=(bool, False) + DEBUG=(bool, False), + SHADOWTEST_URL=(str, "https://shadowtest.akiel.dev/v1/test"), + ALLOWED_HOSTS=(str, ""), + CSRF_TRUSTED_ORIGINS=(str, ""), + CORS_ALLOWED_ORIGINS=(str, ""), + MINIO_ENDPOINT=(str, ""), + MINIO_ACCESS_KEY=(str, ""), + MINIO_SECRET_KEY=(str, ""), ) BASE_DIR = Path(__file__).resolve().parent.parent -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ +SECRET_KEY = env("SECRET_KEY") -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = os.getenv("SECRET_KEY") +DEBUG = env("DEBUG") -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = os.getenv("DEBUG", False) +SHADOWTEST_URL = env("SHADOWTEST_URL") -SHADOWTEST_URL = os.getenv("SHADOWTEST_URL", "https://shadowtest.akiel.dev/v2/test") +ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ") -ALLOWED_HOSTS = [ - "localhost", - "127.0.0.1", - "shadowmere.xyz", - "shadowmere.akiel.dev", - "old.shadowmere.akiel.dev", - "eb7x5hfb3vbb3zgrzi6qf6sqwks64fp63a7ckdl3sdw5nb6bgvskvpyd.onion", -] +CSRF_TRUSTED_ORIGINS: str = env("CSRF_TRUSTED_ORIGINS").split(" ") -CSRF_TRUSTED_ORIGINS = [ - "https://shadowmere.akiel.dev", - "https://shadowmere.xyz", -] +CORS_ALLOWED_ORIGINS: str = env("CORS_ALLOWED_ORIGINS").split(" ") -# Application definition - -INSTALLED_APPS = [ +DJANGO_APPS = [ + "jazzmin", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - "proxylist.apps.ProxylistConfig", +] + +THIRD_PARTY_APPS = [ "storages", "import_export", "django_prometheus", @@ -69,8 +64,13 @@ "django_filters", ] +LOCAL_APPS = [ + "proxylist.apps.ProxylistConfig", +] + +INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS + MIDDLEWARE = [ - "django_prometheus.middleware.PrometheusBeforeMiddleware", "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.locale.LocaleMiddleware", @@ -79,8 +79,6 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "django_ratelimit.middleware.RatelimitMiddleware", - "django_prometheus.middleware.PrometheusAfterMiddleware", ] ROOT_URLCONF = "shadowmere.urls" @@ -103,13 +101,8 @@ WSGI_APPLICATION = "shadowmere.wsgi.application" -# Database -# https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = {"default": env.db()} -# Password validation -# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators - AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", @@ -154,14 +147,10 @@ "level": "INFO", "propagate": True, }, - # Add other loggers here as needed }, } -# Internationalization -# https://docs.djangoproject.com/en/3.2/topics/i18n/ - LANGUAGE_CODE = "en-us" TIME_ZONE = "UTC" @@ -179,34 +168,9 @@ LOCALE_PATHS = ("./locale",) -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.2/howto/static-files/ - STATIC_URL = "/static/" -STATIC_ROOT = "./static_files/" -if not DEBUG: - DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage" - STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage" - MINIO_STORAGE_ENDPOINT = os.getenv("MINIO_ENDPOINT") - MINIO_STORAGE_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY") - MINIO_STORAGE_SECRET_KEY = os.getenv("MINIO_SECRET_KEY") - MINIO_STORAGE_USE_HTTPS = True - MINIO_STORAGE_MEDIA_BUCKET_NAME = ( - f"{os.getenv('MINIO_BUCKET')}-media" - if os.getenv("MINIO_BUCKET") != "" - else "shadowmere-media" - ) - MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True - MINIO_STORAGE_STATIC_BUCKET_NAME = ( - f"{os.getenv('MINIO_BUCKET')}-static" - if os.getenv("MINIO_BUCKET") != "" - else "shadowmere-static" - ) - MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True - -# Default primary key field type -# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field +STATIC_ROOT = "./static_files/" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" @@ -241,10 +205,6 @@ }, } -AdminSite.site_header = "Shadowmere administration" - -PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008) - REST_FRAMEWORK = { "DEFAULT_PAGINATION_CLASS": "proxylist.pagination.ProxiesPagination", "PAGE_SIZE": 10, @@ -253,25 +213,26 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 CONN_MAX_AGE = 60 + CONN_HEALTH_CHECKS = True -if not DEBUG and os.getenv("SENTRY_DSN") != "": - import sentry_sdk - from sentry_sdk.integrations.django import DjangoIntegration - - sentry_sdk.init( - dsn=os.getenv("SENTRY_DSN"), - integrations=[ - DjangoIntegration(), - ], - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for performance monitoring. - # We recommend adjusting this value in production. - traces_sample_rate=0.01, - # If you wish to associate users to errors (assuming you are using - # django.contrib.auth) you may enable sending PII data. - send_default_pii=True, - ) +SECURE_BROWSER_XSS_FILTER = True + +SECURE_CONTENT_TYPE_NOSNIFF = True + +SECURE_HOSTS_INCLUDE_SUBDOMAINS = True + +X_FRAME_OPTIONS = "SAMEORIGIN" + +FILTERS_DEFAULT_LOOKUP_EXPR = "icontains" + +JAZZMIN_SETTINGS = { + "site_title": "Shadowmere Administration", + "site_header": "Shadowmere", + "site_brand": "Shadowmere", + "welcome_sign": "Welcome to Shadowmere Administration", + "copyright": f"Shadowmere {date.year}", +} RATELIMIT_ENABLE = False RATELIMIT_VIEW = "proxylist.views.ratelimited_error" diff --git a/shadowmere/settings/dev.py b/shadowmere/settings/dev.py new file mode 100644 index 0000000..4b40b38 --- /dev/null +++ b/shadowmere/settings/dev.py @@ -0,0 +1 @@ +from .base import * # noqa diff --git a/shadowmere/settings/prod.py b/shadowmere/settings/prod.py new file mode 100644 index 0000000..575ed4b --- /dev/null +++ b/shadowmere/settings/prod.py @@ -0,0 +1,47 @@ +from .base import * # noqa +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration + +MIDDLEWARE = ( + ["django_prometheus.middleware.PrometheusBeforeMiddleware"] + + MIDDLEWARE + + ["django_prometheus.middleware.PrometheusAfterMiddleware"] +) + +THIRD_PARTY_APPS += ["django_prometheus"] + +DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage" + +STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage" + +MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT") + +MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY") + +MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY") + +MINIO_STORAGE_USE_HTTPS = True + +MINIO_STORAGE_MEDIA_BUCKET_NAME = "shadowmere-media" + +MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True + +MINIO_STORAGE_STATIC_BUCKET_NAME = "shadowmere-static" + +MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True + +sentry_sdk.init( + dsn=env("SENTRY_DSN"), + integrations=[ + DjangoIntegration(), + ], + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + # We recommend adjusting this value in production. + traces_sample_rate=0.01, + # If you wish to associate users to errors (assuming you are using + # django.contrib.auth) you may enable sending PII data. + send_default_pii=True, +) + +PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008) From 4b1d1cf76cb9b1119bed278d25ea5bd8636b2444 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:17:09 +0100 Subject: [PATCH 03/32] feat: executing correct settings --- shadowmere/celery.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 shadowmere/celery.py diff --git a/shadowmere/celery.py b/shadowmere/celery.py new file mode 100644 index 0000000..e69de29 From ec8295b5efd5f28691960a9adcaea25a413da233 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:17:19 +0100 Subject: [PATCH 04/32] feat: added docker scripts --- docker/celery/beat/start | 7 +++++++ docker/celery/worker/start | 7 +++++++ docker/entrypoint | 30 ++++++++++++++++++++++++++++++ docker/start | 15 +++++++++++++++ docker/wait_for_migration.sh | 16 ++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 docker/celery/beat/start create mode 100644 docker/celery/worker/start create mode 100755 docker/entrypoint create mode 100755 docker/start create mode 100755 docker/wait_for_migration.sh diff --git a/docker/celery/beat/start b/docker/celery/beat/start new file mode 100644 index 0000000..be41c09 --- /dev/null +++ b/docker/celery/beat/start @@ -0,0 +1,7 @@ +#!/bin/bash + +set -o errexit +set -o nounset + +rm -f './celerybeat.pid' +celery -A shadowmere beat -l info diff --git a/docker/celery/worker/start b/docker/celery/worker/start new file mode 100644 index 0000000..35e1855 --- /dev/null +++ b/docker/celery/worker/start @@ -0,0 +1,7 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + +celery -A shadowmere worker -l info -E diff --git a/docker/entrypoint b/docker/entrypoint new file mode 100755 index 0000000..89d4d8b --- /dev/null +++ b/docker/entrypoint @@ -0,0 +1,30 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +cmd="$@" + +function postgres_ready(){ +python << END +import sys +import psycopg2 +import os + +try: + dbname = os.getenv('POSTGRES_DB') + user = os.getenv('POSTGRES_USER') + password = os.getenv('POSTGRES_PASSWORD') + conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432) +except psycopg2.OperationalError: + sys.exit(-1) +sys.exit(0) +END +} + +until postgres_ready; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - continuing..." +exec $cmd diff --git a/docker/start b/docker/start new file mode 100755 index 0000000..35388e8 --- /dev/null +++ b/docker/start @@ -0,0 +1,15 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset +set -o xtrace + +python manage.py migrate --no-input +python manage.py initadmin +if [ "${DEBUG}" == "True" ]; then + python manage.py runserver 0.0.0.0:8001 +else + python manage.py collectstatic --no-input + gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output +fi diff --git a/docker/wait_for_migration.sh b/docker/wait_for_migration.sh new file mode 100755 index 0000000..8d85db1 --- /dev/null +++ b/docker/wait_for_migration.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +cmd="$@" + +if [ "${IS_DJANGO_SERVICE}" == "True" ]; then + echo "Waiting for the database to become available..." + until python3 manage.py migrate; do + echo "Database is unavailable, sleeping for 5 seconds..." + done +else + sleep 30 +fi + +exec $cmd From 4bea753a39e0c81973a5ed458dcb3e0bc033fa07 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:17:32 +0100 Subject: [PATCH 05/32] feat: static methods for proxyadmin --- proxylist/admin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxylist/admin.py b/proxylist/admin.py index 56396ea..130dbaf 100644 --- a/proxylist/admin.py +++ b/proxylist/admin.py @@ -17,6 +17,8 @@ class Meta: @admin.register(Proxy) class ProxyAdmin(ImportExportModelAdmin): + + @staticmethod def update_status(modeladmin, request, queryset): for proxy in queryset: update_proxy_status(proxy) @@ -26,6 +28,7 @@ def update_status(modeladmin, request, queryset): # This means the proxy is either a duplicate or no longer valid proxy.delete() + @staticmethod def quality(self, obj): if obj.times_checked > 0: return obj.times_check_succeeded * 100 / obj.times_checked From 7e2531e79c9bb9779d4c1fd2799b0c3d81b2ce6f Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:17:43 +0100 Subject: [PATCH 06/32] feat: improved dockerignore --- .dockerignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 02b272a..3948023 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,7 @@ venv/ .env* db.sqlite3 -.github +.github/ +.git/ +.idea/ +.venv/ From d9ab5b322a1057f621a908f47c2fd094d6df035c Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:17:57 +0100 Subject: [PATCH 07/32] feat: added docker compose recipe for dev env --- docker-compose.dev.yml | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docker-compose.dev.yml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..6fae01d --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,53 @@ +version: "3" +volumes: + shadowmere_data: + redis_data: + +services: + redis: + image: redis:alpine + restart: always + volumes: + - redis_data:/data + + db: + image: postgres:alpine + restart: always + volumes: + - shadowmere_data:/var/lib/postgresql/data + env_file: .env + + shadowmere: + &shadowmere + build: + context: . + image: guamulo/shadowmere + restart: always + command: /start + env_file: .env + depends_on: + - db + ports: + - "8001:8001" + + celery: + <<: *shadowmere + image: guamulo/shadowmere-celeryworker + restart: always + command: /wait_for_migration.sh /start-celeryworker + env_file: .env + depends_on: + - redis + ports: [] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + + celery_beat: + <<: *shadowmere + image: guamulo/shadowmere-celerybeat + restart: always + command: /wait_for_migration.sh /start-celerybeat + env_file: .env + ports: [] + depends_on: + - redis From 5b9ea89fe66ea8c6d8474c792fbedfc45e1b65cd Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:18:08 +0100 Subject: [PATCH 08/32] feat: uisng envs --- manage.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/manage.py b/manage.py index 7ec304c..b0afc13 100755 --- a/manage.py +++ b/manage.py @@ -1,12 +1,13 @@ #!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" import os import sys def main(): - """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings") + if os.getenv("DEBUG") == "True": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.dev") + else: + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.prod") try: from django.core.management import execute_from_command_line except ImportError as exc: From 76dfc2ccf0bf948fa1cb1e4a1a86e290cec41b52 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:18:22 +0100 Subject: [PATCH 09/32] feat: potry lock and toml --- poetry.lock | 1515 +++++++++++++++++++++++++++++++++++++++++++++++++++ poetry.toml | 3 + 2 files changed, 1518 insertions(+) create mode 100644 poetry.lock create mode 100644 poetry.toml diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..6c1dacd --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1515 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "amqp" +version = "5.2.0" +description = "Low-level AMQP client for Python (fork of amqplib)." +optional = false +python-versions = ">=3.6" +files = [ + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, +] + +[package.dependencies] +vine = ">=5.0.0,<6.0.0" + +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + +[[package]] +name = "asgiref" +version = "3.7.2" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.7" +files = [ + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "billiard" +version = "4.2.0" +description = "Python multiprocessing fork with improvements and bugfixes" +optional = false +python-versions = ">=3.7" +files = [ + {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, + {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, +] + +[[package]] +name = "botocore" +version = "1.33.11" +description = "Low-level, data-driven core of boto 3." +optional = false +python-versions = ">= 3.7" +files = [ + {file = "botocore-1.33.11-py3-none-any.whl", hash = "sha256:b46227eb3fa9cfdc8f5a83920ef347e67adea8095830ed265a3373b13b54421f"}, + {file = "botocore-1.33.11.tar.gz", hash = "sha256:b14b328f902d120de0a09eaa657a9a701c0ceeb711197c2f01ef0523f855086c"}, +] + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""} + +[package.extras] +crt = ["awscrt (==0.19.17)"] + +[[package]] +name = "cattrs" +version = "23.2.3" +description = "Composable complex class support for attrs and dataclasses." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, + {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, +] + +[package.dependencies] +attrs = ">=23.1.0" +exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} + +[package.extras] +bson = ["pymongo (>=4.4.0)"] +cbor2 = ["cbor2 (>=5.4.6)"] +msgpack = ["msgpack (>=1.0.5)"] +orjson = ["orjson (>=3.9.2)"] +pyyaml = ["pyyaml (>=6.0)"] +tomlkit = ["tomlkit (>=0.11.8)"] +ujson = ["ujson (>=5.7.0)"] + +[[package]] +name = "celery" +version = "5.3.6" +description = "Distributed Task Queue." +optional = false +python-versions = ">=3.8" +files = [ + {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, + {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"}, +] + +[package.dependencies] +billiard = ">=4.2.0,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.3.4,<6.0" +python-dateutil = ">=2.8.2" +tzdata = ">=2022.7" +vine = ">=5.1.0,<6.0" + +[package.extras] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==41.0.5)"] +azureblockblob = ["azure-storage-blob (>=12.15.0)"] +brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0)"] +couchdb = ["pycouchdb (==1.14.2)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"] +eventlet = ["eventlet (>=0.32.0)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +memcache = ["pylibmc (==1.6.3)"] +mongodb = ["pymongo[srv] (>=4.0.2)"] +msgpack = ["msgpack (==1.0.7)"] +pymemcache = ["python-memcached (==1.59)"] +pyro = ["pyro4 (==4.82)"] +pytest = ["pytest-celery (==0.0.0)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +solar = ["ephem (==4.1.5)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=1.3.1)"] +zstd = ["zstandard (==0.22.0)"] + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click-didyoumean" +version = "0.3.0" +description = "Enables git-like *did-you-mean* feature in click" +optional = false +python-versions = ">=3.6.2,<4.0.0" +files = [ + {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, + {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, +] + +[package.dependencies] +click = ">=7" + +[[package]] +name = "click-plugins" +version = "1.1.1" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = false +python-versions = "*" +files = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = false +python-versions = ">=3.6" +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "diff-match-patch" +version = "20230430" +description = "Diff Match and Patch" +optional = false +python-versions = ">=3.7" +files = [ + {file = "diff-match-patch-20230430.tar.gz", hash = "sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c"}, + {file = "diff_match_patch-20230430-py3-none-any.whl", hash = "sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93"}, +] + +[package.extras] +dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1.2.0)", "ufmt (==2.1.0)", "usort (==1.0.6)"] + +[[package]] +name = "django" +version = "5.0" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.10" +files = [ + {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"}, + {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"}, +] + +[package.dependencies] +asgiref = ">=3.7.0" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-admin-rangefilter" +version = "0.12.0" +description = "django-admin-rangefilter app, add the filter by a custom date range on the admin UI." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "django-admin-rangefilter-0.12.0.tar.gz", hash = "sha256:56035f4190d35aad4e699f8fd81306f964642edc96e15ec2a532a1598a466615"}, + {file = "django_admin_rangefilter-0.12.0-py2.py3-none-any.whl", hash = "sha256:4fd7211271c70c51469fc39b182b70f1199ab9ce0b16264654a2eec96751d686"}, +] + +[[package]] +name = "django-environ" +version = "0.11.2" +description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"}, + {file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"}, +] + +[package.extras] +develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] + +[[package]] +name = "django-filter" +version = "23.5" +description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-filter-23.5.tar.gz", hash = "sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c"}, + {file = "django_filter-23.5-py3-none-any.whl", hash = "sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400"}, +] + +[package.dependencies] +Django = ">=3.2" + +[[package]] +name = "django-import-export" +version = "3.3.3" +description = "Django application and library for importing and exporting data with included admin integration." +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-import-export-3.3.3.tar.gz", hash = "sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e"}, + {file = "django_import_export-3.3.3-py3-none-any.whl", hash = "sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978"}, +] + +[package.dependencies] +diff-match-patch = "*" +Django = ">=3.2" +tablib = {version = "3.5.0", extras = ["html", "ods", "xls", "xlsx", "yaml"]} + +[[package]] +name = "django-jazzmin" +version = "2.6.0" +description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "django_jazzmin-2.6.0-py3-none-any.whl", hash = "sha256:fb554c2d564649c65243b13385121fdbdda58521f49544f9d7cb9c414a4908d4"}, + {file = "django_jazzmin-2.6.0.tar.gz", hash = "sha256:5bb07055cf19183030724f976904fd8b6337559727959340a43832fab0531812"}, +] + +[package.dependencies] +django = ">=2.2" + +[[package]] +name = "django-minio-storage" +version = "0.5.7" +description = "Django file storage using the minio python client" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-minio-storage-0.5.7.tar.gz", hash = "sha256:9e499600340b7a7a4bc86063f54218631b65bc46dee9d2faf578f17ebc2a6d92"}, + {file = "django_minio_storage-0.5.7-py3-none-any.whl", hash = "sha256:2e36b4f3c44c83a124e7b811e19c502cbeab77149bc7c73763e901b1948737bb"}, +] + +[package.dependencies] +django = ">=3.2" +minio = ">=7.1.16" + +[[package]] +name = "django-prometheus" +version = "2.3.1" +description = "Django middlewares to monitor your application with Prometheus.io." +optional = false +python-versions = "*" +files = [ + {file = "django-prometheus-2.3.1.tar.gz", hash = "sha256:f9c8b6c780c9419ea01043c63a437d79db2c33353451347894408184ad9c3e1e"}, + {file = "django_prometheus-2.3.1-py2.py3-none-any.whl", hash = "sha256:cf9b26f7ba2e4568f08f8f91480a2882023f5908579681bcf06a4d2465f12168"}, +] + +[package.dependencies] +prometheus-client = ">=0.7" + +[[package]] +name = "django-storages" +version = "1.14.2" +description = "Support for many storage backends in Django" +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"}, + {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"}, +] + +[package.dependencies] +Django = ">=3.2" + +[package.extras] +azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"] +boto3 = ["boto3 (>=1.4.4)"] +dropbox = ["dropbox (>=7.2.1)"] +google = ["google-cloud-storage (>=1.27)"] +libcloud = ["apache-libcloud"] +s3 = ["boto3 (>=1.4.4)"] +sftp = ["paramiko (>=1.15)"] + +[[package]] +name = "djangorestframework" +version = "3.14.0" +description = "Web APIs for Django, made easy." +optional = false +python-versions = ">=3.6" +files = [ + {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, + {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, +] + +[package.dependencies] +django = ">=3.0" +pytz = "*" + +[[package]] +name = "emoji-country-flag" +version = "1.3.2" +description = "En/Decode unicode country flags emoji" +optional = false +python-versions = ">=3.7" +files = [ + {file = "emoji-country-flag-1.3.2.tar.gz", hash = "sha256:42d9fc1a8ec27b3ef2c18a39532dcdbf0527afbc95749be02a3afc1f1b165aa3"}, + {file = "emoji_country_flag-1.3.2-py2.py3-none-any.whl", hash = "sha256:6ddcf8f3bc55b2f59b1d7d9dc830e90f9423f555dd37862c4c2e220d42726f73"}, +] + +[package.extras] +test = ["emoji", "pytest", "setuptools"] + +[[package]] +name = "et-xmlfile" +version = "1.1.0" +description = "An implementation of lxml.xmlfile for the standard library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, + {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "gunicorn" +version = "21.2.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.5" +files = [ + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + +[[package]] +name = "kombu" +version = "5.3.4" +description = "Messaging library for Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "kombu-5.3.4-py3-none-any.whl", hash = "sha256:63bb093fc9bb80cfb3a0972336a5cec1fa7ac5f9ef7e8237c6bf8dda9469313e"}, + {file = "kombu-5.3.4.tar.gz", hash = "sha256:0bb2e278644d11dea6272c17974a3dbb9688a949f3bb60aeb5b791329c44fadc"}, +] + +[package.dependencies] +amqp = ">=5.1.1,<6.0.0" +vine = "*" + +[package.extras] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +mongodb = ["pymongo (>=4.1.1)"] +msgpack = ["msgpack"] +pyro = ["pyro4"] +qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[[package]] +name = "lsprotocol" +version = "2023.0.0" +description = "Python implementation of the Language Server Protocol." +optional = false +python-versions = ">=3.7" +files = [ + {file = "lsprotocol-2023.0.0-py3-none-any.whl", hash = "sha256:e85fc87ee26c816adca9eb497bb3db1a7c79c477a11563626e712eaccf926a05"}, + {file = "lsprotocol-2023.0.0.tar.gz", hash = "sha256:c9d92e12a3f4ed9317d3068226592860aab5357d93cf5b2451dc244eee8f35f2"}, +] + +[package.dependencies] +attrs = ">=21.3.0" +cattrs = "*" + +[[package]] +name = "markuppy" +version = "1.14" +description = "An HTML/XML generator" +optional = false +python-versions = "*" +files = [ + {file = "MarkupPy-1.14.tar.gz", hash = "sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f"}, +] + +[[package]] +name = "minio" +version = "7.2.0" +description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" +optional = false +python-versions = "*" +files = [ + {file = "minio-7.2.0-py3-none-any.whl", hash = "sha256:10656272c16156fa08436ce2b27e25e4134ef5142a8c259513ee26fb514531a6"}, + {file = "minio-7.2.0.tar.gz", hash = "sha256:4b015b018d10c1505f7c3e724fa7c2267760ac7bee6463a624cbf22cd272877b"}, +] + +[package.dependencies] +argon2-cffi = "*" +certifi = "*" +pycryptodome = "*" +urllib3 = "*" + +[[package]] +name = "odfpy" +version = "1.4.1" +description = "Python API and tools to manipulate OpenDocument files" +optional = false +python-versions = "*" +files = [ + {file = "odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec"}, +] + +[package.dependencies] +defusedxml = "*" + +[[package]] +name = "openpyxl" +version = "3.1.2" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +optional = false +python-versions = ">=3.6" +files = [ + {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"}, + {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"}, +] + +[package.dependencies] +et-xmlfile = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pillow" +version = "10.1.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, + {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, + {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, + {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, + {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, + {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, + {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "prometheus-client" +version = "0.19.0" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.8" +files = [ + {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, + {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"}, +] + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.41" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, + {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psycopg2-binary" +version = "2.9.9" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, + {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, + {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, + {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, + {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, + {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pycryptodome" +version = "3.19.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, + {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, +] + +[[package]] +name = "pygls" +version = "1.2.1" +description = "A pythonic generic language server (pronounced like 'pie glass')" +optional = false +python-versions = ">=3.7.9,<4" +files = [ + {file = "pygls-1.2.1-py3-none-any.whl", hash = "sha256:7dcfcf12b6f15beb606afa46de2ed348b65a279c340ef2242a9a35c22eeafe94"}, + {file = "pygls-1.2.1.tar.gz", hash = "sha256:04f9b9c115b622dcc346fb390289066565343d60245a424eca77cb429b911ed8"}, +] + +[package.dependencies] +lsprotocol = "2023.0.0" + +[package.extras] +ws = ["websockets (>=11.0.3,<12.0.0)"] + +[[package]] +name = "pypng" +version = "0.20220715.0" +description = "Pure Python library for saving and loading PNG images" +optional = false +python-versions = "*" +files = [ + {file = "pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"}, + {file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"}, +] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "qrcode" +version = "7.4.2" +description = "QR Code image generator" +optional = false +python-versions = ">=3.7" +files = [ + {file = "qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"}, + {file = "qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +pypng = "*" +typing-extensions = "*" + +[package.extras] +all = ["pillow (>=9.1.0)", "pytest", "pytest-cov", "tox", "zest.releaser[recommended]"] +dev = ["pytest", "pytest-cov", "tox"] +maintainer = ["zest.releaser[recommended]"] +pil = ["pillow (>=9.1.0)"] +test = ["coverage", "pytest"] + +[[package]] +name = "redis" +version = "5.0.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.7" +files = [ + {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, + {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "ruff" +version = "0.1.7" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"}, + {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"}, + {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"}, + {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"}, + {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"}, + {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"}, +] + +[[package]] +name = "ruff-lsp" +version = "0.0.45" +description = "A Language Server Protocol implementation for Ruff." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff_lsp-0.0.45-py3-none-any.whl", hash = "sha256:6be86369fc2ed7a363d9377301beeb60130477d89d09339a2401717e158e9936"}, + {file = "ruff_lsp-0.0.45.tar.gz", hash = "sha256:11c2d4979eabf81327b714f9395b91be1f3620a8861009ae4967f67e7de2671d"}, +] + +[package.dependencies] +lsprotocol = ">=2023.0.0a1" +packaging = ">=23.1" +pygls = ">=1.1.0" +ruff = ">=0.0.274" +typing-extensions = "*" + +[package.extras] +dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0)", "pytest-asyncio (==0.21.1)", "python-lsp-jsonrpc (==1.0.0)"] + +[[package]] +name = "sentry-sdk" +version = "1.38.0" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = "*" +files = [ + {file = "sentry-sdk-1.38.0.tar.gz", hash = "sha256:8feab81de6bbf64f53279b085bd3820e3e737403b0a0d9317f73a2c3374ae359"}, + {file = "sentry_sdk-1.38.0-py2.py3-none-any.whl", hash = "sha256:0017fa73b8ae2d4e57fd2522ee3df30453715b29d2692142793ec5d5f90b94a6"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +loguru = ["loguru (>=0.5)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "tablib" +version = "3.5.0" +description = "Format agnostic tabular data library (XLS, JSON, YAML, CSV, etc.)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tablib-3.5.0-py3-none-any.whl", hash = "sha256:9821caa9eca6062ff7299fa645e737aecff982e6b2b42046928a6413c8dabfd9"}, + {file = "tablib-3.5.0.tar.gz", hash = "sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33"}, +] + +[package.dependencies] +markuppy = {version = "*", optional = true, markers = "extra == \"html\""} +odfpy = {version = "*", optional = true, markers = "extra == \"ods\""} +openpyxl = {version = ">=2.6.0", optional = true, markers = "extra == \"xlsx\""} +pyyaml = {version = "*", optional = true, markers = "extra == \"yaml\""} +xlrd = {version = "*", optional = true, markers = "extra == \"xls\""} +xlwt = {version = "*", optional = true, markers = "extra == \"xls\""} + +[package.extras] +all = ["markuppy", "odfpy", "openpyxl (>=2.6.0)", "pandas", "pyyaml", "tabulate", "xlrd", "xlwt"] +cli = ["tabulate"] +html = ["markuppy"] +ods = ["odfpy"] +pandas = ["pandas"] +xls = ["xlrd", "xlwt"] +xlsx = ["openpyxl (>=2.6.0)"] +yaml = ["pyyaml"] + +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "urllib3" +version = "2.0.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.24.0.post1" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.24.0.post1-py3-none-any.whl", hash = "sha256:7c84fea70c619d4a710153482c0d230929af7bcf76c7bfa6de151f0a3a80121e"}, + {file = "uvicorn-0.24.0.post1.tar.gz", hash = "sha256:09c8e5a79dc466bdf28dead50093957db184de356fcdc48697bad3bde4c2588e"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "vine" +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.12" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, +] + +[[package]] +name = "xlrd" +version = "2.0.1" +description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "xlrd-2.0.1-py2.py3-none-any.whl", hash = "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd"}, + {file = "xlrd-2.0.1.tar.gz", hash = "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88"}, +] + +[package.extras] +build = ["twine", "wheel"] +docs = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "xlwt" +version = "1.3.0" +description = "Library to create spreadsheet files compatible with MS Excel 97/2000/XP/2003 XLS files, on any platform, with Python 2.6, 2.7, 3.3+" +optional = false +python-versions = "*" +files = [ + {file = "xlwt-1.3.0-py2.py3-none-any.whl", hash = "sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e"}, + {file = "xlwt-1.3.0.tar.gz", hash = "sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "05fa8b336882246b6693e65438939ca68b15eec4b1a30c3929b3e9e57961cac1" diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..4f3a13d --- /dev/null +++ b/poetry.toml @@ -0,0 +1,3 @@ +[virtualenvs] +path = ".venv" +in-project = true From 119679147ff68e3896e73afd1c4e0d54a319a4d0 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:18:31 +0100 Subject: [PATCH 10/32] feat: pyproject config --- pyproject.toml | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..07ca803 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[tool.poetry] +name = "shadowmere" +version = "1.0.0" +description = "An automatically tested list of Shadowsocks proxies." +authors = ["Your Name "] +license = "GPLv3" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.12" +django = "^5.0" +celery = "^5.3.6" +django-minio-storage = "^0.5.7" +django-prometheus = "^2.3.1" +django-storages = "^1.14.2" +djangorestframework = "^3.14.0" +emoji-country-flag = "^1.3.2" +psycopg2-binary = "^2.9.9" +pillow = "^10.1.0" +qrcode = "^7.4.2" +requests = "^2.31.0" +redis = "^5.0.1" +sentry-sdk = "^1.38.0" +django-admin-rangefilter = "^0.12.0" +django-filter = "^23.5" +django-import-export = "^3.3.3" +botocore = "^1.33.11" +django-environ = "^0.11.2" +uvicorn = "^0.24.0.post1" +gunicorn = "^21.2.0" +django-jazzmin = "^2.6.0" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.1.7" +ruff-lsp = "^0.0.45" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +select = ["E", "F"] +ignore = [] +line-length = 120 +target-version = "py312" From 93372e08e8cf107d8f858a02cbfab02ce325701d Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:19:20 +0100 Subject: [PATCH 11/32] feat/fix: removed prints and code reformat --- proxylist/tasks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/proxylist/tasks.py b/proxylist/tasks.py index 35ec8de..4e475dc 100644 --- a/proxylist/tasks.py +++ b/proxylist/tasks.py @@ -14,6 +14,7 @@ from proxylist.base64_decoder import decode_base64 from proxylist.models import Proxy, Subscription, get_sip002, TaskLog from proxylist.proxy import update_proxy_status, get_proxy_location +from shadowmere.celery import app CONCURRENT_CHECKS = 200 SUBSCRIPTION_TIMEOUT_SECONDS = 60 From 9c65dd7af8f6579940a14af3186ae64003125cfa Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:19:32 +0100 Subject: [PATCH 12/32] feat: code reformat and correct settings import --- proxylist/proxy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxylist/proxy.py b/proxylist/proxy.py index ec5f70d..3189a88 100644 --- a/proxylist/proxy.py +++ b/proxylist/proxy.py @@ -1,8 +1,8 @@ import requests from django.utils.timezone import now +from django.conf import settings from requests.exceptions import InvalidJSONError -from shadowmere import settings def get_proxy_location(proxy_url): From 4ba584e5741311e5987df991ceb51efdea49d55f Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:19:44 +0100 Subject: [PATCH 13/32] feat: code reformat --- proxylist/models.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/proxylist/models.py b/proxylist/models.py index ad4b2f3..0a31d2b 100644 --- a/proxylist/models.py +++ b/proxylist/models.py @@ -78,14 +78,8 @@ def get_sip002(instance_url): url = url.replace("ss://", "") decoded_url = decode_base64(url.encode("ascii")) if decoded_url: - encoded_bits = ( - base64.b64encode(decoded_url.split(b"@")[0]) - .decode("ascii") - .rstrip("=") - ) - url = ( - f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}' - ) + encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=") + url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}' else: return "" except IndexError: @@ -128,9 +122,7 @@ class SubscriptionKind(models.TextChoices): BASE64 = "BASE64", "base64" url = models.URLField(null=False, unique=True) - kind = models.CharField( - choices=SubscriptionKind.choices, default=SubscriptionKind.PLAIN, max_length=10 - ) + kind = models.CharField(choices=SubscriptionKind.choices, default=SubscriptionKind.PLAIN, max_length=10) alive = models.BooleanField(default=True) alive_timestamp = models.DateTimeField(default=now) enabled = models.BooleanField(default=True) From 228a6c18409b9cba12d45e12dc3942b76df807af Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 10 Dec 2023 22:19:57 +0100 Subject: [PATCH 14/32] feat/wip: multistage build --- Dockerfile | 81 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 98d21bf..88f6e45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,73 @@ -FROM python:3.12-slim -WORKDIR /home/ +FROM python:3.12-slim as python-base -ENV APP_HOME=/home/ -ENV APP_USER=shadowmere +ENV DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 \ + POETRY_VERSION="1.7.1" \ + POETRY_HOME="/opt/poetry" \ + POETRY_VENV="/opt/poetry-venv" \ + POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 \ + POETRY_VIRTUALENVS_CREATE=1 \ + POETRY_CACHE_DIR="/opt/.cache" \ + PROJECT_PATH="/shadowmere" \ + PROJECT_USER="shadowmere" \ + VENV_PATH="/shadowmere/.venv" -RUN groupadd -r $APP_USER && \ - useradd -r -g $APP_USER -d $APP_HOME -s /sbin/nologin -c "Docker image user" $APP_USER -RUN pip install --upgrade pip +ENV PATH="${POETRY_HOME}/bin:${VENV_PATH}/bin:${PATH}" -COPY requirements.txt /home/ -RUN pip install -r requirements.txt -COPY . /home/ +FROM python-base as poetry-base -RUN chown -R $APP_USER:$APP_USER $APP_HOME -USER $APP_USER +RUN python -m venv $POETRY_VENV \ + && $POETRY_VENV/bin/pip install --no-cache-dir -U pip setuptools wheel \ + && $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION} -CMD ["gunicorn", "shadowmere.wsgi:application", "--bind", "0.0.0.0:8001", "-k", "gevent", "-w", "6", "--capture-output"] +FROM python-base as example-app + +COPY --from=poetry-base ${POETRY_VENV} ${POETRY_VENV} + +ENV PYTHONPATH="${PYTHONPATH}:$VENV_PATH/lib/python3.12/site-packages" +ENV PATH="${PATH}:${POETRY_VENV}/bin" + +RUN groupadd -r $PROJECT_USER && \ + useradd -r -g $PROJECT_USER -d $PROJECT_PATH -s /sbin/nologin -c "Docker image user" $PROJECT_USER + +WORKDIR $PROJECT_PATH + +COPY poetry.lock pyproject.toml ./ + +#RUN poetry check + +RUN poetry install --no-interaction --no-cache --without dev + +# upload scripts +COPY ./docker/entrypoint /entrypoint +RUN sed -i 's/\r//' /entrypoint +RUN chmod +x /entrypoint + +COPY ./docker/wait_for_migration.sh /wait_for_migration.sh +RUN sed -i 's/\r//' /wait_for_migration.sh +RUN chmod +x /wait_for_migration.sh + +COPY ./docker/start /start +RUN sed -i 's/\r//' /start +RUN chmod +x /start + +COPY ./docker/celery/worker/start /start-celeryworker +RUN sed -i 's/\r//' /start-celeryworker +RUN chmod +x /start-celeryworker + +COPY ./docker/celery/beat/start /start-celerybeat +RUN sed -i 's/\r//' /start-celerybeat +RUN chmod +x /start-celerybeat + +COPY . $PROJECT_PATH + +USER $PROJECT_USER From f8b4f62e2eba97435dbf69f223abeff5453db412 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:27:17 +0200 Subject: [PATCH 15/32] wip: new project layout --- .../shadowmere/apps}/__init__.py | 0 .../shadowmere/apps/proxylist}/__init__.py | 0 .../shadowmere/apps/proxylist}/admin.py | 6 +- app/shadowmere/apps/proxylist/apps.py | 5 + .../apps/proxylist}/base64_decoder.py | 0 .../apps/proxylist}/fixtures/proxies.json | 0 .../apps/proxylist/management}/__init__.py | 0 .../management/commands}/__init__.py | 0 .../management/commands/clear_stats.py | 0 .../management/commands/initadmin.py | 0 .../management/commands/poll_subscriptions.py | 0 .../management/commands/reduce_checks_by.py | 0 .../management/commands/remove_low_quality.py | 0 .../management/commands/update_status.py | 0 .../shadowmere/apps/proxylist}/metrics.py | 5 +- .../proxylist}/migrations/0001_initial.py | 0 .../migrations/0002_proxy_last_active.py | 1 - .../migrations/0003_alter_proxy_url.py | 5 +- ..._times_check_failed_proxy_times_checked.py | 1 - .../0005_remove_proxy_times_check_failed.py | 1 - .../0006_proxy_times_check_succeeded.py | 1 - ..._ip_address_proxy_location_country_code.py | 1 - ..._proxy_location_country_alter_proxy_url.py | 31 ++++ .../proxylist}/migrations/0009_proxy_port.py | 1 - .../0010_subscription_alter_proxy_url.py | 26 +++ .../0011_alter_subscription_kind.py | 17 ++ ...subscription_alive_subscription_enabled.py | 0 ...3_subscription_alive_timestamp_and_more.py | 0 .../proxylist}/migrations/0014_tasklog.py | 0 .../0015_alter_tasklog_start_time.py | 0 ...og_finish_time_alter_tasklog_start_time.py | 0 .../migrations/0017_tasklog_details.py | 0 .../apps/proxylist/migrations}/__init__.py | 0 .../shadowmere/apps/proxylist}/models.py | 7 +- app/shadowmere/apps/proxylist/pagination.py | 14 ++ .../shadowmere/apps/proxylist}/permissions.py | 2 +- .../shadowmere/apps/proxylist}/proxy.py | 2 +- .../shadowmere/apps/proxylist}/serializers.py | 3 +- .../shadowmere/apps/proxylist}/tasks.py | 10 +- .../apps/proxylist/tests}/__init__.py | 0 .../proxylist}/tests/test_country_codes.py | 0 .../apps/proxylist}/tests/test_ports.py | 0 .../apps/proxylist}/tests/test_proxies.py | 0 .../apps/proxylist}/tests/test_qr.py | 0 .../proxylist}/tests/test_subscription.py | 0 .../apps/proxylist}/tests/test_tasks.py | 0 .../shadowmere/apps/proxylist}/views.py | 39 ++--- docker/entrypoint | 30 ---- Dockerfile => docker/prod/Dockerfile | 0 docker/start | 15 -- docker/wait_for_migration.sh | 16 -- locale/es/LC_MESSAGES/django.mo | Bin 2119 -> 0 bytes locale/es/LC_MESSAGES/django.po | 87 ---------- manage.py | 23 --- proxylist/apps.py | 6 - ..._proxy_location_country_alter_proxy_url.py | 24 --- .../0010_subscription_alter_proxy_url.py | 27 --- .../0011_alter_subscription_kind.py | 18 -- proxylist/pagination.py | 12 -- shadowmere/asgi.py | 16 -- shadowmere/settings/__init__.py | 0 shadowmere/settings/dev.py | 1 - shadowmere/settings/prod.py | 47 ------ shadowmere/urls.py | 24 --- shadowmere/wsgi.py | 16 -- templates/index.html | 158 ------------------ 66 files changed, 121 insertions(+), 577 deletions(-) rename {proxylist => app/shadowmere/apps}/__init__.py (100%) rename {proxylist/management => app/shadowmere/apps/proxylist}/__init__.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/admin.py (95%) create mode 100644 app/shadowmere/apps/proxylist/apps.py rename {proxylist => app/shadowmere/apps/proxylist}/base64_decoder.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/fixtures/proxies.json (100%) rename {proxylist/management/commands => app/shadowmere/apps/proxylist/management}/__init__.py (100%) rename {proxylist/migrations => app/shadowmere/apps/proxylist/management/commands}/__init__.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/clear_stats.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/initadmin.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/poll_subscriptions.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/reduce_checks_by.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/remove_low_quality.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/management/commands/update_status.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/metrics.py (84%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0001_initial.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0002_proxy_last_active.py (99%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0003_alter_proxy_url.py (81%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0004_proxy_times_check_failed_proxy_times_checked.py (99%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0005_remove_proxy_times_check_failed.py (99%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0006_proxy_times_check_succeeded.py (99%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0007_proxy_ip_address_proxy_location_country_code.py (99%) create mode 100644 app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0009_proxy_port.py (99%) create mode 100644 app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py create mode 100644 app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0012_subscription_alive_subscription_enabled.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0013_subscription_alive_timestamp_and_more.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0014_tasklog.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0015_alter_tasklog_start_time.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/migrations/0017_tasklog_details.py (100%) rename {proxylist/tests => app/shadowmere/apps/proxylist/migrations}/__init__.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/models.py (96%) create mode 100644 app/shadowmere/apps/proxylist/pagination.py rename {proxylist => app/shadowmere/apps/proxylist}/permissions.py (81%) rename {proxylist => app/shadowmere/apps/proxylist}/proxy.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/serializers.py (95%) rename {proxylist => app/shadowmere/apps/proxylist}/tasks.py (97%) rename {shadowmere => app/shadowmere/apps/proxylist/tests}/__init__.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_country_codes.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_ports.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_proxies.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_qr.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_subscription.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/tests/test_tasks.py (100%) rename {proxylist => app/shadowmere/apps/proxylist}/views.py (86%) delete mode 100755 docker/entrypoint rename Dockerfile => docker/prod/Dockerfile (100%) delete mode 100755 docker/start delete mode 100755 docker/wait_for_migration.sh delete mode 100644 locale/es/LC_MESSAGES/django.mo delete mode 100644 locale/es/LC_MESSAGES/django.po delete mode 100755 manage.py delete mode 100644 proxylist/apps.py delete mode 100644 proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py delete mode 100644 proxylist/migrations/0010_subscription_alter_proxy_url.py delete mode 100644 proxylist/migrations/0011_alter_subscription_kind.py delete mode 100644 proxylist/pagination.py delete mode 100644 shadowmere/asgi.py delete mode 100644 shadowmere/settings/__init__.py delete mode 100644 shadowmere/settings/dev.py delete mode 100644 shadowmere/settings/prod.py delete mode 100644 shadowmere/urls.py delete mode 100644 shadowmere/wsgi.py delete mode 100644 templates/index.html diff --git a/proxylist/__init__.py b/app/shadowmere/apps/__init__.py similarity index 100% rename from proxylist/__init__.py rename to app/shadowmere/apps/__init__.py diff --git a/proxylist/management/__init__.py b/app/shadowmere/apps/proxylist/__init__.py similarity index 100% rename from proxylist/management/__init__.py rename to app/shadowmere/apps/proxylist/__init__.py diff --git a/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py similarity index 95% rename from proxylist/admin.py rename to app/shadowmere/apps/proxylist/admin.py index 130dbaf..2dce17a 100644 --- a/proxylist/admin.py +++ b/app/shadowmere/apps/proxylist/admin.py @@ -1,4 +1,6 @@ import humanfriendly +from apps.proxylist.models import Proxy, Subscription, TaskLog +from apps.proxylist.proxy import update_proxy_status from django.contrib import admin from django.contrib.auth.models import Group from django.db import IntegrityError @@ -6,9 +8,6 @@ from import_export.admin import ImportExportModelAdmin from rangefilter.filters import DateRangeFilter -from proxylist.models import Proxy, Subscription, TaskLog -from proxylist.proxy import update_proxy_status - class ProxyResource(resources.ModelResource): class Meta: @@ -17,7 +16,6 @@ class Meta: @admin.register(Proxy) class ProxyAdmin(ImportExportModelAdmin): - @staticmethod def update_status(modeladmin, request, queryset): for proxy in queryset: diff --git a/app/shadowmere/apps/proxylist/apps.py b/app/shadowmere/apps/proxylist/apps.py new file mode 100644 index 0000000..1b01159 --- /dev/null +++ b/app/shadowmere/apps/proxylist/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProxylistConfig(AppConfig): + name = "apps.proxylist" diff --git a/proxylist/base64_decoder.py b/app/shadowmere/apps/proxylist/base64_decoder.py similarity index 100% rename from proxylist/base64_decoder.py rename to app/shadowmere/apps/proxylist/base64_decoder.py diff --git a/proxylist/fixtures/proxies.json b/app/shadowmere/apps/proxylist/fixtures/proxies.json similarity index 100% rename from proxylist/fixtures/proxies.json rename to app/shadowmere/apps/proxylist/fixtures/proxies.json diff --git a/proxylist/management/commands/__init__.py b/app/shadowmere/apps/proxylist/management/__init__.py similarity index 100% rename from proxylist/management/commands/__init__.py rename to app/shadowmere/apps/proxylist/management/__init__.py diff --git a/proxylist/migrations/__init__.py b/app/shadowmere/apps/proxylist/management/commands/__init__.py similarity index 100% rename from proxylist/migrations/__init__.py rename to app/shadowmere/apps/proxylist/management/commands/__init__.py diff --git a/proxylist/management/commands/clear_stats.py b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py similarity index 100% rename from proxylist/management/commands/clear_stats.py rename to app/shadowmere/apps/proxylist/management/commands/clear_stats.py diff --git a/proxylist/management/commands/initadmin.py b/app/shadowmere/apps/proxylist/management/commands/initadmin.py similarity index 100% rename from proxylist/management/commands/initadmin.py rename to app/shadowmere/apps/proxylist/management/commands/initadmin.py diff --git a/proxylist/management/commands/poll_subscriptions.py b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py similarity index 100% rename from proxylist/management/commands/poll_subscriptions.py rename to app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py diff --git a/proxylist/management/commands/reduce_checks_by.py b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py similarity index 100% rename from proxylist/management/commands/reduce_checks_by.py rename to app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py diff --git a/proxylist/management/commands/remove_low_quality.py b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py similarity index 100% rename from proxylist/management/commands/remove_low_quality.py rename to app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py diff --git a/proxylist/management/commands/update_status.py b/app/shadowmere/apps/proxylist/management/commands/update_status.py similarity index 100% rename from proxylist/management/commands/update_status.py rename to app/shadowmere/apps/proxylist/management/commands/update_status.py diff --git a/proxylist/metrics.py b/app/shadowmere/apps/proxylist/metrics.py similarity index 84% rename from proxylist/metrics.py rename to app/shadowmere/apps/proxylist/metrics.py index b0c29a4..a70cc93 100644 --- a/proxylist/metrics.py +++ b/app/shadowmere/apps/proxylist/metrics.py @@ -1,8 +1,7 @@ -from prometheus_client.core import GaugeMetricFamily, REGISTRY +from apps.proxylist.models import Proxy +from prometheus_client.core import REGISTRY, GaugeMetricFamily from prometheus_client.registry import Collector -from proxylist.models import Proxy - class CustomCollector(Collector): def collect(self): diff --git a/proxylist/migrations/0001_initial.py b/app/shadowmere/apps/proxylist/migrations/0001_initial.py similarity index 100% rename from proxylist/migrations/0001_initial.py rename to app/shadowmere/apps/proxylist/migrations/0001_initial.py diff --git a/proxylist/migrations/0002_proxy_last_active.py b/app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py similarity index 99% rename from proxylist/migrations/0002_proxy_last_active.py rename to app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py index b616d70..d76ad71 100644 --- a/proxylist/migrations/0002_proxy_last_active.py +++ b/app/shadowmere/apps/proxylist/migrations/0002_proxy_last_active.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0001_initial"), ] diff --git a/proxylist/migrations/0003_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py similarity index 81% rename from proxylist/migrations/0003_alter_proxy_url.py rename to app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py index 20ae4c1..13bb053 100644 --- a/proxylist/migrations/0003_alter_proxy_url.py +++ b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py @@ -1,11 +1,10 @@ # Generated by Django 3.2.11 on 2022-02-09 14:26 from django.db import migrations, models -import proxylist.models +import apps.proxylist.models class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0002_proxy_last_active"), ] @@ -17,7 +16,7 @@ class Migration(migrations.Migration): field=models.CharField( max_length=1024, unique=True, - validators=[proxylist.models.validate_not_existing], + validators=[apps.proxylist.models.validate_not_existing], ), ), ] diff --git a/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py b/app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py similarity index 99% rename from proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py rename to app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py index 0fd80c0..e2e659d 100644 --- a/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py +++ b/app/shadowmere/apps/proxylist/migrations/0004_proxy_times_check_failed_proxy_times_checked.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0003_alter_proxy_url"), ] diff --git a/proxylist/migrations/0005_remove_proxy_times_check_failed.py b/app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py similarity index 99% rename from proxylist/migrations/0005_remove_proxy_times_check_failed.py rename to app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py index 8d5c645..57603b5 100644 --- a/proxylist/migrations/0005_remove_proxy_times_check_failed.py +++ b/app/shadowmere/apps/proxylist/migrations/0005_remove_proxy_times_check_failed.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0004_proxy_times_check_failed_proxy_times_checked"), ] diff --git a/proxylist/migrations/0006_proxy_times_check_succeeded.py b/app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py similarity index 99% rename from proxylist/migrations/0006_proxy_times_check_succeeded.py rename to app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py index bbbc80e..e095a59 100644 --- a/proxylist/migrations/0006_proxy_times_check_succeeded.py +++ b/app/shadowmere/apps/proxylist/migrations/0006_proxy_times_check_succeeded.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0005_remove_proxy_times_check_failed"), ] diff --git a/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py b/app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py similarity index 99% rename from proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py rename to app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py index d3c3c5b..b1af245 100644 --- a/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py +++ b/app/shadowmere/apps/proxylist/migrations/0007_proxy_ip_address_proxy_location_country_code.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0006_proxy_times_check_succeeded"), ] diff --git a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py new file mode 100644 index 0000000..60ef86f --- /dev/null +++ b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py @@ -0,0 +1,31 @@ +# Generated by Django 4.0.4 on 2022-06-06 12:09 + +from django.db import migrations, models +import apps.proxylist.models + + +class Migration(migrations.Migration): + dependencies = [ + ("proxylist", "0007_proxy_ip_address_proxy_location_country_code"), + ] + + operations = [ + migrations.AddField( + model_name="proxy", + name="location_country", + field=models.CharField(default="", max_length=50), + ), + migrations.AlterField( + model_name="proxy", + name="url", + field=models.CharField( + max_length=1024, + unique=True, + validators=[ + apps.proxylist.models.validate_sip002, + apps.proxylist.models.validate_not_existing, + apps.proxylist.models.validate_proxy_can_connect, + ], + ), + ), + ] diff --git a/proxylist/migrations/0009_proxy_port.py b/app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py similarity index 99% rename from proxylist/migrations/0009_proxy_port.py rename to app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py index 869c665..28199aa 100644 --- a/proxylist/migrations/0009_proxy_port.py +++ b/app/shadowmere/apps/proxylist/migrations/0009_proxy_port.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("proxylist", "0008_proxy_location_country_alter_proxy_url"), ] diff --git a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py new file mode 100644 index 0000000..cef7754 --- /dev/null +++ b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py @@ -0,0 +1,26 @@ +# Generated by Django 4.1.7 on 2023-03-04 14:37 + +from django.db import migrations, models +import apps.proxylist.models + + +class Migration(migrations.Migration): + dependencies = [ + ("proxylist", "0009_proxy_port"), + ] + + operations = [ + migrations.CreateModel( + name="Subscription", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("url", models.URLField(unique=True)), + ("kind", models.CharField(choices=[("1", "plain"), ("2", "base64")], default="1", max_length=10)), + ], + ), + migrations.AlterField( + model_name="proxy", + name="url", + field=models.CharField(max_length=1024, unique=True, validators=[apps.proxylist.models.proxy_validator]), + ), + ] diff --git a/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py b/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py new file mode 100644 index 0000000..d57b9f6 --- /dev/null +++ b/app/shadowmere/apps/proxylist/migrations/0011_alter_subscription_kind.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.7 on 2023-03-04 14:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("proxylist", "0010_subscription_alter_proxy_url"), + ] + + operations = [ + migrations.AlterField( + model_name="subscription", + name="kind", + field=models.CharField(choices=[("PLAIN", "plain"), ("BASE64", "base64")], default="PLAIN", max_length=10), + ), + ] diff --git a/proxylist/migrations/0012_subscription_alive_subscription_enabled.py b/app/shadowmere/apps/proxylist/migrations/0012_subscription_alive_subscription_enabled.py similarity index 100% rename from proxylist/migrations/0012_subscription_alive_subscription_enabled.py rename to app/shadowmere/apps/proxylist/migrations/0012_subscription_alive_subscription_enabled.py diff --git a/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py b/app/shadowmere/apps/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py similarity index 100% rename from proxylist/migrations/0013_subscription_alive_timestamp_and_more.py rename to app/shadowmere/apps/proxylist/migrations/0013_subscription_alive_timestamp_and_more.py diff --git a/proxylist/migrations/0014_tasklog.py b/app/shadowmere/apps/proxylist/migrations/0014_tasklog.py similarity index 100% rename from proxylist/migrations/0014_tasklog.py rename to app/shadowmere/apps/proxylist/migrations/0014_tasklog.py diff --git a/proxylist/migrations/0015_alter_tasklog_start_time.py b/app/shadowmere/apps/proxylist/migrations/0015_alter_tasklog_start_time.py similarity index 100% rename from proxylist/migrations/0015_alter_tasklog_start_time.py rename to app/shadowmere/apps/proxylist/migrations/0015_alter_tasklog_start_time.py diff --git a/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py b/app/shadowmere/apps/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py similarity index 100% rename from proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py rename to app/shadowmere/apps/proxylist/migrations/0016_alter_tasklog_finish_time_alter_tasklog_start_time.py diff --git a/proxylist/migrations/0017_tasklog_details.py b/app/shadowmere/apps/proxylist/migrations/0017_tasklog_details.py similarity index 100% rename from proxylist/migrations/0017_tasklog_details.py rename to app/shadowmere/apps/proxylist/migrations/0017_tasklog_details.py diff --git a/proxylist/tests/__init__.py b/app/shadowmere/apps/proxylist/migrations/__init__.py similarity index 100% rename from proxylist/tests/__init__.py rename to app/shadowmere/apps/proxylist/migrations/__init__.py diff --git a/proxylist/models.py b/app/shadowmere/apps/proxylist/models.py similarity index 96% rename from proxylist/models.py rename to app/shadowmere/apps/proxylist/models.py index 0a31d2b..4dc32a8 100644 --- a/proxylist/models.py +++ b/app/shadowmere/apps/proxylist/models.py @@ -1,17 +1,16 @@ import base64 import re +from apps.proxylist.base64_decoder import decode_base64 +from apps.proxylist.proxy import get_proxy_location, update_proxy_status from django.core.cache import cache from django.core.exceptions import ValidationError -from django.db import models, IntegrityError +from django.db import IntegrityError, models from django.db.models.signals import post_save from django.dispatch import receiver from django.utils.timezone import now from django_prometheus.models import ExportModelOperationsMixin -from proxylist.base64_decoder import decode_base64 -from proxylist.proxy import update_proxy_status, get_proxy_location - def validate_sip002(value): if get_sip002(value) == "": diff --git a/app/shadowmere/apps/proxylist/pagination.py b/app/shadowmere/apps/proxylist/pagination.py new file mode 100644 index 0000000..10610e6 --- /dev/null +++ b/app/shadowmere/apps/proxylist/pagination.py @@ -0,0 +1,14 @@ +from rest_framework import pagination +from rest_framework.response import Response + + +class ProxiesPagination(pagination.PageNumberPagination): + def get_paginated_response(self, data): + return Response( + { + "count": self.page.paginator.count, + "total_pages": self.page.paginator.num_pages, + "current_page": self.page.number, + "results": data, + } + ) diff --git a/proxylist/permissions.py b/app/shadowmere/apps/proxylist/permissions.py similarity index 81% rename from proxylist/permissions.py rename to app/shadowmere/apps/proxylist/permissions.py index 205f51b..80b4124 100644 --- a/proxylist/permissions.py +++ b/app/shadowmere/apps/proxylist/permissions.py @@ -1,4 +1,4 @@ -from rest_framework.permissions import BasePermission, SAFE_METHODS +from rest_framework.permissions import SAFE_METHODS, BasePermission class GeneralPermission(BasePermission): diff --git a/proxylist/proxy.py b/app/shadowmere/apps/proxylist/proxy.py similarity index 100% rename from proxylist/proxy.py rename to app/shadowmere/apps/proxylist/proxy.py index 3189a88..120eb40 100644 --- a/proxylist/proxy.py +++ b/app/shadowmere/apps/proxylist/proxy.py @@ -1,6 +1,6 @@ import requests -from django.utils.timezone import now from django.conf import settings +from django.utils.timezone import now from requests.exceptions import InvalidJSONError diff --git a/proxylist/serializers.py b/app/shadowmere/apps/proxylist/serializers.py similarity index 95% rename from proxylist/serializers.py rename to app/shadowmere/apps/proxylist/serializers.py index de1b726..9bb6cf3 100644 --- a/proxylist/serializers.py +++ b/app/shadowmere/apps/proxylist/serializers.py @@ -1,7 +1,6 @@ +from apps.proxylist.models import Proxy from rest_framework import serializers -from proxylist.models import Proxy - class ProxySerializer(serializers.ModelSerializer): class Meta: diff --git a/proxylist/tasks.py b/app/shadowmere/apps/proxylist/tasks.py similarity index 97% rename from proxylist/tasks.py rename to app/shadowmere/apps/proxylist/tasks.py index 4e475dc..6f61b41 100644 --- a/proxylist/tasks.py +++ b/app/shadowmere/apps/proxylist/tasks.py @@ -3,18 +3,16 @@ from concurrent.futures import ThreadPoolExecutor import requests +from apps.proxylist.base64_decoder import decode_base64 +from apps.proxylist.models import Proxy, Subscription, TaskLog, get_sip002 +from apps.proxylist.proxy import get_proxy_location, update_proxy_status from django.db import IntegrityError from django.db.models import F, FloatField from django.db.models.functions import Coalesce from django.utils.timezone import now from huey import crontab from huey.contrib.djhuey import db_periodic_task -from requests.exceptions import SSLError, ConnectionError, ReadTimeout - -from proxylist.base64_decoder import decode_base64 -from proxylist.models import Proxy, Subscription, get_sip002, TaskLog -from proxylist.proxy import update_proxy_status, get_proxy_location -from shadowmere.celery import app +from requests.exceptions import ConnectionError, ReadTimeout, SSLError CONCURRENT_CHECKS = 200 SUBSCRIPTION_TIMEOUT_SECONDS = 60 diff --git a/shadowmere/__init__.py b/app/shadowmere/apps/proxylist/tests/__init__.py similarity index 100% rename from shadowmere/__init__.py rename to app/shadowmere/apps/proxylist/tests/__init__.py diff --git a/proxylist/tests/test_country_codes.py b/app/shadowmere/apps/proxylist/tests/test_country_codes.py similarity index 100% rename from proxylist/tests/test_country_codes.py rename to app/shadowmere/apps/proxylist/tests/test_country_codes.py diff --git a/proxylist/tests/test_ports.py b/app/shadowmere/apps/proxylist/tests/test_ports.py similarity index 100% rename from proxylist/tests/test_ports.py rename to app/shadowmere/apps/proxylist/tests/test_ports.py diff --git a/proxylist/tests/test_proxies.py b/app/shadowmere/apps/proxylist/tests/test_proxies.py similarity index 100% rename from proxylist/tests/test_proxies.py rename to app/shadowmere/apps/proxylist/tests/test_proxies.py diff --git a/proxylist/tests/test_qr.py b/app/shadowmere/apps/proxylist/tests/test_qr.py similarity index 100% rename from proxylist/tests/test_qr.py rename to app/shadowmere/apps/proxylist/tests/test_qr.py diff --git a/proxylist/tests/test_subscription.py b/app/shadowmere/apps/proxylist/tests/test_subscription.py similarity index 100% rename from proxylist/tests/test_subscription.py rename to app/shadowmere/apps/proxylist/tests/test_subscription.py diff --git a/proxylist/tests/test_tasks.py b/app/shadowmere/apps/proxylist/tests/test_tasks.py similarity index 100% rename from proxylist/tests/test_tasks.py rename to app/shadowmere/apps/proxylist/tests/test_tasks.py diff --git a/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py similarity index 86% rename from proxylist/views.py rename to app/shadowmere/apps/proxylist/views.py index 46e387f..29e40ce 100644 --- a/proxylist/views.py +++ b/app/shadowmere/apps/proxylist/views.py @@ -5,9 +5,14 @@ import flag import qrcode +from apps.proxylist.base64_decoder import decode_base64 +from apps.proxylist.metrics import register_metrics +from apps.proxylist.models import Proxy, TaskLog +from apps.proxylist.permissions import GeneralPermission +from apps.proxylist.serializers import ProxySerializer from django.core.paginator import Paginator from django.http import HttpResponse, JsonResponse -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import get_object_or_404, render from django.template.defaultfilters import urlencode from django.utils.decorators import method_decorator from django.utils.text import slugify @@ -17,12 +22,6 @@ from rest_framework import viewsets from rest_framework.response import Response -from proxylist.base64_decoder import decode_base64 -from proxylist.metrics import register_metrics -from proxylist.models import Proxy, TaskLog -from proxylist.permissions import GeneralPermission -from proxylist.serializers import ProxySerializer - @cache_page(None) def list_proxies(request): @@ -34,9 +33,7 @@ def list_proxies(request): .distinct() ) if location_country_code != "": - proxy_list = Proxy.objects.filter( - location_country_code=location_country_code, is_active=True - ).order_by("-id") + proxy_list = Proxy.objects.filter(location_country_code=location_country_code, is_active=True).order_by("-id") else: proxy_list = Proxy.objects.filter(is_active=True).order_by("-id") @@ -75,9 +72,7 @@ def get_flag_or_empty(country_code): def get_proxy_config(proxy): - method_password = decode_base64( - proxy.url.split("@")[0].replace("ss://", "").encode("ascii") - ) + method_password = decode_base64(proxy.url.split("@")[0].replace("ss://", "").encode("ascii")) server_and_port = proxy.url.split("@")[1] config = { "server": re.findall(r"^(.*?):\d+", server_and_port)[0], @@ -108,9 +103,7 @@ def json_proxy_file(request, proxy_id): "method": details["method"], } response = HttpResponse(json.dumps(config), content_type="application/json") - response["Content-Disposition"] = ( - f'attachment; filename="shadowmere_config_{slugify(proxy.location)}.json"' - ) + response["Content-Disposition"] = f'attachment; filename="shadowmere_config_{slugify(proxy.location)}.json"' return response @@ -180,11 +173,7 @@ class PortViewSet(viewsets.ViewSet): @method_decorator(cache_page(20 * 60)) def list(self, request, format=None): ports = [ - port - for port in Proxy.objects.filter(is_active=True) - .values_list("port", flat=True) - .distinct() - if port != 0 + port for port in Proxy.objects.filter(is_active=True).values_list("port", flat=True).distinct() if port != 0 ] ports.sort() ports = [ @@ -212,9 +201,7 @@ class SubViewSet(viewsets.ViewSet): def list(self, request, format=None): servers = [ get_proxy_config(server) - for server in Proxy.objects.filter(is_active=True).order_by( - "location_country_code" - ) + for server in Proxy.objects.filter(is_active=True).order_by("location_country_code") ] return Response(servers) @@ -234,9 +221,7 @@ class Base64SubViewSet(viewsets.ViewSet): @method_decorator(cache_page(20 * 60)) def list(self, request, format=None): server_list = "" - for proxy in Proxy.objects.filter(is_active=True).order_by( - "location_country_code" - ): + for proxy in Proxy.objects.filter(is_active=True).order_by("location_country_code"): server_list += f"\n{proxy.url}#{get_flag_or_empty(proxy.location_country_code)} {proxy.location}" b64_servers = base64.b64encode(server_list.encode("utf-8")) return HttpResponse(b64_servers) diff --git a/docker/entrypoint b/docker/entrypoint deleted file mode 100755 index 89d4d8b..0000000 --- a/docker/entrypoint +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o pipefail -cmd="$@" - -function postgres_ready(){ -python << END -import sys -import psycopg2 -import os - -try: - dbname = os.getenv('POSTGRES_DB') - user = os.getenv('POSTGRES_USER') - password = os.getenv('POSTGRES_PASSWORD') - conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432) -except psycopg2.OperationalError: - sys.exit(-1) -sys.exit(0) -END -} - -until postgres_ready; do - >&2 echo "Postgres is unavailable - sleeping" - sleep 1 -done - ->&2 echo "Postgres is up - continuing..." -exec $cmd diff --git a/Dockerfile b/docker/prod/Dockerfile similarity index 100% rename from Dockerfile rename to docker/prod/Dockerfile diff --git a/docker/start b/docker/start deleted file mode 100755 index 35388e8..0000000 --- a/docker/start +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o pipefail -set -o nounset -set -o xtrace - -python manage.py migrate --no-input -python manage.py initadmin -if [ "${DEBUG}" == "True" ]; then - python manage.py runserver 0.0.0.0:8001 -else - python manage.py collectstatic --no-input - gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output -fi diff --git a/docker/wait_for_migration.sh b/docker/wait_for_migration.sh deleted file mode 100755 index 8d85db1..0000000 --- a/docker/wait_for_migration.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -e - -cmd="$@" - -if [ "${IS_DJANGO_SERVICE}" == "True" ]; then - echo "Waiting for the database to become available..." - until python3 manage.py migrate; do - echo "Database is unavailable, sleeping for 5 seconds..." - done -else - sleep 30 -fi - -exec $cmd diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo deleted file mode 100644 index 14bc8084c9701b56ef4dcb924da72c8b6d7c55cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2119 zcmb_d%WfP+6fMBK29S6xkPwI)OCS*Go`hA@ek7B4l8iDB%P$0oMNRj0PsKe|ovLal z6Lts*i3KZQ!Hy+JERb2TL1O+RU%*Fjsy((R8If#gseD{r)%Tuz>(rSCuP^-|@VtWY zHpbT&uVMUy5uOWA3Goi_BJd^P0QfxcbKnDv6ypuduRe3Uz6X30^C2+oyFbIPfD_EW z1-=DbS`y-E;Jd)9h_MVjhdDnh#B;!JfZ_Y^fPY~9M_}M}3ol;*v#PLl3aDm|dWm;>53mXyZdvGmI5xIvFRPfWtP3D&wWGHa%VV(nc#^5bH8 z{U%$kGb)FqCsoe&)R`S0vX#X`(z1{~aB}BqSa}*xXkQ*0t2`58El|qYo5~kT^Q`Q_ z@vKfBDwKLcCowU}77{Lm#O_I)853Pxt<}PK1I#f9(KT_^;BDxY1Nk^O>B%*IfralN@CK9x= z(wP|O(1Ap3mr@6r?BG+n%R@J7o6*H&?i_rjH5ZOjQxu$f&PWyoNgHB85}vJQAJZos z$n*z0A={zKn9$F$#0HGIu~4obao~C!F&4WuaUPTOG%=MW=!2|s2eB~wV$+)2NEmgp zXpgOf>Jr*)UAxt~(Wbrj)^=ymZ)|aCtdDvwS6Otm%3ZW$5^8J?qAfmD;hShfdQRxm zc55r@4Wf+}-5eyn&PSgO`t3$&SF~fLb`X-W30>dqcB$X$wQ058YjwI;S{oZ%?d|P# zY}I)sbB=acjuYy(`Zsn1lhtnbN}+PTE~8EcjtO^>1(pdQ=LuaJD&N>FDqMx=dXRlWx~!*e?c)_FH>|9E zpy}KiUHovRA$IlgeUgOp@Y6qWknHCDL$uH(lZXy1WBQ8|dyJFMq@_v|R=m6q5iMS% zIT1g`KuT#PnIWp?Q}amG^hn1~j`-hh(YjMjf2(iHNKU|WuEJx>K!tVYLur-7|2SG% z8<#s@vNbeTCoW+Kdl#=fppOmKUHyAnJse)4i7G8X>=P5Od} diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po deleted file mode 100644 index 0c984bc..0000000 --- a/locale/es/LC_MESSAGES/django.po +++ /dev/null @@ -1,87 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-04-12 17:20+0000\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: shadowmere/settings.py:142 -msgid "Spanish" -msgstr "Español" - -#: shadowmere/settings.py:143 -msgid "English" -msgstr "Inglés" - -#: templates/index.html:49 -msgid "A list of Shadowsocks proxies" -msgstr "Una lista de túneles Shadowsocks" - -#: templates/index.html:51 -msgid "Disclaimer:" -msgstr "Aviso:" - -#: templates/index.html:51 -msgid "" -"This website is only a list of tunnels collected all around internet. We do " -"NOT provide or maintain any of these tunnels." -msgstr "" -"Este sitio web es sólo una lista de túneles recolectados en Internet. " -"Nosotros no proveemos ni mantenemos estos túneles." - -#: templates/index.html:52 -msgid "Use them at your own risk." -msgstr "Úselos bajo su propio riesgo" - -#: templates/index.html:57 -msgid "How do I use this?:" -msgstr "¿Cómo uso esto?" - -#: templates/index.html:58 -msgid "" -"Go give shadowsocks.org a quick " -"look for information.\n" -" Here is a list of clients for several\n" -" platforms, but my favorite is Outline for any platform and\n" -" shadowsocks for\n" -" Android

\n" -" " -msgstr "" -"Ve a dar un vistazo a shadowsocks.org para obtener información. Aquí hay una lista de clientes para varias plataformas," -"pero mi favorito es Outline para " -"cualquier plataforma y shadowsocks para Android " - -#: templates/index.html:64 -msgid "Online:" -msgstr "Conectados: " - -#: templates/index.html:69 -msgid "Last check:" -msgstr "Última prueba: " - -#: templates/index.html:135 -msgid "of" -msgstr "de" - -#: templates/index.html:146 -msgid "No active proxies found" -msgstr "No se han encontrado túneles activos" diff --git a/manage.py b/manage.py deleted file mode 100755 index b0afc13..0000000 --- a/manage.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -import os -import sys - - -def main(): - if os.getenv("DEBUG") == "True": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.dev") - else: - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings.prod") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - main() diff --git a/proxylist/apps.py b/proxylist/apps.py deleted file mode 100644 index 493f3ae..0000000 --- a/proxylist/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class ProxylistConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "proxylist" diff --git a/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py deleted file mode 100644 index 162880e..0000000 --- a/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.0.4 on 2022-06-06 12:09 - -from django.db import migrations, models -import proxylist.models - - -class Migration(migrations.Migration): - - dependencies = [ - ('proxylist', '0007_proxy_ip_address_proxy_location_country_code'), - ] - - operations = [ - migrations.AddField( - model_name='proxy', - name='location_country', - field=models.CharField(default='', max_length=50), - ), - migrations.AlterField( - model_name='proxy', - name='url', - field=models.CharField(max_length=1024, unique=True, validators=[proxylist.models.validate_sip002, proxylist.models.validate_not_existing, proxylist.models.validate_proxy_can_connect]), - ), - ] diff --git a/proxylist/migrations/0010_subscription_alter_proxy_url.py b/proxylist/migrations/0010_subscription_alter_proxy_url.py deleted file mode 100644 index 61d3453..0000000 --- a/proxylist/migrations/0010_subscription_alter_proxy_url.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.1.7 on 2023-03-04 14:37 - -from django.db import migrations, models -import proxylist.models - - -class Migration(migrations.Migration): - - dependencies = [ - ('proxylist', '0009_proxy_port'), - ] - - operations = [ - migrations.CreateModel( - name='Subscription', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('url', models.URLField(unique=True)), - ('kind', models.CharField(choices=[('1', 'plain'), ('2', 'base64')], default='1', max_length=10)), - ], - ), - migrations.AlterField( - model_name='proxy', - name='url', - field=models.CharField(max_length=1024, unique=True, validators=[proxylist.models.proxy_validator]), - ), - ] diff --git a/proxylist/migrations/0011_alter_subscription_kind.py b/proxylist/migrations/0011_alter_subscription_kind.py deleted file mode 100644 index 80d2567..0000000 --- a/proxylist/migrations/0011_alter_subscription_kind.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.1.7 on 2023-03-04 14:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('proxylist', '0010_subscription_alter_proxy_url'), - ] - - operations = [ - migrations.AlterField( - model_name='subscription', - name='kind', - field=models.CharField(choices=[('PLAIN', 'plain'), ('BASE64', 'base64')], default='PLAIN', max_length=10), - ), - ] diff --git a/proxylist/pagination.py b/proxylist/pagination.py deleted file mode 100644 index ae8e612..0000000 --- a/proxylist/pagination.py +++ /dev/null @@ -1,12 +0,0 @@ -from rest_framework import pagination -from rest_framework.response import Response - - -class ProxiesPagination(pagination.PageNumberPagination): - def get_paginated_response(self, data): - return Response({ - 'count': self.page.paginator.count, - 'total_pages': self.page.paginator.num_pages, - 'current_page': self.page.number, - 'results': data - }) diff --git a/shadowmere/asgi.py b/shadowmere/asgi.py deleted file mode 100644 index 824093a..0000000 --- a/shadowmere/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for shadowmere project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings") - -application = get_asgi_application() diff --git a/shadowmere/settings/__init__.py b/shadowmere/settings/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/shadowmere/settings/dev.py b/shadowmere/settings/dev.py deleted file mode 100644 index 4b40b38..0000000 --- a/shadowmere/settings/dev.py +++ /dev/null @@ -1 +0,0 @@ -from .base import * # noqa diff --git a/shadowmere/settings/prod.py b/shadowmere/settings/prod.py deleted file mode 100644 index 575ed4b..0000000 --- a/shadowmere/settings/prod.py +++ /dev/null @@ -1,47 +0,0 @@ -from .base import * # noqa -import sentry_sdk -from sentry_sdk.integrations.django import DjangoIntegration - -MIDDLEWARE = ( - ["django_prometheus.middleware.PrometheusBeforeMiddleware"] - + MIDDLEWARE - + ["django_prometheus.middleware.PrometheusAfterMiddleware"] -) - -THIRD_PARTY_APPS += ["django_prometheus"] - -DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage" - -STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage" - -MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT") - -MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY") - -MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY") - -MINIO_STORAGE_USE_HTTPS = True - -MINIO_STORAGE_MEDIA_BUCKET_NAME = "shadowmere-media" - -MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True - -MINIO_STORAGE_STATIC_BUCKET_NAME = "shadowmere-static" - -MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True - -sentry_sdk.init( - dsn=env("SENTRY_DSN"), - integrations=[ - DjangoIntegration(), - ], - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for performance monitoring. - # We recommend adjusting this value in production. - traces_sample_rate=0.01, - # If you wish to associate users to errors (assuming you are using - # django.contrib.auth) you may enable sending PII data. - send_default_pii=True, -) - -PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008) diff --git a/shadowmere/urls.py b/shadowmere/urls.py deleted file mode 100644 index 846f376..0000000 --- a/shadowmere/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.contrib import admin -from django.urls import path, include -from rest_framework import routers - -import proxylist.views -from proxylist import views - -router = routers.DefaultRouter() -router.register(r"proxies", views.ProxyViewSet) -router.register(r"country-codes", views.CountryCodeViewSet, basename="country-codes") -router.register(r"ports", views.PortViewSet, basename="ports") -router.register(r"sub", views.SubViewSet, basename="sub") -router.register(r"b64sub", views.Base64SubViewSet, basename="b64sub") - -urlpatterns = [ - path("admin/", admin.site.urls), - path("", proxylist.views.list_proxies), - path("/config", proxylist.views.json_proxy_file), - path("/qr", proxylist.views.qr_code), - path("health", proxylist.views.healthcheck), - path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), - path("api/", include(router.urls)), - path("", include("django_prometheus.urls")), -] diff --git a/shadowmere/wsgi.py b/shadowmere/wsgi.py deleted file mode 100644 index 107261a..0000000 --- a/shadowmere/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for shadowmere project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings") - -application = get_wsgi_application() diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 04b0901..0000000 --- a/templates/index.html +++ /dev/null @@ -1,158 +0,0 @@ -{% load i18n %} - - - - - - - - Shadowmere - - - - - - - - - - - - - -Fork me on GitHub -
-
- -

Shadowmere

-
-

{% translate "A list of Shadowsocks proxies" %}

-

- {% translate "Disclaimer:" %} {% translate "This website is only a list of tunnels collected all around internet. We do NOT provide or maintain any of these tunnels." %} - {% translate "Use them at your own risk." %}

-

{% translate "How do I use this?:" %} - {% blocktranslate %}Go give shadowsocks.org a quick look for - information. - Here is a list of clients for several - platforms, but my favorite is Outline for any platform and - shadowsocks for - Android

- {% endblocktranslate %} -

{% translate "Online:" %} {{ proxy_list|length }} {% if location_country_code != "" %} - Country flag for {{ location_country_code }} - {% endif %}

- {% if proxy_list|length > 0 %} -

{% translate "Last check:" %} {{ latest_update }} UTC

- {% endif %} - - Planet Earth flag - - {% for country_code in country_codes %} - {% if country_code.location_country_code != "" %} - - Country flag for {{ country_code.location_country }} - - {% endif %} - {% endfor %} -
- {% if proxy_list %} -
    - {% for proxy in page_obj %} -
  • -
    - {{ proxy.location }} - {% widthratio proxy.times_check_succeeded proxy.times_checked 100 %}% -
    -
    -
    {{ proxy.url }}#{{ proxy.location|urlencode }}
    -
    {{ proxy.ip_address }} ⚓{{ proxy.port }}
    -
    -
    -
    ✂ -
    -
    - □ -
    - -
    ↓ -
    -
    -
    - - -
    -
    -
    - × - qr -
    -
    -
    -
  • - {% endfor %} -
-
- -
- {% else %} -

{% translate "No active proxies found" %}

- {% endif %} -
- -Update cookies preferences - - From d4c15112236c3d45c8348fedeed10c2bf9463d9e Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:28:23 +0200 Subject: [PATCH 16/32] WiP: project layout, config files --- app/shadowmere/config/__init__.py | 0 app/shadowmere/config/asgi.py | 16 ++ app/shadowmere/config/settings/__init__.py | 0 app/shadowmere/config/settings/base.py | 224 +++++++++++++++++++++ app/shadowmere/config/settings/dev.py | 3 + app/shadowmere/config/settings/prod.py | 57 ++++++ app/shadowmere/config/urls.py | 32 +++ app/shadowmere/config/wsgi.py | 16 ++ 8 files changed, 348 insertions(+) create mode 100644 app/shadowmere/config/__init__.py create mode 100644 app/shadowmere/config/asgi.py create mode 100644 app/shadowmere/config/settings/__init__.py create mode 100644 app/shadowmere/config/settings/base.py create mode 100644 app/shadowmere/config/settings/dev.py create mode 100644 app/shadowmere/config/settings/prod.py create mode 100644 app/shadowmere/config/urls.py create mode 100644 app/shadowmere/config/wsgi.py diff --git a/app/shadowmere/config/__init__.py b/app/shadowmere/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/shadowmere/config/asgi.py b/app/shadowmere/config/asgi.py new file mode 100644 index 0000000..824093a --- /dev/null +++ b/app/shadowmere/config/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for shadowmere project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings") + +application = get_asgi_application() diff --git a/app/shadowmere/config/settings/__init__.py b/app/shadowmere/config/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/shadowmere/config/settings/base.py b/app/shadowmere/config/settings/base.py new file mode 100644 index 0000000..95b21ae --- /dev/null +++ b/app/shadowmere/config/settings/base.py @@ -0,0 +1,224 @@ +from pathlib import Path + +import environ +from django.utils.translation import gettext_lazy as _ + +BASE_DIR = Path(__file__).resolve(strict=True).parent.parent.parent + +env = environ.Env( + SECRET_KEY=(str, ""), + DEBUG=(bool, False), + SHADOWTEST_URL=(str, ""), + ALLOWED_HOSTS=(str, ""), + CSRF_TRUSTED_ORIGINS=(str, ""), + MINIO_ENDPOINT=(str, ""), + MINIO_ACCESS_KEY=(str, ""), + MINIO_SECRET_KEY=(str, ""), + MINIO_BUCKET=(str, ""), + SENTRY_DSN=(str, ""), + REDIS_HOST=(str, ""), + REDIS_PORT=(int, 0), +) + +SECRET_KEY = env("SECRET_KEY") + +DEBUG = env("DEBUG", default=False) + +SHADOWTEST_URL = env("SHADOWTEST_URL") + +ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ") + +CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS").split(" ") + +SITE_ID = 1 + +APPS_DIR = BASE_DIR / "apps" + +DJANGO_APPS = [ + "jazzmin", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", +] + +THIRD_PARTY_APPS = [ + "storages", + "import_export", + "rangefilter", + "huey.contrib.djhuey", + "rest_framework", + "django_filters", +] + +LOCAL_APPS = ["apps.proxylist"] + +INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django_ratelimit.middleware.RatelimitMiddleware", +] + +ROOT_URLCONF = "config.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "config.wsgi.application" + +DATABASES = {"default": env.db()} + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "filters": { + "require_debug_false": { + "()": "django.utils.log.RequireDebugFalse", + }, + "require_debug_true": { + "()": "django.utils.log.RequireDebugTrue", + }, + }, + "formatters": { + "django.server": { + "()": "django.utils.log.ServerFormatter", + "format": "[%(server_time)s] %(message)s", + } + }, + "handlers": { + "console": { + "level": "INFO", + "filters": ["require_debug_true"], + "class": "logging.StreamHandler", + }, + # Custom handler which we will use with logger 'django'. + # We want errors/warnings to be logged when DEBUG=False + "console_on_not_debug": { + "level": "WARNING", + "filters": ["require_debug_false"], + "class": "logging.StreamHandler", + }, + "django.server": { + "level": "INFO", + "class": "logging.StreamHandler", + "formatter": "django.server", + }, + }, + "loggers": { + "django": { + "handlers": ["console", "console_on_not_debug"], + "level": "INFO", + }, + "django.server": { + "handlers": ["django.server"], + "level": "INFO", + "propagate": False, + }, + }, +} + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +LANGUAGES = [ + ("es", _("Spanish")), + ("en", _("English")), +] + +LOCALE_PATHS = ("./locale",) + +STATIC_URL = "/static/" + +STATIC_ROOT = "./static_files/" + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +HUEY = { + "huey_class": "huey.RedisHuey", + "name": "shadowmere", + "results": True, + "store_none": False, + "immediate": False, + "utc": True, + "blocking": True, + "connection": { + "host": env("REDIS_HOST", default="redis"), + "port": env("REDIS_PORT", default=6379), + "db": 0, + "connection_pool": None, + "read_timeout": 1, + "url": None, + }, + "consumer": { + "workers": 4, + "worker_type": "process", + "initial_delay": 0.1, + "backoff": 1.15, + "max_delay": 10.0, + "scheduler_interval": 1, + "periodic": True, + "check_worker_health": True, + "health_check_interval": 1, + }, +} + +REST_FRAMEWORK = { + "DEFAULT_PAGINATION_CLASS": "apps.proxylist.pagination.ProxiesPagination", + "PAGE_SIZE": 10, +} + +DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 + +RATELIMIT_VIEW = "apps.proxylist.views.ratelimited_error" + +JAZZMIN_SETTINGS = { + "site_title": "Shadowmere Admin", + "site_header": "Shadowmere", + "site_brand": "Shadowmere", + "welcome_sign": "Welcome to Shadowmere Admin", +} diff --git a/app/shadowmere/config/settings/dev.py b/app/shadowmere/config/settings/dev.py new file mode 100644 index 0000000..8ecc929 --- /dev/null +++ b/app/shadowmere/config/settings/dev.py @@ -0,0 +1,3 @@ +from .base import * # noqa + +RATELIMIT_ENABLE = False diff --git a/app/shadowmere/config/settings/prod.py b/app/shadowmere/config/settings/prod.py new file mode 100644 index 0000000..5e4b8ef --- /dev/null +++ b/app/shadowmere/config/settings/prod.py @@ -0,0 +1,57 @@ +from .base import * # noqa + +THIRD_PARTY_APPS += "django_prometheus," # noqa + +MIDDLEWARE.insert( # noqa + 0, + "django_prometheus.middleware.PrometheusBeforeMiddleware", +) + +MIDDLEWARE.append( # noqa + "django_prometheus.middleware.PrometheusAfterMiddleware", +) + +RATELIMIT_ENABLE = True + +DEFAULT_FILE_STORAGE = "minio_storage.storage.MinioMediaStorage" + +STATICFILES_STORAGE = "minio_storage.storage.MinioStaticStorage" + +MINIO_STORAGE_ENDPOINT = env("MINIO_ENDPOINT") # noqa + +MINIO_STORAGE_ACCESS_KEY = env("MINIO_ACCESS_KEY") # noqa + +MINIO_STORAGE_SECRET_KEY = env("MINIO_SECRET_KEY") # noqa + +MINIO_STORAGE_USE_HTTPS = True + +MINIO_STORAGE_MEDIA_BUCKET_NAME = ( + f"{env('MINIO_BUCKET')}-media" # noqa + if env("MINIO_BUCKET") != "" # noqa + else "shadowmere-media" +) + +MINIO_STORAGE_AUTO_CREATE_MEDIA_BUCKET = True + +MINIO_STORAGE_STATIC_BUCKET_NAME = ( + f"{env('MINIO_BUCKET')}-static" # noqa + if env("MINIO_BUCKET") != "" # noqa + else "shadowmere-static" +) + +MINIO_STORAGE_AUTO_CREATE_STATIC_BUCKET = True + +PROMETHEUS_METRICS_EXPORT_PORT_RANGE = range(8002, 8008) + +if env("SENTRY_DSN") != "": # noqa + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + + sentry_sdk.init( + dsn=env("SENTRY_DSN"), # noqa + integrations=[ + DjangoIntegration(), + ], + traces_sample_rate=0.01, + send_default_pii=True, + ) diff --git a/app/shadowmere/config/urls.py b/app/shadowmere/config/urls.py new file mode 100644 index 0000000..38e5f91 --- /dev/null +++ b/app/shadowmere/config/urls.py @@ -0,0 +1,32 @@ +from apps.proxylist.views import ( + Base64SubViewSet, + CountryCodeViewSet, + PortViewSet, + ProxyViewSet, + SubViewSet, + healthcheck, + json_proxy_file, + list_proxies, + qr_code, +) +from django.contrib import admin +from django.urls import include, path +from rest_framework import routers + +router = routers.DefaultRouter() +router.register(r"proxies", ProxyViewSet) +router.register(r"country-codes", CountryCodeViewSet, basename="country-codes") +router.register(r"ports", PortViewSet, basename="ports") +router.register(r"sub", SubViewSet, basename="sub") +router.register(r"b64sub", Base64SubViewSet, basename="b64sub") + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", list_proxies), + path("/config", json_proxy_file), + path("/qr", qr_code), + path("health", healthcheck), + path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), + path("api/", include(router.urls)), + path("", include("django_prometheus.urls")), +] diff --git a/app/shadowmere/config/wsgi.py b/app/shadowmere/config/wsgi.py new file mode 100644 index 0000000..107261a --- /dev/null +++ b/app/shadowmere/config/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for shadowmere project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shadowmere.settings") + +application = get_wsgi_application() From 04effc767cd5931df0a29798d8a251b9a0b1d932 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:29:01 +0200 Subject: [PATCH 17/32] wip: project layout, locales --- .../locale/es/LC_MESSAGES/django.po | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 app/shadowmere/locale/es/LC_MESSAGES/django.po diff --git a/app/shadowmere/locale/es/LC_MESSAGES/django.po b/app/shadowmere/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..0c984bc --- /dev/null +++ b/app/shadowmere/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,87 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-12 17:20+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: shadowmere/settings.py:142 +msgid "Spanish" +msgstr "Español" + +#: shadowmere/settings.py:143 +msgid "English" +msgstr "Inglés" + +#: templates/index.html:49 +msgid "A list of Shadowsocks proxies" +msgstr "Una lista de túneles Shadowsocks" + +#: templates/index.html:51 +msgid "Disclaimer:" +msgstr "Aviso:" + +#: templates/index.html:51 +msgid "" +"This website is only a list of tunnels collected all around internet. We do " +"NOT provide or maintain any of these tunnels." +msgstr "" +"Este sitio web es sólo una lista de túneles recolectados en Internet. " +"Nosotros no proveemos ni mantenemos estos túneles." + +#: templates/index.html:52 +msgid "Use them at your own risk." +msgstr "Úselos bajo su propio riesgo" + +#: templates/index.html:57 +msgid "How do I use this?:" +msgstr "¿Cómo uso esto?" + +#: templates/index.html:58 +msgid "" +"Go give shadowsocks.org a quick " +"look for information.\n" +" Here is a list of clients for several\n" +" platforms, but my favorite is Outline for any platform and\n" +" shadowsocks for\n" +" Android

\n" +" " +msgstr "" +"Ve a dar un vistazo a shadowsocks.org para obtener información. Aquí hay una lista de clientes para varias plataformas," +"pero mi favorito es Outline para " +"cualquier plataforma y shadowsocks para Android " + +#: templates/index.html:64 +msgid "Online:" +msgstr "Conectados: " + +#: templates/index.html:69 +msgid "Last check:" +msgstr "Última prueba: " + +#: templates/index.html:135 +msgid "of" +msgstr "de" + +#: templates/index.html:146 +msgid "No active proxies found" +msgstr "No se han encontrado túneles activos" From da98f6a7f3d91c04122f4af7ab73b0d8b4647abe Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:29:12 +0200 Subject: [PATCH 18/32] wip: project layout, templates --- app/shadowmere/templates/index.html | 158 ++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 app/shadowmere/templates/index.html diff --git a/app/shadowmere/templates/index.html b/app/shadowmere/templates/index.html new file mode 100644 index 0000000..04b0901 --- /dev/null +++ b/app/shadowmere/templates/index.html @@ -0,0 +1,158 @@ +{% load i18n %} + + + + + + + + Shadowmere + + + + + + + + + + + + + +Fork me on GitHub +
+
+ +

Shadowmere

+
+

{% translate "A list of Shadowsocks proxies" %}

+

+ {% translate "Disclaimer:" %} {% translate "This website is only a list of tunnels collected all around internet. We do NOT provide or maintain any of these tunnels." %} + {% translate "Use them at your own risk." %}

+

{% translate "How do I use this?:" %} + {% blocktranslate %}Go give shadowsocks.org a quick look for + information. + Here is a list of clients for several + platforms, but my favorite is Outline for any platform and + shadowsocks for + Android

+ {% endblocktranslate %} +

{% translate "Online:" %} {{ proxy_list|length }} {% if location_country_code != "" %} + Country flag for {{ location_country_code }} + {% endif %}

+ {% if proxy_list|length > 0 %} +

{% translate "Last check:" %} {{ latest_update }} UTC

+ {% endif %} + + Planet Earth flag + + {% for country_code in country_codes %} + {% if country_code.location_country_code != "" %} + + Country flag for {{ country_code.location_country }} + + {% endif %} + {% endfor %} +
+ {% if proxy_list %} +
    + {% for proxy in page_obj %} +
  • +
    + {{ proxy.location }} + {% widthratio proxy.times_check_succeeded proxy.times_checked 100 %}% +
    +
    +
    {{ proxy.url }}#{{ proxy.location|urlencode }}
    +
    {{ proxy.ip_address }} ⚓{{ proxy.port }}
    +
    +
    +
    ✂ +
    +
    + □ +
    + +
    ↓ +
    +
    +
    + + +
    +
    +
    + × + qr +
    +
    +
    +
  • + {% endfor %} +
+
+ +
+ {% else %} +

{% translate "No active proxies found" %}

+ {% endif %} +
+ +Update cookies preferences + + From 20f3e25e283180c1f0cceaffce491accfb734dc5 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:29:27 +0200 Subject: [PATCH 19/32] feat/wip: project layout, entrypoint --- app/shadowmere/__init__.py | 0 app/shadowmere/manage.py | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 app/shadowmere/__init__.py create mode 100755 app/shadowmere/manage.py diff --git a/app/shadowmere/__init__.py b/app/shadowmere/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/shadowmere/manage.py b/app/shadowmere/manage.py new file mode 100755 index 0000000..ae72c44 --- /dev/null +++ b/app/shadowmere/manage.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +import os +import sys +from pathlib import Path + + +def main(): + if os.getenv("DEBUG", "NO").lower() in ("on", "true", "y", "yes"): + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev") + else: + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.prod") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + + current_path = Path(__file__).parent.resolve() + sys.path.append(str(current_path / "shadowmere")) + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() From d836e1d80392162177d0a398d47b76f112f3a5a8 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:29:46 +0200 Subject: [PATCH 20/32] fix: removed unused scripts --- docker/celery/beat/start | 7 ------- docker/celery/worker/start | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 docker/celery/beat/start delete mode 100644 docker/celery/worker/start diff --git a/docker/celery/beat/start b/docker/celery/beat/start deleted file mode 100644 index be41c09..0000000 --- a/docker/celery/beat/start +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset - -rm -f './celerybeat.pid' -celery -A shadowmere beat -l info diff --git a/docker/celery/worker/start b/docker/celery/worker/start deleted file mode 100644 index 35e1855..0000000 --- a/docker/celery/worker/start +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o pipefail -set -o nounset - -celery -A shadowmere worker -l info -E From 6297293a30778a919030ded3561666c4be01911c Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:29:59 +0200 Subject: [PATCH 21/32] feat: docker scripts for dev --- docker/dev/Dockerfile | 70 +++++++++++++++++++++++++++++++++++++++++++ docker/dev/entrypoint | 30 +++++++++++++++++++ docker/dev/start | 15 ++++++++++ 3 files changed, 115 insertions(+) create mode 100644 docker/dev/Dockerfile create mode 100755 docker/dev/entrypoint create mode 100755 docker/dev/start diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile new file mode 100644 index 0000000..b9271d1 --- /dev/null +++ b/docker/dev/Dockerfile @@ -0,0 +1,70 @@ +FROM python:3.12-slim as builder +ENV DEBIAN_FRONTEND=noninteractive \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 \ + POETRY_NO_INTERACTION=1 \ + POETRY_CACHE_DIR=/tmp/poetry_cache \ + POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 \ + POETRY_VIRTUALENVS_CREATE=1 \ + PROJECT_PATH="/shadowmere" + +# install poetry +RUN pip install --upgrade poetry + +# copy poetry and project files +WORKDIR $PROJECT_PATH +COPY ../../poetry.lock pyproject.toml ./ + +# install dependencies and project +RUN poetry install --no-root --no-interaction --no-cache && rm -rf $POETRY_CACHE_DIR + + +# run stage +FROM python:3.12-slim + +# Creating user +ARG USERNAME=shadowmere +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# Timezone +ARG TZ=UTC +ENV TZ ${TZ} +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# OS dependencies +RUN groupadd --gid $USER_GID $USERNAME && \ + useradd --uid $USER_UID --gid $USER_GID -m $USERNAME && \ + apt-get update && \ + apt-get install -y sudo && \ + apt-get clean autoclean && \ + apt-get autoremove --yes && \ + rm -rf /var/lib/apt && \ + rm -rf /var/lib/dpkg && \ + rm -rf /var/cache && \ + rm -rf /var/log && \ + echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \ + chmod 0440 /etc/sudoers.d/$USERNAME + +ENV VIRTUAL_ENV=/shadowmere/.venv +ENV PATH="/shadowmere/.venv/bin:$PATH" + +COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} + +# upload scripts +COPY --chmod=755 ../../docker/dev/entrypoint /entrypoint +RUN sed -i 's/\r//' /entrypoint + +COPY --chmod=755 ../../docker/dev/start /start +RUN sed -i 's/\r//' /start + +USER $USERNAME + +WORKDIR $PROJECT_PATH diff --git a/docker/dev/entrypoint b/docker/dev/entrypoint new file mode 100755 index 0000000..89d4d8b --- /dev/null +++ b/docker/dev/entrypoint @@ -0,0 +1,30 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +cmd="$@" + +function postgres_ready(){ +python << END +import sys +import psycopg2 +import os + +try: + dbname = os.getenv('POSTGRES_DB') + user = os.getenv('POSTGRES_USER') + password = os.getenv('POSTGRES_PASSWORD') + conn = psycopg2.connect(dbname=dbname, user=user, password=password, host='db', port=5432) +except psycopg2.OperationalError: + sys.exit(-1) +sys.exit(0) +END +} + +until postgres_ready; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - continuing..." +exec $cmd diff --git a/docker/dev/start b/docker/dev/start new file mode 100755 index 0000000..35388e8 --- /dev/null +++ b/docker/dev/start @@ -0,0 +1,15 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset +set -o xtrace + +python manage.py migrate --no-input +python manage.py initadmin +if [ "${DEBUG}" == "True" ]; then + python manage.py runserver 0.0.0.0:8001 +else + python manage.py collectstatic --no-input + gunicorn shadowmere.wsgi:application --bind 0.0.0.0:8001 -k gevent -w 6 --capture-output +fi From d302f6440c243d30e025c9d589c56c987a22b21c Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:30:24 +0200 Subject: [PATCH 22/32] wip: prod dockerfile --- docker/prod/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 88f6e45..f35dbb5 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -68,6 +68,6 @@ COPY ./docker/celery/beat/start /start-celerybeat RUN sed -i 's/\r//' /start-celerybeat RUN chmod +x /start-celerybeat -COPY . $PROJECT_PATH +COPY ../.. $PROJECT_PATH USER $PROJECT_USER From 8f00c291a112ebdc159c2e7eef38845d5b150b11 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:30:36 +0200 Subject: [PATCH 23/32] feat: compose recipe for dev env --- docker-compose.dev.yml | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 6fae01d..20fcc9f 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,4 +1,3 @@ -version: "3" volumes: shadowmere_data: redis_data: @@ -9,6 +8,8 @@ services: restart: always volumes: - redis_data:/data + ports: + - "6379:6379" db: image: postgres:alpine @@ -17,37 +18,40 @@ services: - shadowmere_data:/var/lib/postgresql/data env_file: .env - shadowmere: + backend: &shadowmere build: context: . - image: guamulo/shadowmere - restart: always + dockerfile: ./docker/dev/Dockerfile + image: guamulo/shadowmere_backend + volumes: + - ./app/shadowmere:/app/shadowmere + working_dir: /app/shadowmere command: /start + entrypoint: /entrypoint + restart: always env_file: .env - depends_on: - - db ports: - "8001:8001" + depends_on: + - db - celery: + huey: <<: *shadowmere - image: guamulo/shadowmere-celeryworker + image: guamulo/shadowmere_huey restart: always - command: /wait_for_migration.sh /start-celeryworker - env_file: .env + command: ["python", "manage.py", "run_huey"] + env_file: + - .env + ports: [] depends_on: - redis - ports: [] - volumes: - - /var/run/docker.sock:/var/run/docker.sock + - db - celery_beat: - <<: *shadowmere - image: guamulo/shadowmere-celerybeat + frontend: + image: guamulo/shadowmere-frontend-njs restart: always - command: /wait_for_migration.sh /start-celerybeat - env_file: .env - ports: [] + ports: + - "8000:80" depends_on: - - redis + - backend \ No newline at end of file From ce89509943bf941bb03906207cf874ca210e350d Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Wed, 5 Jun 2024 19:30:53 +0200 Subject: [PATCH 24/32] feat: poetry and project config --- poetry.lock | 582 ++++++++++++++++++++++++++----------------------- pyproject.toml | 19 +- 2 files changed, 322 insertions(+), 279 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6c1dacd..ca508b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "amqp" @@ -73,49 +73,36 @@ tests = ["pytest"] [[package]] name = "asgiref" -version = "3.7.2" +version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, ] -[package.dependencies] -typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} - [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "billiard" @@ -130,22 +117,22 @@ files = [ [[package]] name = "botocore" -version = "1.33.11" +version = "1.34.119" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">= 3.7" +python-versions = ">=3.8" files = [ - {file = "botocore-1.33.11-py3-none-any.whl", hash = "sha256:b46227eb3fa9cfdc8f5a83920ef347e67adea8095830ed265a3373b13b54421f"}, - {file = "botocore-1.33.11.tar.gz", hash = "sha256:b14b328f902d120de0a09eaa657a9a701c0ceeb711197c2f01ef0523f855086c"}, + {file = "botocore-1.34.119-py3-none-any.whl", hash = "sha256:4bdf7926a1290b2650d62899ceba65073dd2693e61c35f5cdeb3a286a0aaa27b"}, + {file = "botocore-1.34.119.tar.gz", hash = "sha256:b253f15b24b87b070e176af48e8ef146516090429d30a7d8b136a4c079b28008"}, ] [package.dependencies] jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""} +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.19.17)"] +crt = ["awscrt (==0.20.9)"] [[package]] name = "cattrs" @@ -160,8 +147,6 @@ files = [ [package.dependencies] attrs = ">=23.1.0" -exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} [package.extras] bson = ["pymongo (>=4.4.0)"] @@ -174,13 +159,13 @@ ujson = ["ujson (>=5.7.0)"] [[package]] name = "celery" -version = "5.3.6" +version = "5.4.0" description = "Distributed Task Queue." optional = false python-versions = ">=3.8" files = [ - {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, - {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"}, + {file = "celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64"}, + {file = "celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706"}, ] [package.dependencies] @@ -196,7 +181,7 @@ vine = ">=5.1.0,<6.0" [package.extras] arangodb = ["pyArango (>=2.0.2)"] -auth = ["cryptography (==41.0.5)"] +auth = ["cryptography (==42.0.5)"] azureblockblob = ["azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] cassandra = ["cassandra-driver (>=3.25.0,<4)"] @@ -206,22 +191,23 @@ couchbase = ["couchbase (>=3.0.0)"] couchdb = ["pycouchdb (==1.14.2)"] django = ["Django (>=2.2.28)"] dynamodb = ["boto3 (>=1.26.143)"] -elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"] +elasticsearch = ["elastic-transport (<=8.13.0)", "elasticsearch (<=8.13.0)"] eventlet = ["eventlet (>=0.32.0)"] +gcs = ["google-cloud-storage (>=2.10.0)"] gevent = ["gevent (>=1.5.0)"] librabbitmq = ["librabbitmq (>=2.0.0)"] memcache = ["pylibmc (==1.6.3)"] mongodb = ["pymongo[srv] (>=4.0.2)"] -msgpack = ["msgpack (==1.0.7)"] -pymemcache = ["python-memcached (==1.59)"] +msgpack = ["msgpack (==1.0.8)"] +pymemcache = ["python-memcached (>=1.61)"] pyro = ["pyro4 (==4.82)"] -pytest = ["pytest-celery (==0.0.0)"] +pytest = ["pytest-celery[all] (>=1.0.0)"] redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] s3 = ["boto3 (>=1.26.143)"] slmq = ["softlayer-messaging (>=1.0.3)"] solar = ["ephem (==4.1.5)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] -sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.4)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] @@ -229,13 +215,13 @@ zstd = ["zstandard (==0.22.0)"] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -417,13 +403,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "click-didyoumean" -version = "0.3.0" +version = "0.3.1" description = "Enables git-like *did-you-mean* feature in click" optional = false -python-versions = ">=3.6.2,<4.0.0" +python-versions = ">=3.6.2" files = [ - {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, - {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, ] [package.dependencies] @@ -502,17 +488,17 @@ dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1 [[package]] name = "django" -version = "5.0" +version = "5.0.6" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.10" files = [ - {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"}, - {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"}, + {file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"}, + {file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"}, ] [package.dependencies] -asgiref = ">=3.7.0" +asgiref = ">=3.7.0,<4" sqlparse = ">=0.3.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} @@ -522,13 +508,13 @@ bcrypt = ["bcrypt"] [[package]] name = "django-admin-rangefilter" -version = "0.12.0" +version = "0.12.5" description = "django-admin-rangefilter app, add the filter by a custom date range on the admin UI." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ - {file = "django-admin-rangefilter-0.12.0.tar.gz", hash = "sha256:56035f4190d35aad4e699f8fd81306f964642edc96e15ec2a532a1598a466615"}, - {file = "django_admin_rangefilter-0.12.0-py2.py3-none-any.whl", hash = "sha256:4fd7211271c70c51469fc39b182b70f1199ab9ce0b16264654a2eec96751d686"}, + {file = "django_admin_rangefilter-0.12.5-py2.py3-none-any.whl", hash = "sha256:c2be9ca82115cadb5b5ea04b20bbe96a8aa6935b8921972cd797c2893d272c5d"}, + {file = "django_admin_rangefilter-0.12.5.tar.gz", hash = "sha256:57970e7714f14f2a9b14619143b3695f6c727fa8fad50352ecf4286ec77a1d25"}, ] [[package]] @@ -563,13 +549,13 @@ Django = ">=3.2" [[package]] name = "django-import-export" -version = "3.3.3" +version = "3.3.9" description = "Django application and library for importing and exporting data with included admin integration." optional = false python-versions = ">=3.8" files = [ - {file = "django-import-export-3.3.3.tar.gz", hash = "sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e"}, - {file = "django_import_export-3.3.3-py3-none-any.whl", hash = "sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978"}, + {file = "django_import_export-3.3.9-py3-none-any.whl", hash = "sha256:dd6cabc08ed6d1bd37a392e7fb542bd7d196b615c800168f5c69f0f55f49b103"}, + {file = "django_import_export-3.3.9.tar.gz", hash = "sha256:16797965e93a8001fe812c61e3b71fb858c57c1bd16da195fe276d6de685348e"}, ] [package.dependencies] @@ -579,17 +565,17 @@ tablib = {version = "3.5.0", extras = ["html", "ods", "xls", "xlsx", "yaml"]} [[package]] name = "django-jazzmin" -version = "2.6.0" +version = "2.6.2" description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" files = [ - {file = "django_jazzmin-2.6.0-py3-none-any.whl", hash = "sha256:fb554c2d564649c65243b13385121fdbdda58521f49544f9d7cb9c414a4908d4"}, - {file = "django_jazzmin-2.6.0.tar.gz", hash = "sha256:5bb07055cf19183030724f976904fd8b6337559727959340a43832fab0531812"}, + {file = "django_jazzmin-2.6.2-py3-none-any.whl", hash = "sha256:f7eb509b8a2e92260c2e836dc856fc9ca8888e572094201f9021d7b620bb96b2"}, + {file = "django_jazzmin-2.6.2.tar.gz", hash = "sha256:2bfc33c4e6d59ee647930402d372692ae3514ea45940040eb7f50b481f6ef53b"}, ] [package.dependencies] -django = ">=2.2" +django = ">=3" [[package]] name = "django-minio-storage" @@ -620,15 +606,26 @@ files = [ [package.dependencies] prometheus-client = ">=0.7" +[[package]] +name = "django-ratelimit" +version = "4.1.0" +description = "Cache-based rate-limiting for Django." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-ratelimit-4.1.0.tar.gz", hash = "sha256:555943b283045b917ad59f196829530d63be2a39adb72788d985b90c81ba808b"}, + {file = "django_ratelimit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d047a31cf94d83ef1465d7543ca66c6fc16695559b5f8d814d1b51df15110b92"}, +] + [[package]] name = "django-storages" -version = "1.14.2" +version = "1.14.3" description = "Support for many storage backends in Django" optional = false python-versions = ">=3.7" files = [ - {file = "django-storages-1.14.2.tar.gz", hash = "sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5"}, - {file = "django_storages-1.14.2-py3-none-any.whl", hash = "sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad"}, + {file = "django-storages-1.14.3.tar.gz", hash = "sha256:95a12836cd998d4c7a4512347322331c662d9114c4344f932f5e9c0fce000608"}, + {file = "django_storages-1.14.3-py3-none-any.whl", hash = "sha256:31f263389e95ce3a1b902fb5f739a7ed32895f7d8b80179fe7453ecc0dfe102e"}, ] [package.dependencies] @@ -645,18 +642,17 @@ sftp = ["paramiko (>=1.15)"] [[package]] name = "djangorestframework" -version = "3.14.0" +version = "3.15.1" description = "Web APIs for Django, made easy." optional = false python-versions = ">=3.6" files = [ - {file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"}, - {file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"}, + {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"}, + {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, ] [package.dependencies] django = ">=3.0" -pytz = "*" [[package]] name = "emoji-country-flag" @@ -683,20 +679,6 @@ files = [ {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.0" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "gunicorn" version = "21.2.0" @@ -728,15 +710,43 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "huey" +version = "2.5.0" +description = "huey, a little task queue" +optional = false +python-versions = "*" +files = [ + {file = "huey-2.5.0.tar.gz", hash = "sha256:2ffb52fb5c46a1b0d53c79d59df3622312b27e2ab68d81a580985a8ea4ca3480"}, +] + +[package.extras] +backends = ["redis (>=3.0.0)"] +redis = ["redis (>=3.0.0)"] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -752,13 +762,13 @@ files = [ [[package]] name = "kombu" -version = "5.3.4" +version = "5.3.7" description = "Messaging library for Python." optional = false python-versions = ">=3.8" files = [ - {file = "kombu-5.3.4-py3-none-any.whl", hash = "sha256:63bb093fc9bb80cfb3a0972336a5cec1fa7ac5f9ef7e8237c6bf8dda9469313e"}, - {file = "kombu-5.3.4.tar.gz", hash = "sha256:0bb2e278644d11dea6272c17974a3dbb9688a949f3bb60aeb5b791329c44fadc"}, + {file = "kombu-5.3.7-py3-none-any.whl", hash = "sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9"}, + {file = "kombu-5.3.7.tar.gz", hash = "sha256:011c4cd9a355c14a1de8d35d257314a1d2456d52b7140388561acac3cf1a97bf"}, ] [package.dependencies] @@ -775,7 +785,7 @@ mongodb = ["pymongo (>=4.1.1)"] msgpack = ["msgpack"] pyro = ["pyro4"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] slmq = ["softlayer-messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] @@ -784,18 +794,18 @@ zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "lsprotocol" -version = "2023.0.0" +version = "2023.0.1" description = "Python implementation of the Language Server Protocol." optional = false python-versions = ">=3.7" files = [ - {file = "lsprotocol-2023.0.0-py3-none-any.whl", hash = "sha256:e85fc87ee26c816adca9eb497bb3db1a7c79c477a11563626e712eaccf926a05"}, - {file = "lsprotocol-2023.0.0.tar.gz", hash = "sha256:c9d92e12a3f4ed9317d3068226592860aab5357d93cf5b2451dc244eee8f35f2"}, + {file = "lsprotocol-2023.0.1-py3-none-any.whl", hash = "sha256:c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2"}, + {file = "lsprotocol-2023.0.1.tar.gz", hash = "sha256:cc5c15130d2403c18b734304339e51242d3018a05c4f7d0f198ad6e0cd21861d"}, ] [package.dependencies] attrs = ">=21.3.0" -cattrs = "*" +cattrs = "!=23.2.1" [[package]] name = "markuppy" @@ -809,19 +819,20 @@ files = [ [[package]] name = "minio" -version = "7.2.0" +version = "7.2.7" description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" optional = false python-versions = "*" files = [ - {file = "minio-7.2.0-py3-none-any.whl", hash = "sha256:10656272c16156fa08436ce2b27e25e4134ef5142a8c259513ee26fb514531a6"}, - {file = "minio-7.2.0.tar.gz", hash = "sha256:4b015b018d10c1505f7c3e724fa7c2267760ac7bee6463a624cbf22cd272877b"}, + {file = "minio-7.2.7-py3-none-any.whl", hash = "sha256:59d1f255d852fe7104018db75b3bebbd987e538690e680f7c5de835e422de837"}, + {file = "minio-7.2.7.tar.gz", hash = "sha256:473d5d53d79f340f3cd632054d0c82d2f93177ce1af2eac34a235bea55708d98"}, ] [package.dependencies] argon2-cffi = "*" certifi = "*" pycryptodome = "*" +typing-extensions = "*" urllib3 = "*" [[package]] @@ -839,13 +850,13 @@ defusedxml = "*" [[package]] name = "openpyxl" -version = "3.1.2" +version = "3.1.3" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false python-versions = ">=3.6" files = [ - {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"}, - {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"}, + {file = "openpyxl-3.1.3-py2.py3-none-any.whl", hash = "sha256:25071b558db709de9e8782c3d3e058af3b23ffb2fc6f40c8f0c45a154eced2c3"}, + {file = "openpyxl-3.1.3.tar.gz", hash = "sha256:8dd482e5350125b2388070bb2477927be2e8ebc27df61178709bc8c8751da2f9"}, ] [package.dependencies] @@ -853,91 +864,110 @@ et-xmlfile = "*" [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "pillow" -version = "10.1.0" +version = "10.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, - {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, - {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, - {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, - {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, - {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, - {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, - {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "prometheus-client" -version = "0.19.0" +version = "0.20.0" description = "Python client for the Prometheus monitoring system." optional = false python-versions = ">=3.8" files = [ - {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, - {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"}, + {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, + {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, ] [package.extras] @@ -945,13 +975,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.41" +version = "3.0.46" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, - {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, + {file = "prompt_toolkit-3.0.46-py3-none-any.whl", hash = "sha256:45abe60a8300f3c618b23c16c4bb98c6fc80af8ce8b17c7ae92db48db3ee63c1"}, + {file = "prompt_toolkit-3.0.46.tar.gz", hash = "sha256:869c50d682152336e23c4db7f74667639b5047494202ffe7670817053fd57795"}, ] [package.dependencies] @@ -1040,72 +1070,73 @@ files = [ [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] name = "pycryptodome" -version = "3.19.0" +version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, - {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, ] [[package]] name = "pygls" -version = "1.2.1" +version = "1.3.1" description = "A pythonic generic language server (pronounced like 'pie glass')" optional = false -python-versions = ">=3.7.9,<4" +python-versions = ">=3.8" files = [ - {file = "pygls-1.2.1-py3-none-any.whl", hash = "sha256:7dcfcf12b6f15beb606afa46de2ed348b65a279c340ef2242a9a35c22eeafe94"}, - {file = "pygls-1.2.1.tar.gz", hash = "sha256:04f9b9c115b622dcc346fb390289066565343d60245a424eca77cb429b911ed8"}, + {file = "pygls-1.3.1-py3-none-any.whl", hash = "sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e"}, + {file = "pygls-1.3.1.tar.gz", hash = "sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018"}, ] [package.dependencies] -lsprotocol = "2023.0.0" +cattrs = ">=23.1.2" +lsprotocol = "2023.0.1" [package.extras] -ws = ["websockets (>=11.0.3,<12.0.0)"] +ws = ["websockets (>=11.0.3)"] [[package]] name = "pypng" @@ -1118,31 +1149,31 @@ files = [ {file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"}, ] +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +optional = false +python-versions = "*" +files = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] + [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] six = ">=1.5" -[[package]] -name = "pytz" -version = "2023.3.post1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, -] - [[package]] name = "pyyaml" version = "6.0.1" @@ -1217,31 +1248,28 @@ test = ["coverage", "pytest"] [[package]] name = "redis" -version = "5.0.1" +version = "5.0.4" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, + {file = "redis-5.0.4-py3-none-any.whl", hash = "sha256:7adc2835c7a9b5033b7ad8f8918d09b7344188228809c98df07af226d39dec91"}, + {file = "redis-5.0.4.tar.gz", hash = "sha256:ec31f2ed9675cc54c21ba854cfe0462e6faf1d83c8ce5944709db8a4700b9c61"}, ] -[package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} - [package.extras] hiredis = ["hiredis (>=1.0.0)"] ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1256,28 +1284,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.1.7" +version = "0.1.15" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"}, - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"}, - {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"}, - {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"}, - {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"}, - {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] [[package]] @@ -1303,13 +1331,13 @@ dev = ["mypy (==1.4.1)", "pip-tools (>=6.13.0,<7.0.0)", "pytest (>=7.3.1,<8.0.0) [[package]] name = "sentry-sdk" -version = "1.38.0" +version = "1.45.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.38.0.tar.gz", hash = "sha256:8feab81de6bbf64f53279b085bd3820e3e737403b0a0d9317f73a2c3374ae359"}, - {file = "sentry_sdk-1.38.0-py2.py3-none-any.whl", hash = "sha256:0017fa73b8ae2d4e57fd2522ee3df30453715b29d2692142793ec5d5f90b94a6"}, + {file = "sentry-sdk-1.45.0.tar.gz", hash = "sha256:509aa9678c0512344ca886281766c2e538682f8acfa50fd8d405f8c417ad0625"}, + {file = "sentry_sdk-1.45.0-py2.py3-none-any.whl", hash = "sha256:1ce29e30240cc289a027011103a8c83885b15ef2f316a60bcc7c5300afa144f1"}, ] [package.dependencies] @@ -1323,6 +1351,7 @@ asyncpg = ["asyncpg (>=0.23)"] beam = ["apache-beam (>=2.12)"] bottle = ["bottle (>=0.12.13)"] celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] chalice = ["chalice (>=1.16.0)"] clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] django = ["django (>=1.8)"] @@ -1333,6 +1362,7 @@ grpcio = ["grpcio (>=1.21.1)"] httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] pure-eval = ["asttokens", "executing", "pure-eval"] @@ -1359,19 +1389,18 @@ files = [ [[package]] name = "sqlparse" -version = "0.4.4" +version = "0.5.0" description = "A non-validating SQL parser." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, - {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, + {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"}, + {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"}, ] [package.extras] -dev = ["build", "flake8"] +dev = ["build", "hatch"] doc = ["sphinx"] -test = ["pytest", "pytest-cov"] [[package]] name = "tablib" @@ -1404,40 +1433,40 @@ yaml = ["pyyaml"] [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.12.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, + {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, ] [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1455,7 +1484,6 @@ files = [ [package.dependencies] click = ">=7.0" h11 = ">=0.8" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] @@ -1473,13 +1501,13 @@ files = [ [[package]] name = "wcwidth" -version = "0.2.12" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, - {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -1511,5 +1539,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "05fa8b336882246b6693e65438939ca68b15eec4b1a30c3929b3e9e57961cac1" +python-versions = "^3.12" +content-hash = "292798843bea6f6f117ae3bb6407709dd89a5bd4518f3739fedeb42a99a958bc" diff --git a/pyproject.toml b/pyproject.toml index 07ca803..e603ce3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,4 @@ -[tool.poetry] +[project] name = "shadowmere" version = "1.0.0" description = "An automatically tested list of Shadowsocks proxies." @@ -6,6 +6,9 @@ authors = ["Your Name "] license = "GPLv3" readme = "README.md" +[tool.poetry] +package-mode = false + [tool.poetry.dependencies] python = "^3.12" django = "^5.0" @@ -29,6 +32,9 @@ django-environ = "^0.11.2" uvicorn = "^0.24.0.post1" gunicorn = "^21.2.0" django-jazzmin = "^2.6.0" +huey = "^2.5.0" +humanfriendly = "^10.0" +django-ratelimit = "^4.1.0" [tool.poetry.group.dev.dependencies] ruff = "^0.1.7" @@ -39,7 +45,16 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.ruff] -select = ["E", "F"] +exclude = ["migrations"] +select = ["E", "F", "I", "W", "N"] ignore = [] line-length = 120 target-version = "py312" +fix = true + +[tool.ruff.format] +docstring-code-format = true +docstring-code-line-length = 120 + +[tool.ruff.lint.isort] +combine-as-imports = true From af9748a8d49b80cfe98b45bc3109480dca832b88 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sat, 8 Jun 2024 20:25:46 +0200 Subject: [PATCH 25/32] feat/wip: utils module --- app/shadowmere/utils/__init__.py | 0 .../proxylist => utils}/base64_decoder.py | 0 .../{apps/proxylist => utils}/proxy.py | 0 app/shadowmere/utils/uri_scheme.py | 24 ++++++++++++++++++ app/shadowmere/utils/validators.py | 25 +++++++++++++++++++ 5 files changed, 49 insertions(+) create mode 100644 app/shadowmere/utils/__init__.py rename app/shadowmere/{apps/proxylist => utils}/base64_decoder.py (100%) rename app/shadowmere/{apps/proxylist => utils}/proxy.py (100%) create mode 100644 app/shadowmere/utils/uri_scheme.py create mode 100644 app/shadowmere/utils/validators.py diff --git a/app/shadowmere/utils/__init__.py b/app/shadowmere/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/shadowmere/apps/proxylist/base64_decoder.py b/app/shadowmere/utils/base64_decoder.py similarity index 100% rename from app/shadowmere/apps/proxylist/base64_decoder.py rename to app/shadowmere/utils/base64_decoder.py diff --git a/app/shadowmere/apps/proxylist/proxy.py b/app/shadowmere/utils/proxy.py similarity index 100% rename from app/shadowmere/apps/proxylist/proxy.py rename to app/shadowmere/utils/proxy.py diff --git a/app/shadowmere/utils/uri_scheme.py b/app/shadowmere/utils/uri_scheme.py new file mode 100644 index 0000000..959da23 --- /dev/null +++ b/app/shadowmere/utils/uri_scheme.py @@ -0,0 +1,24 @@ +import base64 + +from utils.base64_decoder import decode_base64 + + +def get_sip002(instance_url): + try: + url = instance_url + if "#" in url: + url = url.split("#")[0] + if "=" in url: + url = url.replace("=", "") + if "@" not in url: + url = url.replace("ss://", "") + decoded_url = decode_base64(url.encode("ascii")) + if decoded_url: + encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=") + url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}' + else: + return "" + except IndexError: + return "" + + return url diff --git a/app/shadowmere/utils/validators.py b/app/shadowmere/utils/validators.py new file mode 100644 index 0000000..5d7d478 --- /dev/null +++ b/app/shadowmere/utils/validators.py @@ -0,0 +1,25 @@ +from django.core.exceptions import ValidationError +from utils.proxy import get_proxy_location +from utils.uri_scheme import get_sip002 + + +def validate_sip002(value: str) -> None: + if get_sip002(value) == "": + raise ValidationError( + "The value entered is not SIP002 compatible", + params={"value": value}, + ) + + +def validate_proxy_can_connect(value: str) -> None: + location = get_proxy_location(get_sip002(value)) + if location is None or location == "unknown": + raise ValidationError( + "Can't get the location for this address", + params={"value": value}, + ) + + +def proxy_validator(value: str) -> None: + validate_sip002(value) + validate_proxy_can_connect(value) From 609c9bdcc49e6cc462fb1b5a5a3324624c7a75c5 Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sat, 8 Jun 2024 20:26:08 +0200 Subject: [PATCH 26/32] feat: using signals module --- app/shadowmere/apps/proxylist/apps.py | 3 ++ app/shadowmere/apps/proxylist/signals.py | 37 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 app/shadowmere/apps/proxylist/signals.py diff --git a/app/shadowmere/apps/proxylist/apps.py b/app/shadowmere/apps/proxylist/apps.py index 1b01159..d7203e4 100644 --- a/app/shadowmere/apps/proxylist/apps.py +++ b/app/shadowmere/apps/proxylist/apps.py @@ -3,3 +3,6 @@ class ProxylistConfig(AppConfig): name = "apps.proxylist" + + def ready(self) -> None: + import apps.proxylist.signals # noqa diff --git a/app/shadowmere/apps/proxylist/signals.py b/app/shadowmere/apps/proxylist/signals.py new file mode 100644 index 0000000..dea6408 --- /dev/null +++ b/app/shadowmere/apps/proxylist/signals.py @@ -0,0 +1,37 @@ +import re + +from apps.proxylist.models import Proxy +from django.core.cache import cache +from django.db import IntegrityError +from django.db.models.signals import post_save +from django.dispatch import receiver +from utils.proxy import update_proxy_status +from utils.uri_scheme import get_sip002 + + +@receiver(post_save, sender=Proxy) +def update_url_and_location_after_save(sender, instance, created, **kwargs): + url = get_sip002(instance.url) + if url != instance.url: + instance.url = url + instance.save() + return + + if instance.port == 0: + server_and_port = instance.url.split("@")[1] + instance.port = int(re.findall(r":(\d+)", server_and_port)[-1]) + instance.save() + return + + if instance.location == "": + update_proxy_status(instance) + try: + instance.save() + except IntegrityError: + # This means the proxy is either a duplicate or no longer valid + instance.delete() + + +@receiver(post_save, sender=Proxy) +def clear_cache(sender, instance, **kwargs): + cache.clear() From e3de031c8a56b9d64af582f541138b5c5404bd2e Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sat, 8 Jun 2024 20:26:33 +0200 Subject: [PATCH 27/32] feat: improved models, updated migrations wih new modules --- .../migrations/0003_alter_proxy_url.py | 1 - ..._proxy_location_country_alter_proxy_url.py | 7 +- .../0010_subscription_alter_proxy_url.py | 4 +- ..._address_alter_proxy_is_active_and_more.py | 43 ++++++++ app/shadowmere/apps/proxylist/models.py | 104 ++---------------- 5 files changed, 56 insertions(+), 103 deletions(-) create mode 100644 app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py diff --git a/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py index 13bb053..04f4573 100644 --- a/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py +++ b/app/shadowmere/apps/proxylist/migrations/0003_alter_proxy_url.py @@ -16,7 +16,6 @@ class Migration(migrations.Migration): field=models.CharField( max_length=1024, unique=True, - validators=[apps.proxylist.models.validate_not_existing], ), ), ] diff --git a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py index 60ef86f..a795708 100644 --- a/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py +++ b/app/shadowmere/apps/proxylist/migrations/0008_proxy_location_country_alter_proxy_url.py @@ -1,7 +1,7 @@ # Generated by Django 4.0.4 on 2022-06-06 12:09 from django.db import migrations, models -import apps.proxylist.models +from utils import validators class Migration(migrations.Migration): @@ -22,9 +22,8 @@ class Migration(migrations.Migration): max_length=1024, unique=True, validators=[ - apps.proxylist.models.validate_sip002, - apps.proxylist.models.validate_not_existing, - apps.proxylist.models.validate_proxy_can_connect, + validators.validate_sip002, + validators.validate_proxy_can_connect, ], ), ), diff --git a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py index cef7754..8aff90f 100644 --- a/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py +++ b/app/shadowmere/apps/proxylist/migrations/0010_subscription_alter_proxy_url.py @@ -1,7 +1,7 @@ # Generated by Django 4.1.7 on 2023-03-04 14:37 from django.db import migrations, models -import apps.proxylist.models +from utils import validators class Migration(migrations.Migration): @@ -21,6 +21,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="proxy", name="url", - field=models.CharField(max_length=1024, unique=True, validators=[apps.proxylist.models.proxy_validator]), + field=models.CharField(max_length=1024, unique=True, validators=[validators.proxy_validator]), ), ] diff --git a/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py b/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py new file mode 100644 index 0000000..bb6cbda --- /dev/null +++ b/app/shadowmere/apps/proxylist/migrations/0018_alter_proxy_ip_address_alter_proxy_is_active_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 5.0.6 on 2024-06-08 18:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('proxylist', '0017_tasklog_details'), + ] + + operations = [ + migrations.AlterField( + model_name='proxy', + name='ip_address', + field=models.CharField(blank=True, db_index=True, max_length=100, null=True), + ), + migrations.AlterField( + model_name='proxy', + name='is_active', + field=models.BooleanField(db_index=True, default=False), + ), + migrations.AlterField( + model_name='proxy', + name='location', + field=models.CharField(blank=True, max_length=100, null=True), + ), + migrations.AlterField( + model_name='proxy', + name='location_country', + field=models.CharField(blank=True, db_index=True, max_length=50, null=True), + ), + migrations.AlterField( + model_name='proxy', + name='location_country_code', + field=models.CharField(blank=True, db_index=True, max_length=3, null=True), + ), + migrations.AlterField( + model_name='proxy', + name='port', + field=models.IntegerField(db_index=True, default=0), + ), + ] diff --git a/app/shadowmere/apps/proxylist/models.py b/app/shadowmere/apps/proxylist/models.py index 4dc32a8..9752b01 100644 --- a/app/shadowmere/apps/proxylist/models.py +++ b/app/shadowmere/apps/proxylist/models.py @@ -1,46 +1,7 @@ -import base64 -import re - -from apps.proxylist.base64_decoder import decode_base64 -from apps.proxylist.proxy import get_proxy_location, update_proxy_status -from django.core.cache import cache -from django.core.exceptions import ValidationError -from django.db import IntegrityError, models -from django.db.models.signals import post_save -from django.dispatch import receiver +from django.db import models from django.utils.timezone import now from django_prometheus.models import ExportModelOperationsMixin - - -def validate_sip002(value): - if get_sip002(value) == "": - raise ValidationError( - "The value entered is not SIP002 compatible", - params={"value": value}, - ) - - -def validate_not_existing(value): - if Proxy.objects.filter(url=get_sip002(value)): - raise ValidationError( - "This proxy was already imported", - params={"value": value}, - ) - - -def validate_proxy_can_connect(value): - location = get_proxy_location(get_sip002(value)) - if location is None or location == "unknown": - raise ValidationError( - "Can't get the location for this address", - params={"value": value}, - ) - - -def proxy_validator(value): - validate_sip002(value) - validate_not_existing(value) - validate_proxy_can_connect(value) +from utils.validators import proxy_validator class Proxy(ExportModelOperationsMixin("proxy"), models.Model): @@ -51,12 +12,12 @@ class Proxy(ExportModelOperationsMixin("proxy"), models.Model): proxy_validator, ], ) - location = models.CharField(max_length=100, default="") - location_country_code = models.CharField(max_length=3, default="") - location_country = models.CharField(max_length=50, default="") - ip_address = models.CharField(max_length=100, default="") - port = models.IntegerField(default=0) - is_active = models.BooleanField(default=False) + location = models.CharField(max_length=100, blank=True, null=True) + location_country_code = models.CharField(max_length=3, blank=True, null=True, db_index=True) + location_country = models.CharField(max_length=50, blank=True, null=True, db_index=True) + ip_address = models.CharField(max_length=100, blank=True, null=True, db_index=True) + port = models.IntegerField(default=0, db_index=True) + is_active = models.BooleanField(default=False, db_index=True) last_checked = models.DateTimeField(auto_now=True) last_active = models.DateTimeField(blank=True, default=now) times_checked = models.IntegerField(default=0) @@ -66,55 +27,6 @@ def __str__(self): return f"{self.location} ({self.url})" -def get_sip002(instance_url): - try: - url = instance_url - if "#" in url: - url = url.split("#")[0] - if "=" in url: - url = url.replace("=", "") - if "@" not in url: - url = url.replace("ss://", "") - decoded_url = decode_base64(url.encode("ascii")) - if decoded_url: - encoded_bits = base64.b64encode(decoded_url.split(b"@")[0]).decode("ascii").rstrip("=") - url = f'ss://{encoded_bits}@{decoded_url.split(b"@")[1].decode("ascii")}' - else: - return "" - except IndexError: - return "" - - return url - - -@receiver(post_save, sender=Proxy) -def update_url_and_location_after_save(sender, instance, created, **kwargs): - url = get_sip002(instance.url) - if url != instance.url: - instance.url = url - instance.save() - return - - if instance.port == 0: - server_and_port = instance.url.split("@")[1] - instance.port = int(re.findall(r":(\d+)", server_and_port)[-1]) - instance.save() - return - - if instance.location == "": - update_proxy_status(instance) - try: - instance.save() - except IntegrityError: - # This means the proxy is either a duplicate or no longer valid - instance.delete() - - -@receiver(post_save, sender=Proxy) -def clear_cache(sender, instance, **kwargs): - cache.clear() - - class Subscription(models.Model): class SubscriptionKind(models.TextChoices): PLAIN = "PLAIN", "plain" From 4029b7cb7a7bb9168cb1b4807b869d4e2969ed7c Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sat, 8 Jun 2024 20:26:45 +0200 Subject: [PATCH 28/32] feat/fix: updated imports --- app/shadowmere/apps/proxylist/admin.py | 2 +- app/shadowmere/apps/proxylist/tasks.py | 7 ++++--- .../apps/proxylist/tests/test_subscription.py | 10 +++++----- app/shadowmere/apps/proxylist/views.py | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/shadowmere/apps/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py index 2dce17a..5033615 100644 --- a/app/shadowmere/apps/proxylist/admin.py +++ b/app/shadowmere/apps/proxylist/admin.py @@ -1,12 +1,12 @@ import humanfriendly from apps.proxylist.models import Proxy, Subscription, TaskLog -from apps.proxylist.proxy import update_proxy_status from django.contrib import admin from django.contrib.auth.models import Group from django.db import IntegrityError from import_export import resources from import_export.admin import ImportExportModelAdmin from rangefilter.filters import DateRangeFilter +from utils.proxy import update_proxy_status class ProxyResource(resources.ModelResource): diff --git a/app/shadowmere/apps/proxylist/tasks.py b/app/shadowmere/apps/proxylist/tasks.py index 6f61b41..9d95cdf 100644 --- a/app/shadowmere/apps/proxylist/tasks.py +++ b/app/shadowmere/apps/proxylist/tasks.py @@ -3,9 +3,7 @@ from concurrent.futures import ThreadPoolExecutor import requests -from apps.proxylist.base64_decoder import decode_base64 -from apps.proxylist.models import Proxy, Subscription, TaskLog, get_sip002 -from apps.proxylist.proxy import get_proxy_location, update_proxy_status +from apps.proxylist.models import Proxy, Subscription, TaskLog from django.db import IntegrityError from django.db.models import F, FloatField from django.db.models.functions import Coalesce @@ -13,6 +11,9 @@ from huey import crontab from huey.contrib.djhuey import db_periodic_task from requests.exceptions import ConnectionError, ReadTimeout, SSLError +from utils.base64_decoder import decode_base64 +from utils.proxy import get_proxy_location, update_proxy_status +from utils.uri_scheme import get_sip002 CONCURRENT_CHECKS = 200 SUBSCRIPTION_TIMEOUT_SECONDS = 60 diff --git a/app/shadowmere/apps/proxylist/tests/test_subscription.py b/app/shadowmere/apps/proxylist/tests/test_subscription.py index 02dc90e..743e1fc 100644 --- a/app/shadowmere/apps/proxylist/tests/test_subscription.py +++ b/app/shadowmere/apps/proxylist/tests/test_subscription.py @@ -1,11 +1,8 @@ -import base64 import json -import flag from django.urls import reverse from rest_framework.test import APITestCase - -from proxylist.base64_decoder import decode_base64 +from utils.base64_decoder import decode_base64 class SubEndpointTests(APITestCase): @@ -52,4 +49,7 @@ def test_get_b64sub(self): response = self.client.get(reverse("b64sub-list")) self.assertEqual(response.status_code, 200) content = decode_base64(response.content).decode("utf-8") - assert content == '\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwcG15SVVQMmV1WU0@37.218.242.73:8091/#πŸ‡³πŸ‡± Waalwijk, NB, Netherlands\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW8@196.196.156.122:807#πŸ‡ΈπŸ‡ͺ Stockholm, AB, Sweden\nss://YWVzLTI1Ni1nY206ZmFCQW9ENTRrODdVSkc3@169.197.142.39:2375#πŸ‡ΊπŸ‡Έ unknown' + assert ( + content + == "\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpwcG15SVVQMmV1WU0@37.218.242.73:8091/#πŸ‡³πŸ‡± Waalwijk, NB, Netherlands\nss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW8@196.196.156.122:807#πŸ‡ΈπŸ‡ͺ Stockholm, AB, Sweden\nss://YWVzLTI1Ni1nY206ZmFCQW9ENTRrODdVSkc3@169.197.142.39:2375#πŸ‡ΊπŸ‡Έ unknown" + ) diff --git a/app/shadowmere/apps/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py index 29e40ce..ce5e746 100644 --- a/app/shadowmere/apps/proxylist/views.py +++ b/app/shadowmere/apps/proxylist/views.py @@ -5,7 +5,6 @@ import flag import qrcode -from apps.proxylist.base64_decoder import decode_base64 from apps.proxylist.metrics import register_metrics from apps.proxylist.models import Proxy, TaskLog from apps.proxylist.permissions import GeneralPermission @@ -21,6 +20,7 @@ from django_ratelimit.decorators import ratelimit from rest_framework import viewsets from rest_framework.response import Response +from utils.base64_decoder import decode_base64 @cache_page(None) From 3f5c2bc634387cdf083bf967450c0aa61e3f413c Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 9 Jun 2024 20:00:20 +0200 Subject: [PATCH 29/32] feat" updated imports for management commands --- .../apps/proxylist/management/commands/clear_stats.py | 3 +-- .../apps/proxylist/management/commands/poll_subscriptions.py | 3 +-- .../apps/proxylist/management/commands/reduce_checks_by.py | 3 +-- .../apps/proxylist/management/commands/remove_low_quality.py | 5 ++--- .../apps/proxylist/management/commands/update_status.py | 3 +-- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/shadowmere/apps/proxylist/management/commands/clear_stats.py b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py index b6dc362..08acf40 100644 --- a/app/shadowmere/apps/proxylist/management/commands/clear_stats.py +++ b/app/shadowmere/apps/proxylist/management/commands/clear_stats.py @@ -1,7 +1,6 @@ +from apps.proxylist.models import Proxy from django.core.management.base import BaseCommand -from proxylist.models import Proxy - class Command(BaseCommand): help = "Clear all quality statistics" diff --git a/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py index 3c5cca0..6e6e981 100644 --- a/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py +++ b/app/shadowmere/apps/proxylist/management/commands/poll_subscriptions.py @@ -1,7 +1,6 @@ +from apps.proxylist.tasks import poll_subscriptions from django.core.management.base import BaseCommand -from proxylist.tasks import poll_subscriptions - class Command(BaseCommand): help = "Poll all subscriptions looking for new keys" diff --git a/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py index 9b7dae8..c593add 100644 --- a/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py +++ b/app/shadowmere/apps/proxylist/management/commands/reduce_checks_by.py @@ -1,7 +1,6 @@ +from apps.proxylist.models import Proxy from django.core.management.base import BaseCommand -from proxylist.models import Proxy - class Command(BaseCommand): help = "Clear all quality statistics" diff --git a/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py index 733c437..6310995 100644 --- a/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py +++ b/app/shadowmere/apps/proxylist/management/commands/remove_low_quality.py @@ -1,8 +1,7 @@ -from django.core.management.base import BaseCommand - -from proxylist.tasks import ( +from apps.proxylist.tasks import ( remove_low_quality_proxies, ) +from django.core.management.base import BaseCommand class Command(BaseCommand): diff --git a/app/shadowmere/apps/proxylist/management/commands/update_status.py b/app/shadowmere/apps/proxylist/management/commands/update_status.py index 407b048..9938107 100644 --- a/app/shadowmere/apps/proxylist/management/commands/update_status.py +++ b/app/shadowmere/apps/proxylist/management/commands/update_status.py @@ -1,7 +1,6 @@ +from apps.proxylist.tasks import update_status from django.core.management.base import BaseCommand -from proxylist.tasks import update_status - class Command(BaseCommand): help = "Update the status of the proxy list" From dcdd12a7f433baf432765e8a4a982cea85efd6bf Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 9 Jun 2024 20:01:24 +0200 Subject: [PATCH 30/32] fix: actions and display attr --- app/shadowmere/apps/proxylist/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/shadowmere/apps/proxylist/admin.py b/app/shadowmere/apps/proxylist/admin.py index 5033615..a60bdd3 100644 --- a/app/shadowmere/apps/proxylist/admin.py +++ b/app/shadowmere/apps/proxylist/admin.py @@ -17,7 +17,7 @@ class Meta: @admin.register(Proxy) class ProxyAdmin(ImportExportModelAdmin): @staticmethod - def update_status(modeladmin, request, queryset): + def update_status(queryset): for proxy in queryset: update_proxy_status(proxy) try: @@ -27,7 +27,7 @@ def update_status(modeladmin, request, queryset): proxy.delete() @staticmethod - def quality(self, obj): + def quality(obj): if obj.times_checked > 0: return obj.times_check_succeeded * 100 / obj.times_checked else: From 41b6d05ba6d4fbcfe58ba286ef519c786a85766f Mon Sep 17 00:00:00 2001 From: "Ozkar L. Garcell" Date: Sun, 9 Jun 2024 20:01:31 +0200 Subject: [PATCH 31/32] feat: removed unused code --- app/shadowmere/apps/proxylist/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/shadowmere/apps/proxylist/views.py b/app/shadowmere/apps/proxylist/views.py index ce5e746..2076e9d 100644 --- a/app/shadowmere/apps/proxylist/views.py +++ b/app/shadowmere/apps/proxylist/views.py @@ -153,7 +153,7 @@ class CountryCodeViewSet(viewsets.ViewSet): """ @method_decorator(cache_page(20 * 60)) - def list(self, request, format=None): + def list(self, request): country_codes = [ {"code": code["location_country_code"], "name": code["location_country"]} for code in Proxy.objects.filter(is_active=True) @@ -171,7 +171,7 @@ class PortViewSet(viewsets.ViewSet): """ @method_decorator(cache_page(20 * 60)) - def list(self, request, format=None): + def list(self, request): ports = [ port for port in Proxy.objects.filter(is_active=True).values_list("port", flat=True).distinct() if port != 0 ] @@ -198,7 +198,7 @@ class SubViewSet(viewsets.ViewSet): ) ) @method_decorator(cache_page(20 * 60)) - def list(self, request, format=None): + def list(self, request): servers = [ get_proxy_config(server) for server in Proxy.objects.filter(is_active=True).order_by("location_country_code") @@ -219,7 +219,7 @@ class Base64SubViewSet(viewsets.ViewSet): ) ) @method_decorator(cache_page(20 * 60)) - def list(self, request, format=None): + def list(self, request): server_list = "" for proxy in Proxy.objects.filter(is_active=True).order_by("location_country_code"): server_list += f"\n{proxy.url}#{get_flag_or_empty(proxy.location_country_code)} {proxy.location}" From fe1774972819e98b5e564d80a4cc324624c4272d Mon Sep 17 00:00:00 2001 From: "Jorge Alberto Diaz Orozco (Akiel)" Date: Sat, 20 Jul 2024 14:09:42 +0200 Subject: [PATCH 32/32] feat/fix: rebased branch --- app/shadowmere/config/settings/base.py | 4 - app/shadowmere/config/settings/dev.py | 12 ++ app/shadowmere/config/settings/prod.py | 15 ++ app/shadowmere/config/urls.py | 7 +- shadowmere/celery.py | 0 shadowmere/settings/base.py | 238 ------------------------- 6 files changed, 31 insertions(+), 245 deletions(-) delete mode 100644 shadowmere/celery.py delete mode 100644 shadowmere/settings/base.py diff --git a/app/shadowmere/config/settings/base.py b/app/shadowmere/config/settings/base.py index 95b21ae..089c6a4 100644 --- a/app/shadowmere/config/settings/base.py +++ b/app/shadowmere/config/settings/base.py @@ -89,8 +89,6 @@ WSGI_APPLICATION = "config.wsgi.application" -DATABASES = {"default": env.db()} - AUTH_PASSWORD_VALIDATORS = [ { "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", @@ -174,8 +172,6 @@ STATIC_URL = "/static/" -STATIC_ROOT = "./static_files/" - DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" HUEY = { diff --git a/app/shadowmere/config/settings/dev.py b/app/shadowmere/config/settings/dev.py index 8ecc929..7e0bfa7 100644 --- a/app/shadowmere/config/settings/dev.py +++ b/app/shadowmere/config/settings/dev.py @@ -1,3 +1,15 @@ from .base import * # noqa RATELIMIT_ENABLE = False + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + +CSRF_TRUSTED_ORIGINS = [ + "http://127.0.0.1:8000", + "http://localhost:8000", +] diff --git a/app/shadowmere/config/settings/prod.py b/app/shadowmere/config/settings/prod.py index 5e4b8ef..e7bf015 100644 --- a/app/shadowmere/config/settings/prod.py +++ b/app/shadowmere/config/settings/prod.py @@ -55,3 +55,18 @@ traces_sample_rate=0.01, send_default_pii=True, ) + +DATABASES = { + "default": { + "ENGINE": "django_prometheus.db.backends.postgresql", + "NAME": "shadowmere", + "USER": "shadowmere", + "PASSWORD": env("POSTGRES_PASSWORD"), + "HOST": "db", + } +} + +CSRF_TRUSTED_ORIGINS = [ + "https://shadowmere.akiel.dev", + "https://shadowmere.xyz", +] diff --git a/app/shadowmere/config/urls.py b/app/shadowmere/config/urls.py index 38e5f91..8aadfef 100644 --- a/app/shadowmere/config/urls.py +++ b/app/shadowmere/config/urls.py @@ -1,3 +1,7 @@ +from django.contrib import admin +from django.urls import include, path +from rest_framework import routers + from apps.proxylist.views import ( Base64SubViewSet, CountryCodeViewSet, @@ -9,9 +13,6 @@ list_proxies, qr_code, ) -from django.contrib import admin -from django.urls import include, path -from rest_framework import routers router = routers.DefaultRouter() router.register(r"proxies", ProxyViewSet) diff --git a/shadowmere/celery.py b/shadowmere/celery.py deleted file mode 100644 index e69de29..0000000 diff --git a/shadowmere/settings/base.py b/shadowmere/settings/base.py deleted file mode 100644 index 54c86b0..0000000 --- a/shadowmere/settings/base.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -Django settings for shadowmere project. - -Generated by 'django-admin startproject' using Django 3.2.8. - -For more information on this file, see -https://docs.djangoproject.com/en/3.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/3.2/ref/settings/ -""" -import os -import environ -from pathlib import Path -from datetime import date - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -from celery.schedules import crontab -from django.contrib.admin import AdminSite -from django.utils.translation import gettext_lazy as _ - -env = environ.Env( - DEBUG=(bool, False), - SHADOWTEST_URL=(str, "https://shadowtest.akiel.dev/v1/test"), - ALLOWED_HOSTS=(str, ""), - CSRF_TRUSTED_ORIGINS=(str, ""), - CORS_ALLOWED_ORIGINS=(str, ""), - MINIO_ENDPOINT=(str, ""), - MINIO_ACCESS_KEY=(str, ""), - MINIO_SECRET_KEY=(str, ""), -) - -BASE_DIR = Path(__file__).resolve().parent.parent - -SECRET_KEY = env("SECRET_KEY") - -DEBUG = env("DEBUG") - -SHADOWTEST_URL = env("SHADOWTEST_URL") - -ALLOWED_HOSTS = env("ALLOWED_HOSTS").split(" ") - -CSRF_TRUSTED_ORIGINS: str = env("CSRF_TRUSTED_ORIGINS").split(" ") - -CORS_ALLOWED_ORIGINS: str = env("CORS_ALLOWED_ORIGINS").split(" ") - -DJANGO_APPS = [ - "jazzmin", - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", -] - -THIRD_PARTY_APPS = [ - "storages", - "import_export", - "django_prometheus", - "rangefilter", - "huey.contrib.djhuey", - "rest_framework", - "django_filters", -] - -LOCAL_APPS = [ - "proxylist.apps.ProxylistConfig", -] - -INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS - -MIDDLEWARE = [ - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.locale.LocaleMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "shadowmere.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [BASE_DIR / "templates"], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "shadowmere.wsgi.application" - -DATABASES = {"default": env.db()} - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - -from pythonjsonlogger import jsonlogger - -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "json": { - "()": "pythonjsonlogger.jsonlogger.JsonFormatter", - "format": "%(levelname)s %(name)s %(message)s %(asctime)s %(module)s %(task)s", - }, - }, - "handlers": { - "console": { - "level": "DEBUG", - "class": "logging.StreamHandler", - "formatter": "json", - }, - }, - "loggers": { - "django": { - "handlers": ["console"], - "level": "INFO", - "propagate": True, - }, - "django.server": { - "handlers": ["console"], - "level": "INFO", - "propagate": True, - }, - }, -} - - -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - -LANGUAGES = [ - ("es", _("Spanish")), - ("en", _("English")), -] - -LOCALE_PATHS = ("./locale",) - -STATIC_URL = "/static/" - -STATIC_ROOT = "./static_files/" - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" - -HUEY = { - "huey_class": "huey.RedisHuey", # Huey implementation to use. - "name": "shadowmere", # Use db name for huey. - "results": True, # Store return values of tasks. - "store_none": False, # If a task returns None, do not save to results. - "immediate": False, # If DEBUG=True, run synchronously. - "utc": True, # Use UTC for all times internally. - "blocking": True, # Perform blocking pop rather than poll Redis. - "connection": { - "host": "localhost" if DEBUG else "redis", - "port": 6379, - "db": 0, - "connection_pool": None, # Definitely you should use pooling! - # ... tons of other options, see redis-py for details. - # huey-specific connection parameters. - "read_timeout": 1, # If not polling (blocking pop), use timeout. - "url": None, # Allow Redis config via a DSN. - }, - "consumer": { - "workers": 4, - "worker_type": "process", - "initial_delay": 0.1, # Smallest polling interval, same as -d. - "backoff": 1.15, # Exponential backoff using this rate, -b. - "max_delay": 10.0, # Max possible polling interval, -m. - "scheduler_interval": 1, # Check schedule every second, -s. - "periodic": True, # Enable crontab feature. - "check_worker_health": True, # Enable worker health checks. - "health_check_interval": 1, # Check worker health every second. - }, -} - -REST_FRAMEWORK = { - "DEFAULT_PAGINATION_CLASS": "proxylist.pagination.ProxiesPagination", - "PAGE_SIZE": 10, -} - -DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 - -CONN_MAX_AGE = 60 - -CONN_HEALTH_CHECKS = True - -SECURE_BROWSER_XSS_FILTER = True - -SECURE_CONTENT_TYPE_NOSNIFF = True - -SECURE_HOSTS_INCLUDE_SUBDOMAINS = True - -X_FRAME_OPTIONS = "SAMEORIGIN" - -FILTERS_DEFAULT_LOOKUP_EXPR = "icontains" - -JAZZMIN_SETTINGS = { - "site_title": "Shadowmere Administration", - "site_header": "Shadowmere", - "site_brand": "Shadowmere", - "welcome_sign": "Welcome to Shadowmere Administration", - "copyright": f"Shadowmere {date.year}", -} - -RATELIMIT_ENABLE = False -RATELIMIT_VIEW = "proxylist.views.ratelimited_error"