diff options
author | Micah Lee <micah@micahflee.com> | 2018-12-16 17:11:18 -0800 |
---|---|---|
committer | Micah Lee <micah@micahflee.com> | 2018-12-16 17:11:18 -0800 |
commit | 043237bc20f34177dfae327998afbb22f2f824f1 (patch) | |
tree | fa2ff9a78a36b7f84dadd3a85c72ab2f8efa6bd3 /onionshare | |
parent | 3a0c8dc32317d4b66230663c1c3a40f6969d9275 (diff) | |
parent | c059af97e1f0e484bdfb83521e5bab5e385cdd78 (diff) | |
download | onionshare-043237bc20f34177dfae327998afbb22f2f824f1.tar.gz onionshare-043237bc20f34177dfae327998afbb22f2f824f1.zip |
Merge branch 'develop' into 406_osx_sandbox
Diffstat (limited to 'onionshare')
-rw-r--r-- | onionshare/__init__.py | 7 | ||||
-rw-r--r-- | onionshare/common.py | 5 | ||||
-rw-r--r-- | onionshare/onion.py | 10 | ||||
-rw-r--r-- | onionshare/settings.py | 6 | ||||
-rw-r--r-- | onionshare/strings.py | 2 | ||||
-rw-r--r-- | onionshare/web/receive_mode.py | 106 | ||||
-rw-r--r-- | onionshare/web/web.py | 23 |
7 files changed, 102 insertions, 57 deletions
diff --git a/onionshare/__init__.py b/onionshare/__init__.py index 1e81333e..0d064639 100644 --- a/onionshare/__init__.py +++ b/onionshare/__init__.py @@ -209,6 +209,13 @@ def main(cwd=None): print(strings._("close_on_timeout")) web.stop(app.port) break + if mode == 'receive': + if web.receive_mode.upload_count == 0 or not web.receive_mode.uploads_in_progress: + print(strings._("close_on_timeout")) + web.stop(app.port) + break + else: + web.receive_mode.can_upload = False # Allow KeyboardInterrupt exception to be handled with threads # https://stackoverflow.com/questions/3788208/python-threading-ignores-keyboardinterrupt-exception time.sleep(0.2) diff --git a/onionshare/common.py b/onionshare/common.py index 6b3d85c4..c84046f0 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -390,6 +390,11 @@ class Common(object): 'settings_whats_this': """ QLabel { font-size: 12px; + }""", + + 'settings_connect_to_tor': """ + QLabel { + font-style: italic; }""" } diff --git a/onionshare/onion.py b/onionshare/onion.py index 7b4f1daa..c747984e 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -146,6 +146,9 @@ class Onion(object): # The tor process self.tor_proc = None + # The Tor controller + self.c = None + # Start out not connected to Tor self.connected_to_tor = False @@ -389,6 +392,7 @@ class Onion(object): # Get the tor version self.tor_version = self.c.get_version().version_str + self.common.log('Onion', 'connect', 'Connected to tor {}'.format(self.tor_version)) # Do the versions of stem and tor that I'm using support ephemeral onion services? list_ephemeral_hidden_services = getattr(self.c, "list_ephemeral_hidden_services", None) @@ -405,7 +409,9 @@ class Onion(object): self.supports_stealth = False # Does this version of Tor support next-gen ('v3') onions? - self.supports_next_gen_onions = self.tor_version > Version('0.3.3.1') + # Note, this is the version of Tor where this bug was fixed: + # https://trac.torproject.org/projects/tor/ticket/28619 + self.supports_v3_onions = self.tor_version >= Version('0.4.0.0') def is_authenticated(self): """ @@ -463,7 +469,7 @@ class Onion(object): else: key_type = "NEW" # Work out if we can support v3 onion services, which are preferred - if Version(self.tor_version) >= Version('0.3.3.1') and not self.settings.get('use_legacy_v2_onions'): + if self.supports_v3_onions and not self.settings.get('use_legacy_v2_onions'): key_content = "ED25519-V3" else: # fall back to v2 onion services diff --git a/onionshare/settings.py b/onionshare/settings.py index 3397c1fd..00ba7d67 100644 --- a/onionshare/settings.py +++ b/onionshare/settings.py @@ -62,8 +62,9 @@ class Settings(object): 'fr': 'Français', # French 'it': 'Italiano', # Italian 'nl': 'Nederlands', # Dutch - 'no': 'Norsk', # Norweigan - 'pt': 'Português', # Portuguese + 'no': 'Norsk', # Norwegian + 'pt_BR': 'Português Brasil', # Portuguese Brazil + 'pt_PT': 'Português Portugal', # Portuguese Portugal 'ru': 'Русский', # Russian 'tr': 'Türkçe' # Turkish } @@ -95,7 +96,6 @@ class Settings(object): 'slug': '', 'hidservauth_string': '', 'downloads_dir': self.build_default_downloads_dir(), - 'receive_allow_receiver_shutdown': True, 'locale': None # this gets defined in fill_in_defaults() } self._settings = {} diff --git a/onionshare/strings.py b/onionshare/strings.py index b730933d..643186dd 100644 --- a/onionshare/strings.py +++ b/onionshare/strings.py @@ -45,7 +45,7 @@ def load_strings(common): current_locale = common.settings.get('locale') strings = {} for s in translations[default_locale]: - if s in translations[current_locale]: + if s in translations[current_locale] and translations[current_locale][s] != "": strings[s] = translations[current_locale][s] else: strings[s] = translations[default_locale][s] diff --git a/onionshare/web/receive_mode.py b/onionshare/web/receive_mode.py index 3149029f..6985f38a 100644 --- a/onionshare/web/receive_mode.py +++ b/onionshare/web/receive_mode.py @@ -17,7 +17,9 @@ class ReceiveModeWeb(object): self.web = web + self.can_upload = True self.upload_count = 0 + self.uploads_in_progress = [] self.define_routes() @@ -30,25 +32,25 @@ class ReceiveModeWeb(object): if self.common.settings.get('public_mode'): upload_action = '/upload' - close_action = '/close' else: upload_action = '/{}/upload'.format(self.web.slug) - close_action = '/{}/close'.format(self.web.slug) r = make_response(render_template( 'receive.html', - upload_action=upload_action, - close_action=close_action, - receive_allow_receiver_shutdown=self.common.settings.get('receive_allow_receiver_shutdown'))) + upload_action=upload_action)) return self.web.add_security_headers(r) @self.web.app.route("/<slug_candidate>") def index(slug_candidate): + if not self.can_upload: + return self.web.error403() self.web.check_slug_candidate(slug_candidate) return index_logic() @self.web.app.route("/") def index_public(): + if not self.can_upload: + return self.web.error403() if not self.common.settings.get('public_mode'): return self.web.error404() return index_logic() @@ -144,43 +146,41 @@ class ReceiveModeWeb(object): for filename in filenames: flash('Sent {}'.format(filename), 'info') - if self.common.settings.get('public_mode'): - return redirect('/') + if self.can_upload: + if self.common.settings.get('public_mode'): + path = '/' + else: + path = '/{}'.format(slug_candidate) + + return redirect('{}'.format(path)) else: - return redirect('/{}'.format(slug_candidate)) + # It was the last upload and the timer ran out + if self.common.settings.get('public_mode'): + return thankyou_logic(slug_candidate) + else: + return thankyou_logic() + + def thankyou_logic(slug_candidate=''): + r = make_response(render_template( + 'thankyou.html')) + return self.web.add_security_headers(r) @self.web.app.route("/<slug_candidate>/upload", methods=['POST']) def upload(slug_candidate): + if not self.can_upload: + return self.web.error403() self.web.check_slug_candidate(slug_candidate) return upload_logic(slug_candidate) @self.web.app.route("/upload", methods=['POST']) def upload_public(): + if not self.can_upload: + return self.web.error403() if not self.common.settings.get('public_mode'): return self.web.error404() return upload_logic() - def close_logic(slug_candidate=''): - if self.common.settings.get('receive_allow_receiver_shutdown'): - self.web.force_shutdown() - r = make_response(render_template('closed.html')) - self.web.add_request(self.web.REQUEST_CLOSE_SERVER, request.path) - return self.web.add_security_headers(r) - else: - return redirect('/{}'.format(slug_candidate)) - - @self.web.app.route("/<slug_candidate>/close", methods=['POST']) - def close(slug_candidate): - self.web.check_slug_candidate(slug_candidate) - return close_logic(slug_candidate) - - @self.web.app.route("/close", methods=['POST']) - def close_public(): - if not self.common.settings.get('public_mode'): - return self.web.error404() - return close_logic() - class ReceiveModeWSGIMiddleware(object): """ @@ -256,28 +256,34 @@ class ReceiveModeRequest(Request): # A dictionary that maps filenames to the bytes uploaded so far self.progress = {} - # Create an upload_id, attach it to the request - self.upload_id = self.web.receive_mode.upload_count - self.web.receive_mode.upload_count += 1 + # Prevent new uploads if we've said so (timer expired) + if self.web.receive_mode.can_upload: - # Figure out the content length - try: - self.content_length = int(self.headers['Content-Length']) - except: - self.content_length = 0 + # Create an upload_id, attach it to the request + self.upload_id = self.web.receive_mode.upload_count - print("{}: {}".format( - datetime.now().strftime("%b %d, %I:%M%p"), - strings._("receive_mode_upload_starting").format(self.web.common.human_readable_filesize(self.content_length)) - )) + self.web.receive_mode.upload_count += 1 - # Tell the GUI - self.web.add_request(self.web.REQUEST_STARTED, self.path, { - 'id': self.upload_id, - 'content_length': self.content_length - }) + # Figure out the content length + try: + self.content_length = int(self.headers['Content-Length']) + except: + self.content_length = 0 + + print("{}: {}".format( + datetime.now().strftime("%b %d, %I:%M%p"), + strings._("receive_mode_upload_starting").format(self.web.common.human_readable_filesize(self.content_length)) + )) + + # Tell the GUI + self.web.add_request(self.web.REQUEST_STARTED, self.path, { + 'id': self.upload_id, + 'content_length': self.content_length + }) + + self.web.receive_mode.uploads_in_progress.append(self.upload_id) - self.previous_file = None + self.previous_file = None def _get_file_stream(self, total_content_length, content_type, filename=None, content_length=None): """ @@ -297,11 +303,15 @@ class ReceiveModeRequest(Request): Closing the request. """ super(ReceiveModeRequest, self).close() - if self.upload_request: + try: + upload_id = self.upload_id # Inform the GUI that the upload has finished self.web.add_request(self.web.REQUEST_UPLOAD_FINISHED, self.path, { - 'id': self.upload_id + 'id': upload_id }) + self.web.receive_mode.uploads_in_progress.remove(upload_id) + except AttributeError: + pass def file_write_func(self, filename, length): """ diff --git a/onionshare/web/web.py b/onionshare/web/web.py index a423b2e1..21e9cd8f 100644 --- a/onionshare/web/web.py +++ b/onionshare/web/web.py @@ -142,6 +142,12 @@ class Web(object): r = make_response(render_template('404.html'), 404) return self.add_security_headers(r) + def error403(self): + self.add_request(Web.REQUEST_OTHER, request.path) + + r = make_response(render_template('403.html'), 403) + return self.add_security_headers(r) + def add_security_headers(self, r): """ Add security headers to a request @@ -178,9 +184,20 @@ class Web(object): """ Turn on debugging mode, which will log flask errors to a debug file. """ - temp_dir = tempfile.gettempdir() - log_handler = logging.FileHandler( - os.path.join(temp_dir, 'onionshare_server.log')) + if self.common.platform == 'Windows': + try: + appdata = os.environ['APPDATA'] + flask_debug_filename = '{}\\OnionShare\\flask_debug.log'.format(appdata) + except: + # If for some reason we don't have the 'APPDATA' environment variable + # (like running tests in Linux while pretending to be in Windows) + flask_debug_filename = os.path.expanduser('~/.config/onionshare/flask_debug.log') + elif self.common.platform == 'Darwin': + flask_debug_filename = os.path.expanduser('~/Library/Application Support/OnionShare/flask_debug.log') + else: + flask_debug_filename = os.path.expanduser('~/.config/onionshare/flask_debug.log') + + log_handler = logging.FileHandler(flask_debug_filename) log_handler.setLevel(logging.WARNING) self.app.logger.addHandler(log_handler) |