From cc6af53359a8cc376aec8f029eaf011b4bf65060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20A=2E=20S=C3=A1nchez=20L=C3=B3pez?= Date: Thu, 17 Mar 2011 10:38:32 +0000 Subject: [PATCH] Require submission hash in the url to perfom edit/post/cancel actions as a non secretariat user. See #618 - Legacy-Id: 2889 --- ietf/submit/models.py | 15 ++++++++ ietf/submit/urls.py | 3 ++ ietf/submit/views.py | 50 ++++++++++++++++++------- ietf/templates/submit/draft_status.html | 10 ++++- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/ietf/submit/models.py b/ietf/submit/models.py index 6f6eeae75..69fbd66a3 100644 --- a/ietf/submit/models.py +++ b/ietf/submit/models.py @@ -1,4 +1,6 @@ +from django.conf import settings from django.db import models +from django.utils.hashcompat import md5_constructor from ietf.idtracker.models import IETFWG @@ -46,6 +48,19 @@ class IdSubmissionDetail(models.Model): class Meta: db_table = 'id_submission_detail' + def create_hash(self): + self.submission_hash = md5_constructor(settings.SECRET_KEY + self.filename).hexdigest() + + def get_hash(self): + if not self.submission_hash: + create_hash() + self.save() + return self.submission_hash + +def create_submission_hash(sender, instance, **kwargs): + instance.create_hash() + +models.signals.pre_save.connect(create_submission_hash, sender=IdSubmissionDetail) class IdApprovedDetail(models.Model): id = models.AutoField(primary_key=True) diff --git a/ietf/submit/urls.py b/ietf/submit/urls.py index 7e39c6d92..44d312bb0 100644 --- a/ietf/submit/urls.py +++ b/ietf/submit/urls.py @@ -10,6 +10,9 @@ urlpatterns = patterns('ietf.submit.views', url(r'^status/(?P\d+)/cancel/$', 'draft_cancel', name='draft_cancel'), url(r'^status/(?P\d+)/approve/$', 'draft_approve', name='draft_approve'), url(r'^status/(?P\d+)/force/$', 'draft_force', name='draft_force'), + url(r'^status/(?P\d+)/(?P[a-f\d]+)/$', 'draft_status', name='draft_status_by_hash'), + url(r'^status/(?P\d+)/(?P[a-f\d]+)/cancel/$', 'draft_cancel', name='draft_cancel_by_hash'), + url(r'^status/(?P\d+)/(?P[a-f\d]+)/edit/$', 'draft_edit', name='draft_edit_by_hash'), ) urlpatterns += patterns('django.views.generic.simple', diff --git a/ietf/submit/views.py b/ietf/submit/views.py index f174c8ca8..f951d0e4f 100644 --- a/ietf/submit/views.py +++ b/ietf/submit/views.py @@ -23,7 +23,7 @@ def submit_index(request): form = UploadForm(request=request, data=request.POST, files=request.FILES) if form.is_valid(): submit = form.save() - return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id})) + return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id, 'submission_hash': submit.get_hash()})) else: form = UploadForm(request=request) return render_to_response('submit/submit_index.html', @@ -37,7 +37,7 @@ def submit_status(request): filename = None if request.method == 'POST': filename = request.POST.get('filename', '') - detail = IdSubmissionDetail.objects.filter(filename=filename) + detail = IdSubmissionDetail.objects.filter(filename=filename).order_by('-pk') if detail: return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail[0].submission_id})) error = 'No valid history found for %s' % filename @@ -65,22 +65,35 @@ def _can_force_post(user, detail): return True return False -def _can_cancel(user, detail): - if detail.status_id == UPLOADED: +def _can_cancel(user, detail, submission_hash): + if detail.status_id in [CANCELED, POSTED]: + return None + if is_secretariat(user): return True - if is_secretariat(user) and detail.status_id not in [CANCELED, POSTED]: + if submission_hash and detail.get_hash() == submission_hash: return True return False -def draft_status(request, submission_id, message=None): +def _can_edit(user, detail, submission_hash): + if detail.status_id != 'UPLOADED': + return None + if is_secretariat(user): + return True + if submission_hash and detail.get_hash() == submission_hash: + return True + return False + +def draft_status(request, submission_id, submission_hash=None, message=None): detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id) + if submission_hash and not detail.get_hash() == submission_hash: + raise Http404 validation = DraftValidation(detail) is_valid = validation.is_valid() status = None - allow_edit = True + allow_edit = _can_edit(request.user, detail, submission_hash) can_force_post = _can_force_post(request.user, detail) can_approve = _can_approve(request.user, detail) - can_cancel = _can_cancel(request.user, detail) + can_cancel = _can_cancel(request.user, detail, submission_hash) if detail.status_id != UPLOADED: if detail.status_id == CANCELED: message = ('error', 'This submission has been canceled, modification is no longer possible') @@ -120,7 +133,7 @@ def draft_status(request, submission_id, message=None): status = detail.status can_force_post = _can_force_post(request.user, detail) can_approve = _can_approve(request.user, detail) - can_cancel = _can_cancel(request.user, detail) + can_cancel = _can_cancel(request.user, detail, submission_hash) allow_edit = False message = ('success', 'Your submission is pending of email authentication. An email has been sent you with instructions') else: @@ -139,22 +152,31 @@ def draft_status(request, submission_id, message=None): 'can_force_post': can_force_post, 'can_approve': can_approve, 'can_cancel': can_cancel, + 'submission_hash': submission_hash, }, context_instance=RequestContext(request)) -def draft_cancel(request, submission_id): +def draft_cancel(request, submission_id, submission_hash=None): detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id) + can_cancel = _can_cancel(request.user, detail, submission_hash) + if not can_cancel: + if can_cancel == None: + raise Http404 + return HttpResponseForbidden('You have no permission to perform this action') detail.status_id = CANCELED detail.save() remove_docs(detail) return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id})) -def draft_edit(request, submission_id): +def draft_edit(request, submission_id, submission_hash=None): detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id) - if detail.status_id != UPLOADED: - raise Http404 + can_edit = _can_edit(request.user, detail, submission_hash) + if not can_edit: + if can_edit == None: + raise Http404 + return HttpResponseForbidden('You have no permission to perform this action') validation = DraftValidation(detail) validation.validate_wg() if request.method == 'POST': @@ -183,7 +205,7 @@ def draft_confirm(request, submission_id, auth_key): else: message = ('success', 'Authorization key accepted. Auto-Post complete') perform_post(detail) - return draft_status(request, submission_id, message) + return draft_status(request, submission_id, message=message) def draft_approve(request, submission_id, check_function=_can_approve): diff --git a/ietf/templates/submit/draft_status.html b/ietf/templates/submit/draft_status.html index 6ee28c0b9..93243b33d 100644 --- a/ietf/templates/submit/draft_status.html +++ b/ietf/templates/submit/draft_status.html @@ -21,12 +21,20 @@ pre.twopages { margin: 0px; } {% block pagehead %} +{% if can_cancel %} +{% endif %} +