Skip to content

Commit cc6af53

Browse files
committed
Require submission hash in the url to perfom edit/post/cancel actions as a non secretariat user. See ietf-tools#618
- Legacy-Id: 2889
1 parent be8fb66 commit cc6af53

4 files changed

Lines changed: 63 additions & 15 deletions

File tree

ietf/submit/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from django.conf import settings
12
from django.db import models
3+
from django.utils.hashcompat import md5_constructor
24

35
from ietf.idtracker.models import IETFWG
46

@@ -46,6 +48,19 @@ class IdSubmissionDetail(models.Model):
4648
class Meta:
4749
db_table = 'id_submission_detail'
4850

51+
def create_hash(self):
52+
self.submission_hash = md5_constructor(settings.SECRET_KEY + self.filename).hexdigest()
53+
54+
def get_hash(self):
55+
if not self.submission_hash:
56+
create_hash()
57+
self.save()
58+
return self.submission_hash
59+
60+
def create_submission_hash(sender, instance, **kwargs):
61+
instance.create_hash()
62+
63+
models.signals.pre_save.connect(create_submission_hash, sender=IdSubmissionDetail)
4964

5065
class IdApprovedDetail(models.Model):
5166
id = models.AutoField(primary_key=True)

ietf/submit/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
url(r'^status/(?P<submission_id>\d+)/cancel/$', 'draft_cancel', name='draft_cancel'),
1111
url(r'^status/(?P<submission_id>\d+)/approve/$', 'draft_approve', name='draft_approve'),
1212
url(r'^status/(?P<submission_id>\d+)/force/$', 'draft_force', name='draft_force'),
13+
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/$', 'draft_status', name='draft_status_by_hash'),
14+
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/cancel/$', 'draft_cancel', name='draft_cancel_by_hash'),
15+
url(r'^status/(?P<submission_id>\d+)/(?P<submission_hash>[a-f\d]+)/edit/$', 'draft_edit', name='draft_edit_by_hash'),
1316
)
1417

1518
urlpatterns += patterns('django.views.generic.simple',

ietf/submit/views.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def submit_index(request):
2323
form = UploadForm(request=request, data=request.POST, files=request.FILES)
2424
if form.is_valid():
2525
submit = form.save()
26-
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id}))
26+
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id, 'submission_hash': submit.get_hash()}))
2727
else:
2828
form = UploadForm(request=request)
2929
return render_to_response('submit/submit_index.html',
@@ -37,7 +37,7 @@ def submit_status(request):
3737
filename = None
3838
if request.method == 'POST':
3939
filename = request.POST.get('filename', '')
40-
detail = IdSubmissionDetail.objects.filter(filename=filename)
40+
detail = IdSubmissionDetail.objects.filter(filename=filename).order_by('-pk')
4141
if detail:
4242
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': detail[0].submission_id}))
4343
error = 'No valid history found for %s' % filename
@@ -65,22 +65,35 @@ def _can_force_post(user, detail):
6565
return True
6666
return False
6767

68-
def _can_cancel(user, detail):
69-
if detail.status_id == UPLOADED:
68+
def _can_cancel(user, detail, submission_hash):
69+
if detail.status_id in [CANCELED, POSTED]:
70+
return None
71+
if is_secretariat(user):
72+
return True
73+
if submission_hash and detail.get_hash() == submission_hash:
74+
return True
75+
return False
76+
77+
def _can_edit(user, detail, submission_hash):
78+
if detail.status_id != 'UPLOADED':
79+
return None
80+
if is_secretariat(user):
7081
return True
71-
if is_secretariat(user) and detail.status_id not in [CANCELED, POSTED]:
82+
if submission_hash and detail.get_hash() == submission_hash:
7283
return True
7384
return False
7485

75-
def draft_status(request, submission_id, message=None):
86+
def draft_status(request, submission_id, submission_hash=None, message=None):
7687
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
88+
if submission_hash and not detail.get_hash() == submission_hash:
89+
raise Http404
7790
validation = DraftValidation(detail)
7891
is_valid = validation.is_valid()
7992
status = None
80-
allow_edit = True
93+
allow_edit = _can_edit(request.user, detail, submission_hash)
8194
can_force_post = _can_force_post(request.user, detail)
8295
can_approve = _can_approve(request.user, detail)
83-
can_cancel = _can_cancel(request.user, detail)
96+
can_cancel = _can_cancel(request.user, detail, submission_hash)
8497
if detail.status_id != UPLOADED:
8598
if detail.status_id == CANCELED:
8699
message = ('error', 'This submission has been canceled, modification is no longer possible')
@@ -120,7 +133,7 @@ def draft_status(request, submission_id, message=None):
120133
status = detail.status
121134
can_force_post = _can_force_post(request.user, detail)
122135
can_approve = _can_approve(request.user, detail)
123-
can_cancel = _can_cancel(request.user, detail)
136+
can_cancel = _can_cancel(request.user, detail, submission_hash)
124137
allow_edit = False
125138
message = ('success', 'Your submission is pending of email authentication. An email has been sent you with instructions')
126139
else:
@@ -139,22 +152,31 @@ def draft_status(request, submission_id, message=None):
139152
'can_force_post': can_force_post,
140153
'can_approve': can_approve,
141154
'can_cancel': can_cancel,
155+
'submission_hash': submission_hash,
142156
},
143157
context_instance=RequestContext(request))
144158

145159

146-
def draft_cancel(request, submission_id):
160+
def draft_cancel(request, submission_id, submission_hash=None):
147161
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
162+
can_cancel = _can_cancel(request.user, detail, submission_hash)
163+
if not can_cancel:
164+
if can_cancel == None:
165+
raise Http404
166+
return HttpResponseForbidden('You have no permission to perform this action')
148167
detail.status_id = CANCELED
149168
detail.save()
150169
remove_docs(detail)
151170
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submission_id}))
152171

153172

154-
def draft_edit(request, submission_id):
173+
def draft_edit(request, submission_id, submission_hash=None):
155174
detail = get_object_or_404(IdSubmissionDetail, submission_id=submission_id)
156-
if detail.status_id != UPLOADED:
157-
raise Http404
175+
can_edit = _can_edit(request.user, detail, submission_hash)
176+
if not can_edit:
177+
if can_edit == None:
178+
raise Http404
179+
return HttpResponseForbidden('You have no permission to perform this action')
158180
validation = DraftValidation(detail)
159181
validation.validate_wg()
160182
if request.method == 'POST':
@@ -183,7 +205,7 @@ def draft_confirm(request, submission_id, auth_key):
183205
else:
184206
message = ('success', 'Authorization key accepted. Auto-Post complete')
185207
perform_post(detail)
186-
return draft_status(request, submission_id, message)
208+
return draft_status(request, submission_id, message=message)
187209

188210

189211
def draft_approve(request, submission_id, check_function=_can_approve):

ietf/templates/submit/draft_status.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,20 @@
2121

2222
{% block pagehead %}
2323
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
24+
{% if can_cancel %}
2425
<script type="text/javascript">
2526
function confirmCancelation(){
2627
{% if is_valid %}if (confirm("Cancel this submission?")){% endif %}
27-
document.location = "/submit/status/{{ detail.submission_id }}/cancel/";
28+
{% if submission_hash %}
29+
document.location = "{% url draft_cancel_by_hash detail.submission_id submission_hash %}";
30+
{% else %}
31+
document.location = "{% url draft_cancel detail.submission_id %}";
32+
{% endif %}
2833
}
34+
</script>
35+
{% endif %}
2936

37+
<script type="text/javascript">
3038
(function ($) {
3139

3240
$(document).ready(function () {

0 commit comments

Comments
 (0)