diff options
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | src/leap/bitmask/core/_web.py | 59 | ||||
-rw-r--r-- | src/leap/bitmask/core/configurable.py | 1 | ||||
-rw-r--r-- | src/leap/bitmask/core/service.py | 7 |
4 files changed, 60 insertions, 11 deletions
@@ -28,11 +28,13 @@ if platform.system() == "Windows": mail_deps = ['leap.soledad.client', 'gnupg'] gui_deps = ['vext.pyqt5', 'leap.bitmask_js'] +tor_deps = ['txtorcon'] extras = { 'mail': mail_deps, 'gui': gui_deps, 'backend': mail_deps, - 'all': mail_deps + gui_deps + 'all': mail_deps + gui_deps, + 'tor': tor_deps } diff --git a/src/leap/bitmask/core/_web.py b/src/leap/bitmask/core/_web.py index 1798e7f..715356d 100644 --- a/src/leap/bitmask/core/_web.py +++ b/src/leap/bitmask/core/_web.py @@ -26,6 +26,7 @@ import pkg_resources from twisted.internet import reactor from twisted.application import service +from twisted.internet import endpoints from twisted.web.resource import Resource from twisted.web.server import Site, NOT_DONE_YET from twisted.web.static import File @@ -39,6 +40,11 @@ try: except ImportError: HAS_WEB_UI = False +try: + import txtorcon +except Exception: + pass + log = Logger() @@ -46,12 +52,16 @@ class HTTPDispatcherService(service.Service): """ A Dispatcher for BitmaskCore exposing a REST API. + If the leap.bitmask_js package is available in the search path, it will + serve the UI under this same service too. """ - def __init__(self, core, port=7070, debug=False): + def __init__(self, core, port=7070, debug=False, onion=False): self._core = core self.port = port self.debug = debug + self.onion = onion + self.uri = '' def startService(self): if HAS_WEB_UI: @@ -67,14 +77,49 @@ class HTTPDispatcherService(service.Service): api = Api(CommandDispatcher(self._core)) root.putChild(u'API', api) - site = Site(root) - self.site = site + factory = Site(root) + self.site = factory + + if self.onion: + try: + import txtorcon + except ImportError: + log.error('onion is enabled, but could not find txtorcon') + return + self._start_onion_service(factory) - # TODO use endpoints instead - self.listener = reactor.listenTCP(self.port, site, - interface='127.0.0.1') + else: + interface = '127.0.0.1' + endpoint = endpoints.TCP4ServerEndpoint( + reactor, self.port, interface=interface) + self.uri = 'https://%s:%s' % (interface, self.port) + endpoint.listen(factory) + # TODO this should be set in a callback to the listen call self.running = True + def _start_onion_service(self, factory): + + def progress(percent, tag, message): + bar = int(percent / 10) + log.debug('[%s%s] %s' % ('#' * bar, '.' * (10 - bar), message)) + + def setup_complete(port): + port = txtorcon.IHiddenService(port) + self.uri = "http://%s" % (port.getHost().onion_uri) + log.info('I have set up a hidden service, advertised at: %s' + % self.uri) + log.info('locally listening on %s' % port.local_address.getHost()) + + def setup_failed(args): + log.error('onion service setup FAILED: %r' % args) + + endpoint = endpoints.serverFromString(reactor, 'onion:80') + txtorcon.IProgressProvider(endpoint).add_progress_listener(progress) + d = endpoint.listen(factory) + d.addCallback(setup_complete) + d.addErrback(setup_failed) + return d + def stopService(self): self.site.stopFactory() self.listener.stopListening() @@ -82,7 +127,7 @@ class HTTPDispatcherService(service.Service): def do_status(self): status = 'running' if self.running else 'disabled' - return {'web': status} + return {'web': status, 'uri': self.uri} class Api(Resource): diff --git a/src/leap/bitmask/core/configurable.py b/src/leap/bitmask/core/configurable.py index 8bd2ecf..f305cc3 100644 --- a/src/leap/bitmask/core/configurable.py +++ b/src/leap/bitmask/core/configurable.py @@ -103,5 +103,6 @@ mail = True eip = True zmq = True web = True +onion = False websockets = False """ diff --git a/src/leap/bitmask/core/service.py b/src/leap/bitmask/core/service.py index b6447dd..9fde788 100644 --- a/src/leap/bitmask/core/service.py +++ b/src/leap/bitmask/core/service.py @@ -74,7 +74,8 @@ class BitmaskBackend(configurable.ConfigurableService): on_start(self._init_zmq) if enabled('web'): - on_start(self._init_web) + onion = enabled('onion') + on_start(self._init_web, onion=onion) if enabled('websockets'): on_start(self._init_websockets) @@ -151,9 +152,9 @@ class BitmaskBackend(configurable.ConfigurableService): zs = _zmq.ZMQServerService(self) zs.setServiceParent(self) - def _init_web(self): + def _init_web(self, onion=False): service = _web.HTTPDispatcherService - self._maybe_init_service('web', service, self) + self._maybe_init_service('web', service, self, onion=onion) def _init_websockets(self): from leap.bitmask.core import websocket |