Private
Public Access
1
0
This commit is contained in:
2025-10-30 15:38:40 +01:00
parent 12eb7cb978
commit 4ce06f75a9
5 changed files with 43 additions and 9 deletions

View File

@@ -1066,7 +1066,8 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
month=4, month=4,
day=15)) day=15))
url = HoneypotField(label="URL") hp_field = HoneypotField(label="URL")
timestamp = forms.CharField(widget=forms.HiddenInput(), required=False)
def clean_birthdate(self): def clean_birthdate(self):
dob = self.cleaned_data['birthdate'] dob = self.cleaned_data['birthdate']
@@ -1087,6 +1088,22 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
adaptiveclass = forms.ChoiceField(label='Adaptive Classification', adaptiveclass = forms.ChoiceField(label='Adaptive Classification',
choices=adaptivecategories, initial='None', required=False) choices=adaptivecategories, initial='None', required=False)
captcha = ReCaptchaField(widget=ReCaptchaV3(
attrs={
'required_score': 0.85,
}))
def clean(self):
cleaned_data = super().clean()
timestamp = cleaned_data.get('timestamp')
if timestamp:
submission_time = timezone.now()
form_render_time = timezone.datetime.fromtimestamp(float(timestamp), tz=timezone.get_current_timezone())
if (submission_time - form_render_time).seconds < 3:
raise forms.ValidationError("Form submitted too quickly. Are you a bot?")
return cleaned_data
class PowerIntervalUpdateForm(forms.Form): class PowerIntervalUpdateForm(forms.Form):
selectorchoices = ( selectorchoices = (

View File

@@ -31,6 +31,8 @@
<table width=100%> <table width=100%>
{{ form.as_table }} {{ form.as_table }}
</table> </table>
<!-- Manually add the timestamp field -->
<input type="hidden" name="timestamp" value="{{ timestamp }}">
<p> <p>
<a href="/rowers/legal/">Terms of Service</a> <a href="/rowers/legal/">Terms of Service</a>
</p> </p>

View File

@@ -5,7 +5,8 @@ from __future__ import unicode_literals
#from __future__ import print_function #from __future__ import print_function
from .statements import * from .statements import *
from django_recaptcha.client import RecaptchaResponse
from django_recaptcha.fields import ReCaptchaField
nu = datetime.datetime.now() nu = datetime.datetime.now()
#@pytest.mark.django_db #@pytest.mark.django_db
@@ -22,7 +23,11 @@ class NewUserRegistrationTest(TestCase):
pass pass
@patch('rowers.dataprep.workout_summary_to_df',side_effect=mock_workout_summaries) @patch('rowers.dataprep.workout_summary_to_df',side_effect=mock_workout_summaries)
def test_newuser(self,mock_workout_summaries): @patch("django_recaptcha.fields.client.submit")
def test_newuser(self,mock_submit, mock_workout_summaries):
mock_response = RecaptchaResponse(is_valid=True, extra_data={'score': 0.95})
mock_submit.return_value = mock_response
form_data = { form_data = {
'first_name':'Jan', 'first_name':'Jan',
'last_name':'Roeiert', 'last_name':'Roeiert',
@@ -30,16 +35,21 @@ class NewUserRegistrationTest(TestCase):
'username':'janderoeiert', 'username':'janderoeiert',
'password1':'Aapindewei2', 'password1':'Aapindewei2',
'password2':'Aapindewei2', 'password2':'Aapindewei2',
'url': '', 'hp_field': '',
'tos':True, 'tos':True,
'weightcategory':'hwt', 'weightcategory':'hwt',
'adaptiveclass': 'None', 'adaptiveclass': 'None',
'sex':'male', 'sex':'male',
'captcha': 'PASSED',
'g-recaptcha-response': 'PASSED',
'next':'/rowers/list-workouts', 'next':'/rowers/list-workouts',
'birthdate':datetime.datetime(year=1970,month=4,day=2) 'birthdate':datetime.datetime(year=1970,month=4,day=2)
} }
form = RegistrationFormSex(form_data) form = RegistrationFormSex(form_data)
if not form.is_valid():
print(form.errors)
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
response = self.c.post('/rowers/register/', form_data, follow=True) response = self.c.post('/rowers/register/', form_data, follow=True)
@@ -118,7 +128,7 @@ class NewUserRegistrationTest(TestCase):
'password1':'aapindewei2', 'password1':'aapindewei2',
'password2':'aapindewei2', 'password2':'aapindewei2',
'tos':True, 'tos':True,
'url': '', 'hp_field': '',
'weightcategory':'hwt', 'weightcategory':'hwt',
'adaptiveclass': 'None', 'adaptiveclass': 'None',
'sex':'male', 'sex':'male',
@@ -126,6 +136,7 @@ class NewUserRegistrationTest(TestCase):
'birthdate':datetime.datetime(year=1970,month=4,day=2) 'birthdate':datetime.datetime(year=1970,month=4,day=2)
} }
form = RegistrationFormSex(form_data) form = RegistrationFormSex(form_data)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
@@ -138,7 +149,7 @@ class NewUserRegistrationTest(TestCase):
'username':'janderoeiert', 'username':'janderoeiert',
'password1':'Aapindewei2', 'password1':'Aapindewei2',
'password2':'Aapindewei2', 'password2':'Aapindewei2',
'url': 'http://example.com', 'hp_field': 'http://example.com',
'tos':True, 'tos':True,
'weightcategory':'hwt', 'weightcategory':'hwt',
'adaptiveclass': 'None', 'adaptiveclass': 'None',

Binary file not shown.

View File

@@ -5,6 +5,7 @@ from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.backends import ModelBackend
from rowers.views.statements import * from rowers.views.statements import *
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django_ratelimit.decorators import ratelimit
from rowers import credits from rowers import credits
@@ -888,6 +889,7 @@ def useractivate(request, uidb64, token): # pragma: no cover
# User registration # User registration
@ratelimit(key='ip', rate='5/h', method='POST')
def rower_register_view(request): def rower_register_view(request):
nextpage = request.GET.get('next', '/rowers/list-workouts/') nextpage = request.GET.get('next', '/rowers/list-workouts/')
@@ -896,7 +898,7 @@ def rower_register_view(request):
if request.method == 'POST': if request.method == 'POST':
# Check if honeypot was triggered (optional logging) # Check if honeypot was triggered (optional logging)
honeypot_value = request.POST.get('url', '') honeypot_value = request.POST.get('hp_field', '')
if honeypot_value: if honeypot_value:
# bot user, do not register # bot user, do not register
messages.error(request, "Registration failed. Please try again.") messages.error(request, "Registration failed. Please try again.")
@@ -985,13 +987,15 @@ def rower_register_view(request):
return render(request, return render(request,
"registration_form.html", "registration_form.html",
{'form': form, {'form': form,
'next': nextpage, }) 'next': nextpage,
'timestamp': timezone.now().timestamp(),})
else: else:
form = RegistrationFormSex() form = RegistrationFormSex()
return render(request, return render(request,
"registration_form.html", "registration_form.html",
{'form': form, {'form': form,
'next': nextpage, }) 'next': nextpage,
'timestamp': timezone.now().timestamp(),})
# User registration # User registration