Skip to content

Commit 63d78ed

Browse files
committed
DoS Tresholds. Retrieve WG in a previous stage. Fixes ietf-tools#592
- Legacy-Id: 2837
1 parent 6aa16f2 commit 63d78ed

6 files changed

Lines changed: 109 additions & 29 deletions

File tree

ietf/settings.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,15 @@
197197
IDNITS_PATH = '/a/www/ietf-datatracker/release/idnits'
198198
MAX_PLAIN_DRAFT_SIZE = 6291456 # Max size of the txt draft in bytes
199199

200+
# DOS THRESHOLDS PER DAY (Sizes are in MB)
201+
MAX_SAME_DRAFT_NAME = 20
202+
MAX_SAME_DRAFT_NAME_SIZE = 50
203+
MAX_SAME_SUBMITTER = 50
204+
MAX_SAME_SUBMITTER_SIZE = 150
205+
MAX_SAME_WG_DRAFT = 150
206+
MAX_SAME_WG_DRAFT_SIZE = 450
207+
MAX_DAILY_SUBMISSION = 1000
208+
MAX_DAILY_SUBMISSION_SIZE = 2000
200209
# End of ID Submission Tool settings
201210

202211
# Put SECRET_KEY in here, or any other sensitive or site-specific

ietf/submit/forms.py

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from django import forms
66
from django.conf import settings
77
from django.template.loader import render_to_string
8+
from django.utils.html import mark_safe
89

9-
from ietf.idtracker.models import InternetDraft
10+
from ietf.idtracker.models import InternetDraft, IETFWG
1011
from ietf.proceedings.models import Meeting
1112
from ietf.submit.models import IdSubmissionDetail, TempIdAuthors
1213
from ietf.submit.parsers.pdf_parser import PDFParser
@@ -32,16 +33,19 @@ class Media:
3233
css = {'all': ("/css/liaisons.css", )}
3334

3435
def __init__(self, *args, **kwargs):
36+
self.request=kwargs.pop('request', None)
37+
self.remote_ip=self.request.META.get('REMOTE_ADDR', None)
3538
super(UploadForm, self).__init__(*args, **kwargs)
3639
self.in_first_cut_off = False
3740
self.idnits_message = None
3841
self.shutdown = False
3942
self.draft = None
4043
self.filesize = None
44+
self.group = None
4145
self.read_dates()
4246

4347
def read_dates(self):
44-
now = datetime.datetime.now()
48+
now = datetime.datetime.utcnow()
4549
first_cut_off = Meeting.get_first_cut_off()
4650
second_cut_off = Meeting.get_second_cut_off()
4751
ietf_monday = Meeting.get_ietf_monday()
@@ -120,6 +124,51 @@ def clean_xml(self):
120124
def clean(self):
121125
if self.shutdown:
122126
raise forms.ValidationError('The tool is shut down')
127+
self.check_paths()
128+
if self.cleaned_data.get('txt', None):
129+
self.get_draft()
130+
self.group=self.get_working_group()
131+
self.check_previous_submission()
132+
self.check_tresholds()
133+
return super(UploadForm, self).clean()
134+
135+
def check_tresholds(self):
136+
filename = self.draft.filename
137+
revision = self.draft.revision
138+
remote_ip = self.remote_ip
139+
today = datetime.date.today()
140+
141+
# Same draft by name
142+
same_name = IdSubmissionDetail.objects.filter(filename=filename, revision=revision, submission_date=today)
143+
if same_name.count() > settings.MAX_SAME_DRAFT_NAME:
144+
raise forms.ValidationError('A same I-D cannot be submitted more than %s times a day' % settings.MAX_SAME_DRAFT_NAME)
145+
if sum([i.filesize for i in same_name]) > (settings.MAX_SAME_DRAFT_NAME_SIZE * 1048576):
146+
raise forms.ValidationError('A same I-D submission cannot exceed more than %s MByte a day' % settings.MAX_SAME_DRAFT_NAME_SIZE)
147+
148+
# Total from same ip
149+
same_ip = IdSubmissionDetail.objects.filter(remote_ip=remote_ip, submission_date=today)
150+
if same_ip.count() > settings.MAX_SAME_SUBMITTER:
151+
raise forms.ValidationError('The same submitter cannot submit more than %s I-Ds a day' % settings.MAX_SAME_SUBMITTER)
152+
if sum([i.filesize for i in same_ip]) > (settings.MAX_SAME_SUBMITTER_SIZE * 1048576):
153+
raise forms.ValidationError('The same submitter cannot exceed more than %s MByte a day' % settings.MAX_SAME_SUBMITTER_SIZE)
154+
155+
# Total in same group
156+
if self.group:
157+
same_group = IdSubmissionDetail.objects.filter(group_acronym=self.group, submission_date=today)
158+
if same_group.count() > settings.MAX_SAME_WG_DRAFT:
159+
raise forms.ValidationError('A same working group I-Ds cannot be submitted more than %s times a day' % settings.MAX_SAME_WG_DRAFT)
160+
if sum([i.filesize for i in same_group]) > (settings.MAX_SAME_WG_DRAFT_SIZE * 1048576):
161+
raise forms.ValidationError('Total size of same working group I-Ds cannot exceed %s MByte a day' % settings.MAX_SAME_WG_DRAFT_SIZE)
162+
163+
164+
# Total drafts for today
165+
total_today = IdSubmissionDetail.objects.filter(submission_date=today)
166+
if total_today.count() > settings.MAX_DAILY_SUBMISSION:
167+
raise forms.ValidationError('The total number of today\'s submission has reached the maximum number of submission per day')
168+
if sum([i.filesize for i in total_today]) > (settings.MAX_DAILY_SUBMISSION_SIZE * 1048576):
169+
raise forms.ValidationError('The total size of today\'s submission has reached the maximum size of submission per day')
170+
171+
def check_paths(self):
123172
self.staging_path = getattr(settings, 'STAGING_PATH', None)
124173
self.idnits = getattr(settings, 'IDNITS_PATH', None)
125174
if not self.staging_path:
@@ -130,18 +179,14 @@ def clean(self):
130179
raise forms.ValidationError('IDNITS_PATH not defined on settings.py')
131180
if not os.path.exists(self.idnits):
132181
raise forms.ValidationError('IDNITS_PATH defined on settings.py does not exist')
133-
if self.cleaned_data.get('txt', None):
134-
self.get_draft()
135-
self.check_previous_submission()
136-
return super(UploadForm, self).clean()
137182

138183
def check_previous_submission(self):
139184
filename = self.draft.filename
140185
revision = self.draft.revision
141186
existing = IdSubmissionDetail.objects.filter(filename=filename, revision=revision,
142187
status__pk__gte=0, status__pk__lt=100)
143188
if existing:
144-
raise forms.ValidationError('Duplicate Internet-Draft submission is currently in process.')
189+
raise forms.ValidationError('Duplicate Internet-Draft submission is currently in process')
145190

146191
def get_draft(self):
147192
if self.draft:
@@ -170,6 +215,29 @@ def check_idnits(self):
170215
p = subprocess.Popen([self.idnits, '--submitcheck', '--nitcount', filepath], stdout=subprocess.PIPE)
171216
self.idnits_message = p.stdout.read()
172217

218+
def get_working_group(self):
219+
filename = self.draft.filename
220+
existing_draft = InternetDraft.objects.filter(filename=filename)
221+
if existing_draft:
222+
group = existing_draft[0].group and existing_draft[0].group.ietfwg or None
223+
if group and group.pk != 1027:
224+
return group
225+
else:
226+
return None
227+
else:
228+
if filename.startswith('draft-ietf-'):
229+
# Extra check for WG that contains dashes
230+
for group in IETFWG.objects.filter(group_acronym__acronym__contains='-'):
231+
if filename.startswith('draft-ietf-%s-' % group.group_acronym.acronym):
232+
return group
233+
group_acronym = filename.split('-')[2]
234+
try:
235+
return IETFWG.objects.get(group_acronym__acronym=group_acronym)
236+
except IETFWG.DoesNotExist:
237+
raise forms.ValidationError('There is no active group with acronym \'%s\', please rename your draft' % group_acronym)
238+
else:
239+
return None
240+
173241
def save_draft_info(self, draft):
174242
document_id = 0
175243
existing_draft = InternetDraft.objects.filter(filename=draft.filename)
@@ -185,6 +253,8 @@ def save_draft_info(self, draft):
185253
submission_date=datetime.date.today(),
186254
idnits_message=self.idnits_message,
187255
temp_id_document_tag=document_id,
256+
group_acronym=self.group,
257+
remote_ip=self.remote_ip,
188258
first_two_pages=''.join(draft.pages[:2]),
189259
status_id=1, # Status 1 - upload
190260
)

ietf/submit/models.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
from django.db import models
22

3+
from ietf.idtracker.models import IETFWG
4+
5+
36
class IdSubmissionStatus(models.Model):
47
status_id = models.IntegerField(primary_key=True)
58
status_value = models.CharField(blank=True, max_length=255)
69

710
class Meta:
811
db_table = 'id_submission_status'
912

13+
1014
class IdSubmissionDetail(models.Model):
1115
submission_id = models.AutoField(primary_key=True)
1216
temp_id_document_tag = models.IntegerField(null=True, blank=True)
1317
status = models.ForeignKey(IdSubmissionStatus, db_column='status_id', null=True, blank=True)
1418
last_updated_date = models.DateField(null=True, blank=True)
1519
last_updated_time = models.CharField(blank=True, max_length=25)
1620
id_document_name = models.CharField(blank=True, max_length=255)
17-
group_acronym_id = models.IntegerField(null=True, blank=True)
21+
group_acronym = models.ForeignKey(IETFWG, null=True, blank=True)
1822
filename = models.CharField(blank=True, max_length=255)
1923
creation_date = models.DateField(null=True, blank=True)
2024
submission_date = models.DateField(null=True, blank=True)
@@ -41,6 +45,7 @@ class IdSubmissionDetail(models.Model):
4145
class Meta:
4246
db_table = 'id_submission_detail'
4347

48+
4449
class TempIdAuthors(models.Model):
4550
id = models.AutoField(primary_key=True)
4651
id_document_tag = models.IntegerField()

ietf/submit/utils.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
import datetime
23

34
from ietf.idtracker.models import InternetDraft, EmailAddress
45

@@ -17,24 +18,9 @@ def passes_idnits(self):
1718
return passes_idnits
1819

1920
def get_working_group(self):
20-
filename = self.draft.filename
21-
existing_draft = InternetDraft.objects.filter(filename=filename)
22-
if existing_draft:
23-
return existing_draft[0].group and existing_draft[0].group.ietfwg or None
24-
else:
25-
if filename.startswith('draft-ietf-'):
26-
# Extra check for WG that contains dashes
27-
for group in IETFWG.objects.filter(group_acronym__acronym__contains='-'):
28-
if filename.startswith('draft-ietf-%s-' % group.group_acronym.acronym):
29-
return group
30-
group_acronym = filename.split('-')[2]
31-
try:
32-
return IETFWG.objects.get(group_acronym__acronym=group_acronym)
33-
except IETFWG.DoesNotExist:
34-
self.add_warning('group', 'Invalid WG ID: %s' % group_acronym)
35-
return None
36-
else:
37-
return None
21+
if self.draft.group_acronym and self.draft.group_acronym.pk == 1027:
22+
return None
23+
return self.draft.group_acronym
3824

3925
def check_idnits_success(self, idnits_message):
4026
success_re = re.compile('\s+Summary:\s+0\s+|No nits found')
@@ -54,6 +40,7 @@ def is_valid(self):
5440
def validate_metadata(self):
5541
self.validate_revision()
5642
self.validate_authors()
43+
self.validate_creation_date()
5744

5845
def add_warning(self, key, value):
5946
self.warnings.update({key: value})
@@ -71,6 +58,15 @@ def validate_authors(self):
7158
if not self.authors:
7259
self.add_warning('authors', 'No authors found')
7360

61+
def validate_creation_date(self):
62+
date = self.draft.creation_date
63+
if not date:
64+
self.add_warning('creation_date', 'Creation Date field is empty or the creation date is not in a proper format.')
65+
return
66+
submit_date = self.draft.submission_date
67+
if date + datetime.timedelta(days=3) > submit_date:
68+
self.add_warning('creation_date', 'Creation Date must be within 3 days of submission date.')
69+
7470
def get_authors(self):
7571
tmpauthors = self.draft.tempidauthors_set.all().order_by('author_order')
7672
authors = []

ietf/submit/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
def submit_index(request):
1414
if request.method == 'POST':
15-
form = UploadForm(data=request.POST, files=request.FILES)
15+
form = UploadForm(request=request, data=request.POST, files=request.FILES)
1616
if form.is_valid():
1717
submit = form.save()
1818
return HttpResponseRedirect(reverse(draft_status, None, kwargs={'submission_id': submit.submission_id}))
1919
else:
20-
form = UploadForm()
20+
form = UploadForm(request=request)
2121
return render_to_response('submit/submit_index.html',
2222
{'selected': 'index',
2323
'form': form},

ietf/templates/submit/draft_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ <h3>Meta-Data errors found</h3>
114114
<tr{% if validation.warnings.revision %} class="warning"{% endif %}><th>Revision</th><td>{{ detail.revision }}<div class="warn_message">{{ validation.warnings.revision }}</div></td></tr>
115115
<tr><th>Submission date</th><td>{{ detail.submission_date }}</td></tr>
116116
<tr><th>Title</th><td>{{ detail.id_document_name }}</td></tr>
117-
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"" }}<div class="warn_message">{{ validation.warnings.group }}</td></tr>
117+
<tr{% if validation.warnings.group %} class="warning"{% endif %}><th>WG</th><td>{{ validation.wg|default:"Individual Submission" }}<div class="warn_message">{{ validation.warnings.group }}</td></tr>
118118
<tr><th>File size</th><td>{{ detail.filesize|filesizeformat }}</td></tr>
119119
<tr{% if validation.warnings.creation_date %} class="warning"{% endif %}><th>Creation date</th><td>{{ detail.creation_date }}<div class="warn_message">{{ validation.warnings.creation_date }}</td></tr>
120120
<tr{% if validation.warnings.authors %} class="warning"{% endif %}><th colspan="2">Author(s) information</th></tr>

0 commit comments

Comments
 (0)