From ce852fc60a3c4d7a0b826d3f01da9fcd00302b93 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 6 Mar 2018 02:54:12 -0800 Subject: [PATCH] Create separate templates and static folder, and make the web app use both of these. Yay, now we have real static resources --- MANIFEST.in | 3 +- install/pyinstaller.spec | 3 +- onionshare/web.py | 80 ++++++++---------------- setup.py | 3 +- share/{images => static}/favicon.ico | Bin share/static/logo.png | Bin 0 -> 3824 bytes share/{images => static}/web_file.png | Bin share/{images => static}/web_folder.png | Bin share/{html => templates}/404.html | 2 +- share/{html => templates}/denied.html | 2 +- share/{html => templates}/receive.html | 4 +- share/{html => templates}/send.html | 8 +-- 12 files changed, 39 insertions(+), 66 deletions(-) rename share/{images => static}/favicon.ico (100%) create mode 100644 share/static/logo.png rename share/{images => static}/web_file.png (100%) rename share/{images => static}/web_folder.png (100%) rename share/{html => templates}/404.html (77%) rename share/{html => templates}/denied.html (79%) rename share/{html => templates}/receive.html (91%) rename share/{html => templates}/send.html (93%) diff --git a/MANIFEST.in b/MANIFEST.in index f4d1c078..c8a4d87c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,7 +4,8 @@ include BUILD.md include share/* include share/images/* include share/locale/* -include share/html/* +include share/templates/* +include share/static/* include install/onionshare.desktop include install/onionshare.appdata.xml include install/onionshare80.xpm diff --git a/install/pyinstaller.spec b/install/pyinstaller.spec index 6ca2fdbe..a4f1532a 100644 --- a/install/pyinstaller.spec +++ b/install/pyinstaller.spec @@ -20,7 +20,8 @@ a = Analysis( ('../share/torrc_template-windows', 'share'), ('../share/images/*', 'share/images'), ('../share/locale/*', 'share/locale'), - ('../share/html/*', 'share/html') + ('../share/templates/*', 'share/templates'), + ('../share/static/*', 'share/static') ], hiddenimports=[], hookspath=[], diff --git a/onionshare/web.py b/onionshare/web.py index 7e488a86..5d1d0cb8 100644 --- a/onionshare/web.py +++ b/onionshare/web.py @@ -26,12 +26,11 @@ import queue import socket import sys import tempfile -import base64 from distutils.version import LooseVersion as Version from urllib.request import urlopen from flask import ( - Flask, Response, request, render_template_string, abort, make_response, + Flask, Response, request, render_template, abort, make_response, __version__ as flask_version ) @@ -43,7 +42,9 @@ class Web(object): """ def __init__(self, debug, stay_open, gui_mode, receive_mode=False): # The flask app - self.app = Flask(__name__) + self.app = Flask(__name__, + static_folder=common.get_resource_path('static'), + template_folder=common.get_resource_path('templates')) # Debug mode? if debug: @@ -88,12 +89,6 @@ class Web(object): self.REQUEST_RATE_LIMIT = 5 self.q = queue.Queue() - # Load and base64 encode images to pass into templates - self.favicon_b64 = self.base64_image('favicon.ico') - self.logo_b64 = self.base64_image('logo.png') - self.folder_b64 = self.base64_image('web_folder.png') - self.file_b64 = self.base64_image('web_file.png') - self.slug = None self.download_count = 0 @@ -137,29 +132,18 @@ class Web(object): # currently a download deny_download = not self.stay_open and self.download_in_progress if deny_download: - r = make_response(render_template_string( - open(common.get_resource_path('html/denied.html')).read(), - favicon_b64=self.favicon_b64 - )) - for header, value in self.security_headers: - r.headers.set(header, value) - return r + r = make_response(render_template('denied.html')) + return self.add_security_headers(r) # If download is allowed to continue, serve download page - r = make_response(render_template_string( - open(common.get_resource_path('html/send.html')).read(), - favicon_b64=self.favicon_b64, - logo_b64=self.logo_b64, - folder_b64=self.folder_b64, - file_b64=self.file_b64, + r = make_response(render_template( + 'send.html', slug=self.slug, file_info=self.file_info, filename=os.path.basename(self.zip_filename), filesize=self.zip_filesize, filesize_human=common.human_readable_filesize(self.zip_filesize))) - for header, value in self.security_headers: - r.headers.set(header, value) - return r + return self.add_security_headers(r) @self.app.route("//download") def download(slug_candidate): @@ -172,13 +156,8 @@ class Web(object): # currently a download deny_download = not self.stay_open and self.download_in_progress if deny_download: - r = make_response(render_template_string( - open(common.get_resource_path('html/denied.html')).read(), - favicon_b64=self.favicon_b64 - )) - for header,value in self.security_headers: - r.headers.set(header, value) - return r + r = make_response(render_template('denied.html')) + return self.add_security_headers(r) # each download has a unique id download_id = self.download_count @@ -261,8 +240,7 @@ class Web(object): r = Response(generate()) r.headers.set('Content-Length', self.zip_filesize) r.headers.set('Content-Disposition', 'attachment', filename=basename) - for header,value in self.security_headers: - r.headers.set(header, value) + r = self.add_security_headers(r) # guess content type (content_type, _) = mimetypes.guess_type(basename, strict=False) if content_type is not None: @@ -278,15 +256,10 @@ class Web(object): self.check_slug_candidate(slug_candidate) # If download is allowed to continue, serve download page - r = make_response(render_template_string( - open(common.get_resource_path('html/receive.html')).read(), - favicon_b64=self.favicon_b64, - logo_b64=self.logo_b64, + r = make_response(render_template( + 'receive.html', slug=self.slug)) - for header, value in self.security_headers: - r.headers.set(header, value) - return r - + return self.add_security_headers(r) def common_routes(self): """ @@ -306,13 +279,8 @@ class Web(object): self.force_shutdown() print(strings._('error_rate_limit')) - r = make_response(render_template_string( - open(common.get_resource_path('html/404.html')).read(), - favicon_b64=self.favicon_b64 - ), 404) - for header, value in self.security_headers: - r.headers.set(header, value) - return r + r = make_response(render_template('404.html'), 404) + return self.add_security_headers(r) @self.app.route("//shutdown") def shutdown(slug_candidate): @@ -323,6 +291,14 @@ class Web(object): self.force_shutdown() return "" + def add_security_headers(self, r): + """ + Add security headers to a request + """ + for header, value in self.security_headers: + r.headers.set(header, value) + return r + def set_file_info(self, filenames, processed_size_callback=None): """ Using the list of filenames being shared, fill in details that the web @@ -362,12 +338,6 @@ class Web(object): return True return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) - def base64_image(self, filename): - """ - Base64-encode an image file to use data URIs in the web app - """ - return base64.b64encode(open(common.get_resource_path('images/{}'.format(filename)), 'rb').read()).decode() - def add_request(self, request_type, path, data=None): """ Add a request to the queue, to communicate with the GUI. diff --git a/setup.py b/setup.py index 23e1ea17..99222ef0 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,8 @@ data_files=[ (os.path.join(sys.prefix, 'share/onionshare'), file_list('share')), (os.path.join(sys.prefix, 'share/onionshare/images'), file_list('share/images')), (os.path.join(sys.prefix, 'share/onionshare/locale'), file_list('share/locale')), - (os.path.join(sys.prefix, 'share/onionshare/html'), file_list('share/html')), + (os.path.join(sys.prefix, 'share/onionshare/templates'), file_list('share/templates')), + (os.path.join(sys.prefix, 'share/onionshare/static'), file_list('share/static')) ] if platform.system() != 'OpenBSD': data_files.append(('/usr/share/nautilus-python/extensions/', ['install/scripts/onionshare-nautilus.py'])) diff --git a/share/images/favicon.ico b/share/static/favicon.ico similarity index 100% rename from share/images/favicon.ico rename to share/static/favicon.ico diff --git a/share/static/logo.png b/share/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..43884c1f7845fa0eec517677958c6660fe79a7de GIT binary patch literal 3824 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 Error 404 - +