feat: add e-mail change with confirmation and undo

Page at /email asks for the new address and the current password (shared failure counter with the password page, five requests per hour) and mails a one-hour confirmation link to the new address. Confirming writes the address and mails the old address a 24-hour undo link; undoing restores it, ends every session of the user and notifies the Admin (ADMIN_NOTIFY_EMAIL). Link pages show on GET and apply on POST; tokens are stored only as hashes, single use, and are blanked from every log line. New table owned by profile, German text, tests; review findings logged in the plan.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FocPJ75XPma7TcuYEMy8zm
This commit is contained in:
Ebbe Baß
2026-10-19 10:05:41 +02:00
co-authored by Claude Sonnet 5.5
parent 3fd8f27127
commit 94c1d39c9d
35 changed files with 1792 additions and 14 deletions
@@ -0,0 +1,9 @@
{% load i18n %}{% autoescape off %}{% blocktrans with name=name %}Hello {{ name }},{% endblocktrans %}
{% trans "this e-mail address was entered as the new e-mail address of your portal account. To confirm it, open this link and press the button. The link is valid for one hour:" %}
{{ link }}
{% trans "Your address changes only after you confirm. If you did not ask for this, ignore this e-mail. Nothing will change." %}
{% trans "This e-mail never contains your password." %}{% endautoescape %}
@@ -0,0 +1 @@
{% load i18n %}{% autoescape off %}{% trans "Please confirm your new e-mail address" %}{% endautoescape %}
@@ -0,0 +1,11 @@
{% load i18n tz %}{% autoescape off %}{% blocktrans with name=name %}Hello {{ name }},{% endblocktrans %}
{% timezone zone_name %}{% blocktrans with when=changed_at|date:"j. F Y, H:i" zone=changed_at|date:"T" address=new_address %}the e-mail address of your portal account was changed on {{ when }} ({{ zone }}) to {{ address }}.{% endblocktrans %}{% endtimezone %}
{% trans "If you did this, you do not need to do anything. If you did not, open this link to restore this address. The link is valid for 24 hours:" %}
{{ link }}
{% trans "Undoing signs you out on all devices and informs the administrator." %}
{% trans "This e-mail never contains your password." %}{% endautoescape %}
@@ -0,0 +1 @@
{% load i18n %}{% autoescape off %}{% trans "Your e-mail address was changed" %}{% endautoescape %}
@@ -0,0 +1,5 @@
{% load i18n tz %}{% autoescape off %}{% trans "Hello," %}
{% timezone zone_name %}{% blocktrans with when=undone_at|date:"j. F Y, H:i" zone=undone_at|date:"T" username=username %}the user {{ username }} undid an e-mail change on {{ when }} ({{ zone }}). All sessions of this user were ended.{% endblocktrans %}{% endtimezone %}
{% trans "The user may have lost control of the account. Please check it." %}{% endautoescape %}
@@ -0,0 +1 @@
{% load i18n %}{% autoescape off %}{% trans "An e-mail change was undone" %}{% endautoescape %}