diff --git a/fedcode/forms.py b/fedcode/forms.py index 98550b9..261c384 100644 --- a/fedcode/forms.py +++ b/fedcode/forms.py @@ -8,8 +8,12 @@ # from django import forms +from django.contrib.admin.forms import AdminAuthenticationForm +from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User +from django_recaptcha.fields import ReCaptchaField +from django_recaptcha.widgets import ReCaptchaV2Checkbox from .models import Note from .models import Repository @@ -58,6 +62,9 @@ def __init__(self, *args, **kwargs): class PersonSignUpForm(UserCreationForm): + captcha = ReCaptchaField( + error_messages={"required": ("Captcha is required")}, widget=ReCaptchaV2Checkbox + ) email = forms.EmailField(max_length=254) class Meta: @@ -141,3 +148,21 @@ class SearchRepositoryForm(forms.Form): }, ), ) + + +class UserLoginForm(AuthenticationForm): + captcha = ReCaptchaField( + error_messages={ + "required": ("Captcha is required"), + }, + widget=ReCaptchaV2Checkbox, + ) + + +class AdminLoginForm(AdminAuthenticationForm): + captcha = ReCaptchaField( + error_messages={ + "required": ("Captcha is required"), + }, + widget=ReCaptchaV2Checkbox(), + ) diff --git a/fedcode/templates/admin_login.html b/fedcode/templates/admin_login.html new file mode 100644 index 0000000..074ca6e --- /dev/null +++ b/fedcode/templates/admin_login.html @@ -0,0 +1,66 @@ +{% extends "admin/base_site.html" %} +{% load i18n static %} + +{% block extrastyle %}{{ block.super }} +{{ form.media }} +{% endblock %} + +{% block bodyclass %}{{ block.super }} login{% endblock %} + +{% block usertools %}{% endblock %} + +{% block nav-global %}{% endblock %} + +{% block nav-sidebar %}{% endblock %} + +{% block content_title %}{% endblock %} + +{% block nav-breadcrumbs %}{% endblock %} + +{% block content %} + +{% if form.errors %} +{% for error in form.errors.values %} +

{{ error }}

+{% endfor %} +{% endif %} + + +
+ + {% if user.is_authenticated %} +

+ {% blocktranslate trimmed %} + You are authenticated as {{ username }}, but are not authorized to + access this page. Would you like to login to a different account? + {% endblocktranslate %} +

+ {% endif %} + +
{% csrf_token %} +
+ {{ form.username.errors }} + {{ form.username.label_tag }} {{ form.username }} +
+
+ {{ form.password.errors }} + {{ form.password.label_tag }} {{ form.password }} + +
+ {% url 'admin_password_reset' as password_reset_url %} + {% if password_reset_url %} + + {% endif %} +
+
+ {{ form.captcha }} +
+
+
+ +
+
+
+{% endblock %} diff --git a/fedcode/templates/login.html b/fedcode/templates/login.html index 6e3d27a..834312d 100644 --- a/fedcode/templates/login.html +++ b/fedcode/templates/login.html @@ -10,7 +10,10 @@ {% if form.errors %}
- Error! Your username and password didn't match. Please try again. + Error! + {% for error in form.errors.values %} + {{ error }} + {% endfor %}
{% endif %} @@ -32,7 +35,11 @@

User Login

autocomplete="current-password" required id="id_password"> - +
+
+ {{ form.captcha }} +
+
diff --git a/fedcode/templates/user_sign_up.html b/fedcode/templates/user_sign_up.html index 601e798..4924ea8 100644 --- a/fedcode/templates/user_sign_up.html +++ b/fedcode/templates/user_sign_up.html @@ -17,7 +17,9 @@

Error

- {{ form.errors }} + {% for error in form.errors.values %} + {{ error }} + {% endfor %}
@@ -61,6 +63,11 @@

User Signup

autocomplete="new-password" required id="id_password2"> +
+
+ {{ form.captcha }} +
+
diff --git a/fedcode/views.py b/fedcode/views.py index de95a09..de129b6 100644 --- a/fedcode/views.py +++ b/fedcode/views.py @@ -10,7 +10,6 @@ import json import logging import os.path -from urllib.parse import urlparse import requests from django.contrib import messages @@ -47,6 +46,7 @@ from fedcode.activitypub import AP_CONTEXT from fedcode.activitypub import create_activity_obj from fedcode.activitypub import has_valid_header +from fedcode.forms import AdminLoginForm from fedcode.forms import CreateGitRepoForm from fedcode.forms import CreateNoteForm from fedcode.forms import CreateReviewForm @@ -57,6 +57,7 @@ from fedcode.forms import SearchRepositoryForm from fedcode.forms import SearchReviewForm from fedcode.forms import SubscribePackageForm +from fedcode.forms import UserLoginForm from fedcode.models import Follow from fedcode.models import Note from fedcode.models import Package @@ -277,6 +278,7 @@ def post(self, request, repository_id): class UserLogin(LoginView): template_name = "login.html" next_page = "/" + form_class = UserLoginForm def dispatch(self, request, *args, **kwargs): # If user is already logged in, redirect to the next_page. @@ -887,3 +889,8 @@ def revoke_token(request): }, ) return JsonResponse(json.loads(r.content), status=r.status_code, content_type=AP_CONTENT_TYPE) + + +class AdminLoginView(LoginView): + template_name = "admin_login.html" + authentication_form = AdminLoginForm diff --git a/federatedcode/settings.py b/federatedcode/settings.py index bc7285b..07d36e5 100644 --- a/federatedcode/settings.py +++ b/federatedcode/settings.py @@ -61,6 +61,10 @@ FEDERATEDCODE_CLIENT_ID = env.str("FEDERATEDCODE_CLIENT_ID") FEDERATEDCODE_CLIENT_SECRET = env.str("FEDERATEDCODE_CLIENT_SECRET") +RECAPTCHA_PUBLIC_KEY = env.str("RECAPTCHA_PUBLIC_KEY", "") +RECAPTCHA_PRIVATE_KEY = env.str("RECAPTCHA_PRIVATE_KEY", "") +SILENCED_SYSTEM_CHECKS = ["captcha.recaptcha_test_key_error"] +RECAPTCHA_DOMAIN = env.str("RECAPTCHA_DOMAIN", "www.recaptcha.net") # Application definition @@ -78,6 +82,7 @@ "django.contrib.humanize", # Third-party apps "oauth2_provider", + "django_recaptcha", ] MIDDLEWARE = [ diff --git a/federatedcode/urls.py b/federatedcode/urls.py index 5457cd9..934528b 100644 --- a/federatedcode/urls.py +++ b/federatedcode/urls.py @@ -13,6 +13,7 @@ from django.urls import path from fedcode import views +from fedcode.views import AdminLoginView from fedcode.views import CreateReview from fedcode.views import CreateSync from fedcode.views import CreatGitView @@ -45,6 +46,7 @@ from fedcode.views import redirect_vulnerability urlpatterns = [ + path("admin/login/", AdminLoginView.as_view(), name="admin-login"), path("admin/", admin.site.urls), path(".well-known/webfinger", WebfingerView.as_view(), name="web-finger"), path("", HomeView.as_view(), name="home-page"), diff --git a/requirements.txt b/requirements.txt index 28cd1cb..e617873 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ Django==5.1.2 django-environ==0.11.2 django-ninja==1.3.0 django-oauth-toolkit==3.0.1 +django-recaptcha==4.0.0 djangorestframework==3.15.2 doc8==1.1.2 docutils==0.21.2 diff --git a/setup.cfg b/setup.cfg index 7285ae8..a2368bd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -76,6 +76,9 @@ install_requires = python-dotenv==1.0.1 click==8.1.7 + # Captcha + django-recaptcha==4.0.0 + [options.extras_require] dev = # Validation