Improved the verification of submitted file extensions and mimetype.
- Legacy-Id: 9986
This commit is contained in:
parent
b751aeb29c
commit
6c253ee48b
1
bin/.gitignore
vendored
1
bin/.gitignore
vendored
|
@ -21,3 +21,4 @@
|
||||||
/ipcontroller*
|
/ipcontroller*
|
||||||
/ipengine*
|
/ipengine*
|
||||||
/iptest*
|
/iptest*
|
||||||
|
/xml2rfc
|
||||||
|
|
|
@ -130,7 +130,7 @@ class SubmissionUploadForm(forms.Form):
|
||||||
continue
|
continue
|
||||||
self.file_types.append('.%s' % ext)
|
self.file_types.append('.%s' % ext)
|
||||||
if not ('.txt' in self.file_types or '.xml' in self.file_types):
|
if not ('.txt' in self.file_types or '.xml' in self.file_types):
|
||||||
raise forms.ValidationError('You must submit either a .txt or an .xml file; didn\'t find either.')
|
raise forms.ValidationError('You must submit at least a valid .txt or a valid .xml file; didn\'t find either.')
|
||||||
|
|
||||||
#debug.show('self.cleaned_data["xml"]')
|
#debug.show('self.cleaned_data["xml"]')
|
||||||
if self.cleaned_data.get('xml'):
|
if self.cleaned_data.get('xml'):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import magic
|
import magic
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -40,6 +40,8 @@ class ParseInfo(object):
|
||||||
|
|
||||||
|
|
||||||
class FileParser(object):
|
class FileParser(object):
|
||||||
|
ext = None
|
||||||
|
mimetype = None
|
||||||
|
|
||||||
def __init__(self, fd):
|
def __init__(self, fd):
|
||||||
self.fd = fd
|
self.fd = fd
|
||||||
|
@ -50,6 +52,8 @@ class FileParser(object):
|
||||||
def critical_parse(self):
|
def critical_parse(self):
|
||||||
self.parse_invalid_chars_in_filename()
|
self.parse_invalid_chars_in_filename()
|
||||||
self.parse_max_size();
|
self.parse_max_size();
|
||||||
|
self.parse_filename_extension()
|
||||||
|
self.parse_file_type()
|
||||||
self.parsed_info.metadata.submission_date = datetime.date.today()
|
self.parsed_info.metadata.submission_date = datetime.date.today()
|
||||||
return self.parsed_info
|
return self.parsed_info
|
||||||
|
|
||||||
|
@ -61,20 +65,18 @@ class FileParser(object):
|
||||||
self.parsed_info.add_error('Invalid characters were found in the name of the file which was just submitted: %s' % ', '.join(set(chars)))
|
self.parsed_info.add_error('Invalid characters were found in the name of the file which was just submitted: %s' % ', '.join(set(chars)))
|
||||||
|
|
||||||
def parse_max_size(self):
|
def parse_max_size(self):
|
||||||
__, ext = os.path.splitext(self.fd.name)
|
max_size = settings.IDSUBMIT_MAX_DRAFT_SIZE[self.ext]
|
||||||
ext = ext.lstrip('.')
|
|
||||||
max_size = settings.IDSUBMIT_MAX_DRAFT_SIZE[ext]
|
|
||||||
if self.fd.size > max_size:
|
if self.fd.size > max_size:
|
||||||
self.parsed_info.add_error('File size is larger than the permitted maximum of %s' % filesizeformat(max_size))
|
self.parsed_info.add_error('File size is larger than the permitted maximum of %s' % filesizeformat(max_size))
|
||||||
self.parsed_info.metadata.file_size = self.fd.size
|
self.parsed_info.metadata.file_size = self.fd.size
|
||||||
|
|
||||||
def parse_filename_extension(self, ext):
|
def parse_filename_extension(self):
|
||||||
if not self.fd.name.lower().endswith('.'+ext):
|
if not self.fd.name.lower().endswith('.'+self.ext):
|
||||||
self.parsed_info.add_error('Expected the %s file to have extension ".%s", found "%s"' % (ext.upper(), ext, self.fd.name))
|
self.parsed_info.add_error('Expected the %s file to have extension ".%s", found the name "%s"' % (self.ext.upper(), self.ext, self.fd.name))
|
||||||
|
|
||||||
def parse_file_type(self, ext, expected):
|
def parse_file_type(self):
|
||||||
self.fd.file.seek(0)
|
self.fd.file.seek(0)
|
||||||
content = self.fd.file.read(4096)
|
content = self.fd.file.read(4096)
|
||||||
mimetype = magic.from_buffer(content, mime=True)
|
mimetype = magic.from_buffer(content, mime=True)
|
||||||
if not mimetype == expected:
|
if not mimetype == self.mimetype:
|
||||||
self.parsed_info.add_error('Expected an %s file of type "%s", found one of type "%s"' % (ext.upper(), expected, mimetype))
|
self.parsed_info.add_error('Expected an %s file of type "%s", found one of type "%s"' % (self.ext.upper(), self.mimetype, mimetype))
|
||||||
|
|
|
@ -2,11 +2,11 @@ from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
|
||||||
class PDFParser(FileParser):
|
class PDFParser(FileParser):
|
||||||
|
ext = 'pdf'
|
||||||
|
mimetype = 'application/pdf'
|
||||||
|
|
||||||
# If some error is found after this method invocation
|
# If some error is found after this method invocation
|
||||||
# no other file parsing is recommended
|
# no other file parsing is recommended
|
||||||
def critical_parse(self):
|
def critical_parse(self):
|
||||||
super(PDFParser, self).critical_parse()
|
super(PDFParser, self).critical_parse()
|
||||||
self.parse_filename_extension('pdf')
|
|
||||||
self.parse_file_type('pdf', 'application/pdf')
|
|
||||||
return self.parsed_info
|
return self.parsed_info
|
||||||
|
|
|
@ -4,6 +4,8 @@ from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
|
||||||
class PlainParser(FileParser):
|
class PlainParser(FileParser):
|
||||||
|
ext = 'txt'
|
||||||
|
mimetype = 'text/plain'
|
||||||
|
|
||||||
def __init__(self, fd):
|
def __init__(self, fd):
|
||||||
super(PlainParser, self).__init__(fd)
|
super(PlainParser, self).__init__(fd)
|
||||||
|
@ -12,8 +14,6 @@ class PlainParser(FileParser):
|
||||||
# no other file parsing is recommended
|
# no other file parsing is recommended
|
||||||
def critical_parse(self):
|
def critical_parse(self):
|
||||||
super(PlainParser, self).critical_parse()
|
super(PlainParser, self).critical_parse()
|
||||||
self.parse_filename_extension('txt')
|
|
||||||
self.parse_file_type('txt', 'text/plain')
|
|
||||||
self.parse_file_charset()
|
self.parse_file_charset()
|
||||||
self.parse_name()
|
self.parse_name()
|
||||||
return self.parsed_info
|
return self.parsed_info
|
||||||
|
|
|
@ -2,11 +2,11 @@ from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
|
||||||
class PSParser(FileParser):
|
class PSParser(FileParser):
|
||||||
|
ext = 'ps'
|
||||||
|
mimetype = 'application/postscript'
|
||||||
|
|
||||||
# If some error is found after this method invocation
|
# If some error is found after this method invocation
|
||||||
# no other file parsing is recommended
|
# no other file parsing is recommended
|
||||||
def critical_parse(self):
|
def critical_parse(self):
|
||||||
super(PSParser, self).critical_parse()
|
super(PSParser, self).critical_parse()
|
||||||
self.parse_filename_extension('ps')
|
|
||||||
self.parse_file_type('ps', 'application/postscript')
|
|
||||||
return self.parsed_info
|
return self.parsed_info
|
||||||
|
|
|
@ -2,12 +2,12 @@ from ietf.submit.parsers.base import FileParser
|
||||||
|
|
||||||
|
|
||||||
class XMLParser(FileParser):
|
class XMLParser(FileParser):
|
||||||
|
ext = 'xml'
|
||||||
|
mimetype = 'application/xml'
|
||||||
|
|
||||||
# If some error is found after this method invocation
|
# If some error is found after this method invocation
|
||||||
# no other file parsing is recommended
|
# no other file parsing is recommended
|
||||||
def critical_parse(self):
|
def critical_parse(self):
|
||||||
super(XMLParser, self).critical_parse()
|
super(XMLParser, self).critical_parse()
|
||||||
self.parse_filename_extension('xml')
|
|
||||||
self.parse_file_type('xml', 'application/xml')
|
|
||||||
return self.parsed_info
|
return self.parsed_info
|
||||||
|
|
||||||
|
|
BIN
ietf/submit/test_submission.bad
Normal file
BIN
ietf/submit/test_submission.bad
Normal file
Binary file not shown.
|
@ -726,6 +726,61 @@ class SubmitTests(TestCase):
|
||||||
q = PyQuery(r.content)
|
q = PyQuery(r.content)
|
||||||
self.assertEqual(len(q('input[type=file][name=txt]')), 1)
|
self.assertEqual(len(q('input[type=file][name=txt]')), 1)
|
||||||
|
|
||||||
|
def submit_bad_file(self, name, formats):
|
||||||
|
|
||||||
|
make_test_data()
|
||||||
|
|
||||||
|
rev = ""
|
||||||
|
group = None
|
||||||
|
|
||||||
|
# break early in case of missing configuration
|
||||||
|
self.assertTrue(os.path.exists(settings.IDSUBMIT_IDNITS_BINARY))
|
||||||
|
|
||||||
|
# get
|
||||||
|
url = urlreverse('submit_upload_submission')
|
||||||
|
r = self.client.get(url)
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
q = PyQuery(r.content)
|
||||||
|
|
||||||
|
# submit
|
||||||
|
files = {}
|
||||||
|
for format in formats:
|
||||||
|
files[format] = self.submission_file(name, rev, group, "bad", "test_submission.bad")
|
||||||
|
|
||||||
|
r = self.client.post(url, files)
|
||||||
|
|
||||||
|
self.assertEqual(r.status_code, 200)
|
||||||
|
q = PyQuery(r.content)
|
||||||
|
self.assertTrue(len(q("form .has-error")) > 0)
|
||||||
|
m = q('div.has-error span.help-block').text()
|
||||||
|
|
||||||
|
return r, q, m
|
||||||
|
|
||||||
|
def test_submit_bad_file_txt(self):
|
||||||
|
r, q, m = self.submit_bad_file("some name", ["txt"])
|
||||||
|
self.assertIn('Invalid characters were found in the name', m)
|
||||||
|
self.assertIn('Expected the TXT file to have extension ".txt"', m)
|
||||||
|
self.assertIn('Expected an TXT file of type "text/plain"', m)
|
||||||
|
self.assertIn('document does not contain a legitimate name', m)
|
||||||
|
|
||||||
|
def test_submit_bad_file_xml(self):
|
||||||
|
r, q, m = self.submit_bad_file("some name", ["xml"])
|
||||||
|
self.assertIn('Invalid characters were found in the name', m)
|
||||||
|
self.assertIn('Expected the XML file to have extension ".xml"', m)
|
||||||
|
self.assertIn('Expected an XML file of type "application/xml"', m)
|
||||||
|
|
||||||
|
def test_submit_bad_file_pdf(self):
|
||||||
|
r, q, m = self.submit_bad_file("some name", ["pdf"])
|
||||||
|
self.assertIn('Invalid characters were found in the name', m)
|
||||||
|
self.assertIn('Expected the PDF file to have extension ".pdf"', m)
|
||||||
|
self.assertIn('Expected an PDF file of type "application/pdf"', m)
|
||||||
|
|
||||||
|
def test_submit_bad_file_ps(self):
|
||||||
|
r, q, m = self.submit_bad_file("some name", ["ps"])
|
||||||
|
self.assertIn('Invalid characters were found in the name', m)
|
||||||
|
self.assertIn('Expected the PS file to have extension ".ps"', m)
|
||||||
|
self.assertIn('Expected an PS file of type "application/postscript"', m)
|
||||||
|
|
||||||
class ApprovalsTestCase(TestCase):
|
class ApprovalsTestCase(TestCase):
|
||||||
def test_approvals(self):
|
def test_approvals(self):
|
||||||
make_test_data()
|
make_test_data()
|
||||||
|
|
1
static/.gitignore
vendored
1
static/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
|
/*
|
||||||
/*.pyc
|
/*.pyc
|
||||||
|
|
Loading…
Reference in a new issue