summaryrefslogtreecommitdiff
path: root/onionshare
diff options
context:
space:
mode:
authorMiguel Jacq <mig@mig5.net>2019-03-05 10:28:27 +1100
committerMiguel Jacq <mig@mig5.net>2019-03-05 10:28:27 +1100
commit31c360b44d411fc9507eeb5815728a26af6781cf (patch)
tree5ecc6d80b80989fdbd064611d7b5bfd9742f359a /onionshare
parent3af05dcc2041026380a71b8aed1af9af849416a5 (diff)
downloadonionshare-31c360b44d411fc9507eeb5815728a26af6781cf.tar.gz
onionshare-31c360b44d411fc9507eeb5815728a26af6781cf.zip
Add a Startup Timer feature (scheduled start / dead man's switch)
Diffstat (limited to 'onionshare')
-rw-r--r--onionshare/__init__.py24
-rw-r--r--onionshare/onion.py18
-rw-r--r--onionshare/onionshare.py9
-rw-r--r--onionshare/settings.py1
-rw-r--r--onionshare/web/web.py8
5 files changed, 49 insertions, 11 deletions
diff --git a/onionshare/__init__.py b/onionshare/__init__.py
index 2f44c846..601631a2 100644
--- a/onionshare/__init__.py
+++ b/onionshare/__init__.py
@@ -53,6 +53,7 @@ def main(cwd=None):
parser = argparse.ArgumentParser(formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=28))
parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only"))
parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open"))
+ parser.add_argument('--startup-timer', metavar='<int>', dest='startup_timer', default=0, help=strings._("help_startup_timer"))
parser.add_argument('--shutdown-timeout', metavar='<int>', dest='shutdown_timeout', default=0, help=strings._("help_shutdown_timeout"))
parser.add_argument('--stealth', action='store_true', dest='stealth', help=strings._("help_stealth"))
parser.add_argument('--receive', action='store_true', dest='receive', help=strings._("help_receive"))
@@ -68,6 +69,7 @@ def main(cwd=None):
local_only = bool(args.local_only)
debug = bool(args.debug)
stay_open = bool(args.stay_open)
+ startup_timer = int(args.startup_timer)
shutdown_timeout = int(args.shutdown_timeout)
stealth = bool(args.stealth)
receive = bool(args.receive)
@@ -120,10 +122,28 @@ def main(cwd=None):
# Start the onionshare app
try:
+ common.settings.load()
+ if not common.settings.get('public_mode'):
+ web.generate_slug(common.settings.get('slug'))
+ else:
+ web.slug = None
app = OnionShare(common, onion, local_only, shutdown_timeout)
app.set_stealth(stealth)
app.choose_port()
- app.start_onion_service()
+ # Delay the startup if a startup timer was set
+ if startup_timer > 0:
+ app.start_onion_service(False, True)
+ if common.settings.get('public_mode'):
+ url = 'http://{0:s}'.format(app.onion_host)
+ else:
+ url = 'http://{0:s}/{1:s}'.format(app.onion_host, web.slug)
+ print(strings._("scheduled_onion_service").format(url))
+ app.onion.cleanup()
+ print(strings._("waiting_for_startup_timer"))
+ time.sleep(startup_timer)
+ app.start_onion_service()
+ else:
+ app.start_onion_service()
except KeyboardInterrupt:
print("")
sys.exit()
@@ -149,7 +169,7 @@ def main(cwd=None):
print('')
# Start OnionShare http service in new thread
- t = threading.Thread(target=web.start, args=(app.port, stay_open, common.settings.get('public_mode'), common.settings.get('slug')))
+ t = threading.Thread(target=web.start, args=(app.port, stay_open, common.settings.get('public_mode'), web.slug))
t.daemon = True
t.start()
diff --git a/onionshare/onion.py b/onionshare/onion.py
index ed4fde7b..17621b01 100644
--- a/onionshare/onion.py
+++ b/onionshare/onion.py
@@ -133,6 +133,7 @@ class Onion(object):
self.stealth = False
self.service_id = None
+ self.scheduled_key = None
# Is bundled tor supported?
if (self.common.platform == 'Windows' or self.common.platform == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
@@ -423,7 +424,7 @@ class Onion(object):
return False
- def start_onion_service(self, port):
+ def start_onion_service(self, port, await_publication, save_scheduled_key=False):
"""
Start a onion service on port 80, pointing to the given port, and
return the onion hostname.
@@ -455,6 +456,14 @@ class Onion(object):
# Assume it was a v3 key. Stem will throw an error if it's something illegible
key_type = "ED25519-V3"
+ elif self.scheduled_key:
+ key_content = self.scheduled_key
+ if self.is_v2_key(key_content):
+ key_type = "RSA1024"
+ else:
+ # Assume it was a v3 key. Stem will throw an error if it's something illegible
+ key_type = "ED25519-V3"
+
else:
key_type = "NEW"
# Work out if we can support v3 onion services, which are preferred
@@ -474,7 +483,6 @@ class Onion(object):
if key_type == "NEW":
debug_message += ', key_content={}'.format(key_content)
self.common.log('Onion', 'start_onion_service', '{}'.format(debug_message))
- await_publication = True
try:
if basic_auth != None:
res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=await_publication, basic_auth=basic_auth, key_type=key_type, key_content=key_content)
@@ -493,6 +501,12 @@ class Onion(object):
if not self.settings.get('private_key'):
self.settings.set('private_key', res.private_key)
+ # If we were scheduling a future share, register the private key for later re-use
+ if save_scheduled_key:
+ self.scheduled_key = res.private_key
+ else:
+ self.scheduled_key = None
+
if self.stealth:
# Similar to the PrivateKey, the Control port only returns the ClientAuth
# in the response if it was responsible for creating the basic_auth password
diff --git a/onionshare/onionshare.py b/onionshare/onionshare.py
index 551b8314..a91f28ba 100644
--- a/onionshare/onionshare.py
+++ b/onionshare/onionshare.py
@@ -41,6 +41,7 @@ class OnionShare(object):
self.onion_host = None
self.port = None
self.stealth = None
+ self.scheduled_key = None
# files and dirs to delete on shutdown
self.cleanup_filenames = []
@@ -68,7 +69,7 @@ class OnionShare(object):
except:
raise OSError(strings._('no_available_port'))
- def start_onion_service(self):
+ def start_onion_service(self, await_publication=True, save_scheduled_key=False):
"""
Start the onionshare onion service.
"""
@@ -84,16 +85,20 @@ class OnionShare(object):
self.onion_host = '127.0.0.1:{0:d}'.format(self.port)
return
- self.onion_host = self.onion.start_onion_service(self.port)
+ self.onion_host = self.onion.start_onion_service(self.port, await_publication, save_scheduled_key)
if self.stealth:
self.auth_string = self.onion.auth_string
+ if self.onion.scheduled_key:
+ self.scheduled_key = self.onion.scheduled_key
+
def cleanup(self):
"""
Shut everything down and clean up temporary files, etc.
"""
self.common.log('OnionShare', 'cleanup')
+ self.scheduled_key = None
# Cleanup files
try:
diff --git a/onionshare/settings.py b/onionshare/settings.py
index 68cbb857..d015c5ce 100644
--- a/onionshare/settings.py
+++ b/onionshare/settings.py
@@ -85,6 +85,7 @@ class Settings(object):
'auth_password': '',
'close_after_first_download': True,
'shutdown_timeout': False,
+ 'startup_timer': False,
'use_stealth': False,
'use_autoupdate': True,
'autoupdate_timestamp': None,
diff --git a/onionshare/web/web.py b/onionshare/web/web.py
index 66ba5b24..7ce87108 100644
--- a/onionshare/web/web.py
+++ b/onionshare/web/web.py
@@ -228,13 +228,11 @@ class Web(object):
pass
self.running = False
- def start(self, port, stay_open=False, public_mode=False, persistent_slug=None):
+ def start(self, port, stay_open=False, public_mode=False, slug=None):
"""
Start the flask web server.
"""
- self.common.log('Web', 'start', 'port={}, stay_open={}, public_mode={}, persistent_slug={}'.format(port, stay_open, public_mode, persistent_slug))
- if not public_mode:
- self.generate_slug(persistent_slug)
+ self.common.log('Web', 'start', 'port={}, stay_open={}, public_mode={}, slug={}'.format(port, stay_open, public_mode, slug))
self.stay_open = stay_open
@@ -264,7 +262,7 @@ class Web(object):
self.stop_q.put(True)
# Reset any slug that was in use
- self.slug = ''
+ self.slug = None
# To stop flask, load http://127.0.0.1:<port>/<shutdown_slug>/shutdown
if self.running: