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
26 lines
1.1 KiB
Python
26 lines
1.1 KiB
Python
from django.db import models
|
|
|
|
|
|
class PendingEmailChange(models.Model):
|
|
"""A one-time link for an e-mail change. Owned by `profile` (AD-19).
|
|
|
|
The token itself is never stored, only its SHA-256 hash (AD-9). A `confirm` row holds the
|
|
address the user asked for (`new_address`) and the one they had then (`old_address`). An
|
|
`undo` row holds the address to restore (`old_address`) and the one that was confirmed
|
|
(`new_address`).
|
|
"""
|
|
|
|
class Kind(models.TextChoices):
|
|
CONFIRM = "confirm"
|
|
UNDO = "undo"
|
|
|
|
user_key = models.CharField(max_length=256, db_index=True) # lower case
|
|
sam = models.CharField(max_length=256) # exact sAMAccountName, for directory calls
|
|
kind = models.CharField(max_length=10, choices=Kind.choices)
|
|
token_hash = models.CharField(max_length=64, unique=True)
|
|
old_address = models.CharField(max_length=254, blank=True)
|
|
new_address = models.CharField(max_length=254)
|
|
created_at = models.DateTimeField()
|
|
expires_at = models.DateTimeField()
|
|
used_at = models.DateTimeField(null=True, blank=True)
|