summaryrefslogtreecommitdiff
path: root/onionshare
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2019-09-01 17:49:22 -0400
committerMicah Lee <micah@micahflee.com>2019-09-01 17:49:22 -0400
commit328b1500abc105b029b1944304399b51b13a57ea (patch)
tree9cc38d2274c6b597cfc268469b32515c918da74c /onionshare
parent4dd26f6d1655a1e437b3a16739f873a0df18614b (diff)
parent2604ef52b51424c42c2a06212ab745242de0fa58 (diff)
downloadonionshare-328b1500abc105b029b1944304399b51b13a57ea.tar.gz
onionshare-328b1500abc105b029b1944304399b51b13a57ea.zip
Merge branch 'share-code' of https://github.com/hiromipaw/onionshare into hiromipaw-share-code
Diffstat (limited to 'onionshare')
-rw-r--r--onionshare/web/base_mode.py218
-rw-r--r--onionshare/web/receive_mode.py5
-rw-r--r--onionshare/web/share_mode.py58
-rw-r--r--onionshare/web/web.py18
-rw-r--r--onionshare/web/website_mode.py150
5 files changed, 241 insertions, 208 deletions
diff --git a/onionshare/web/base_mode.py b/onionshare/web/base_mode.py
new file mode 100644
index 00000000..905414f6
--- /dev/null
+++ b/onionshare/web/base_mode.py
@@ -0,0 +1,218 @@
+import os
+import sys
+import tempfile
+import mimetypes
+from flask import Response, request, render_template, make_response, send_from_directory
+
+from .. import strings
+
+class BaseModeWeb(object):
+ """
+ All of the web logic shared between share and website mode
+ """
+ def __init__(self, common, web):
+ super(BaseModeWeb, self).__init__()
+ self.common = common
+ self.web = web
+
+ # Information about the file to be shared
+ self.file_info = []
+ self.is_zipped = False
+ self.download_filename = None
+ self.download_filesize = None
+ self.gzip_filename = None
+ self.gzip_filesize = None
+ self.zip_writer = None
+
+ # Dictionary mapping file paths to filenames on disk
+ self.files = {}
+ # This is only the root files and dirs, as opposed to all of them
+ self.root_files = {}
+ self.cleanup_filenames = []
+ self.file_info = {'files': [], 'dirs': []}
+
+ self.visit_count = 0
+ self.download_count = 0
+
+ # If "Stop After First Download" is checked (stay_open == False), only allow
+ # one download at a time.
+ self.download_in_progress = False
+
+ self.define_routes()
+
+
+ def init(self):
+ """
+ Add custom initialization here.
+ """
+ pass
+
+
+ def directory_listing(self, filenames, path='', filesystem_path=None):
+ # If filesystem_path is None, this is the root directory listing
+ files = []
+ dirs = []
+ r = ''
+
+ files, dirs = self.build_directory_listing(filenames, filesystem_path)
+
+ if self.web.mode == 'website':
+ r = make_response(render_template('listing.html',
+ path=path,
+ files=files,
+ dirs=dirs,
+ static_url_path=self.web.static_url_path))
+
+ elif self.web.mode == 'share':
+ r = make_response(render_template(
+ 'send.html',
+ file_info=self.file_info,
+ files=files,
+ dirs=dirs,
+ filename=os.path.basename(self.download_filename),
+ filesize=self.filesize,
+ filesize_human=self.common.human_readable_filesize(self.download_filesize),
+ is_zipped=self.is_zipped,
+ static_url_path=self.web.static_url_path))
+
+ return self.web.add_security_headers(r)
+
+
+ def build_directory_listing(self, filenames, filesystem_path):
+ files = []
+ dirs = []
+
+ for filename in filenames:
+ if filesystem_path:
+ this_filesystem_path = os.path.join(filesystem_path, filename)
+ else:
+ this_filesystem_path = self.files[filename]
+
+ is_dir = os.path.isdir(this_filesystem_path)
+
+ if is_dir:
+ dirs.append({
+ 'basename': filename
+ })
+ else:
+ size = os.path.getsize(this_filesystem_path)
+ size_human = self.common.human_readable_filesize(size)
+ files.append({
+ 'basename': filename,
+ 'size_human': size_human
+ })
+ return files, dirs
+
+
+ def set_file_info(self, filenames, processed_size_callback=None):
+ """
+ Build a data structure that describes the list of files
+ """
+
+ # If there's just one folder, replace filenames with a list of files inside that folder
+ if len(filenames) == 1 and os.path.isdir(filenames[0]):
+ filenames = [os.path.join(filenames[0], x) for x in os.listdir(filenames[0])]
+
+ self.build_file_list(filenames)
+
+ if self.web.mode == 'share':
+ self.common.log("ShareModeWeb", "set_file_info")
+ self.web.cancel_compression = False
+ self.build_zipfile_list(filenames, processed_size_callback)
+
+ elif self.web.mode == 'website':
+ self.common.log("WebsiteModeWeb", "set_file_info")
+ self.web.cancel_compression = True
+
+ return True
+
+
+ def build_file_list(self, filenames):
+ """
+ Build a data structure that describes the list of files that make up
+ the static website.
+ """
+ self.common.log("BaseModeWeb", "build_file_list")
+
+ # Loop through the files
+ for filename in filenames:
+ basename = os.path.basename(filename.rstrip('/'))
+
+ # If it's a filename, add it
+ if os.path.isfile(filename):
+ self.files[basename] = filename
+ self.root_files[basename] = filename
+
+ # If it's a directory, add it recursively
+ elif os.path.isdir(filename):
+ self.root_files[basename + '/'] = filename
+
+ for root, _, nested_filenames in os.walk(filename):
+ # Normalize the root path. So if the directory name is "/home/user/Documents/some_folder",
+ # and it has a nested folder foobar, the root is "/home/user/Documents/some_folder/foobar".
+ # The normalized_root should be "some_folder/foobar"
+ normalized_root = os.path.join(basename, root[len(filename):].lstrip('/')).rstrip('/')
+
+ # Add the dir itself
+ self.files[normalized_root + '/'] = root
+
+ # Add the files in this dir
+ for nested_filename in nested_filenames:
+ self.files[os.path.join(normalized_root, nested_filename)] = os.path.join(root, nested_filename)
+
+ return True
+
+ def render_logic(self, path=''):
+ if path in self.files:
+ filesystem_path = self.files[path]
+
+ # If it's a directory
+ if os.path.isdir(filesystem_path):
+ # Is there an index.html?
+ index_path = os.path.join(path, 'index.html')
+ if self.web.mode == 'website' and index_path in self.files:
+ # Render it
+ dirname = os.path.dirname(self.files[index_path])
+ basename = os.path.basename(self.files[index_path])
+
+ return send_from_directory(dirname, basename)
+
+ else:
+ # Otherwise, render directory listing
+ filenames = []
+ for filename in os.listdir(filesystem_path):
+ if os.path.isdir(os.path.join(filesystem_path, filename)):
+ filenames.append(filename + '/')
+ else:
+ filenames.append(filename)
+ filenames.sort()
+ return self.directory_listing(filenames, path, filesystem_path)
+
+ # If it's a file
+ elif os.path.isfile(filesystem_path):
+ dirname = os.path.dirname(filesystem_path)
+ basename = os.path.basename(filesystem_path)
+ return send_from_directory(dirname, basename)
+
+ # If it's not a directory or file, throw a 404
+ else:
+ return self.web.error404()
+ else:
+ # Special case loading /
+
+ if path == '':
+ index_path = 'index.html'
+ if self.web.mode == 'website' and index_path in self.files:
+ # Render it
+ dirname = os.path.dirname(self.files[index_path])
+ basename = os.path.basename(self.files[index_path])
+ return send_from_directory(dirname, basename)
+ else:
+ # Root directory listing
+ filenames = list(self.root_files)
+ filenames.sort()
+ return self.directory_listing(filenames, path)
+
+ else:
+ # If the path isn't found, throw a 404
+ return self.web.error404()
diff --git a/onionshare/web/receive_mode.py b/onionshare/web/receive_mode.py
index 3f848d2f..b444deb2 100644
--- a/onionshare/web/receive_mode.py
+++ b/onionshare/web/receive_mode.py
@@ -18,9 +18,6 @@ class ReceiveModeWeb(object):
self.web = web
- # Reset assets path
- self.web.app.static_folder=self.common.get_resource_path('static')
-
self.can_upload = True
self.upload_count = 0
self.uploads_in_progress = []
@@ -34,7 +31,7 @@ class ReceiveModeWeb(object):
@self.web.app.route("/")
def index():
self.web.add_request(self.web.REQUEST_LOAD, request.path)
- r = make_response(render_template('receive.html',
+ r = make_response(render_template('receive.html',
static_url_path=self.web.static_url_path))
return self.web.add_security_headers(r)
diff --git a/onionshare/web/share_mode.py b/onionshare/web/share_mode.py
index 0dfa7e0a..afcbdcd9 100644
--- a/onionshare/web/share_mode.py
+++ b/onionshare/web/share_mode.py
@@ -6,46 +6,26 @@ import mimetypes
import gzip
from flask import Response, request, render_template, make_response
+from .base_mode import BaseModeWeb
from .. import strings
-class ShareModeWeb(object):
+class ShareModeWeb(BaseModeWeb):
"""
All of the web logic for share mode
"""
- def __init__(self, common, web):
- self.common = common
+ def init(self):
self.common.log('ShareModeWeb', '__init__')
- self.web = web
-
- # Information about the file to be shared
- self.file_info = []
- self.is_zipped = False
- self.download_filename = None
- self.download_filesize = None
- self.gzip_filename = None
- self.gzip_filesize = None
- self.zip_writer = None
-
- self.download_count = 0
-
- # If "Stop After First Download" is checked (stay_open == False), only allow
- # one download at a time.
- self.download_in_progress = False
-
- # Reset assets path
- self.web.app.static_folder=self.common.get_resource_path('static')
-
-
self.define_routes()
def define_routes(self):
"""
The web app routes for sharing files
"""
- @self.web.app.route("/")
- def index():
+ @self.web.app.route('/', defaults={'path': ''})
+ @self.web.app.route('/<path:path>')
+ def index(path):
"""
Render the template for the onionshare landing page.
"""
@@ -65,15 +45,8 @@ class ShareModeWeb(object):
else:
self.filesize = self.download_filesize
- r = make_response(render_template(
- 'send.html',
- file_info=self.file_info,
- filename=os.path.basename(self.download_filename),
- filesize=self.filesize,
- filesize_human=self.common.human_readable_filesize(self.download_filesize),
- is_zipped=self.is_zipped,
- static_url_path=self.web.static_url_path))
- return self.web.add_security_headers(r)
+ return self.render_logic(path)
+
@self.web.app.route("/download")
def download():
@@ -198,19 +171,8 @@ class ShareModeWeb(object):
r.headers.set('Content-Type', content_type)
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
- page will need to display. This includes zipping up the file in order to
- get the zip file's name and size.
- """
- self.common.log("ShareModeWeb", "set_file_info")
- self.web.cancel_compression = False
-
- self.cleanup_filenames = []
-
- # build file info list
- self.file_info = {'files': [], 'dirs': []}
+ def build_zipfile_list(self, filenames, processed_size_callback=None):
+ self.common.log("ShareModeWeb", "build_zipfile_list")
for filename in filenames:
info = {
'filename': filename,
diff --git a/onionshare/web/web.py b/onionshare/web/web.py
index 1d2a3fec..17dd8c15 100644
--- a/onionshare/web/web.py
+++ b/onionshare/web/web.py
@@ -51,12 +51,16 @@ class Web(object):
self.common = common
self.common.log('Web', '__init__', 'is_gui={}, mode={}'.format(is_gui, mode))
+ # The static URL path has a 128-bit random number in it to avoid having name
+ # collisions with files that might be getting shared
+ self.static_url_path = '/static_{}'.format(self.common.random_string(16))
+
# The flask app
self.app = Flask(__name__,
+ static_url_path=self.static_url_path,
static_folder=self.common.get_resource_path('static'),
template_folder=self.common.get_resource_path('templates'))
self.app.secret_key = self.common.random_string(8)
- self.generate_static_url_path()
self.auth = HTTPBasicAuth()
self.auth.error_handler(self.error401)
@@ -225,18 +229,6 @@ class Web(object):
self.password = self.common.build_password()
self.common.log('Web', 'generate_password', 'built random password: "{}"'.format(self.password))
- def generate_static_url_path(self):
- # The static URL path has a 128-bit random number in it to avoid having name
- # collisions with files that might be getting shared
- self.static_url_path = '/static_{}'.format(self.common.random_string(16))
- self.common.log('Web', 'generate_static_url_path', 'new static_url_path is {}'.format(self.static_url_path))
-
- # Update the flask route to handle the new static URL path
- self.app.static_url_path = self.static_url_path
- self.app.add_url_rule(
- self.static_url_path + '/<path:filename>',
- endpoint='static', view_func=self.app.send_static_file)
-
def verbose_mode(self):
"""
Turn on verbose mode, which will log flask errors to a file.
diff --git a/onionshare/web/website_mode.py b/onionshare/web/website_mode.py
index d2cd6db9..b8e4dfdf 100644
--- a/onionshare/web/website_mode.py
+++ b/onionshare/web/website_mode.py
@@ -2,30 +2,21 @@ import os
import sys
import tempfile
import mimetypes
-from flask import Response, request, render_template, make_response, send_from_directory
+from flask import Response, request, render_template, make_response
+from .base_mode import BaseModeWeb
from .. import strings
-class WebsiteModeWeb(object):
+class WebsiteModeWeb(BaseModeWeb):
"""
- All of the web logic for share mode
+ All of the web logic for website mode
"""
- def __init__(self, common, web):
- self.common = common
+ def init(self):
self.common.log('WebsiteModeWeb', '__init__')
-
- self.web = web
-
- # Dictionary mapping file paths to filenames on disk
- self.files = {}
- self.visit_count = 0
-
- # Reset assets path
- self.web.app.static_folder=self.common.get_resource_path('static')
-
self.define_routes()
+
def define_routes(self):
"""
The web app routes for sharing a website
@@ -51,131 +42,4 @@ class WebsiteModeWeb(object):
'action': 'visit'
})
- if path in self.files:
- filesystem_path = self.files[path]
-
- # If it's a directory
- if os.path.isdir(filesystem_path):
- # Is there an index.html?
- index_path = os.path.join(path, 'index.html')
- if index_path in self.files:
- # Render it
- dirname = os.path.dirname(self.files[index_path])
- basename = os.path.basename(self.files[index_path])
- return send_from_directory(dirname, basename)
-
- else:
- # Otherwise, render directory listing
- filenames = []
- for filename in os.listdir(filesystem_path):
- if os.path.isdir(os.path.join(filesystem_path, filename)):
- filenames.append(filename + '/')
- else:
- filenames.append(filename)
- filenames.sort()
- return self.directory_listing(path, filenames, filesystem_path)
-
- # If it's a file
- elif os.path.isfile(filesystem_path):
- dirname = os.path.dirname(filesystem_path)
- basename = os.path.basename(filesystem_path)
- return send_from_directory(dirname, basename)
-
- # If it's not a directory or file, throw a 404
- else:
- return self.web.error404()
- else:
- # Special case loading /
- if path == '':
- index_path = 'index.html'
- if index_path in self.files:
- # Render it
- dirname = os.path.dirname(self.files[index_path])
- basename = os.path.basename(self.files[index_path])
- return send_from_directory(dirname, basename)
- else:
- # Root directory listing
- filenames = list(self.root_files)
- filenames.sort()
- return self.directory_listing(path, filenames)
-
- else:
- # If the path isn't found, throw a 404
- return self.web.error404()
-
- def directory_listing(self, path, filenames, filesystem_path=None):
- # If filesystem_path is None, this is the root directory listing
- files = []
- dirs = []
-
- for filename in filenames:
- if filesystem_path:
- this_filesystem_path = os.path.join(filesystem_path, filename)
- else:
- this_filesystem_path = self.files[filename]
-
- is_dir = os.path.isdir(this_filesystem_path)
-
- if is_dir:
- dirs.append({
- 'basename': filename
- })
- else:
- size = os.path.getsize(this_filesystem_path)
- size_human = self.common.human_readable_filesize(size)
- files.append({
- 'basename': filename,
- 'size_human': size_human
- })
-
- r = make_response(render_template('listing.html',
- path=path,
- files=files,
- dirs=dirs,
- static_url_path=self.web.static_url_path))
- return self.web.add_security_headers(r)
-
- def set_file_info(self, filenames):
- """
- Build a data structure that describes the list of files that make up
- the static website.
- """
- self.common.log("WebsiteModeWeb", "set_file_info")
-
- # This is a dictionary that maps HTTP routes to filenames on disk
- self.files = {}
-
- # This is only the root files and dirs, as opposed to all of them
- self.root_files = {}
-
- # If there's just one folder, replace filenames with a list of files inside that folder
- if len(filenames) == 1 and os.path.isdir(filenames[0]):
- filenames = [os.path.join(filenames[0], x) for x in os.listdir(filenames[0])]
-
- # Loop through the files
- for filename in filenames:
- basename = os.path.basename(filename.rstrip('/'))
-
- # If it's a filename, add it
- if os.path.isfile(filename):
- self.files[basename] = filename
- self.root_files[basename] = filename
-
- # If it's a directory, add it recursively
- elif os.path.isdir(filename):
- self.root_files[basename + '/'] = filename
-
- for root, _, nested_filenames in os.walk(filename):
- # Normalize the root path. So if the directory name is "/home/user/Documents/some_folder",
- # and it has a nested folder foobar, the root is "/home/user/Documents/some_folder/foobar".
- # The normalized_root should be "some_folder/foobar"
- normalized_root = os.path.join(basename, root[len(filename):].lstrip('/')).rstrip('/')
-
- # Add the dir itself
- self.files[normalized_root + '/'] = root
-
- # Add the files in this dir
- for nested_filename in nested_filenames:
- self.files[os.path.join(normalized_root, nested_filename)] = os.path.join(root, nested_filename)
-
- return True
+ return self.render_logic(path)