aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2022-09-05 19:25:07 -0400
committerBobby <[email protected]>2022-09-05 19:25:07 -0400
commit10dccc6faa8c95b34a96cdfeae6daa335fe9b76d (patch)
tree1da99e8b123768c8a28913ed88cb1431522501cb
parent49b2cf3987378971d05cdcac996c69d7f862461e (diff)
downloadthatcomputerscientist-10dccc6faa8c95b34a96cdfeae6daa335fe9b76d.tar.xz
thatcomputerscientist-10dccc6faa8c95b34a96cdfeae6daa335fe9b76d.zip
Added captcha to register page
-rw-r--r--Dockerfile4
-rw-r--r--blog/urls.py1
-rw-r--r--blog/views.py43
-rw-r--r--requirements.txt1
-rw-r--r--static/css/main.css16
-rw-r--r--static/images/icons/button_refresh.jpegbin0 -> 26372 bytes
-rw-r--r--static/js/captcha.js15
-rw-r--r--templates/blog/register.html16
-rw-r--r--users/migrations/0003_captchastore.py22
-rw-r--r--users/migrations/0004_remove_captchastore_id_alter_captchastore_csrf_token.py22
-rw-r--r--users/models.py7
11 files changed, 145 insertions, 2 deletions
diff --git a/Dockerfile b/Dockerfile
index 3c91da9e..12d04373 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,6 +17,10 @@ RUN pip install -r requirements.txt
COPY . .
+# Migrations
+RUN python manage.py makemigrations
+RUN python manage.py migrate
+
RUN python manage.py collectstatic --noinput
diff --git a/blog/urls.py b/blog/urls.py
index 568d0cb9..1884e810 100644
--- a/blog/urls.py
+++ b/blog/urls.py
@@ -8,5 +8,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('my/homepage', views.homepage, name='homepage'),
]
diff --git a/blog/views.py b/blog/views.py
index b5c54182..c656f020 100644
--- a/blog/views.py
+++ b/blog/views.py
@@ -1,7 +1,14 @@
+from http.client import HTTPResponse
from django.shortcuts import render, redirect
-from users.models import UserProfile
+from django.http import HttpResponse
+from users.models import UserProfile, CaptchaStore
from urllib.parse import urlparse
import hashlib
+from captcha.image import ImageCaptcha
+from random import choice
+from string import ascii_letters, digits
+import base64
+import json
# Create your views here.
@@ -32,5 +39,37 @@ 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):
- return render(request, 'blog/register.html', {'title': 'Register New User'})
+ csrf_token = request.META.get('CSRF_COOKIE')
+ 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 New User', 'captcha': base64_data})
+
+
+def refresh_captcha(request):
+ csrf_token = request.META.get('CSRF_COOKIE')
+ if not csrf_token or 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")
diff --git a/requirements.txt b/requirements.txt
index 58cda50f..35143047 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,3 +5,4 @@ gunicorn==20.1.0
whitenoise==6.2.0
six==1.16.0
cryptocode==0.1
+captcha==0.4
diff --git a/static/css/main.css b/static/css/main.css
index a524db34..32afdeb8 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -153,6 +153,22 @@ nav > ul > li {
display: none;
}
+#captcha {
+ display: flex;
+ flex-direction: row;
+}
+
+#captcha > img:nth-child(1) {
+ height: 60px;
+ margin-right: 10px;
+}
+
+#captcha > img:nth-child(2) {
+ height: 30px;
+ transform: translateY(15px);
+ cursor: pointer;
+}
+
/* Optimize for phones */
@media only screen and (max-width: 480px) {
body {
diff --git a/static/images/icons/button_refresh.jpeg b/static/images/icons/button_refresh.jpeg
new file mode 100644
index 00000000..1d6b5567
--- /dev/null
+++ b/static/images/icons/button_refresh.jpeg
Binary files differ
diff --git a/static/js/captcha.js b/static/js/captcha.js
new file mode 100644
index 00000000..93be88da
--- /dev/null
+++ b/static/js/captcha.js
@@ -0,0 +1,15 @@
+const refreshCaptchaButton = document.getElementById('refresh_captcha');
+
+refreshCaptchaButton.addEventListener('click', function() {
+ const refreshCaptchaURl = refreshCaptchaButton.getAttribute('data-refresh-captcha-url');
+
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', refreshCaptchaURl, true);
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhr.onload = function() {
+ const data = JSON.parse(this.responseText);
+ const captchaImage = document.getElementById('captcha_image');
+ captchaImage.src = data['captcha'];
+ }
+ xhr.send();
+});
diff --git a/templates/blog/register.html b/templates/blog/register.html
index aa0600da..44fbc116 100644
--- a/templates/blog/register.html
+++ b/templates/blog/register.html
@@ -42,8 +42,24 @@
{% 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 '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>
<button type="submit" class="btn btn-primary" style="margin-top:10px">Register</button>
</div>
</section>
</div>
+<script src={% static 'js/captcha.js' %}></script>
{% endblock %}
+
diff --git a/users/migrations/0003_captchastore.py b/users/migrations/0003_captchastore.py
new file mode 100644
index 00000000..9aebc0aa
--- /dev/null
+++ b/users/migrations/0003_captchastore.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.0.6 on 2022-09-05 22:27
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('users', '0002_userprofile_email_verified'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CaptchaStore',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('captcha_string', models.CharField(max_length=6)),
+ ('csrf_token', models.CharField(max_length=100)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ ]
diff --git a/users/migrations/0004_remove_captchastore_id_alter_captchastore_csrf_token.py b/users/migrations/0004_remove_captchastore_id_alter_captchastore_csrf_token.py
new file mode 100644
index 00000000..1dd16bcc
--- /dev/null
+++ b/users/migrations/0004_remove_captchastore_id_alter_captchastore_csrf_token.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.0.6 on 2022-09-05 22:30
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('users', '0003_captchastore'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='captchastore',
+ name='id',
+ ),
+ migrations.AlterField(
+ model_name='captchastore',
+ name='csrf_token',
+ field=models.CharField(max_length=100, primary_key=True, serialize=False),
+ ),
+ ]
diff --git a/users/models.py b/users/models.py
index 808e197a..dab44f38 100644
--- a/users/models.py
+++ b/users/models.py
@@ -17,3 +17,10 @@ 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, primary_key=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return self.captcha_string