Ticket #7495: sagenb-7495.2.patch

File sagenb-7495.2.patch, 5.3 KB (added by mpatel, 12 years ago)

Version 2. Minor simplifications. Apply only this patch to sagenb repo.

  • sagenb/notebook/twist.py

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1258683500 28800
    # Node ID 9be9f6374d872ddcf9e9625e6f2ab49ab19a8fcc
    # Parent  37b088f98b4a5292d0d6bced165ef8c0bd82123a
    trac 7495 -- 7495 -- notebook: fix massive security vulnerability and get rid of all possible "internal server errors" when doing "Data --> Upload or attach file"
    
    diff --git a/sagenb/notebook/twist.py b/sagenb/notebook/twist.py
    a b def gzip_handler(request): 
    127127############################
    128128# An error message
    129129############################
    130 def message(msg, cont=None):
     130def message(msg, cont='/'):
    131131    template_dict = {'msg': msg, 'cont': cont}
    132132    return template(os.path.join('html', 'error_message.html'),
    133133                    **template_dict)
    class Worksheet_upload_data(WorksheetRes 
    546546
    547547class Worksheet_do_upload_data(WorksheetResource, resource.PostableResource):
    548548    def render(self, ctx):
    549         name = ''
    550         if ctx.args.has_key('newField'):
    551             newfield = ctx.args['newField'][0].strip()
    552         else:
    553             newfield = None
     549        # Backlinks.
     550        worksheet_url = '/home/' + self.worksheet.filename()
     551        upload_url = worksheet_url + '/upload_data'
     552        backlinks = """ Return to <a href="%s" title="Upload or create a data file in a wide range of formats"><strong>Upload or Create Data File</strong></a> or <a href="%s" title="Interactively use the worksheet"><strong>%s</strong></a>.""" % (upload_url, worksheet_url, self.worksheet.name())
    554553
    555         if ctx.args.has_key('nameField'):
    556             name = ctx.args['nameField'][0].strip()
     554        # Check for the form's fields.  They need not be filled.
     555        if not ctx.files.has_key('fileField'):
     556            return HTMLResponse(stream=message('Error uploading file (missing fileField file).%s' % backlinks, worksheet_url))
    557557
    558         url = ctx.args['urlField'][0].strip()
     558        text_fields = ['urlField', 'newField', 'nameField']
     559        for field in text_fields:
     560            if not ctx.args.has_key(field):
     561                return HTMLResponse(stream=message('Error uploading file (missing %s arg).%s' % (field, backlinks), worksheet_url))
     562
     563        # Get the fields.
     564        newfield = ctx.args.get('newField', [''])[0].strip()
     565        name = ctx.args.get('nameField', [''])[0].strip()
     566        url = ctx.args.get('urlField', [''])[0].strip()
     567
     568        name = name or ctx.files['fileField'][0][0] or newfield
     569        if url and not name:
     570            name = url.split('/')[-1]
     571
     572        # The next line makes sure that name is plain filename, so
     573        # that dest below is a file in the data directory.  See trac
     574        # 7495 for why this is critically important.
     575        name = os.path.split(name)[-1]
    559576
    560577        if not name:
    561             name = ctx.files['fileField'][0][0]
    562 
    563         if not name:
    564             name = newfield
    565 
    566         if url and not name:
    567             name = os.path.split(url)[-1]
    568 
     578            return HTMLResponse(stream=message('Error uploading file (missing filename).%s' % backlinks, worksheet_url))
    569579        dest = os.path.join(self.worksheet.data_directory(), name)
    570580        if os.path.exists(dest):
     581            if not os.path.isfile(dest):
     582                return HTMLResponse(stream=message('Suspicious filename "%s" encountered uploading file.%s' % (name, backlinks), worksheet_url))
    571583            os.unlink(dest)
    572         response = http.RedirectResponse('/home/'+self.worksheet.filename() + '/datafile?name=%s'%name)
     584           
     585        response = http.RedirectResponse(worksheet_url + '/datafile?name=%s' % name)
    573586
    574587        if url != '':
    575             #Here we use twisted's downloadPage function which
    576             #returns a deferred object.  We return the deferred to the server,
    577             #and it will wait until the download has finished while
    578             #still serving other requests.  At the end of the deferred
    579             #callback chain should be the response that we wanted to return.
     588            # Here we use twisted's downloadPage function which
     589            # returns a deferred object.  We return the deferred to
     590            # the server, and it will wait until the download has
     591            # finished while still serving other requests.  At the end
     592            # of the deferred callback chain should be the response
     593            # that we wanted to return.
    580594            from twisted.web.client import downloadPage
    581595
    582             #The callback just returns the response
     596            # The callback just returns the response
    583597            def callback(result):
    584598                return response
     599            def errback(result):
     600                msg = "There was an error uploading '%s' (please recheck the URL).%s" % (url, backlinks)
     601                return HTMLResponse(stream=message(msg, worksheet_url))
    585602
    586603            d = downloadPage(url, dest)
    587604            d.addCallback(callback)
     605            d.addErrback(errback)
    588606            return d
    589607        elif newfield:
    590             if os.path.exists(dest): os.unlink(dest)
    591             open(dest,'w').close()
     608            open(dest, 'w').close()
    592609            return response
    593610        else:
    594             f = file(dest,'wb')
     611            f = file(dest, 'wb')
    595612            f.write(ctx.files['fileField'][0][2].read())
    596613            f.close()
    597614            return response