Add csrf token checks to team join/leave as well as event attending views. Fixes #96

This commit is contained in:
Michael Hall 2018-07-07 12:06:01 -04:00
commit f720f626eb
5 changed files with 36 additions and 11 deletions

View file

@ -1,5 +1,8 @@
import re
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 = '-_~'
@ -19,3 +22,18 @@ def slugify(s, ok=SLUG_OK, lower=True, spaces=False):
new = re.sub('[-\s]+', '-', 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

View file

@ -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.profiles import Team, UserProfile, Member, Sponsor, SponsorSerializer
from .forms import EventCommentForm
from .utils import verify_csrf
import simplejson
@ -104,7 +105,9 @@ def sponsor_list(request):
return Response(serializer.data)
@verify_csrf(token_key='csrftoken')
def join_team(request, team_id):
if request.user.is_anonymous:
messages.add_message(request, messages.WARNING, message=_('You must be logged in to join a team.'))
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!'))
return redirect('show-team', team_id=team_id)
@verify_csrf(token_key='csrftoken')
def leave_team(request, team_id):
if request.user.is_anonymous:
messages.add_message(request, messages.WARNING, message=_('You must be logged in to leave a team.'))

View file

@ -124,13 +124,13 @@
{% endif %}
{% if not is_attending %}
<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">
<span class="sr-only">Attendance options</span>
</button>
<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=no">No</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&csrftoken={{csrf_token}}">No</a>
</div>
</div>
{% endif %}
@ -287,20 +287,20 @@
{% 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>
<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=no">No</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&csrftoken={{csrf_token}}">No</a>
</div>
{% 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>
<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=no">No</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&csrftoken={{csrf_token}}">No</a>
</div>
{% 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>
<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=maybe">Maybe</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&csrftoken={{csrf_token}}">Maybe</a>
</div>
{% endif %}
{% else %}

View file

@ -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>
{% endif %}
{% 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 %}
<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 %}
<hr/>

View file

@ -43,6 +43,7 @@ from events.forms import (
SponsorForm,
)
from events import location
from events.utils import verify_csrf
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):
event = get_object_or_404(Event, id=event_id)
if request.user.is_anonymous: