From a305350f5f400492de175b359a982799eaa22b4b Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Sat, 24 Dec 2016 18:34:34 -0800 Subject: [PATCH] Fix handling of unicode filename downloads Add photo attribute dot_extension Fix bug using unnormalized offset in calculations --- etiquette.py | 15 +++++++-------- helpers.py | 3 --- objects.py | 5 +++++ phototagger.py | 10 +++++++++- templates/photo.html | 7 +++---- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/etiquette.py b/etiquette.py index c7cce00..f49e88b 100644 --- a/etiquette.py +++ b/etiquette.py @@ -4,6 +4,7 @@ import json import mimetypes import os import random +import urllib.parse import warnings import zipstream @@ -303,10 +304,10 @@ def get_album_zip(albumid): download_as = '%s - %s.zip' % (album.id, album.title) else: download_as = '%s.zip' % album.id - download_as = download_as.replace('"', '\\"') + download_as = urllib.parse.quote(download_as) outgoing_headers = { 'Content-Type': 'application/octet-stream', - 'Content-Disposition': 'attachment; filename=%s' % download_as, + 'Content-Disposition': 'attachment; filename*=UTF-8\'\'%s' % download_as, } return flask.Response(streamed_zip, headers=outgoing_headers) @@ -354,13 +355,11 @@ def get_file(photoid): if use_original_filename: download_as = photo.basename else: - download_as = photo.id - if photo.extension: - download_as += photo.extension + download_as = photo.id + photo.dot_extension - download_as = download_as.replace('"', '\\"') + download_as = urllib.parse.quote(download_as) response = flask.make_response(send_file(photo.real_filepath)) - response.headers['Content-Disposition'] = 'attachment; filename="%s"' % download_as + response.headers['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'%s' % download_as return response else: return send_file(photo.real_filepath) @@ -485,7 +484,7 @@ def get_search_core(): total_tags = sorted(total_tags) # PREV-NEXT PAGE URLS - offset = offset or 0 + offset = search_kwargs['offset'] or 0 original_params = request.args.to_dict() if len(photos) == limit: next_params = helpers.edit_params(original_params, {'offset': offset + limit}) diff --git a/helpers.py b/helpers.py index 9c1da2a..313034a 100644 --- a/helpers.py +++ b/helpers.py @@ -191,9 +191,6 @@ def is_xor(*args): ''' return [bool(a) for a in args].count(True) == 1 -def normalize_extension(extension): - pass - def normalize_filepath(filepath, allowed=''): ''' Remove some bad characters. diff --git a/objects.py b/objects.py index 818bc80..a0f3e03 100644 --- a/objects.py +++ b/objects.py @@ -292,6 +292,11 @@ class Photo(ObjectBase): self.extension = row_tuple['extension'] self.tagged_at = row_tuple['tagged_at'] + if self.extension == '': + self.dot_extension = '' + else: + self.dot_extension = '.' + self.extension + self.area = row_tuple['area'] self.bytes = row_tuple['bytes'] self.duration = row_tuple['duration'] diff --git a/phototagger.py b/phototagger.py index bf98ee6..204ecc5 100644 --- a/phototagger.py +++ b/phototagger.py @@ -567,6 +567,7 @@ class PDBPhotoMixin: extension_not: A string or list of strings of unacceptable file extensions. + Including '*' will forbid all extensions filename: A string or list of strings which will be split into words. The file's basename @@ -722,7 +723,14 @@ class PDBPhotoMixin: #print('Failed extension') continue - if extension_not and photo.extension in extension_not: + ext_fail = ( + extension_not and + ( + ('*' in extension_not and photo.extension) or + (photo.extension in extension_not) + ) + ) + if (ext_fail): #print('Failed extension_not') continue diff --git a/templates/photo.html b/templates/photo.html index 5222937..148e84b 100644 --- a/templates/photo.html +++ b/templates/photo.html @@ -6,7 +6,7 @@ - {% set filename = photo.id + "." + photo.extension %} + {% set filename = photo.id + photo.dot_extension %} {% set link = "/file/" + filename %}