ungleich-user/dal/models.py
Sajeyks dad66040ed Keep passwords out of activation links
The activation link carried base64-encoded username, password, names
and email, so plaintext passwords ended up in mail archives, browser
history and proxy logs.

Registration now hashes the password to {SSHA} immediately and stores
it in a new PendingRegistration table (migration 0002). The emailed
link is /activate/<token>/ with a random token only, and activation
writes the stored hash into LDAP. Pending entries expire after 24h,
like reset tokens. This also drops the PseudoUser/token-generator
workaround.

Links in emails sent before deployment stop working; those users must
register again.
2026-11-06 15:02:41 +03:00

48 lines
1.7 KiB
Python

from django.db import models
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User
# Basic DB to correlate tokens, users and creation time
class ResetToken(models.Model):
# users wouldn't use usernames >100 chars
user = models.CharField(max_length=100)
# Not so sure about tokens, better make it big
# should be <100, but big usernames make bigger tokens
# if I read that correctly
token = models.CharField(max_length=255)
# creation time in epoch (UTC)
# BigInt just so we are save for the next few decades ;)
creation = models.BigIntegerField()
class PendingRegistration(models.Model):
"""A sign-up waiting for its email to be confirmed.
Only the {SSHA} hash of the password is kept, and the activation link
carries nothing but the random token.
"""
token = models.CharField(max_length=64, unique=True)
username = models.CharField(max_length=100)
email = models.EmailField(max_length=254)
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
password_hash = models.CharField(max_length=255)
# creation time in epoch (UTC), like ResetToken
creation = models.BigIntegerField()
def get_validation_slug():
return make_password(None)
class UserAccountValidationDetail(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated'))
validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0)
validation_slug = models.CharField(
db_index=True, unique=True, max_length=50,
default=get_validation_slug
)
date_validation_started = models.DateTimeField(auto_now_add=True)