mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-13 03:36:23 +00:00
- Always enable OpenTelemetry instrumentation, use OTEL_EXPORT_ENABLED for data export control - Remove conditional checks from middleware, metrics, and decorators - Simplify CI configuration to use single test job instead of parallel jobs - Update tests to remove conditional logic and mocking of is_enabled() - Add comprehensive environment variable documentation to README - Update config.py to always add OpenTelemetry middleware - Replace ENABLE_OPENTELEMETRY/OTEL_ENABLED with OTEL_EXPORT_ENABLED This approach is much simpler and eliminates the complexity of conditional OpenTelemetry loading while still allowing control over data export.
329 lines
9.7 KiB
Python
329 lines
9.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
Configuration overrides for settings.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from django.urls import reverse_lazy
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.contrib.messages import constants as message_constants
|
|
from ivatar.settings import BASE_DIR
|
|
|
|
from ivatar.settings import MIDDLEWARE
|
|
from ivatar.settings import INSTALLED_APPS
|
|
from ivatar.settings import TEMPLATES
|
|
|
|
ADMIN_USERS = []
|
|
ALLOWED_HOSTS = ["*"]
|
|
|
|
INSTALLED_APPS.extend(
|
|
[
|
|
"django_extensions",
|
|
"django_openid_auth",
|
|
"bootstrap4",
|
|
"anymail",
|
|
"ivatar",
|
|
"ivatar.ivataraccount",
|
|
"ivatar.tools",
|
|
]
|
|
)
|
|
|
|
MIDDLEWARE.extend(
|
|
[
|
|
"ivatar.middleware.CustomLocaleMiddleware",
|
|
]
|
|
)
|
|
|
|
# Add OpenTelemetry middleware (always enabled now)
|
|
MIDDLEWARE.insert(0, "ivatar.opentelemetry_middleware.OpenTelemetryMiddleware")
|
|
|
|
# Add OpenTelemetry middleware only if feature flag is enabled
|
|
# Note: This will be checked at runtime, not at import time
|
|
MIDDLEWARE.insert(
|
|
0,
|
|
"ivatar.middleware.MultipleProxyMiddleware",
|
|
)
|
|
|
|
AUTHENTICATION_BACKENDS = (
|
|
# Enable this to allow LDAP authentication.
|
|
# See INSTALL for more information.
|
|
# 'django_auth_ldap.backend.LDAPBackend',
|
|
"django_openid_auth.auth.OpenIDBackend",
|
|
"ivatar.ivataraccount.auth.FedoraOpenIdConnect",
|
|
"django.contrib.auth.backends.ModelBackend",
|
|
)
|
|
|
|
TEMPLATES[0]["DIRS"].extend(
|
|
[
|
|
os.path.join(BASE_DIR, "templates"),
|
|
]
|
|
)
|
|
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
|
"ivatar.context_processors.basepage",
|
|
)
|
|
|
|
OPENID_CREATE_USERS = True
|
|
OPENID_UPDATE_DETAILS_FROM_SREG = True
|
|
SOCIAL_AUTH_JSONFIELD_ENABLED = True
|
|
# Fedora authentication (OIDC). You need to set these two values to use it.
|
|
SOCIAL_AUTH_FEDORA_KEY = None # Also known as client_id
|
|
SOCIAL_AUTH_FEDORA_SECRET = None # Also known as client_secret
|
|
|
|
SITE_NAME = os.environ.get("SITE_NAME", "libravatar")
|
|
IVATAR_VERSION = "1.8.0"
|
|
|
|
SCHEMAROOT = "https://www.libravatar.org/schemas/export/0.2"
|
|
|
|
SECURE_BASE_URL = os.environ.get(
|
|
"SECURE_BASE_URL", "https://avatars.linux-kernel.at/avatar/"
|
|
)
|
|
BASE_URL = os.environ.get("BASE_URL", "http://avatars.linux-kernel.at/avatar/")
|
|
|
|
LOGIN_REDIRECT_URL = reverse_lazy("profile")
|
|
MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
|
|
|
|
MAX_NUM_PHOTOS = 5
|
|
MAX_NUM_UNCONFIRMED_EMAILS = 5
|
|
MAX_PHOTO_SIZE = 10485760 # in bytes
|
|
MAX_PIXELS = 7000
|
|
AVATAR_MAX_SIZE = 512
|
|
JPEG_QUALITY = 85
|
|
|
|
# I'm not 100% sure if single character domains are possible
|
|
# under any tld... so MIN_LENGTH_EMAIL/_URL, might be +1
|
|
MIN_LENGTH_URL = 11 # eg. http://a.io
|
|
MAX_LENGTH_URL = 255 # MySQL can't handle more than that (LP: 1018682)
|
|
MIN_LENGTH_EMAIL = 6 # eg. x@x.xx
|
|
MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
|
|
|
|
BOOTSTRAP4 = {
|
|
"include_jquery": False,
|
|
"javascript_in_head": False,
|
|
"css_url": {
|
|
"href": "/static/css/bootstrap.min.css",
|
|
"integrity": "sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB",
|
|
"crossorigin": "anonymous",
|
|
},
|
|
"javascript_url": {
|
|
"url": "/static/js/bootstrap.min.js",
|
|
"integrity": "",
|
|
"crossorigin": "anonymous",
|
|
},
|
|
"popper_url": {
|
|
"url": "/static/js/popper.min.js",
|
|
"integrity": "sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49",
|
|
"crossorigin": "anonymous",
|
|
},
|
|
}
|
|
|
|
if "EMAIL_BACKEND" in os.environ:
|
|
EMAIL_BACKEND = os.environ["EMAIL_BACKEND"] # pragma: no cover
|
|
else:
|
|
if "test" in sys.argv or "collectstatic" in sys.argv:
|
|
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
|
else:
|
|
try:
|
|
ANYMAIL = { # pragma: no cover
|
|
"MAILGUN_API_KEY": os.environ["IVATAR_MAILGUN_API_KEY"],
|
|
"MAILGUN_SENDER_DOMAIN": os.environ["IVATAR_MAILGUN_SENDER_DOMAIN"],
|
|
}
|
|
EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" # pragma: no cover
|
|
except Exception: # pragma: nocover # pylint: disable=broad-except
|
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
|
|
|
SERVER_EMAIL = os.environ.get("SERVER_EMAIL", "ivatar@mg.linux-kernel.at")
|
|
DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL", "ivatar@mg.linux-kernel.at")
|
|
|
|
try:
|
|
from ivatar.settings import DATABASES
|
|
except ImportError: # pragma: no cover
|
|
DATABASES = [] # pragma: no cover
|
|
|
|
if "default" not in DATABASES:
|
|
DATABASES["default"] = { # pragma: no cover
|
|
"ENGINE": "django.db.backends.sqlite3",
|
|
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
|
}
|
|
|
|
if "MYSQL_DATABASE" in os.environ:
|
|
DATABASES["default"] = { # pragma: no cover
|
|
"ENGINE": "django.db.backends.mysql",
|
|
"NAME": os.environ["MYSQL_DATABASE"],
|
|
"USER": os.environ["MYSQL_USER"],
|
|
"PASSWORD": os.environ["MYSQL_PASSWORD"],
|
|
"HOST": "mysql",
|
|
}
|
|
|
|
if "POSTGRESQL_DATABASE" in os.environ:
|
|
DATABASES["default"] = { # pragma: no cover
|
|
"ENGINE": "django.db.backends.postgresql",
|
|
"NAME": os.environ["POSTGRESQL_DATABASE"],
|
|
"USER": os.environ["POSTGRESQL_USER"],
|
|
"PASSWORD": os.environ["POSTGRESQL_PASSWORD"],
|
|
"HOST": "postgresql",
|
|
}
|
|
|
|
# CI/CD config has different naming
|
|
if "POSTGRES_DB" in os.environ:
|
|
DATABASES["default"] = { # pragma: no cover
|
|
"ENGINE": "django.db.backends.postgresql",
|
|
"NAME": os.environ["POSTGRES_DB"],
|
|
"USER": os.environ["POSTGRES_USER"],
|
|
"PASSWORD": os.environ["POSTGRES_PASSWORD"],
|
|
"HOST": os.environ["POSTGRES_HOST"],
|
|
# Let Django use its default test database naming
|
|
# "TEST": {
|
|
# "NAME": os.environ["POSTGRES_DB"],
|
|
# },
|
|
}
|
|
|
|
SESSION_SERIALIZER = "django.contrib.sessions.serializers.JSONSerializer"
|
|
|
|
USE_X_FORWARDED_HOST = True
|
|
ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [
|
|
"avatars.linux-kernel.at",
|
|
"localhost",
|
|
]
|
|
|
|
DEFAULT_AVATAR_SIZE = 80
|
|
|
|
LANGUAGES = (
|
|
("de", _("Deutsch")),
|
|
("en", _("English")),
|
|
("ca", _("Català")),
|
|
("cs", _("Česky")),
|
|
("es", _("Español")),
|
|
("eu", _("Basque")),
|
|
("fr", _("Français")),
|
|
("it", _("Italiano")),
|
|
("ja", _("日本語")),
|
|
("nl", _("Nederlands")),
|
|
("pt", _("Português")),
|
|
("ru", _("Русский")),
|
|
("sq", _("Shqip")),
|
|
("tr", _("Türkçe")),
|
|
("uk", _("Українська")),
|
|
)
|
|
|
|
MESSAGE_TAGS = {
|
|
message_constants.DEBUG: "debug",
|
|
message_constants.INFO: "info",
|
|
message_constants.SUCCESS: "success",
|
|
message_constants.WARNING: "warning",
|
|
message_constants.ERROR: "danger",
|
|
}
|
|
|
|
CACHES = {
|
|
"default": {
|
|
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
|
|
"LOCATION": [
|
|
"127.0.0.1:11211",
|
|
],
|
|
# "OPTIONS": {"MAX_ENTRIES": 1000000},
|
|
},
|
|
"filesystem": {
|
|
"BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
|
|
"LOCATION": "/var/tmp/ivatar_cache",
|
|
"TIMEOUT": 900, # 15 minutes
|
|
"OPTIONS": {"MAX_ENTRIES": 1000000},
|
|
},
|
|
}
|
|
|
|
# This is 5 minutes caching for generated/resized images,
|
|
# so the sites don't hit ivatar so much - it's what's set in the HTTP header
|
|
CACHE_IMAGES_MAX_AGE = 5 * 60
|
|
|
|
CACHE_RESPONSE = True
|
|
|
|
# Trusted URLs for default redirection
|
|
TRUSTED_DEFAULT_URLS = [
|
|
{"schemes": ["https"], "host_equals": "ui-avatars.com", "path_prefix": "/api/"},
|
|
{
|
|
"schemes": ["http", "https"],
|
|
"host_equals": "gravatar.com",
|
|
"path_prefix": "/avatar/",
|
|
},
|
|
{
|
|
"schemes": ["http", "https"],
|
|
"host_suffix": ".gravatar.com",
|
|
"path_prefix": "/avatar/",
|
|
},
|
|
{
|
|
"schemes": ["http", "https"],
|
|
"host_equals": "www.gravatar.org",
|
|
"path_prefix": "/avatar/",
|
|
},
|
|
{
|
|
"schemes": ["https"],
|
|
"host_equals": "avatars.dicebear.com",
|
|
"path_prefix": "/api/",
|
|
},
|
|
{
|
|
"schemes": ["https"],
|
|
"host_equals": "api.dicebear.com",
|
|
"path_prefix": "/",
|
|
},
|
|
{
|
|
"schemes": ["https"],
|
|
"host_equals": "badges.fedoraproject.org",
|
|
"path_prefix": "/static/img/",
|
|
},
|
|
{
|
|
"schemes": ["http"],
|
|
"host_equals": "www.planet-libre.org",
|
|
"path_prefix": "/themes/planetlibre/images/",
|
|
},
|
|
{"schemes": ["https"], "host_equals": "www.azuracast.com", "path_prefix": "/img/"},
|
|
{
|
|
"schemes": ["https"],
|
|
"host_equals": "reps.mozilla.org",
|
|
"path_prefix": "/static/base/img/remo/",
|
|
},
|
|
]
|
|
|
|
URL_TIMEOUT = 10
|
|
|
|
|
|
def map_legacy_config(trusted_url):
|
|
"""
|
|
For backward compability with the legacy configuration
|
|
for trusting URLs. Adapts them to fit the new config.
|
|
"""
|
|
if isinstance(trusted_url, str):
|
|
return {"url_prefix": trusted_url}
|
|
|
|
return trusted_url
|
|
|
|
|
|
# Backward compability for legacy behavior
|
|
TRUSTED_DEFAULT_URLS = list(map(map_legacy_config, TRUSTED_DEFAULT_URLS))
|
|
|
|
# Bluesky settings
|
|
BLUESKY_IDENTIFIER = os.environ.get("BLUESKY_IDENTIFIER", None)
|
|
BLUESKY_APP_PASSWORD = os.environ.get("BLUESKY_APP_PASSWORD", None)
|
|
|
|
# File upload security settings
|
|
FILE_UPLOAD_MAX_MEMORY_SIZE = 5 * 1024 * 1024 # 5MB
|
|
DATA_UPLOAD_MAX_MEMORY_SIZE = 5 * 1024 * 1024 # 5MB
|
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
|
|
|
# Enhanced file upload security
|
|
ENABLE_FILE_SECURITY_VALIDATION = True
|
|
ENABLE_EXIF_SANITIZATION = True
|
|
ENABLE_MALICIOUS_CONTENT_SCAN = True
|
|
|
|
# Logging configuration - can be overridden in local config
|
|
# Example: LOGS_DIR = "/var/log/ivatar" # For production deployments
|
|
|
|
# OpenTelemetry feature flag - can be disabled for F/LOSS deployments
|
|
ENABLE_OPENTELEMETRY = os.environ.get("ENABLE_OPENTELEMETRY", "false").lower() in (
|
|
"true",
|
|
"1",
|
|
"yes",
|
|
)
|
|
|
|
# This MUST BE THE LAST!
|
|
if os.path.isfile(os.path.join(BASE_DIR, "config_local.py")):
|
|
from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover
|