Skip to content
Snippets Groups Projects
Commit 9ee3b1cd authored by Gunnar Schaefer's avatar Gunnar Schaefer
Browse files

improve security of uploads and downloads

parent a69a79fb
No related branches found
No related tags found
No related merge requests found
......@@ -155,10 +155,10 @@ class Container(base.RequestHandler):
ticket_id = self.request.GET.get('ticket')
if ticket_id:
ticket = self.app.db.downloads.find_one({'_id': ticket_id})
if not ticket: # FIXME need better security
if not ticket:
self.abort(404, 'no such ticket')
if ticket['target'] != _id or ticket['filename'] != filename:
self.abort(400, 'ticket not for this resource')
if ticket['target'] != _id or ticket['filename'] != filename or ticket['ip'] != self.request.client_addr:
self.abort(400, 'ticket not for this resource or source IP')
elif not container.get('public', False):
self.abort(403, 'this ' + dbc_name + ' is not public')
del container['permissions']
......@@ -249,7 +249,7 @@ class Container(base.RequestHandler):
self.response.headers['Content-Type'] = 'application/octet-stream'
self.response.headers['Content-Disposition'] = 'attachment; filename="' + filename + '"'
elif self.request.method == 'POST':
ticket = util.download_ticket('file', _id, filename, fileinfo['filesize'])
ticket = util.download_ticket(self.request.client_addr, 'file', _id, filename, fileinfo['filesize'])
tkt_id = self.app.db.downloads.insert(ticket)
return {'ticket': tkt_id}
elif self.request.method == 'DELETE':
......
......@@ -278,7 +278,7 @@ class Core(base.RequestHandler):
acq_no = overwrites.get('acq_no')
arcname = overwrites['series_uid'] + ('_' + str(acq_no) if acq_no is not None else '') + '_' + filetype
ticket = util.upload_ticket(arcname=arcname) # store arcname for later reference
ticket = util.upload_ticket(self.request.client_addr, arcname=arcname) # store arcname for later reference
self.app.db.uploads.insert_one(ticket)
arcpath = os.path.join(self.app.config['upload_path'], ticket['_id'] + '.tar')
store_file(self.request.body_file, filename, self.request.headers['Content-MD5'], arcpath, arcname)
......@@ -287,6 +287,8 @@ class Core(base.RequestHandler):
ticket = self.app.db.uploads.find_one({'_id': ticket_id})
if not ticket:
self.abort(404, 'no such ticket')
if ticket['ip'] != self.request.client_addr:
self.abort(400, 'ticket not for this source IP')
arcpath = os.path.join(self.app.config['upload_path'], ticket_id + '.tar')
if self.request.GET.get('complete', '').lower() not in ('1', 'true'):
......@@ -364,7 +366,7 @@ class Core(base.RequestHandler):
total_size, file_cnt = append_targets(targets, acq, prefix, total_size, file_cnt)
log.debug(json.dumps(targets, sort_keys=True, indent=4, separators=(',', ': ')))
filename = 'sdm_' + datetime.datetime.utcnow().strftime('%Y%m%d_%H%M%S') + '.tar'
ticket = util.download_ticket('batch', targets, filename, total_size)
ticket = util.download_ticket(self.request.client_addr, 'batch', targets, filename, total_size)
self.app.db.downloads.insert(ticket)
return {'ticket': ticket['_id'], 'file_cnt': file_cnt, 'size': total_size}
......@@ -389,6 +391,8 @@ class Core(base.RequestHandler):
ticket = self.app.db.downloads.find_one({'_id': ticket_id})
if not ticket:
self.abort(404, 'no such ticket')
if ticket['ip'] != self.request.client_addr:
self.abort(400, 'ticket not for this source IP')
self.response.app_iter = self._archivestream(ticket)
self.response.headers['Content-Type'] = 'application/octet-stream'
self.response.headers['Content-Disposition'] = 'attachment; filename=' + str(ticket['filename'])
......
......@@ -233,19 +233,21 @@ def user_perm(permissions, _id, site=None):
return {}
def upload_ticket(**kwargs):
def upload_ticket(ip, **kwargs):
ticket = {
'_id': str(uuid.uuid4()),
'timestamp': datetime.datetime.utcnow(),
'ip': ip,
}
ticket.update(kwargs)
return ticket
def download_ticket(type_, target, filename, size):
def download_ticket(ip, type_, target, filename, size):
return {
'_id': str(uuid.uuid4()),
'timestamp': datetime.datetime.utcnow(),
'ip': ip,
'type': type_,
'target': target,
'filename': filename,
......@@ -275,7 +277,7 @@ def guess_mimetype(filepath):
def guess_filetype(filepath, mimetype):
"""Guess MIME type based on filename."""
"""Guess file type based on filename and MIME type."""
type_, subtype = mimetype.split('/')
if filepath.endswith('.nii') or filepath.endswith('.nii.gz'):
return 'nifti'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment