From ee1928aeed53ab1cd248f956596825eef5f5e396 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 29 Apr 2020 11:25:22 +0200 Subject: [PATCH] Do not expose secret keys in global settings --- src/pretix/base/forms/__init__.py | 38 +++++++++++++++++++++ src/pretix/control/forms/global_settings.py | 4 +-- src/pretix/plugins/stripe/signals.py | 5 +-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/pretix/base/forms/__init__.py b/src/pretix/base/forms/__init__.py index a9462cd014..4c9552f7ce 100644 --- a/src/pretix/base/forms/__init__.py +++ b/src/pretix/base/forms/__init__.py @@ -48,6 +48,9 @@ class I18nInlineFormSet(i18nfield.forms.I18nInlineFormSet): super().__init__(*args, **kwargs) +SECRET_REDACTED = '*****' + + class SettingsForm(i18nfield.forms.I18nFormMixin, HierarkeyForm): auto_fields = [] @@ -73,6 +76,12 @@ class SettingsForm(i18nfield.forms.I18nFormMixin, HierarkeyForm): if isinstance(f, (RelativeDateTimeField, RelativeDateField)): f.set_event(self.obj) + def save(self): + for k, v in self.cleaned_data.items(): + if isinstance(self.fields[k], SecretKeySettingsField) and self.cleaned_data[k] == SECRET_REDACTED: + self.cleaned_data[k] = self.initial[k] + return super().save() + def get_new_filename(self, name: str) -> str: from pretix.base.models import Event @@ -111,3 +120,32 @@ class SafeSessionWizardView(SessionWizardView): } ) return context + + +class SecretKeySettingsWidget(forms.TextInput): + def __init__(self, attrs=None): + if attrs is None: + attrs = {} + attrs.update({ + 'autocomplete': 'new-password' # see https://bugs.chromium.org/p/chromium/issues/detail?id=370363#c7 + }) + super().__init__(attrs) + + def get_context(self, name, value, attrs): + if value: + value = SECRET_REDACTED + return super().get_context(name, value, attrs) + + +class SecretKeySettingsField(forms.CharField): + widget = SecretKeySettingsWidget + + def has_changed(self, initial, data): + if data == SECRET_REDACTED: + return False + return super().has_changed(initial, data) + + def run_validators(self, value): + if value == SECRET_REDACTED: + return + return super().run_validators(value) diff --git a/src/pretix/control/forms/global_settings.py b/src/pretix/control/forms/global_settings.py index 4e98345bed..142dce17ca 100644 --- a/src/pretix/control/forms/global_settings.py +++ b/src/pretix/control/forms/global_settings.py @@ -4,7 +4,7 @@ from django import forms from django.utils.translation import gettext_lazy as _ from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput -from pretix.base.forms import SettingsForm +from pretix.base.forms import SecretKeySettingsField, SettingsForm from pretix.base.settings import GlobalSettingsObject from pretix.base.signals import register_global_settings @@ -37,7 +37,7 @@ class GlobalSettingsForm(SettingsForm): required=False, label=_("Global message banner detail text"), )), - ('opencagedata_apikey', forms.CharField( + ('opencagedata_apikey', SecretKeySettingsField( required=False, label=_("OpenCage API key for geocoding"), )), diff --git a/src/pretix/plugins/stripe/signals.py b/src/pretix/plugins/stripe/signals.py index ff22f6b9af..b4a94b98f0 100644 --- a/src/pretix/plugins/stripe/signals.py +++ b/src/pretix/plugins/stripe/signals.py @@ -7,6 +7,7 @@ from django.template.loader import get_template from django.urls import resolve, reverse from django.utils.translation import gettext_lazy as _ +from pretix.base.forms import SecretKeySettingsField from pretix.base.settings import settings_hierarkey from pretix.base.signals import ( logentry_display, register_global_settings, register_payment_providers, @@ -98,7 +99,7 @@ def register_global_settings(sender, **kwargs): StripeKeyValidator('ca_'), ), )), - ('payment_stripe_connect_secret_key', forms.CharField( + ('payment_stripe_connect_secret_key', SecretKeySettingsField( label=_('Stripe Connect: Secret key'), required=False, validators=( @@ -112,7 +113,7 @@ def register_global_settings(sender, **kwargs): StripeKeyValidator('pk_live_'), ), )), - ('payment_stripe_connect_test_secret_key', forms.CharField( + ('payment_stripe_connect_test_secret_key', SecretKeySettingsField( label=_('Stripe Connect: Secret key (test)'), required=False, validators=(