diff --git a/config.yaml b/config.yaml deleted file mode 100644 index 1233d99..0000000 --- a/config.yaml +++ /dev/null @@ -1,706 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: settings - namespace: memelord-jake -data: - settings.py: | - """ - Django settings for myproject project. - - Generated by 'django-admin startproject' using Django 3.2.16. - - 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/ - """ - - from pathlib import Path - from dotenv import load_dotenv - import os - import pytz - import secrets - from django.utils.html import escape - from django.utils.translation import gettext_lazy as _ - from csp.constants import NONE, SELF, UNSAFE_INLINE, UNSAFE_EVAL - - # Load environment variables from .env file - load_dotenv() - - # Build paths inside the project like this: BASE_DIR / 'subdir'. - BASE_DIR = Path(__file__).resolve().parent.parent - - # get debug modus from env - DEBUG = os.environ.get('DEBUG', 'False').lower() in ['true'] - - # get container version from env - VERSION = escape(os.environ.get("VERSION", '')) - - # Enable/disable public meme feed feature (must be after import os) - ENABLE_PUBLIC_FEED = os.environ.get('ENABLE_PUBLIC_FEED', 'False').lower() in ['true', '1', 'yes'] - - # auto-generate a secure secret key or use from env variable - SECRET_KEY = os.environ.get("SECRET_KEY", secrets.token_urlsafe(32)) - - # define allowed hosts and trusted domains via env variables - DOMAIN = "" - ALLOWED_HOSTS = ["127.0.0.1"] - CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000"] - - DOMAIN = str(os.environ.get("DOMAIN", "localhost")) - TRUSTED_PORT = str(os.environ.get("PORT", "8000")) - - if DOMAIN: - domains = DOMAIN.split(',') - for domain in domains: - domain = domain.strip().rstrip('/').replace('http://', '').replace('https://', '') - if domain: - ALLOWED_HOSTS.append(domain) - TRUSTED_USER_DOMAIN_HTTP = f"http://{domain}:{TRUSTED_PORT}" - TRUSTED_USER_DOMAIN_HTTP_80_DEFAULT = f"http://{domain}" - TRUSTED_USER_DOMAIN_HTTPS = f"https://{domain}:{TRUSTED_PORT}" - TRUSTED_USER_DOMAIN_HTTPS_443_DEFAULT = f"https://{domain}" - CSRF_TRUSTED_ORIGINS.extend([TRUSTED_USER_DOMAIN_HTTP, TRUSTED_USER_DOMAIN_HTTPS, TRUSTED_USER_DOMAIN_HTTP_80_DEFAULT, TRUSTED_USER_DOMAIN_HTTPS_443_DEFAULT]) - - #Session Management - CSRF_COOKIE_HTTPONLY = True - SESSION_EXPIRE_AT_BROWSER_CLOSE = os.environ.get('SESSION_EXPIRE_AT_BROWSER_CLOSE', 'True').lower() in ['true'] - SESSION_COOKIE_AGE = int(os.environ.get('SESSION_COOKIE_AGE', '30')) * 60 - SESSION_COOKIE_NAME = 'Session' - SESSION_COOKIE_SAMESITE = 'Lax' - - # ============================================================================= - # REDIS CACHE CONFIGURATION (for sessions and general caching) - # ============================================================================= - # If REDIS_HOST is not set, sessions will use database (backward compatible) - REDIS_HOST = os.environ.get("REDIS_HOST", "") - REDIS_PORT = os.environ.get("REDIS_PORT", "6379") - REDIS_DB = os.environ.get("REDIS_DB", "0") - REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", "") - - if REDIS_HOST: - # Redis is available - use it for caching and sessions - CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}", - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - "PASSWORD": REDIS_PASSWORD if REDIS_PASSWORD else None, - "SOCKET_CONNECT_TIMEOUT": 5, # seconds - "SOCKET_TIMEOUT": 5, # seconds - "RETRY_ON_TIMEOUT": True, - "CONNECTION_POOL_KWARGS": { - "max_connections": 50, - "retry_on_timeout": True, - }, - "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor", - "IGNORE_EXCEPTIONS": True, # Don't crash if Redis is down - }, - "KEY_PREFIX": "memelord", - "TIMEOUT": 300, # 5 minutes default - } - } - - # Use Redis for session storage (cloud-native) - SESSION_ENGINE = "django.contrib.sessions.backends.cache" - SESSION_CACHE_ALIAS = "default" - else: - # Redis not configured - use database sessions (backward compatible) - SESSION_ENGINE = "django.contrib.sessions.backends.db" - # No CACHES configuration - Django will use local memory cache - - SECURE_COOKIES = os.environ.get('SECURE_COOKIES', 'False').lower() in ['true'] - - if SECURE_COOKIES: - # transmit cookies over encrypted https only - SESSION_COOKIE_SECURE = True - CSRF_COOKIE_SECURE = True - # also set hsts response header - SECURE_HSTS_SECONDS = "31536000" - SECURE_HSTS_PRELOAD = True - SECURE_HSTS_INCLUDE_SUBDOMAINS = True - else: - # transmit cookies over unencrypted http - SESSION_COOKIE_SECURE = False - CSRF_COOKIE_SECURE = False - - # http security response headers - SECURE_BROWSER_XSS_FILTER = True - SECURE_CONTENT_TYPE_NOSNIFF = True - X_FRAME_OPTIONS = 'DENY' - REFERRER_POLICY = 'same-origin' - - # Load from environment, default to "'self'" - raw_frame_ancestors = os.environ.get("CSP_FRAME_ANCESTORS", "'none'") - # Split by comma, strip spaces, and keep properly quoted entries - FRAME_ANCESTORS = [item.strip() for item in raw_frame_ancestors.split(',') if item.strip()] - - # Build CSP img-src list dynamically based on storage backend - STORAGE_BACKEND = os.environ.get('STORAGE_BACKEND', 'local').lower() - IMG_SRC_LIST = ["'self'", "data:", "blob:", "https://img.logo.dev"] - - # Add S3 domains to CSP if using S3 storage - if STORAGE_BACKEND == 's3': - AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') - AWS_S3_CUSTOM_DOMAIN = os.environ.get('AWS_S3_CUSTOM_DOMAIN') - AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1') - AWS_S3_ENDPOINT_URL = os.environ.get('AWS_S3_ENDPOINT_URL') - AWS_S3_USE_ACCELERATE_ENDPOINT = os.environ.get('AWS_S3_USE_ACCELERATE_ENDPOINT', 'False').lower() in ['true'] - - # Always add custom domain if specified (CDN like CloudFront) - if AWS_S3_CUSTOM_DOMAIN: - IMG_SRC_LIST.append(f"https://{AWS_S3_CUSTOM_DOMAIN}") - - # Detect S3 provider based on endpoint URL - if AWS_S3_ENDPOINT_URL: - # S3-compatible service detected - from urllib.parse import urlparse - parsed_url = urlparse(AWS_S3_ENDPOINT_URL) - endpoint_domain = parsed_url.netloc - endpoint_scheme = parsed_url.scheme or 'https' - - # Add the endpoint domain - IMG_SRC_LIST.append(f"{endpoint_scheme}://{endpoint_domain}") - - # Add bucket-based subdomain format if applicable - if endpoint_domain and AWS_STORAGE_BUCKET_NAME: - IMG_SRC_LIST.append(f"{endpoint_scheme}://{AWS_STORAGE_BUCKET_NAME}.{endpoint_domain}") - - # Provider-specific URL patterns - endpoint_lower = endpoint_domain.lower() if endpoint_domain else "" - - # DigitalOcean Spaces: also add CDN domain - if 'digitaloceanspaces.com' in endpoint_lower: - # DigitalOcean Spaces CDN format: bucket-name.region.cdn.digitaloceanspaces.com - if AWS_STORAGE_BUCKET_NAME and AWS_S3_REGION_NAME: - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.{AWS_S3_REGION_NAME}.cdn.digitaloceanspaces.com") - - # Cloudflare R2: also add public bucket URL format - elif 'r2.cloudflarestorage.com' in endpoint_lower: - # Cloudflare R2 can use custom domains via public.r2.dev - # Format: https://bucket-name.account-id.r2.dev (if public) - # This is typically set via AWS_S3_CUSTOM_DOMAIN, but we note it here - pass - - # Wasabi: supports path-style and virtual-hosted-style - elif 'wasabisys.com' in endpoint_lower: - # Already covered by endpoint_domain and bucket subdomain - pass - - # Linode Object Storage: supports path-style and virtual-hosted-style - elif 'linodeobjects.com' in endpoint_lower: - # Already covered by endpoint_domain and bucket subdomain - pass - - # Backblaze B2: supports path-style and virtual-hosted-style - elif 'backblazeb2.com' in endpoint_lower: - # Already covered by endpoint_domain and bucket subdomain - pass - - # MinIO: custom deployment, already covered - # Other S3-compatible services: already covered - - else: - # No endpoint URL = Standard AWS S3 - if AWS_STORAGE_BUCKET_NAME: - # Add AWS S3 virtual-hosted-style URLs - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com") - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com") - - # Add path-style URL format (legacy but still supported) - IMG_SRC_LIST.append("https://s3.amazonaws.com") - IMG_SRC_LIST.append(f"https://s3.{AWS_S3_REGION_NAME}.amazonaws.com") - - # Add dual-stack endpoints (IPv6 support) - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.dualstack.{AWS_S3_REGION_NAME}.amazonaws.com") - - # Add S3 Transfer Acceleration endpoint if enabled - if AWS_S3_USE_ACCELERATE_ENDPOINT: - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3-accelerate.amazonaws.com") - IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3-accelerate.dualstack.amazonaws.com") - - # Add Azure domains to CSP if using Azure storage - elif STORAGE_BACKEND == 'azure': - AZURE_ACCOUNT_NAME = os.environ.get('AZURE_ACCOUNT_NAME') - AZURE_CUSTOM_DOMAIN = os.environ.get('AZURE_CUSTOM_DOMAIN') - - if AZURE_CUSTOM_DOMAIN: - IMG_SRC_LIST.append(f"https://{AZURE_CUSTOM_DOMAIN}") - - if AZURE_ACCOUNT_NAME: - IMG_SRC_LIST.append(f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net") - - # Add GCS domains to CSP if using GCS storage - elif STORAGE_BACKEND == 'gcs': - GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME') - GS_CUSTOM_ENDPOINT = os.environ.get('GS_CUSTOM_ENDPOINT') - - if GS_CUSTOM_ENDPOINT: - IMG_SRC_LIST.append(GS_CUSTOM_ENDPOINT) - - if GS_BUCKET_NAME: - # GCS can use multiple URL formats - IMG_SRC_LIST.append("https://storage.googleapis.com") - IMG_SRC_LIST.append("https://storage.cloud.google.com") - IMG_SRC_LIST.append(f"https://{GS_BUCKET_NAME}.storage.googleapis.com") - - # SFTP/Dropbox typically serve through Django (using 'self' origin) - elif STORAGE_BACKEND == 'sftp': - # SFTP files are retrieved by Django and served through Django views - # Optional: If you have nginx serving the same SFTP directory via HTTP - SFTP_CUSTOM_DOMAIN = os.environ.get('SFTP_CUSTOM_DOMAIN') - if SFTP_CUSTOM_DOMAIN: - IMG_SRC_LIST.append(f"https://{SFTP_CUSTOM_DOMAIN}") - - elif STORAGE_BACKEND == 'dropbox': - # Dropbox files are retrieved by Django and served through Django views - # No additional CSP configuration needed - pass - - CSP_IMG_SRC_EXTRA = os.environ.get('CSP_IMG_SRC_EXTRA', '') - if CSP_IMG_SRC_EXTRA: - extra_domains = [domain.strip() for domain in CSP_IMG_SRC_EXTRA.split(',') if domain.strip()] - IMG_SRC_LIST.extend(extra_domains) - - CONTENT_SECURITY_POLICY = { - "DIRECTIVES": { - "default-src": ["'self'"], - "style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "https://cdn.jsdelivr.net"], - "script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.jsdelivr.net"], - "font-src": ["'self'", "https://fonts.googleapis.com", "https://fonts.gstatic.com"], - "img-src": IMG_SRC_LIST, - "object-src": ["'none'"], - "connect-src": ["'self'"], - "frame-ancestors": FRAME_ANCESTORS, - }, - } - - # Application definition - INSTALLED_APPS = [ - 'myapp', - 'django_celery_beat', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'csp', - 'storages', - ] - - 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_http_referrer_policy.middleware.ReferrerPolicyMiddleware', - 'csp.middleware.CSPMiddleware', - ] - - ROOT_URLCONF = 'myproject.urls' - - TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'myapp/templates/registration')], - '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', - ], - }, - }, - ] - - # Database - # https://docs.djangoproject.com/en/3.2/ref/settings/#databases - - DB_ENGINE = os.environ.get("DB_ENGINE", "sqlite3") - - if DB_ENGINE == "sqlite3": - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'database', 'db.sqlite3'), - } - } - - elif DB_ENGINE == "postgres": - - DB_HOST = os.environ.get("POSTGRES_HOST", "db") - DB_PORT = os.environ.get("POSTGRES_PORT", "5432") - DB_USER = os.environ.get("POSTGRES_USER", "memelord") - DB_PASSWORD = os.environ.get("POSTGRES_PASSWORD", "memelord") - DB_NAME = os.environ.get("POSTGRES_DB", "memelord") - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': DB_NAME, - 'HOST': DB_HOST, - 'PORT': DB_PORT, - 'USER': DB_USER, - 'PASSWORD': DB_PASSWORD, - } - } - - # Password validation - # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators - - 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', - }, - ] - - # Internationalization - # https://docs.djangoproject.com/en/3.2/topics/i18n/ - LANGUAGE_CODE = 'en-us' - TIME_ZONE = os.environ.get('TZ', 'Europe/Berlin') - USE_I18N = True - USE_L10N = True - USE_TZ = True - - LANGUAGES = [ - ('en', _('English')), - ('de', _('German')), - ('fr', _('French')), - ('it', _('Italian')), - ] - - LOCALE_PATHS = [ - os.path.join(BASE_DIR, 'locale') - ] - - # Celery configuration - # http://docs.celeryproject.org/en/latest/configuration.html - - LOGS_DIR = os.path.join(BASE_DIR, 'logs') - - # ============================================================================= - # LOGGING CONFIGURATION - # ============================================================================= - LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'verbose': { - 'format': '{levelname} {asctime} {module} {message}', - 'style': '{', - }, - 'simple': { - 'format': '{levelname} {message}', - 'style': '{', - }, - }, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - 'formatter': 'verbose', - }, - 'file': { - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': os.path.join(LOGS_DIR, 'django.log'), - 'maxBytes': 1024 * 1024 * 15, # 15MB - 'backupCount': 10, - 'formatter': 'verbose', - }, - }, - 'loggers': { - 'django': { - 'handlers': ['console', 'file'], - 'level': os.environ.get('DJANGO_LOG_LEVEL', 'INFO'), - 'propagate': False, - }, - 'myapp': { - 'handlers': ['console', 'file'], - 'level': os.environ.get('DJANGO_LOG_LEVEL', 'INFO'), - 'propagate': False, - }, - 'storages': { - 'handlers': ['console', 'file'], - 'level': 'DEBUG' if DEBUG else 'INFO', - 'propagate': False, - }, - 'boto3': { - 'handlers': ['console', 'file'], - 'level': 'DEBUG' if DEBUG else 'INFO', - 'propagate': False, - }, - 'botocore': { - 'handlers': ['console', 'file'], - 'level': 'DEBUG' if DEBUG else 'INFO', - 'propagate': False, - }, - }, - 'root': { - 'handlers': ['console', 'file'], - 'level': 'INFO', - }, - } - - # Create logs directory if it doesn't exist - os.makedirs(LOGS_DIR, exist_ok=True) - - STATIC_URL = '/static/' - STATIC_ROOT = os.path.join(BASE_DIR, 'myapp', 'static') - - DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - - LOGIN_URL = '/accounts/login/' - LOGIN_REDIRECT_URL = '/' - LOGOUT_REDIRECT_URL = '/post-logout/' - ALLOW_LOGOUT_GET_METHOD = True - - WSGI_APPLICATION = 'myproject.wsgi.application' - - # check if oidc is enabled - OIDC_ENABLED = os.environ.get('OIDC_ENABLED', 'False').lower() in ['true'] - OIDC_AUTOLOGIN = os.environ.get('OIDC_AUTOLOGIN', 'False').lower() in ['true'] - - # Max file upload size in MB (default: 10MB) - # Can be configured via MAX_UPLOAD_SIZE_MB environment variable - MAX_UPLOAD_SIZE_MB = int(os.environ.get('MAX_UPLOAD_SIZE_MB', '10')) * 1024 * 1024 - - # ============================================================================= - # STORAGE BACKEND CONFIGURATION - # ============================================================================= - # IMPORTANT: This must be set BEFORE MEDIA_URL and MEDIA_ROOT - # Configure storage backend via STORAGE_BACKEND environment variable - # Supported backends: local, s3, azure, gcs, sftp, dropbox - # Default: local (filesystem storage) - - STORAGE_BACKEND = os.environ.get('STORAGE_BACKEND', 'local').lower() - - # Django 5.0+ uses STORAGES instead of DEFAULT_FILE_STORAGE - # Set both for compatibility - if STORAGE_BACKEND == 's3': - # Amazon S3 / Compatible S3 Storage (MinIO, DigitalOcean Spaces, etc.) - AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') - AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') - AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') - AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1') - AWS_S3_CUSTOM_DOMAIN = os.environ.get('AWS_S3_CUSTOM_DOMAIN') - AWS_S3_ENDPOINT_URL = os.environ.get('AWS_S3_ENDPOINT_URL') # Only set for S3-compatible services (MinIO, etc.) - AWS_DEFAULT_ACL = os.environ.get('AWS_DEFAULT_ACL', 'private') - AWS_S3_OBJECT_PARAMETERS = { - 'CacheControl': 'max-age=86400', - } - AWS_QUERYSTRING_AUTH = os.environ.get('AWS_QUERYSTRING_AUTH', 'True').lower() in ['true'] - AWS_S3_FILE_OVERWRITE = os.environ.get('AWS_S3_FILE_OVERWRITE', 'False').lower() in ['true'] - AWS_LOCATION = os.environ.get('AWS_LOCATION', 'media') - - # Use signature version 4 (required for all regions) - AWS_S3_SIGNATURE_VERSION = 's3v4' - - # Use virtual-hosted-style URLs (bucket-name.s3.region.amazonaws.com) - # This is the default and recommended format - AWS_S3_ADDRESSING_STYLE = 'path' - - # Django 5.0+ STORAGES configuration - STORAGES = { - "default": { - "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - # Legacy setting for older Django versions - DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' - - # Update MEDIA_URL - if AWS_S3_CUSTOM_DOMAIN: - MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_LOCATION}/' - elif AWS_STORAGE_BUCKET_NAME: - # Use region-specific virtual-hosted-style URL - if AWS_S3_REGION_NAME == 'us-east-1': - MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/{AWS_LOCATION}/' - else: - MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com/{AWS_LOCATION}/' - else: - MEDIA_URL = "/media/" - - MEDIA_ROOT = BASE_DIR / "media" - - elif STORAGE_BACKEND == 'azure': - # Microsoft Azure Blob Storage - AZURE_ACCOUNT_NAME = os.environ.get('AZURE_ACCOUNT_NAME') - AZURE_ACCOUNT_KEY = os.environ.get('AZURE_ACCOUNT_KEY') - AZURE_CONTAINER = os.environ.get('AZURE_CONTAINER', 'media') - AZURE_SSL = os.environ.get('AZURE_SSL', 'True').lower() in ['true'] - AZURE_UPLOAD_MAX_CONN = int(os.environ.get('AZURE_UPLOAD_MAX_CONN', '2')) - AZURE_CONNECTION_TIMEOUT_SECS = int(os.environ.get('AZURE_CONNECTION_TIMEOUT_SECS', '20')) - AZURE_BLOB_MAX_MEMORY_SIZE = os.environ.get('AZURE_BLOB_MAX_MEMORY_SIZE', '2MB') - AZURE_URL_EXPIRATION_SECS = int(os.environ.get('AZURE_URL_EXPIRATION_SECS', '3600')) - AZURE_OVERWRITE_FILES = os.environ.get('AZURE_OVERWRITE_FILES', 'False').lower() in ['true'] - AZURE_LOCATION = os.environ.get('AZURE_LOCATION', '') - AZURE_CUSTOM_DOMAIN = os.environ.get('AZURE_CUSTOM_DOMAIN') - - STORAGES = { - "default": { - "BACKEND": "storages.backends.azure_storage.AzureStorage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - DEFAULT_FILE_STORAGE = 'storages.backends.azure_storage.AzureStorage' - - if AZURE_CUSTOM_DOMAIN: - MEDIA_URL = f'https://{AZURE_CUSTOM_DOMAIN}/{AZURE_LOCATION}' - elif AZURE_ACCOUNT_NAME: - MEDIA_URL = f'https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/{AZURE_CONTAINER}/{AZURE_LOCATION}' - else: - MEDIA_URL = "/media/" - - MEDIA_ROOT = BASE_DIR / "media" - - elif STORAGE_BACKEND == 'gcs': - # Google Cloud Storage - GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME') - GS_PROJECT_ID = os.environ.get('GS_PROJECT_ID') - GS_CREDENTIALS = os.environ.get('GS_CREDENTIALS') - GS_DEFAULT_ACL = os.environ.get('GS_DEFAULT_ACL', 'private') - GS_FILE_OVERWRITE = os.environ.get('GS_FILE_OVERWRITE', 'False').lower() in ['true'] - GS_LOCATION = os.environ.get('GS_LOCATION', 'media') - GS_CUSTOM_ENDPOINT = os.environ.get('GS_CUSTOM_ENDPOINT') - GS_QUERYSTRING_AUTH = os.environ.get('GS_QUERYSTRING_AUTH', 'True').lower() in ['true'] - - STORAGES = { - "default": { - "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage' - - if GS_CUSTOM_ENDPOINT: - MEDIA_URL = f'{GS_CUSTOM_ENDPOINT}/{GS_LOCATION}/' - elif GS_BUCKET_NAME: - MEDIA_URL = f'https://storage.googleapis.com/{GS_BUCKET_NAME}/{GS_LOCATION}/' - else: - MEDIA_URL = "/media/" - - MEDIA_ROOT = BASE_DIR / "media" - - elif STORAGE_BACKEND == 'sftp': - # SFTP Storage - SFTP_STORAGE_HOST = os.environ.get('SFTP_STORAGE_HOST') - SFTP_STORAGE_ROOT = os.environ.get('SFTP_STORAGE_ROOT', '/media/') - SFTP_STORAGE_PARAMS = { - 'port': int(os.environ.get('SFTP_STORAGE_PORT', '22')), - 'username': os.environ.get('SFTP_STORAGE_USERNAME'), - 'password': os.environ.get('SFTP_STORAGE_PASSWORD'), - 'pkey': os.environ.get('SFTP_STORAGE_PRIVATE_KEY'), - } - SFTP_STORAGE_INTERACTIVE = os.environ.get('SFTP_STORAGE_INTERACTIVE', 'False').lower() in ['true'] - SFTP_STORAGE_FILE_MODE = os.environ.get('SFTP_STORAGE_FILE_MODE') - SFTP_STORAGE_DIR_MODE = os.environ.get('SFTP_STORAGE_DIR_MODE') - SFTP_STORAGE_UID = os.environ.get('SFTP_STORAGE_UID') - SFTP_STORAGE_GID = os.environ.get('SFTP_STORAGE_GID') - SFTP_KNOWN_HOST_FILE = os.environ.get('SFTP_KNOWN_HOST_FILE') - - STORAGES = { - "default": { - "BACKEND": "storages.backends.sftpstorage.SFTPStorage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - DEFAULT_FILE_STORAGE = 'storages.backends.sftpstorage.SFTPStorage' - MEDIA_URL = "/media/" - MEDIA_ROOT = BASE_DIR / "media" - - elif STORAGE_BACKEND == 'dropbox': - # Dropbox Storage - DROPBOX_OAUTH2_TOKEN = os.environ.get('DROPBOX_OAUTH2_TOKEN') - DROPBOX_ROOT_PATH = os.environ.get('DROPBOX_ROOT_PATH', '/media') - DROPBOX_TIMEOUT = int(os.environ.get('DROPBOX_TIMEOUT', '100')) - DROPBOX_WRITE_MODE = os.environ.get('DROPBOX_WRITE_MODE', 'add') - - STORAGES = { - "default": { - "BACKEND": "storages.backends.dropbox.DropBoxStorage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage' - MEDIA_URL = "/media/" - MEDIA_ROOT = BASE_DIR / "media" - - else: - # Local filesystem storage (default) - STORAGES = { - "default": { - "BACKEND": "django.core.files.storage.FileSystemStorage", - }, - "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", - }, - } - - DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' - MEDIA_URL = "/media/" - MEDIA_ROOT = BASE_DIR / "media" - - if OIDC_ENABLED: - # get oidc config from env - OIDC_CREATE_USER = os.environ.get('OIDC_CREATE_USER', 'True').lower() in ['true'] - OIDC_RP_SIGN_ALGO = os.environ.get('OIDC_RP_SIGN_ALGO', 'HS256') - OIDC_OP_JWKS_ENDPOINT = os.environ.get('OIDC_OP_JWKS_ENDPOINT') - OIDC_RP_IDP_SIGN_KEY = os.environ.get('OIDC_RP_IDP_SIGN_KEY') - OIDC_RP_CLIENT_ID = os.environ.get('OIDC_RP_CLIENT_ID') - OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_RP_CLIENT_SECRET') - OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get('OIDC_OP_AUTHORIZATION_ENDPOINT') - OIDC_OP_TOKEN_ENDPOINT = os.environ.get('OIDC_OP_TOKEN_ENDPOINT') - OIDC_OP_USER_ENDPOINT = os.environ.get('OIDC_OP_USER_ENDPOINT') - OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = float(os.environ.get('OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS', 900)) - OIDC_USERNAME_ALGO = 'myapp.utils.generate_username' - - # Add 'mozilla_django_oidc.middleware.SessionRefresh' to INSTALLED_APPS - INSTALLED_APPS.append('mozilla_django_oidc') - - # Add 'mozilla_django_oidc' authentication backend - AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', - ) - - # Add 'mozilla_django_oidc.middleware.SessionRefresh' to MIDDLEWARE - # https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html#validate-id-tokens-by-renewing-them - MIDDLEWARE.append('mozilla_django_oidc.middleware.SessionRefresh') - - # Fix http callback issue in mozilla-django-oidc by forcing https; https://github.com/mozilla/mozilla-django-oidc/issues/417 - # OIDC should only be setup behind a TLS reverse proxy anyways - SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")