Typically encryption is not a good idea either, since if the decryption key gets known, people can decrypt all possible content, furthermore it would also make it rather easy to start hacking this application with the encryption key: if I somehow find out the encryption key, I can construct a URL to for example reset the password of an arbitrary email address, and thus reset the password of Bob, and login as Bob later.
A typical solution for this is constructing a table of "unsubscribe sessions". In case somebody requests to unsubscribe, you add that person to the table, and you add some sort of random id
to it. It is better not to use things like a primary key, since it is predictable what the previous and next id
s will be, and then people can "hack" this system to confirm the unsubscription of another person.
We thus create a table, with for example a GUID (globally unique identifier):
from datetime import datetime, timedelta
from django.conf import settings
from django.db.models import CASCADE, DateTimeField, ForeignKey, Model, UUIDField
from uuid import uuid4
def tomorrow():
return datetime.now() + timedelta(days=1)
class UnsubscribingUser(Model):
uuid = UUIDField(default=uuid4, editable=False, unique=True)
user = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
expires = DateTimeField(default=tomorrow)
So now in case you want to unsubscribe somebody, you can construct such UnsubscribingUser
model instance, and send an email with a link:
def unsubscribe(request):
uu = UnsubscribingUser.objects.create(user=request.user)
# send mail with uu.uuid
# ...
pass
The email then should contain a URL that links to a view that process the UUID:
from datetime import datetime
from django.http import Http404
def unsubscribe_url(request, uuid):
uu = get_object_or_404(UnsubScribingUser, uuid=uuid)
if uu.expires <= datetime.now():
# unsubscribe logic
# ...
uu.delete()
else:
# too late
# do something in that case, for example
uu.delete()
raise Http404
We thus first check if there exists such UnsubscribingUser
model instance, in that case we check if the "session" already expired. If not we unsubscribe.
The email thus contains the reverse(unsubscribe_url, uuid=uu.uid)
URL. Expiring is typically desirable, since otherwise eventually the table will store a huge amount of UUIDs, and after a white it becomes more likely that entering a random UUID can unsubscribe a random person.