summaryrefslogtreecommitdiff
path: root/onionshare
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2018-12-16 17:11:18 -0800
committerMicah Lee <micah@micahflee.com>2018-12-16 17:11:18 -0800
commit043237bc20f34177dfae327998afbb22f2f824f1 (patch)
treefa2ff9a78a36b7f84dadd3a85c72ab2f8efa6bd3 /onionshare
parent3a0c8dc32317d4b66230663c1c3a40f6969d9275 (diff)
parentc059af97e1f0e484bdfb83521e5bab5e385cdd78 (diff)
downloadonionshare-043237bc20f34177dfae327998afbb22f2f824f1.tar.gz
onionshare-043237bc20f34177dfae327998afbb22f2f824f1.zip
Merge branch 'develop' into 406_osx_sandbox
Diffstat (limited to 'onionshare')
-rw-r--r--onionshare/__init__.py7
-rw-r--r--onionshare/common.py5
-rw-r--r--onionshare/onion.py10
-rw-r--r--onionshare/settings.py6
-rw-r--r--onionshare/strings.py2
-rw-r--r--onionshare/web/receive_mode.py106
-rw-r--r--onionshare/web/web.py23
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)