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
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 typing import Any, Dict, List, Iterable
import requests
import nh3
from django.conf import settings as s
from django.contrib.auth import get_user_model
@ -147,6 +148,11 @@ def handler500(request):
def login(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":
context["title"] = "enviPath"
context["next"] = request.GET.get("next", "")
@ -224,6 +230,11 @@ def logout(request):
def register(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":
# Redirect to unified login page with signup tab
next_url = request.GET.get("next", "")
@ -238,6 +249,33 @@ def register(request):
if next := request.POST.get("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()
email = request.POST.get("email", "").strip()
password = request.POST.get("password", "").strip()

View File

@ -218,6 +218,12 @@
<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 -->
<div class="text-xs text-base-content/70 mt-2">
<p>
@ -233,7 +239,6 @@
enviPath is free for academic and non-commercial use only.
</p>
</div>
<button type="submit" name="confirmsignup" class="btn btn-success w-full">
Sign Up
</button>

View File

@ -19,7 +19,16 @@
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>
<body class="bg-base-100">
<div class="flex h-screen">