aboutsummaryrefslogtreecommitdiffstats
path: root/library/blueimp_upload/server/gae-python/main.py
diff options
context:
space:
mode:
authorMike Macgirvin <mike@macgirvin.com>2018-10-31 15:56:08 +1100
committerMike Macgirvin <mike@macgirvin.com>2018-10-31 15:56:08 +1100
commit7e1f431eca7a8aa68fc0badfaa88e88de3ba094c (patch)
tree16beba352cd4ace4aa6eb13c7f9c1c82c92013b4 /library/blueimp_upload/server/gae-python/main.py
parent70c55da1df69d90dcbeb5a78c994b23a8456bfc9 (diff)
downloadvolse-hubzilla-7e1f431eca7a8aa68fc0badfaa88e88de3ba094c.tar.gz
volse-hubzilla-7e1f431eca7a8aa68fc0badfaa88e88de3ba094c.tar.bz2
volse-hubzilla-7e1f431eca7a8aa68fc0badfaa88e88de3ba094c.zip
yet another blueimp vulnerability. Move to composer.
Diffstat (limited to 'library/blueimp_upload/server/gae-python/main.py')
-rw-r--r--library/blueimp_upload/server/gae-python/main.py204
1 files changed, 0 insertions, 204 deletions
diff --git a/library/blueimp_upload/server/gae-python/main.py b/library/blueimp_upload/server/gae-python/main.py
deleted file mode 100644
index 1955ac00a..000000000
--- a/library/blueimp_upload/server/gae-python/main.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# jQuery File Upload Plugin GAE Python Example
-# https://github.com/blueimp/jQuery-File-Upload
-#
-# Copyright 2011, Sebastian Tschan
-# https://blueimp.net
-#
-# Licensed under the MIT license:
-# https://opensource.org/licenses/MIT
-#
-
-from google.appengine.api import memcache, images
-import json
-import os
-import re
-import urllib
-import webapp2
-
-DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev')
-WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'
-MIN_FILE_SIZE = 1 # bytes
-# Max file size is memcache limit (1MB) minus key size minus overhead:
-MAX_FILE_SIZE = 999000 # bytes
-IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
-ACCEPT_FILE_TYPES = IMAGE_TYPES
-THUMB_MAX_WIDTH = 80
-THUMB_MAX_HEIGHT = 80
-THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png'
-EXPIRATION_TIME = 300 # seconds
-# If set to None, only allow redirects to the referer protocol+host.
-# Set to a regexp for custom pattern matching against the redirect value:
-REDIRECT_ALLOW_TARGET = None
-
-class CORSHandler(webapp2.RequestHandler):
- def cors(self):
- headers = self.response.headers
- headers['Access-Control-Allow-Origin'] = '*'
- headers['Access-Control-Allow-Methods'] =\
- 'OPTIONS, HEAD, GET, POST, DELETE'
- headers['Access-Control-Allow-Headers'] =\
- 'Content-Type, Content-Range, Content-Disposition'
-
- def initialize(self, request, response):
- super(CORSHandler, self).initialize(request, response)
- self.cors()
-
- def json_stringify(self, obj):
- return json.dumps(obj, separators=(',', ':'))
-
- def options(self, *args, **kwargs):
- pass
-
-class UploadHandler(CORSHandler):
- def validate(self, file):
- if file['size'] < MIN_FILE_SIZE:
- file['error'] = 'File is too small'
- elif file['size'] > MAX_FILE_SIZE:
- file['error'] = 'File is too big'
- elif not ACCEPT_FILE_TYPES.match(file['type']):
- file['error'] = 'Filetype not allowed'
- else:
- return True
- return False
-
- def validate_redirect(self, redirect):
- if redirect:
- if REDIRECT_ALLOW_TARGET:
- return REDIRECT_ALLOW_TARGET.match(redirect)
- referer = self.request.headers['referer']
- if referer:
- from urlparse import urlparse
- parts = urlparse(referer)
- redirect_allow_target = '^' + re.escape(
- parts.scheme + '://' + parts.netloc + '/'
- )
- return re.match(redirect_allow_target, redirect)
- return False
-
- def get_file_size(self, file):
- file.seek(0, 2) # Seek to the end of the file
- size = file.tell() # Get the position of EOF
- file.seek(0) # Reset the file position to the beginning
- return size
-
- def write_blob(self, data, info):
- key = urllib.quote(info['type'].encode('utf-8'), '') +\
- '/' + str(hash(data)) +\
- '/' + urllib.quote(info['name'].encode('utf-8'), '')
- try:
- memcache.set(key, data, time=EXPIRATION_TIME)
- except: #Failed to add to memcache
- return (None, None)
- thumbnail_key = None
- if IMAGE_TYPES.match(info['type']):
- try:
- img = images.Image(image_data=data)
- img.resize(
- width=THUMB_MAX_WIDTH,
- height=THUMB_MAX_HEIGHT
- )
- thumbnail_data = img.execute_transforms()
- thumbnail_key = key + THUMB_SUFFIX
- memcache.set(
- thumbnail_key,
- thumbnail_data,
- time=EXPIRATION_TIME
- )
- except: #Failed to resize Image or add to memcache
- thumbnail_key = None
- return (key, thumbnail_key)
-
- def handle_upload(self):
- results = []
- for name, fieldStorage in self.request.POST.items():
- if type(fieldStorage) is unicode:
- continue
- result = {}
- result['name'] = urllib.unquote(fieldStorage.filename)
- result['type'] = fieldStorage.type
- result['size'] = self.get_file_size(fieldStorage.file)
- if self.validate(result):
- key, thumbnail_key = self.write_blob(
- fieldStorage.value,
- result
- )
- if key is not None:
- result['url'] = self.request.host_url + '/' + key
- result['deleteUrl'] = result['url']
- result['deleteType'] = 'DELETE'
- if thumbnail_key is not None:
- result['thumbnailUrl'] = self.request.host_url +\
- '/' + thumbnail_key
- else:
- result['error'] = 'Failed to store uploaded file.'
- results.append(result)
- return results
-
- def head(self):
- pass
-
- def get(self):
- self.redirect(WEBSITE)
-
- def post(self):
- if (self.request.get('_method') == 'DELETE'):
- return self.delete()
- result = {'files': self.handle_upload()}
- s = self.json_stringify(result)
- redirect = self.request.get('redirect')
- if self.validate_redirect(redirect):
- return self.redirect(str(
- redirect.replace('%s', urllib.quote(s, ''), 1)
- ))
- if 'application/json' in self.request.headers.get('Accept'):
- self.response.headers['Content-Type'] = 'application/json'
- self.response.write(s)
-
-class FileHandler(CORSHandler):
- def normalize(self, str):
- return urllib.quote(urllib.unquote(str), '')
-
- def get(self, content_type, data_hash, file_name):
- content_type = self.normalize(content_type)
- file_name = self.normalize(file_name)
- key = content_type + '/' + data_hash + '/' + file_name
- data = memcache.get(key)
- if data is None:
- return self.error(404)
- # Prevent browsers from MIME-sniffing the content-type:
- self.response.headers['X-Content-Type-Options'] = 'nosniff'
- content_type = urllib.unquote(content_type)
- if not IMAGE_TYPES.match(content_type):
- # Force a download dialog for non-image types:
- content_type = 'application/octet-stream'
- elif file_name.endswith(THUMB_SUFFIX):
- content_type = 'image/png'
- self.response.headers['Content-Type'] = content_type
- # Cache for the expiration time:
- self.response.headers['Cache-Control'] = 'public,max-age=%d' \
- % EXPIRATION_TIME
- self.response.write(data)
-
- def delete(self, content_type, data_hash, file_name):
- content_type = self.normalize(content_type)
- file_name = self.normalize(file_name)
- key = content_type + '/' + data_hash + '/' + file_name
- result = {key: memcache.delete(key)}
- content_type = urllib.unquote(content_type)
- if IMAGE_TYPES.match(content_type):
- thumbnail_key = key + THUMB_SUFFIX
- result[thumbnail_key] = memcache.delete(thumbnail_key)
- if 'application/json' in self.request.headers.get('Accept'):
- self.response.headers['Content-Type'] = 'application/json'
- s = self.json_stringify(result)
- self.response.write(s)
-
-app = webapp2.WSGIApplication(
- [
- ('/', UploadHandler),
- ('/(.+)/([^/]+)/([^/]+)', FileHandler)
- ],
- debug=DEBUG
-)