diff options
author | Miguel Jacq <mig@mig5.net> | 2019-03-05 10:28:27 +1100 |
---|---|---|
committer | Miguel Jacq <mig@mig5.net> | 2019-03-05 10:28:27 +1100 |
commit | 31c360b44d411fc9507eeb5815728a26af6781cf (patch) | |
tree | 5ecc6d80b80989fdbd064611d7b5bfd9742f359a /onionshare | |
parent | 3af05dcc2041026380a71b8aed1af9af849416a5 (diff) | |
download | onionshare-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__.py | 24 | ||||
-rw-r--r-- | onionshare/onion.py | 18 | ||||
-rw-r--r-- | onionshare/onionshare.py | 9 | ||||
-rw-r--r-- | onionshare/settings.py | 1 | ||||
-rw-r--r-- | onionshare/web/web.py | 8 |
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: |