aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2022-12-28 07:51:38 -0500
committerBobby <[email protected]>2022-12-28 07:51:38 -0500
commit54988a928d37fc12e1f6eb83c6ecfc2babe55e29 (patch)
tree42f5a62061fc3b0a4e70484d6bfb4afe184224d1
parent3ff3acef57e95ecd2e8dde429d4735e7c2e8e684 (diff)
downloadthatcomputerscientist-54988a928d37fc12e1f6eb83c6ecfc2babe55e29.tar.xz
thatcomputerscientist-54988a928d37fc12e1f6eb83c6ecfc2babe55e29.zip
Registraion function with captcha working
-rw-r--r--blog/urls.py1
-rw-r--r--blog/views.py70
-rw-r--r--ignis/urls.py1
-rw-r--r--ignis/views.py8
-rw-r--r--requirements.txt21
-rw-r--r--templates/blog/register.html99
-rw-r--r--users/admin.py3
-rw-r--r--users/forms.py67
-rw-r--r--users/migrations/0009_delete_captchastore.py16
-rw-r--r--users/models.py7
-rw-r--r--users/tokens.py16
-rw-r--r--users/urls.py1
-rw-r--r--users/views.py51
13 files changed, 162 insertions, 199 deletions
diff --git a/blog/urls.py b/blog/urls.py
index f575fc7a..4ee3a159 100644
--- a/blog/urls.py
+++ b/blog/urls.py
@@ -9,7 +9,6 @@ urlpatterns = [
path('account/', RedirectView.as_view(pattern_name='account', permanent=False)),
path('my/account', views.account, name='account'),
path('register/', views.register, name='register'),
- path('register/refresh_captcha/', name='refresh_captcha', view=views.refresh_captcha),
path('articles/post/<str:slug>', views.post, name='post'),
path('articles/post/<str:slug>/comment', views.comment, name='comment'),
path('articles/post/<str:slug>/edit_comment', views.edit_comment, name='edit_comment'),
diff --git a/blog/views.py b/blog/views.py
index a31fca7f..04818531 100644
--- a/blog/views.py
+++ b/blog/views.py
@@ -1,17 +1,16 @@
from datetime import datetime
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
-from users.models import UserProfile, CaptchaStore
+from users.models import UserProfile
import hashlib
-from captcha.image import ImageCaptcha
from random import choice
from string import ascii_letters, digits
-import base64
-import json
from .models import Post, Comment
from .context_processors import recent_posts, avatar_list
from announcements.models import Announcement
-
+from users.forms import RegisterForm
+from users.tokens import CaptchaTokenGenerator
+from django.contrib import messages
# Create your views here.
@@ -47,52 +46,31 @@ def account(request):
def homepage(request):
return render(request, 'blog/homepage.html', {'title': 'Homepage'})
-
-def get_base64_captcha():
- image = ImageCaptcha()
- random_string = ''.join([choice(ascii_letters + digits) for n in range(6)])
- data = image.generate(random_string)
- base64_data = "data:image/png;base64," + base64.b64encode(data.getvalue()).decode()
- return base64_data, random_string
-
def register(request):
user = request.user
- csrf_token = request.META.get('CSRF_COOKIE')
- try:
- # Delete old captcha
- CaptchaStore.objects.get(csrf_token=csrf_token).delete()
- except CaptchaStore.DoesNotExist:
- pass
+
+ # print request host
+ print(request.get_host())
+
+
if user.is_authenticated:
return redirect('blog:account')
else:
- if not csrf_token:
- # Create a new CSRF token
- csrf_token = ''.join([choice(ascii_letters + digits) for n in range(100)])
- base64_data, random_string = get_base64_captcha()
- try:
- # Delete old captcha
- CaptchaStore.objects.get(csrf_token=csrf_token).delete()
- except CaptchaStore.DoesNotExist:
- pass
- # Create new captcha
- CaptchaStore.objects.create(captcha_string=random_string, csrf_token=csrf_token)
- return render(request, 'blog/register.html', {'title': 'Register', 'captcha': base64_data})
-
-
-def refresh_captcha(request):
- csrf_token = request.META.get('CSRF_COOKIE')
- if not request.META.get('HTTP_REFERER') or request.META.get('HTTP_REFERER').split('/')[-2] != 'register':
- response_data = {'status': 'error', 'message': 'Unauthorized!'}
- return HttpResponse(json.dumps(response_data), content_type="application/json", status=401)
- base64_data, random_string = get_base64_captcha()
- try:
- CaptchaStore.objects.get(csrf_token=csrf_token).delete()
- except CaptchaStore.DoesNotExist:
- pass
- CaptchaStore.objects.create(captcha_string=random_string, csrf_token=csrf_token)
- response_data = {'captcha': base64_data}
- return HttpResponse(json.dumps(response_data), content_type="application/json")
+ random_string = ''.join([choice(ascii_letters + digits) for n in range(6)])
+ captcha = CaptchaTokenGenerator().encrypt(random_string)
+ if request.method == 'POST':
+ expected_captcha = CaptchaTokenGenerator().decrypt(request.POST.get('expected_captcha'))
+ form = RegisterForm(request.POST, expected_captcha=expected_captcha)
+ if form.is_valid():
+ form.save(request=request)
+ messages.success(request, 'Account was created! Please check your email to verify your account.', extra_tags='accountCreated')
+ return redirect('blog:register')
+ # return redirect('blog:home')
+ else:
+ return render(request, 'blog/register.html', {'title': 'Register', 'form': form, 'captcha': captcha})
+ else:
+ form = RegisterForm(expected_captcha=random_string)
+ return render(request, 'blog/register.html', {'title': 'Register', 'form': form, 'captcha': captcha})
def post(request, slug):
try:
diff --git a/ignis/urls.py b/ignis/urls.py
index b190a40f..44ed5de1 100644
--- a/ignis/urls.py
+++ b/ignis/urls.py
@@ -8,4 +8,5 @@ urlpatterns = [
path('/upload', views.upload_image, name='upload_image'),
path('/image/<post_id>/<image_name>', views.get_image, name='get_image'),
path('/cover/<str:repository>', views.cover_image, name='cover_image'),
+ path('/captcha/<str:captcha_string>', views.captcha_image, name='captcha_image')
]
diff --git a/ignis/views.py b/ignis/views.py
index 1e822cbf..211346eb 100644
--- a/ignis/views.py
+++ b/ignis/views.py
@@ -9,6 +9,8 @@ from .models import PostImage, RepositoryTitle
import json
import requests
from django.core.files.base import ContentFile
+from captcha.image import ImageCaptcha
+from users.tokens import CaptchaTokenGenerator
# from .github import get_cover
# Create your views here.
@@ -134,3 +136,9 @@ def upload_image(request):
return HttpResponse(json.dumps(response), content_type='application/json')
return HttpResponse('Method not allowed', status=405)
+def captcha_image(request, captcha_string):
+ captcha = CaptchaTokenGenerator().decrypt(captcha_string)
+ imgcaptcha = ImageCaptcha()
+ data = imgcaptcha.generate(captcha)
+ return HttpResponse(data, content_type='image/png')
+
diff --git a/requirements.txt b/requirements.txt
index 47cbb152..684ae086 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,11 @@
-Django==4.0.6
-python-dotenv==0.20.0
-gunicorn==20.1.0
-whitenoise==6.2.0
-six==1.16.0
-cryptocode==0.1
-captcha==0.4
-PyGithub==1.55
-requests==2.28.1
-pillow==9.2.0 \ No newline at end of file
+Django
+python-dotenv
+gunicorn
+whitenoise
+six
+cryptocode
+captcha
+PyGithub
+requests
+pillow
+pycryptodome \ No newline at end of file
diff --git a/templates/blog/register.html b/templates/blog/register.html
index d94e545f..b168c153 100644
--- a/templates/blog/register.html
+++ b/templates/blog/register.html
@@ -1,86 +1,19 @@
{% extends 'blog/partials/base.html' %} {% block content %}
-<div class="main">
- <section>
- <h1>Register for an account</h1>
- <p>Register for an account to post your thoughts and get feedback from other users.</p>
- <form action="{% url 'users:register' %}" method="post" autocomplete="off">
- {% csrf_token %}
- <div>
- <label for="username">Username</label>
- <input type="text" name="username" id="username" class="form-control" placeholder="Username" required>
- {% for message in messages %}
- {% if 'usernameError' in message.tags %}
- <small class="error" style="display:block;">{{ message.message }}</small>
- {% endif %}
- {% endfor %}
- </div>
- <div>
- <label for="email">Email</label>
- <input type="email" name="email" id="email" class="form-control" placeholder="Email" required>
- {% for message in messages %}
- {% if 'emailError' in message.tags %}
- <small class="error" style="display:block;">{{ message.message }}</small>
- {% endif %}
- {% endfor %}
- </div>
- <div>
- <label for="password">Password</label>
- <input type="password" name="password" id="password" class="form-control" placeholder="Password" required>
- {% for message in messages %}
- {% if 'passwordError' in message.tags %}
- {% load replace %}
- <small class="error" style="display:block;">{{ message.message|replace:"[']" }}</small>
- {% endif %}
- {% endfor %}
- </div>
- <div>
- <label for="password2">Confirm Password</label>
- <input type="password" name="password2" id="password2" class="form-control" placeholder="Confirm Password" required>
- {% for message in messages %}
- {% if 'password2Error' in message.tags %}
- <small class="error" style="display:block;">{{ message.message }}</small>
- {% endif %}
- {% endfor %}
- </div>
- <div>
- <label for="captcha" style="margin: 5px 0px; display: block;">Type Captcha</label>
- <div id="captcha">
- {% load static %}
- <img src="{{ captcha }}" alt="captcha" class="captcha" id="captcha_image" style="display: block;">
- <img src="{% static 'images/icons/button_refresh.jpeg' %}" alt="Refresh Captcha" id="refresh_captcha" data-refresh-captcha-url="{% url 'blog:refresh_captcha' %}">
- </div>
- <input type="text" name="captcha" id="captcha" class="form-control" placeholder="Type Captcha" required>
- {% for message in messages %}
- {% if 'captchaError' in message.tags %}
- <small class="error" style="display:block;">{{ message.message }}</small>
- {% endif %}
- {% endfor %}
- </div>
- <div>
- <input type="submit" class="btn btn-primary" style="margin-top:10px" value="Register">
- </div>
- <br>
- {% for message in messages %}
- {% if 'accountCreated' in message.tags %}
- <small class="success" style="display:block;">{{ message.message }}</small>
- {% endif %}
- {% endfor %}
- </section>
-</div>
-<script src={% static 'js/captcha.js' %}></script>
-<script>
- var username = new URLSearchParams(window.location.search).get('u');
- var email = new URLSearchParams(window.location.search).get('e');
- if (username) {
- document.getElementsByName("username").forEach(function(input) {
- input.value = username;
- });
- }
- if (email) {
- document.getElementsByName("email").forEach(function(input) {
- input.value = email.split('?u=')[0];
- });
- }
-</script>
+<h1>Register for an account</h1>
+<p>Register for an account to post your thoughts and get feedback from other users.</p>
+<hr>
+<form method="post" id="register_form">
+ <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}" style="display: none;">
+ {{ form.as_p }}
+ <img src="{% url 'ignis:captcha_image' captcha %}" alt="Captcha" id="captcha">
+ <input type="hidden" name="expected_captcha" value="{{ captcha }}">
+ <input type="submit" value="Register" class="button button-special">
+</form>
+{% for message in messages %}
+ {% if 'accountCreated' in message.tags %}
+ <p><small class="success">{{ message.message }}</small></p>
+ {% endif %}
+{% endfor %}
{% endblock %}
+
diff --git a/users/admin.py b/users/admin.py
index 49d40cef..f5116502 100644
--- a/users/admin.py
+++ b/users/admin.py
@@ -1,7 +1,6 @@
from django.contrib import admin
# Register your models here.
-from .models import UserProfile, CaptchaStore
+from .models import UserProfile
admin.site.register(UserProfile)
-admin.site.register(CaptchaStore)
diff --git a/users/forms.py b/users/forms.py
new file mode 100644
index 00000000..de13fe27
--- /dev/null
+++ b/users/forms.py
@@ -0,0 +1,67 @@
+# Registration form
+
+from django import forms
+from django.contrib.auth.models import User
+from users.models import UserProfile
+from django.core.mail import send_mail
+from django.conf import settings
+from django.template.loader import render_to_string
+from django.utils.html import strip_tags
+from django.utils.encoding import force_bytes
+from django.utils.http import urlsafe_base64_encode
+from .tokens import account_activation_token
+
+class RegisterForm(forms.Form):
+ username = forms.CharField(label='Username', max_length=30)
+ email = forms.EmailField(label='Email')
+ password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
+ password2 = forms.CharField(label='Password (again)', widget=forms.PasswordInput)
+ captcha = forms.CharField(label='Captcha', max_length=6)
+ expected_captcha = None
+
+ def __init__(self, *args, **kwargs):
+ if 'expected_captcha' in kwargs:
+ self.expected_captcha = kwargs.pop('expected_captcha')
+ super().__init__(*args, **kwargs)
+
+ def clean(self):
+ cleaned_data = super().clean()
+ password1 = cleaned_data.get('password1')
+ password2 = cleaned_data.get('password2')
+ captcha = cleaned_data.get('captcha')
+ if password1 and password2:
+ if password1 != password2:
+ raise forms.ValidationError('Passwords do not match.')
+ if str.lower(captcha) != str.lower(self.expected_captcha):
+ raise forms.ValidationError('Captcha does not match.')
+ if User.objects.filter(username=cleaned_data.get('username')).exists():
+ raise forms.ValidationError('Username already exists.')
+ if User.objects.filter(email=cleaned_data.get('email')).exists():
+ raise forms.ValidationError('Email already exists.')
+ return cleaned_data
+
+ def save(self, request):
+ user = User.objects.create_user(
+ username=self.cleaned_data.get('username'),
+ email=self.cleaned_data.get('email'),
+ password=self.cleaned_data.get('password1'),
+ )
+ user.save()
+ user_profile = UserProfile.objects.create(user=user)
+ user_profile.save()
+
+ # Send verification email
+ subject = 'Verify your email address'
+ message = render_to_string('verification_email.html', {
+ 'user': user.username if user.first_name is None else user.first_name,
+ 'site_name': 'That Computer Scientist',
+ 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
+ 'token': account_activation_token.make_token(user),
+ 'protocol': 'https://' if request.is_secure() else 'http://',
+ 'domain': request.get_host(),
+ })
+ message = strip_tags(message)
+ send_mail(subject, message, 'That Computer Scientist <' + settings.EMAIL_HOST_USER + '>', [user.email], fail_silently=False)
+
+ return user
+
diff --git a/users/migrations/0009_delete_captchastore.py b/users/migrations/0009_delete_captchastore.py
new file mode 100644
index 00000000..dbde60c8
--- /dev/null
+++ b/users/migrations/0009_delete_captchastore.py
@@ -0,0 +1,16 @@
+# Generated by Django 4.1.4 on 2022-12-28 12:41
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("users", "0008_remove_userprofile_gravatar_email_and_more"),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name="CaptchaStore",
+ ),
+ ]
diff --git a/users/models.py b/users/models.py
index 746814ef..1b97e871 100644
--- a/users/models.py
+++ b/users/models.py
@@ -16,11 +16,4 @@ class UserProfile(models.Model):
def __str__(self):
return self.user.username
-
-class CaptchaStore(models.Model):
- captcha_string = models.CharField(max_length=6)
- csrf_token = models.CharField(max_length=100)
- created_at = models.DateTimeField(auto_now_add=True)
- def __str__(self):
- return self.captcha_string
diff --git a/users/tokens.py b/users/tokens.py
index c127fa45..77bd4e88 100644
--- a/users/tokens.py
+++ b/users/tokens.py
@@ -3,6 +3,9 @@ import os
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from dotenv import load_dotenv
from six import text_type
+from Crypto.Cipher import AES
+
+load_dotenv()
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
@@ -20,4 +23,17 @@ class EmailChangeTokenGenerator():
auth_string = os.getenv('AUTHORIZATION_STRING')
return cryptocode.decrypt(token, auth_string)
+class CaptchaTokenGenerator():
+ def encrypt(self, captcha_string):
+ auth_string = os.getenv('AUTHORIZATION_STRING')
+ key = auth_string.encode('utf-8')[0:16]
+ cipher = AES.new(key, AES.MODE_CFB, key)
+ return cipher.encrypt(captcha_string.encode('utf-8')).hex()
+
+ def decrypt(self, token):
+ auth_string = os.getenv('AUTHORIZATION_STRING')
+ key = auth_string.encode('utf-8')[0:16]
+ cipher = AES.new(key, AES.MODE_CFB, key)
+ return cipher.decrypt(bytes.fromhex(token)).decode('utf-8')
+
account_activation_token = AccountActivationTokenGenerator()
diff --git a/users/urls.py b/users/urls.py
index 220f57f3..02a7e302 100644
--- a/users/urls.py
+++ b/users/urls.py
@@ -12,7 +12,6 @@ urlpatterns = [
path('/verifyemail/<uidb64>/<token>', views.verify_email, name='verifyemail'),
path('/sendchangeuseremail', views.send_change_user_email, name='sendchangeuseremail'),
path('/changeemail/<uidb64>/<token>', views.change_email, name='changeemail'),
- path('/register', views.register, name='register'),
]
# Configure Admin Site
diff --git a/users/views.py b/users/views.py
index 7857bbe7..05d379ff 100644
--- a/users/views.py
+++ b/users/views.py
@@ -1,8 +1,8 @@
from django.http import HttpResponseRedirect
-from django.shortcuts import render, redirect
+from django.shortcuts import redirect
from django.contrib.auth import authenticate, login, logout, update_session_auth_hash
from django.contrib import messages
-from .models import UserProfile, CaptchaStore
+from .models import UserProfile
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.conf import settings
@@ -13,7 +13,6 @@ from django.utils.http import urlsafe_base64_encode
from django.contrib.sites.shortcuts import get_current_site
from .tokens import account_activation_token, EmailChangeTokenGenerator
from django.utils.http import urlsafe_base64_decode
-import django.contrib.auth.password_validation as validators
# Create your views here.
def login_user(request):
@@ -195,49 +194,3 @@ def change_email(request, uidb64, token):
else:
messages.error(request, 'The verification link is invalid!')
return redirect('blog:home')
-
-
-def register(request):
- if request.method == 'POST':
- username = request.POST['username']
- email = request.POST['email']
- password = request.POST['password']
- confirm_password = request.POST['password2']
- captcha = request.POST['captcha']
- csrf_token = request.META.get('CSRF_COOKIE')
- current_captcha = CaptchaStore.objects.get(csrf_token=csrf_token).captcha_string
- if str(captcha).lower() != str(current_captcha).lower():
- messages.error(request, 'Captcha is incorrect!', extra_tags='captchaError')
- return HttpResponseRedirect(request.META.get('HTTP_REFERER') + '?u={}&e={}'.format(username, email))
- if password != confirm_password:
- messages.error(request, 'Passwords do not match!', extra_tags='password2Error')
- return HttpResponseRedirect(request.META.get('HTTP_REFERER') + '?u={}&e={}'.format(username, email))
- if User.objects.filter(username=username).exists():
- messages.error(request, 'Username is already in use!', extra_tags='usernameError')
- return HttpResponseRedirect(request.META.get('HTTP_REFERER') + '?e={}'.format(email))
- if User.objects.filter(email=email).exists():
- messages.error(request, 'Email is already in use!', extra_tags='emailError')
- return HttpResponseRedirect(request.META.get('HTTP_REFERER') + '?u={}'.format(username))
- try:
- validators.validate_password(password=password)
- except Exception as e:
- messages.error(request, e, extra_tags='passwordError')
- return HttpResponseRedirect(request.META.get('HTTP_REFERER') + '?u={}&e={}'.format(username, email))
- user = User.objects.create_user(username=username, email=email, password=password)
- user.save()
- user_profile = UserProfile(user=user)
- user_profile.save()
- # Send verification email
- subject = 'Verify your email address'
- message = render_to_string('verification_email.html', {
- 'user': user.username if user.first_name is None else user.first_name,
- 'site_name': 'That Computer Scientist',
- 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
- 'token': account_activation_token.make_token(user),
- 'protocol': 'https://' if request.is_secure() else 'http://',
- 'domain': get_current_site(request).domain,
- })
- message = strip_tags(message)
- send_mail(subject, message, 'That Computer Scientist <' + settings.EMAIL_HOST_USER + '>', [email])
- messages.success(request, 'Account was created! Please check your email to verify your account.', extra_tags='accountCreated')
- return redirect('blog:register')