|
6 | 6 | import webauthn
|
7 | 7 | from django import forms
|
8 | 8 | from django.conf import settings
|
| 9 | +from django.contrib.auth import authenticate |
9 | 10 | from django.contrib.auth.forms import AuthenticationForm
|
10 | 11 | from django.contrib.auth.models import User
|
11 | 12 | from django.core.exceptions import ValidationError
|
|
47 | 48 | }
|
48 | 49 |
|
49 | 50 |
|
| 51 | +def get_client_ip(request): |
| 52 | + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') |
| 53 | + if x_forwarded_for: |
| 54 | + ip = x_forwarded_for.split(',')[0] |
| 55 | + else: |
| 56 | + ip = request.META.get('REMOTE_ADDR') |
| 57 | + return ip |
| 58 | + |
| 59 | + |
50 | 60 | class ProfileForm(ModelForm):
|
51 | 61 | if newsletter_id is not None:
|
52 | 62 | newsletter = forms.BooleanField(label=_('Subscribe to contest updates'), initial=False, required=False)
|
@@ -428,13 +438,37 @@ def _has_social_auth(self, key):
|
428 | 438 | getattr(settings, 'SOCIAL_AUTH_%s_SECRET' % key, None))
|
429 | 439 |
|
430 | 440 | def clean(self):
|
431 |
| - username = self.cleaned_data.get('username') |
| 441 | + is_ip_login = self.request.POST.get('ip-login', 'false') == 'true' |
| 442 | + |
432 | 443 | try:
|
433 |
| - user = User.objects.get(username=username) |
434 |
| - except User.DoesNotExist: |
| 444 | + if is_ip_login: |
| 445 | + ip = get_client_ip(self.request) |
| 446 | + user = Profile.objects.filter(ip=ip).select_related('user').first().user |
| 447 | + else: |
| 448 | + username = self.cleaned_data.get('username') |
| 449 | + user = User.objects.get(username=username) |
| 450 | + except (Profile.DoesNotExist, User.DoesNotExist): |
435 | 451 | user = None
|
| 452 | + |
436 | 453 | if user is not None:
|
437 | 454 | self.confirm_login_allowed(user)
|
| 455 | + |
| 456 | + if is_ip_login: |
| 457 | + # a hack to remove the username/password errors, since we don't need them |
| 458 | + del self.errors['username'] |
| 459 | + del self.errors['password'] |
| 460 | + |
| 461 | + # set the password to the user's password to pass the form_valid check |
| 462 | + self.cleaned_data['password'] = user.password |
| 463 | + |
| 464 | + # super.clean() will skip the check, since there is no username/password when logging in by IP address, |
| 465 | + # so this is a hack to process that manually |
| 466 | + self.user_cache = authenticate(self.request, ip_address=ip) |
| 467 | + if self.user_cache is None: |
| 468 | + raise self.get_invalid_login_error() |
| 469 | + else: |
| 470 | + self.confirm_login_allowed(self.user_cache) |
| 471 | + |
438 | 472 | return super(CustomAuthenticationForm, self).clean()
|
439 | 473 |
|
440 | 474 | def confirm_login_allowed(self, user):
|
|
0 commit comments