Skip to content

Commit

Permalink
Merge pull request #5073 from mozilla/filter-settings-mpp-3905
Browse files Browse the repository at this point in the history
MPP-3905: Filter more settings / environment variables
  • Loading branch information
groovecoder authored Oct 7, 2024
2 parents 4c20c0b + d835c90 commit a4f2fe4
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 0 deletions.
40 changes: 40 additions & 0 deletions privaterelay/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import re

from django.views.debug import SafeExceptionReporterFilter


class RelaySaferExceptionReporterFilter(SafeExceptionReporterFilter):
"""
Add more settings values that should be hidden in debug and exception reports.
This is also used by the Django Debug Toolbar settings panel.
"""

# Hide any variable value that starts with these prefixes
UNSAFE_PREFIXES = ["AWS_", "IQ_", "TWILIO_", "REDIS_"]

# Hide any variable value named in this list
UNSAFE_NAMES = [
# Settings
"ALLOWED_ACCOUNTS",
"ALLOWED_HOSTS",
"DJANGO_ALLOWED_HOSTS",
"INTERNAL_IPS",
# Environment Variables / META
"CSRF_COOKIE",
"DATABASE_URL",
"DJANGO_ALLOWED_HOST",
"DJANGO_ALLOWED_SUBNET",
"DJANGO_INTERNAL_IPS",
"GOOGLE_APPLICATION_CREDENTIALS",
"GOOGLE_CLOUD_PROFILER_CREDENTIALS_B64",
"SENTRY_DSN",
]

hidden_settings = re.compile(
"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE|"
+ "|".join(f"^{prefix}" for prefix in UNSAFE_PREFIXES)
+ "|"
+ "|".join(f"^{name}$" for name in UNSAFE_NAMES),
re.IGNORECASE,
)
3 changes: 3 additions & 0 deletions privaterelay/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
INTERNAL_IPS = config("DJANGO_INTERNAL_IPS", default="", cast=Csv())
IN_PYTEST: bool = "pytest" in sys.modules
USE_SILK = DEBUG and HAS_SILK and not IN_PYTEST
DEFAULT_EXCEPTION_REPORTER_FILTER = (
"privaterelay.debug.RelaySaferExceptionReporterFilter"
)

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
Expand Down
126 changes: 126 additions & 0 deletions privaterelay/tests/debug_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
from django.conf import settings
from django.http import HttpRequest
from django.test import RequestFactory
from django.views.debug import get_default_exception_reporter_filter

import pytest

from privaterelay.debug import RelaySaferExceptionReporterFilter


def test_default_filter() -> None:
assert isinstance(
get_default_exception_reporter_filter(), RelaySaferExceptionReporterFilter
)


@pytest.mark.parametrize(
"name",
(
"ACCOUNT_ADAPTER",
"LOGGING_CONFIG",
),
)
def test_safe_settings(name: str) -> None:
assert hasattr(settings, name)
safe_settings = RelaySaferExceptionReporterFilter().get_safe_settings()
assert name in safe_settings
assert safe_settings[name] == getattr(settings, name)


@pytest.mark.parametrize(
"name",
(
"ALLOWED_ACCOUNTS",
"ALLOWED_HOSTS",
"AUTH_PASSWORD_VALIDATORS",
"AWS_ACCESS_KEY_ID",
"AWS_REGION",
"AWS_SECRET_ACCESS_KEY",
"AWS_SES_CONFIGSET",
"AWS_SNS_KEY_CACHE",
"AWS_SNS_TOPIC",
"AWS_SQS_EMAIL_DLQ_URL",
"AWS_SQS_EMAIL_QUEUE_URL",
"AWS_SQS_QUEUE_URL",
"DJANGO_ALLOWED_HOSTS",
"IQ_ENABLED",
"IQ_FOR_NEW_NUMBERS",
"IQ_FOR_VERIFICATION",
"IQ_INBOUND_API_KEY",
"IQ_MAIN_NUMBER",
"IQ_MESSAGE_API_ORIGIN",
"IQ_MESSAGE_PATH",
"IQ_OUTBOUND_API_KEY",
"IQ_PUBLISH_MESSAGE_URL",
"PASSWORD_HASHERS",
"PASSWORD_RESET_TIMEOUT",
"SECRET_KEY",
"SECRET_KEY_FALLBACKS",
"TWILIO_ACCOUNT_SID",
"TWILIO_ALLOWED_COUNTRY_CODES",
"TWILIO_AUTH_TOKEN",
"TWILIO_MAIN_NUMBER",
"TWILIO_MESSAGING_SERVICE_SID",
"TWILIO_NEEDS_10DLC_CAMPAIGN",
"TWILIO_SMS_APPLICATION_SID",
"TWILIO_TEST_ACCOUNT_SID",
"TWILIO_TEST_AUTH_TOKEN",
),
)
def test_unsafe_settings(name: str) -> None:
assert hasattr(settings, name)
safe_settings = RelaySaferExceptionReporterFilter().get_safe_settings()
assert name in safe_settings
assert safe_settings[name] != getattr(settings, name)
assert safe_settings[name] == RelaySaferExceptionReporterFilter.cleansed_substitute


@pytest.fixture
def meta_request(rf: RequestFactory) -> HttpRequest:
request = rf.get(
path="/meta-test",
CSRF_COOKIE="cross-site-request-forgery-cookie",
DATABASE_URL="postgres://user:[email protected]:5432/relay_db",
DJANGO_ALLOWED_HOST="relay.example.com",
GOOGLE_CLOUD_PROFILER_CREDENTIALS_B64="eyJwYXNzd29yZCI6ICJzZWNyZXQifQo=",
REDIS_TEMPORARY_URL="redis://user:[email protected]:10001",
REDIS_TLS_URL="rediss://user:[email protected]:10001",
REDIS_URL="redis://user:[email protected]:10001",
SENTRY_DSN="https://[email protected]/long_number",
)
return request


@pytest.mark.parametrize(
"name",
(
"REMOTE_ADDR",
"SCRIPT_NAME",
"wsgi.version",
),
)
def test_safe_meta(name: str, meta_request: HttpRequest) -> None:
safe_meta = RelaySaferExceptionReporterFilter().get_safe_request_meta(meta_request)
assert name in safe_meta
assert safe_meta[name] == meta_request.META[name]


@pytest.mark.parametrize(
"name",
(
"CSRF_COOKIE",
"DATABASE_URL",
"DJANGO_ALLOWED_HOST",
"GOOGLE_CLOUD_PROFILER_CREDENTIALS_B64",
"REDIS_TEMPORARY_URL",
"REDIS_TLS_URL",
"REDIS_URL",
"SENTRY_DSN",
),
)
def test_unsafe_meta(name: str, meta_request: HttpRequest) -> None:
safe_meta = RelaySaferExceptionReporterFilter().get_safe_request_meta(meta_request)
assert name in safe_meta
assert safe_meta[name] != meta_request.META[name]
assert safe_meta[name] == RelaySaferExceptionReporterFilter.cleansed_substitute

0 comments on commit a4f2fe4

Please sign in to comment.