mirror of
https://github.com/pretix/pretix.git
synced 2026-08-27 13:24:41 +00:00
Account security notifications via email
This commit is contained in:
@@ -5,6 +5,8 @@ from django.contrib.auth.models import (
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django_otp.models import Device
|
from django_otp.models import Device
|
||||||
|
from pretix.base.i18n import language
|
||||||
|
from pretix.helpers.urls import build_absolute_uri
|
||||||
|
|
||||||
from .base import LoggingMixin
|
from .base import LoggingMixin
|
||||||
|
|
||||||
@@ -128,6 +130,28 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
|||||||
else:
|
else:
|
||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
|
def send_security_notice(self, messages, email=None):
|
||||||
|
from pretix.base.services.mail import mail, SendMailException
|
||||||
|
|
||||||
|
try:
|
||||||
|
with language(self.locale):
|
||||||
|
msg = '- ' + '\n- '.join(str(m) for m in messages)
|
||||||
|
|
||||||
|
mail(
|
||||||
|
email or self.email,
|
||||||
|
_('Account information changed'),
|
||||||
|
'pretixcontrol/email/security_notice.txt',
|
||||||
|
{
|
||||||
|
'user': self,
|
||||||
|
'messages': msg,
|
||||||
|
'url': build_absolute_uri('control:user.settings')
|
||||||
|
},
|
||||||
|
event=None,
|
||||||
|
locale=self.locale
|
||||||
|
)
|
||||||
|
except SendMailException:
|
||||||
|
pass # Already logged
|
||||||
|
|
||||||
|
|
||||||
class U2FDevice(Device):
|
class U2FDevice(Device):
|
||||||
json_data = models.TextField()
|
json_data = models.TextField()
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{% load i18n %}{% blocktrans with url=url|safe %}Hello,
|
||||||
|
|
||||||
|
this is to inform you that the account information of your pretix account has been
|
||||||
|
changed. In particular, the following changes have been performed:
|
||||||
|
|
||||||
|
{{ messages }}
|
||||||
|
|
||||||
|
If this change was not performed by you, please contact us immediately.
|
||||||
|
|
||||||
|
You can review and change your account settings here:
|
||||||
|
|
||||||
|
{{ url }}
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
Your pretix team
|
||||||
|
{% endblocktrans %}
|
||||||
@@ -31,6 +31,7 @@ class UserSettings(UpdateView):
|
|||||||
template_name = 'pretixcontrol/user/settings.html'
|
template_name = 'pretixcontrol/user/settings.html'
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
|
self._old_email = self.request.user.email
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
@@ -44,7 +45,6 @@ class UserSettings(UpdateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
messages.success(self.request, _('Your changes have been saved.'))
|
messages.success(self.request, _('Your changes have been saved.'))
|
||||||
sup = super().form_valid(form)
|
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for k in form.changed_data:
|
for k in form.changed_data:
|
||||||
@@ -53,6 +53,21 @@ class UserSettings(UpdateView):
|
|||||||
data['new_pw'] = True
|
data['new_pw'] = True
|
||||||
else:
|
else:
|
||||||
data[k] = form.cleaned_data[k]
|
data[k] = form.cleaned_data[k]
|
||||||
|
|
||||||
|
msgs = []
|
||||||
|
|
||||||
|
if 'new_pw' in form.changed_data:
|
||||||
|
msgs.append(_('Your password has been changed.'))
|
||||||
|
|
||||||
|
if 'email' in form.changed_data:
|
||||||
|
msgs.append(_('Your email address has been changed to {email}.').format(email=form.cleaned_data['email']))
|
||||||
|
|
||||||
|
if msgs:
|
||||||
|
self.request.user.send_security_notice(msgs, email=form.cleaned_data['email'])
|
||||||
|
if self._old_email != form.cleaned_data['email']:
|
||||||
|
self.request.user.send_security_notice(msgs, email=self._old_email)
|
||||||
|
|
||||||
|
sup = super().form_valid(form)
|
||||||
self.request.user.log_action('pretix.user.settings.changed', user=self.request.user, data=data)
|
self.request.user.log_action('pretix.user.settings.changed', user=self.request.user, data=data)
|
||||||
|
|
||||||
update_session_auth_hash(self.request, self.request.user)
|
update_session_auth_hash(self.request, self.request.user)
|
||||||
@@ -126,11 +141,16 @@ class User2FADeviceDeleteView(TemplateView):
|
|||||||
'id': self.device.pk
|
'id': self.device.pk
|
||||||
})
|
})
|
||||||
self.device.delete()
|
self.device.delete()
|
||||||
|
msgs = [
|
||||||
|
_('A two-factor authentication device has been removed from your account.')
|
||||||
|
]
|
||||||
if not any(dt.objects.filter(user=self.request.user, confirmed=True) for dt in REAL_DEVICE_TYPES):
|
if not any(dt.objects.filter(user=self.request.user, confirmed=True) for dt in REAL_DEVICE_TYPES):
|
||||||
self.request.user.require_2fa = False
|
self.request.user.require_2fa = False
|
||||||
self.request.user.save()
|
self.request.user.save()
|
||||||
self.request.user.log_action('pretix.user.settings.2fa.disabled', user=self.request.user)
|
self.request.user.log_action('pretix.user.settings.2fa.disabled', user=self.request.user)
|
||||||
|
msgs.append(_('Two-factor authentication has been disabled.'))
|
||||||
|
|
||||||
|
self.request.user.send_security_notice(msgs)
|
||||||
messages.success(request, _('The device has been removed.'))
|
messages.success(request, _('The device has been removed.'))
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
|
|
||||||
@@ -170,6 +190,9 @@ class User2FADeviceConfirmU2FView(TemplateView):
|
|||||||
'id': self.device.pk,
|
'id': self.device.pk,
|
||||||
'devicetype': 'u2f'
|
'devicetype': 'u2f'
|
||||||
})
|
})
|
||||||
|
self.request.user.send_security_notice([
|
||||||
|
_('A new two-factor authentication device has been added to your account.')
|
||||||
|
])
|
||||||
|
|
||||||
messages.success(request, _('The device has been verified and can now be used.'))
|
messages.success(request, _('The device has been verified and can now be used.'))
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
@@ -209,6 +232,9 @@ class User2FADeviceConfirmTOTPView(TemplateView):
|
|||||||
'id': self.device.pk,
|
'id': self.device.pk,
|
||||||
'devicetype': 'totp'
|
'devicetype': 'totp'
|
||||||
})
|
})
|
||||||
|
self.request.user.send_security_notice([
|
||||||
|
_('A new two-factor authentication device has been added to your account.')
|
||||||
|
])
|
||||||
|
|
||||||
messages.success(request, _('The device has been verified and can now be used.'))
|
messages.success(request, _('The device has been verified and can now be used.'))
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
@@ -235,6 +261,9 @@ class User2FAEnableView(TemplateView):
|
|||||||
self.request.user.save()
|
self.request.user.save()
|
||||||
self.request.user.log_action('pretix.user.settings.2fa.enabled', user=self.request.user)
|
self.request.user.log_action('pretix.user.settings.2fa.enabled', user=self.request.user)
|
||||||
messages.success(request, _('Two-factor authentication is now enabled for your account.'))
|
messages.success(request, _('Two-factor authentication is now enabled for your account.'))
|
||||||
|
self.request.user.send_security_notice([
|
||||||
|
_('Two-factor authentication has been enabled.')
|
||||||
|
])
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
|
|
||||||
|
|
||||||
@@ -246,6 +275,9 @@ class User2FADisableView(TemplateView):
|
|||||||
self.request.user.save()
|
self.request.user.save()
|
||||||
self.request.user.log_action('pretix.user.settings.2fa.disabled', user=self.request.user)
|
self.request.user.log_action('pretix.user.settings.2fa.disabled', user=self.request.user)
|
||||||
messages.success(request, _('Two-factor authentication is now disabled for your account.'))
|
messages.success(request, _('Two-factor authentication is now disabled for your account.'))
|
||||||
|
self.request.user.send_security_notice([
|
||||||
|
_('Two-factor authentication has been disabled.')
|
||||||
|
])
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
|
|
||||||
|
|
||||||
@@ -258,6 +290,9 @@ class User2FARegenerateEmergencyView(TemplateView):
|
|||||||
for i in range(10):
|
for i in range(10):
|
||||||
d.token_set.create(token=get_random_string(length=12, allowed_chars='1234567890'))
|
d.token_set.create(token=get_random_string(length=12, allowed_chars='1234567890'))
|
||||||
self.request.user.log_action('pretix.user.settings.2fa.regenemergency', user=self.request.user)
|
self.request.user.log_action('pretix.user.settings.2fa.regenemergency', user=self.request.user)
|
||||||
|
self.request.user.send_security_notice([
|
||||||
|
_('Your two-factor emergency codes have been regenerated.')
|
||||||
|
])
|
||||||
messages.success(request, _('Your emergency codes have been newly generated. Remember to store them in a safe '
|
messages.success(request, _('Your emergency codes have been newly generated. Remember to store them in a safe '
|
||||||
'place in case you lose access to your devices.'))
|
'place in case you lose access to your devices.'))
|
||||||
return redirect(reverse('control:user.settings.2fa'))
|
return redirect(reverse('control:user.settings.2fa'))
|
||||||
|
|||||||
Reference in New Issue
Block a user