Add csrf checks to join/leave team and event attending status. Fixes #96
This commit is contained in:
parent
2951309f9c
commit
ac62b76c18
5 changed files with 36 additions and 11 deletions
|
@ -1,5 +1,8 @@
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
from django.middleware.csrf import _sanitize_token, _compare_salted_tokens
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
SLUG_OK = '-_~'
|
SLUG_OK = '-_~'
|
||||||
|
|
||||||
|
@ -19,3 +22,18 @@ def slugify(s, ok=SLUG_OK, lower=True, spaces=False):
|
||||||
new = re.sub('[-\s]+', '-', new)
|
new = re.sub('[-\s]+', '-', new)
|
||||||
return new.lower() if lower else new
|
return new.lower() if lower else new
|
||||||
|
|
||||||
|
|
||||||
|
def verify_csrf(token_key='csrftoken'):
|
||||||
|
|
||||||
|
def wrap_view(view_func):
|
||||||
|
def check_csrf_token(request, *args, **kwargs):
|
||||||
|
csrf_token = _sanitize_token(request.GET.get(token_key, ''))
|
||||||
|
match = _compare_salted_tokens(csrf_token, request.COOKIES[settings.CSRF_COOKIE_NAME])
|
||||||
|
if not match:
|
||||||
|
raise PermissionDenied
|
||||||
|
else:
|
||||||
|
return view_func(request, *args, **kwargs)
|
||||||
|
|
||||||
|
return check_csrf_token
|
||||||
|
return wrap_view
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from .models.events import Event, EventComment, Place, PlaceSerializer, Attendee
|
||||||
from .models.locale import Country ,CountrySerializer, SPR, SPRSerializer, City, CitySerializer
|
from .models.locale import Country ,CountrySerializer, SPR, SPRSerializer, City, CitySerializer
|
||||||
from .models.profiles import Team, UserProfile, Member, Sponsor, SponsorSerializer
|
from .models.profiles import Team, UserProfile, Member, Sponsor, SponsorSerializer
|
||||||
from .forms import EventCommentForm
|
from .forms import EventCommentForm
|
||||||
|
from .utils import verify_csrf
|
||||||
|
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
|
@ -104,7 +105,9 @@ def sponsor_list(request):
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
@verify_csrf(token_key='csrftoken')
|
||||||
def join_team(request, team_id):
|
def join_team(request, team_id):
|
||||||
|
|
||||||
if request.user.is_anonymous:
|
if request.user.is_anonymous:
|
||||||
messages.add_message(request, messages.WARNING, message=_('You must be logged in to join a team.'))
|
messages.add_message(request, messages.WARNING, message=_('You must be logged in to join a team.'))
|
||||||
return redirect('show-team', team_id=team_id)
|
return redirect('show-team', team_id=team_id)
|
||||||
|
@ -116,6 +119,8 @@ def join_team(request, team_id):
|
||||||
messages.add_message(request, messages.SUCCESS, message=_('Welcome to the team!'))
|
messages.add_message(request, messages.SUCCESS, message=_('Welcome to the team!'))
|
||||||
return redirect('show-team', team_id=team_id)
|
return redirect('show-team', team_id=team_id)
|
||||||
|
|
||||||
|
|
||||||
|
@verify_csrf(token_key='csrftoken')
|
||||||
def leave_team(request, team_id):
|
def leave_team(request, team_id):
|
||||||
if request.user.is_anonymous:
|
if request.user.is_anonymous:
|
||||||
messages.add_message(request, messages.WARNING, message=_('You must be logged in to leave a team.'))
|
messages.add_message(request, messages.WARNING, message=_('You must be logged in to leave a team.'))
|
||||||
|
|
|
@ -124,13 +124,13 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not is_attending %}
|
{% if not is_attending %}
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="{% url 'attend-event' event.id %}" class="btn btn-success btn-sm"><i class="fa fa-check-square-o"></i> Attend</a>
|
<a href="{% url 'attend-event' event.id %}?csrftoken={{csrf_token}}" class="btn btn-success btn-sm"><i class="fa fa-check-square-o"></i> Attend</a>
|
||||||
<button type="button" class="btn btn-success btn-sm dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button type="button" class="btn btn-success btn-sm dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="sr-only">Attendance options</span>
|
<span class="sr-only">Attendance options</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe">Maybe</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe&csrftoken={{csrf_token}}">Maybe</a>
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no">No</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no&csrftoken={{csrf_token}}">No</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -287,20 +287,20 @@
|
||||||
{% if attendee.status == attendee.YES %}
|
{% if attendee.status == attendee.YES %}
|
||||||
<span class="badge badge-success dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
<span class="badge badge-success dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe">Maybe</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe&csrftoken={{csrf_token}}">Maybe</a>
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no">No</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no&csrftoken={{csrf_token}}">No</a>
|
||||||
</div>
|
</div>
|
||||||
{% elif attendee.status == attendee.MAYBE %}
|
{% elif attendee.status == attendee.MAYBE %}
|
||||||
<span class="badge badge-default dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
<span class="badge badge-default dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=yes">Yes</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=yes&csrftoken={{csrf_token}}">Yes</a>
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no">No</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=no&csrftoken={{csrf_token}}">No</a>
|
||||||
</div>
|
</div>
|
||||||
{% elif attendee.status == attendee.NO %}
|
{% elif attendee.status == attendee.NO %}
|
||||||
<span class="badge badge-danger dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
<span class="badge badge-danger dropdown-toggle align-top" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ attendee.status_name }}</span>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=yes">Yes</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=yes&csrftoken={{csrf_token}}">Yes</a>
|
||||||
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe">Maybe</a>
|
<a class="dropdown-item" href="{% url 'attend-event' event.id %}?response=maybe&csrftoken={{csrf_token}}">Maybe</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
<a href="{% url 'manage-members' team.id %}" class="btn btn-secondary btn-sm"><i class="fa fa-users"></i> Manage Members</a>
|
<a href="{% url 'manage-members' team.id %}" class="btn btn-secondary btn-sm"><i class="fa fa-users"></i> Manage Members</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_member %}
|
{% if is_member %}
|
||||||
{% if not team.owner_profile == request.user.profile %}<a href="{% url 'leave-team' team.id %}" class="btn btn-danger btn-sm">Leave Team</a>{% endif %}
|
{% if not team.owner_profile == request.user.profile %}<a href="{% url 'leave-team' team.id %}?csrftoken={{csrf_token}}" class="btn btn-danger btn-sm">Leave Team</a>{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'join-team' team.id %}" class="btn btn-success btn-sm">Join Team</a>
|
<a href="{% url 'join-team' team.id %}?csrftoken={{csrf_token}}" class="btn btn-success btn-sm">Join Team</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ from events.forms import (
|
||||||
SponsorForm,
|
SponsorForm,
|
||||||
)
|
)
|
||||||
from events import location
|
from events import location
|
||||||
|
from events.utils import verify_csrf
|
||||||
|
|
||||||
from accounts.models import EmailRecord
|
from accounts.models import EmailRecord
|
||||||
|
|
||||||
|
@ -421,6 +422,7 @@ def contact_attendee(attendee, body, sender):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@verify_csrf(token_key='csrftoken')
|
||||||
def attend_event(request, event_id):
|
def attend_event(request, event_id):
|
||||||
event = get_object_or_404(Event, id=event_id)
|
event = get_object_or_404(Event, id=event_id)
|
||||||
if request.user.is_anonymous:
|
if request.user.is_anonymous:
|
||||||
|
|
Loading…
Reference in a new issue