From 3bb51a16e13863abc724f5899098a6540bb83062 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Tue, 11 Feb 2020 16:47:30 -0600 Subject: [PATCH 1/2] check for onionr exit when awaiting onboarding completion --- src/communicator/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/communicator/__init__.py b/src/communicator/__init__.py index 304e8011..4091ced3 100755 --- a/src/communicator/__init__.py +++ b/src/communicator/__init__.py @@ -242,8 +242,9 @@ class OnionrCommunicatorDaemon: 'First run detected. Run openhome to get setup.', terminal=True) - while not config.get('onboarding.done', True): - time.sleep(5) + while not config.get('onboarding.done', True) and \ + not self.shutdown: + time.sleep(2) # Main daemon loop, mainly for calling timers, # don't do any complex operations here to avoid locking From 353b2f1c63426aa23fcf7d867fa2b751bdd32d97 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Tue, 11 Feb 2020 19:49:44 -0600 Subject: [PATCH 2/2] + added check for Tor to be ready before openhome works * fixed not being able to stop Onionr when awaiting onboarding survey to be finished --- docs/dev/http-api.md | 5 ++++- src/communicator/__init__.py | 5 ++++- src/httpapi/miscclientapi/endpoints.py | 10 ++++++--- src/netcontroller/torcontrol/__init__.py | 9 ++++---- src/onionrcommands/openwebinterface.py | 27 ++++++++++++++++++++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/dev/http-api.md b/docs/dev/http-api.md index e44d2b7a..6c189fd8 100755 --- a/docs/dev/http-api.md +++ b/docs/dev/http-api.md @@ -4,7 +4,7 @@ All HTTP interfaces in the Onionr reference client use the [Flask](http://flask. ## Client & Public difference -The client API server is a locked down interface intended for authenticated local communication. +The client API server is a locked down interface intended for authenticated local communication. The public API server is available only remotely from Tor & I2P. It is the interface in which peers use to communicate with one another. @@ -73,6 +73,9 @@ Please note: endpoints that simply provide static web app files are not document * /insertblock - Methods: POST - Accepts JSON data for creating a new block. 'message' contains the block data, 'to' specifies the peer's public key to encrypt the data to, 'sign' is a boolean for signing the message. +* /torready + - Methods: POST + - Returns boolean if Tor is started or not # Public API diff --git a/src/communicator/__init__.py b/src/communicator/__init__.py index 4091ced3..0f0f5782 100755 --- a/src/communicator/__init__.py +++ b/src/communicator/__init__.py @@ -244,7 +244,10 @@ class OnionrCommunicatorDaemon: while not config.get('onboarding.done', True) and \ not self.shutdown: - time.sleep(2) + try: + time.sleep(2) + except KeyboardInterrupt: + self.shutdown = True # Main daemon loop, mainly for calling timers, # don't do any complex operations here to avoid locking diff --git a/src/httpapi/miscclientapi/endpoints.py b/src/httpapi/miscclientapi/endpoints.py index 186dfcae..0c48dfea 100644 --- a/src/httpapi/miscclientapi/endpoints.py +++ b/src/httpapi/miscclientapi/endpoints.py @@ -7,8 +7,8 @@ import subprocess import platform from flask import Response, Blueprint, request, send_from_directory, abort +from flask import g from gevent import spawn -from gevent import sleep import unpaddedbase32 from httpapi import apiutils @@ -126,13 +126,17 @@ class PrivateEndpoints: @private_endpoints_bp.route('/gettorsocks') def get_tor_socks(): - return Response(str(client_api._too_many.get(NetController).socksPort)) + return Response(str(g.too_many.get(NetController).socksPort)) @private_endpoints_bp.route('/setonboarding', methods=['POST']) def set_onboarding(): return Response(config.onboarding.set_config_from_onboarding(request.get_json())) - + @private_endpoints_bp.route('/os') def get_os_system(): return Response(platform.system().lower()) + @private_endpoints_bp.route('/torready') + def is_tor_ready(): + """If Tor is starting up, the web UI is not ready to be used.""" + return Response(str(g.too_many.get(NetController).readyState).lower()) diff --git a/src/netcontroller/torcontrol/__init__.py b/src/netcontroller/torcontrol/__init__.py index 6fca8809..3f6b386b 100644 --- a/src/netcontroller/torcontrol/__init__.py +++ b/src/netcontroller/torcontrol/__init__.py @@ -13,7 +13,6 @@ import platform # For windows sigkill workaround from onionrtypes import BooleanSuccessState import logger -import filepaths from .. import getopenport from .. import watchdog from . import customtorrc @@ -109,10 +108,6 @@ class NetController: logger.fatal('Got keyboard interrupt. Onionr will exit soon.', timestamp = False, terminal=True) return False - logger.info('Finished starting Tor.', terminal=True) - - self.readyState = True - try: myID = open(self.dataDir + 'hs/hostname', 'r') self.myID = myID.read().replace('\n', '') @@ -125,6 +120,10 @@ class NetController: multiprocessing.Process(target=watchdog.watchdog, args=[os.getpid(), tor.pid]).start() + + logger.info('Finished starting Tor.', terminal=True) + + self.readyState = True return True def killTor(self): diff --git a/src/onionrcommands/openwebinterface.py b/src/onionrcommands/openwebinterface.py index 4147aaeb..f2fddb1b 100755 --- a/src/onionrcommands/openwebinterface.py +++ b/src/onionrcommands/openwebinterface.py @@ -3,9 +3,12 @@ Open the web interface properly into a web browser """ import webbrowser +from time import sleep + import logger from onionrutils import getclientapiserver import config +from onionrutils.localcommand import local_command """ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,8 +25,27 @@ import config """ +def _tell_if_ui_not_ready(): + if local_command('/torready') != 'true': + logger.warn('The UI is not ready yet, waiting on Tor to start.', terminal=True) + + +def _wait_for_ui_to_be_ready(): + if config.get('general.offline_mode', False) or \ + not config.get('transports.tor', True) or \ + config.get('tor.use_existing_tor'): + return + _tell_if_ui_not_ready() + while local_command('/torready') != 'true': + sleep(0.5) + logger.info("Tor is ready, opening UI", terminal=True) + + def get_url() -> str: """Build UI URL string and return it.""" + onboarding = "" + if not config.get('onboarding.done', False): + onboarding = "onboarding/" try: url = getclientapiserver.get_client_API_server() except FileNotFoundError: @@ -32,7 +54,7 @@ def get_url() -> str: 'Onionr seems to not be running (could not get api host)', terminal=True) else: - url = 'http://%s/#%s' % (url, config.get('client.webpassword')) + url = 'http://%s/%s#%s' % (url, onboarding, config.get('client.webpassword')) logger.info('Onionr web interface URL: ' + url, terminal=True) return url @@ -50,7 +72,8 @@ def open_home(): 'Onionr seems to not be running (could not get api host)', terminal=True) else: - url = 'http://%s/#%s' % (url, config.get('client.webpassword')) + _wait_for_ui_to_be_ready() + url = get_url() logger.info( 'If Onionr does not open automatically, use this URL: ' + url, terminal=True)