django-simplekeys/simplekeys/views.py
2024-12-16 23:04:51 -06:00

123 lines
4.1 KiB
Python

import hashlib
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.mail import send_mail
from django.shortcuts import render, redirect
from django.template import loader
from django.views.generic import View
from django.http import HttpResponseBadRequest
from .forms import KeyRegistrationForm, KeyConfirmationForm
from .models import Tier, Key
def _get_confirm_hash(key, email):
value = '{}{}{}'.format(key, email, settings.SECRET_KEY)
return hashlib.sha256(value.encode()).hexdigest()
class RegistrationView(View):
"""
present user with a form to fill out to get a key
upon submission, send an email sending user to confirmation page
"""
template_name = "simplekeys/register.html"
email_subject = 'API Key Registration'
email_message_template = 'simplekeys/confirmation_email.txt'
from_email = settings.DEFAULT_FROM_EMAIL
tier = 'default'
redirect = '/'
confirmation_url = '/confirm/'
def get(self, request):
return render(request, self.template_name,
{'form': KeyRegistrationForm()})
def post(self, request):
form = KeyRegistrationForm(request.POST)
if not form.is_valid():
return render(request, self.template_name,
{'form': form})
# go ahead w/ creation
key = form.instance
key.tier = Tier.objects.get(slug=self.tier)
# TODO: option to override this and avoid sending email?
key.status = 'u'
key.save()
# send email & redirect user
confirm_hash = _get_confirm_hash(key.key, key.email)
# if URL is relative, make absolute
if not self.confirmation_url.startswith(('http:', 'https:')):
confirmation_url = '{protocol}://{site}{confirmation_url}'.format(
protocol='https' if request.is_secure else 'http',
site=Site.objects.get_current().domain,
confirmation_url=self.confirmation_url
)
else:
confirmation_url = self.confirmation_url
confirmation_url = (
'{base}?key={key}&email={email}&confirm_hash={confirm_hash}'
).format(
base=confirmation_url,
key=key.key,
email=key.email,
confirm_hash=confirm_hash
)
message = loader.render_to_string(
self.email_message_template,
{'key': key, 'confirmation_url': confirmation_url}
)
send_mail(self.email_subject,
message,
self.from_email,
[key.email])
return redirect(self.redirect)
class ConfirmationView(View):
"""
present user with a simple form that just needs to be submitted
to activate the key (don't do activation on GET to prevent
email clients from clicking link)
"""
confirmation_template_name = "simplekeys/confirmation.html"
confirmed_template_name = "simplekeys/confirmed.html"
def get(self, request):
form = KeyConfirmationForm(request.GET)
if form.is_valid():
return render(request, self.confirmation_template_name,
{'form': form})
else:
return HttpResponseBadRequest('invalid request')
def post(self, request):
form = KeyConfirmationForm(request.POST)
if form.is_valid():
hash = _get_confirm_hash(form.cleaned_data['key'],
form.cleaned_data['email'])
if hash != form.cleaned_data['confirm_hash']:
return HttpResponseBadRequest('invalid request - bad hash')
# update the key
try:
key = Key.objects.get(key=form.cleaned_data['key'],
status__in=('u', 'a'))
except Key.DoesNotExist:
return HttpResponseBadRequest('invalid request - no key')
key.status = 'a'
key.save()
return render(request, self.confirmed_template_name, {'key': key})
else:
return HttpResponseBadRequest('invalid request - invalid form')