2 Commits

Author SHA1 Message Date
3cc7fa9e8b [Fix] Add Captcha vars to Template (#359)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#359
2026-03-13 11:46:34 +13:00
21f3390a43 [Feature] Add Captchas to avoid spam registrations (#358)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#358
2026-03-13 11:36:48 +13:00
4 changed files with 60 additions and 2 deletions

View File

@ -408,3 +408,9 @@ if MS_ENTRA_ENABLED:
# Site ID 10 -> beta.envipath.org # Site ID 10 -> beta.envipath.org
MATOMO_SITE_ID = os.environ.get("MATOMO_SITE_ID", "10") MATOMO_SITE_ID = os.environ.get("MATOMO_SITE_ID", "10")
# CAP
CAP_ENABLED = os.environ.get("CAP_ENABLED", "False") == "True"
CAP_API_BASE = os.environ.get("CAP_API_BASE", None)
CAP_SITE_KEY = os.environ.get("CAP_SITE_KEY", None)
CAP_SECRET_KEY = os.environ.get("CAP_SECRET_KEY", None)

View File

@ -3,6 +3,7 @@ import logging
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Iterable from typing import Any, Dict, List, Iterable
import requests
import nh3 import nh3
from django.conf import settings as s from django.conf import settings as s
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -147,6 +148,11 @@ def handler500(request):
def login(request): def login(request):
context = get_base_context(request) context = get_base_context(request)
if s.CAP_ENABLED:
context["CAP_ENABLED"] = s.CAP_ENABLED
context["CAP_API_BASE"] = s.CAP_API_BASE
context["CAP_SITE_KEY"] = s.CAP_SITE_KEY
if request.method == "GET": if request.method == "GET":
context["title"] = "enviPath" context["title"] = "enviPath"
context["next"] = request.GET.get("next", "") context["next"] = request.GET.get("next", "")
@ -224,6 +230,11 @@ def logout(request):
def register(request): def register(request):
context = get_base_context(request) context = get_base_context(request)
if s.CAP_ENABLED:
context["CAP_ENABLED"] = s.CAP_ENABLED
context["CAP_API_BASE"] = s.CAP_API_BASE
context["CAP_SITE_KEY"] = s.CAP_SITE_KEY
if request.method == "GET": if request.method == "GET":
# Redirect to unified login page with signup tab # Redirect to unified login page with signup tab
next_url = request.GET.get("next", "") next_url = request.GET.get("next", "")
@ -238,6 +249,33 @@ def register(request):
if next := request.POST.get("next"): if next := request.POST.get("next"):
context["next"] = next context["next"] = next
# Catpcha
if s.CAP_ENABLED:
cap_token = request.POST.get("cap-token")
if not cap_token:
context["message"] = "Missing CAP Token."
return render(request, "static/login.html", context)
verify_url = f"{s.CAP_API_BASE}/{s.CAP_SITE_KEY}/siteverify"
payload = {
"secret": s.CAP_SECRET_KEY,
"response": cap_token,
}
try:
resp = requests.post(verify_url, json=payload, timeout=10)
resp.raise_for_status()
verify_data = resp.json()
except requests.RequestException:
context["message"] = "Captcha verification failed."
return render(request, "static/login.html", context)
if not verify_data.get("success"):
context["message"] = "Captcha check failed. Please try again."
return render(request, "static/login.html", context)
# End Captcha
username = request.POST.get("username", "").strip() username = request.POST.get("username", "").strip()
email = request.POST.get("email", "").strip() email = request.POST.get("email", "").strip()
password = request.POST.get("password", "").strip() password = request.POST.get("password", "").strip()

View File

@ -218,6 +218,12 @@
<input type="hidden" name="next" value="{{ next }}" /> <input type="hidden" name="next" value="{{ next }}" />
{% if CAP_ENABLED %}
<cap-widget
data-cap-api-endpoint="{{ CAP_API_BASE }}/{{ CAP_SITE_KEY }}/"
></cap-widget>
{% endif %}
<!-- ToS and Academic Use Notice --> <!-- ToS and Academic Use Notice -->
<div class="text-xs text-base-content/70 mt-2"> <div class="text-xs text-base-content/70 mt-2">
<p> <p>
@ -233,7 +239,6 @@
enviPath is free for academic and non-commercial use only. enviPath is free for academic and non-commercial use only.
</p> </p>
</div> </div>
<button type="submit" name="confirmsignup" class="btn btn-success w-full"> <button type="submit" name="confirmsignup" class="btn btn-success w-full">
Sign Up Sign Up
</button> </button>

View File

@ -19,7 +19,16 @@
type="text/css" type="text/css"
/> />
{% block extra_styles %}{% endblock %} {% if CAP_ENABLED %}
<script src="https://cdn.jsdelivr.net/npm/@cap.js/widget@0.1.41/cap.min.js"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@cap.js/widget@0.1.41/src/cap.min.css"
/>
{% endif %}
{% block extra_styles %}
{% endblock %}
</head> </head>
<body class="bg-base-100"> <body class="bg-base-100">
<div class="flex h-screen"> <div class="flex h-screen">