Browse Source

Allow user to configure host,port of onion.

Fixes #1027. Previous to this commit, the onion
service used by the payjoin receiver was automatically
served on localhost (at an arbitrary port), after this
commit these values can be specified in the PAYJOIN
section of the config.
master
Adam Gibson 4 years ago
parent
commit
b5a4ba3336
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 54
      jmbase/jmbase/twisted_utils.py
  2. 4
      jmclient/jmclient/client_protocol.py
  3. 11
      jmclient/jmclient/configure.py
  4. 7
      jmdaemon/jmdaemon/daemon_protocol.py

54
jmbase/jmbase/twisted_utils.py

@ -2,7 +2,8 @@
from zope.interface import implementer from zope.interface import implementer
from twisted.internet.error import ReactorNotRunning from twisted.internet.error import ReactorNotRunning
from twisted.internet import reactor, defer from twisted.internet import reactor, defer
from twisted.internet.endpoints import TCP4ClientEndpoint, UNIXClientEndpoint from twisted.internet.endpoints import (TCP4ClientEndpoint,
UNIXClientEndpoint, serverFromString)
from twisted.web.client import Agent, BrowserLikePolicyForHTTPS from twisted.web.client import Agent, BrowserLikePolicyForHTTPS
import txtorcon import txtorcon
from txtorcon.web import tor_agent from txtorcon.web import tor_agent
@ -105,6 +106,12 @@ def get_nontor_agent(tls_whitelist=[]):
contextFactory=WhitelistContextFactory(tls_whitelist)) contextFactory=WhitelistContextFactory(tls_whitelist))
return agent return agent
def config_to_hs_ports(virtual_port, host, port):
# See https://github.com/meejah/txtorcon/blob/0c416cc8fe18b913cd0c7422935885a1bfecf4c0/txtorcon/onion.py#L1320
# for non default config, pass port mapping strings like:
# "80 127.0.0.1:1234"
return "{} {}:{}".format(virtual_port, host, port)
class JMHiddenService(object): class JMHiddenService(object):
""" Wrapper class around the actions needed to """ Wrapper class around the actions needed to
create and serve on a hidden service; an object of create and serve on a hidden service; an object of
@ -113,7 +120,8 @@ class JMHiddenService(object):
""" """
def __init__(self, resource, info_callback, error_callback, def __init__(self, resource, info_callback, error_callback,
onion_hostname_callback, tor_control_host, onion_hostname_callback, tor_control_host,
tor_control_port, serving_port = None, tor_control_port, serving_host, serving_port,
virtual_port = None,
shutdown_callback = None): shutdown_callback = None):
self.site = Site(resource) self.site = Site(resource)
self.site.displayTracebacks = False self.site.displayTracebacks = False
@ -124,20 +132,23 @@ class JMHiddenService(object):
# known and is 80 by default) # known and is 80 by default)
self.onion_hostname_callback = onion_hostname_callback self.onion_hostname_callback = onion_hostname_callback
self.shutdown_callback = shutdown_callback self.shutdown_callback = shutdown_callback
if not serving_port: if not virtual_port:
self.port = 80 self.virtual_port = 80
else: else:
self.port = serving_port self.virtual_port = virtual_port
self.tor_control_host = tor_control_host self.tor_control_host = tor_control_host
self.tor_control_port = tor_control_port self.tor_control_port = tor_control_port
print("got these settings: ", self.port, self.site, self.tor_control_host, self.tor_control_port) # note that defaults only exist in jmclient
# config object, so no default here:
self.serving_host = serving_host
self.serving_port = serving_port
def start_tor(self): def start_tor(self):
""" This function executes the workflow """ This function executes the workflow
of starting the hidden service and returning its hostname of starting the hidden service and returning its hostname
""" """
self.info_callback("Attempting to start onion service on port: {} " self.info_callback("Attempting to start onion service on port: {} "
"...".format(self.port)) "...".format(self.virtual_port))
if str(self.tor_control_host).startswith('unix:'): if str(self.tor_control_host).startswith('unix:'):
control_endpoint = UNIXClientEndpoint(reactor, control_endpoint = UNIXClientEndpoint(reactor,
self.tor_control_host[5:]) self.tor_control_host[5:])
@ -158,20 +169,27 @@ class JMHiddenService(object):
def create_onion_ep(self, t): def create_onion_ep(self, t):
self.tor_connection = t self.tor_connection = t
return t.create_onion_endpoint(self.port, private_key=txtorcon.DISCARD) portmap_string = config_to_hs_ports(self.virtual_port,
self.serving_host, self.serving_port)
def onion_listen(self, onion_ep): return t.create_onion_service(
return onion_ep.listen(self.site) ports=[portmap_string], private_key=txtorcon.DISCARD)
def onion_listen(self, onion):
# 'onion' arg is the created EphemeralOnionService object;
# now we know it exists, we start serving the Site on the
# relevant port:
self.onion = onion
serverstring = "tcp:{}:interface={}".format(self.serving_port,
self.serving_host)
onion_endpoint = serverFromString(reactor, serverstring)
return onion_endpoint.listen(self.site)
def print_host(self, ep): def print_host(self, ep):
""" Callback fired once the HS is available; """ Callback fired once the HS is available
we let the caller know the hidden service onion hostname, and the site is up ready to receive requests.
which is not otherwise available to them: The hidden service hostname will be used in the BIP21 uri.
""" """
# Note that ep,getHost().onion_port must return the same self.onion_hostname_callback(self.onion.hostname)
# port as we chose in self.port; if not there is an error.
assert ep.getHost().onion_port == self.port
self.onion_hostname_callback(ep.getHost().onion_uri)
def shutdown(self): def shutdown(self):
self.tor_connection.protocol.transport.loseConnection() self.tor_connection.protocol.transport.loseConnection()

4
jmclient/jmclient/client_protocol.py

@ -86,7 +86,9 @@ class BIP78ClientProtocol(BaseClientProtocol):
else: else:
netconfig = {"port": 80, netconfig = {"port": 80,
"tor_control_host": jcg("PAYJOIN", "tor_control_host"), "tor_control_host": jcg("PAYJOIN", "tor_control_host"),
"tor_control_port": jcg("PAYJOIN", "tor_control_port")} "tor_control_port": jcg("PAYJOIN", "tor_control_port"),
"onion_serving_host": jcg("PAYJOIN", "onion_serving_host"),
"onion_serving_port": jcg("PAYJOIN", "onion_serving_port")}
d = self.callRemote(commands.BIP78ReceiverInit, d = self.callRemote(commands.BIP78ReceiverInit,
netconfig=netconfig) netconfig=netconfig)
self.defaultCallbacks(d) self.defaultCallbacks(d)

11
jmclient/jmclient/configure.py

@ -374,15 +374,22 @@ max_additional_fee_contribution = default
# transaction; note it is decimal, not integer. # transaction; note it is decimal, not integer.
min_fee_rate = 1.1 min_fee_rate = 1.1
# for payjoins to hidden service endpoints, the socks5 configuration: # for payjoins as sender (i.e. client) to hidden service endpoints,
# the socks5 configuration:
onion_socks5_host = localhost onion_socks5_host = localhost
onion_socks5_port = 9050 onion_socks5_port = 9050
# for payjoin onion service creation, the tor control configuration: # for payjoin onion service creation:
# the tor control configuration:
tor_control_host = localhost tor_control_host = localhost
# or, to use a UNIX socket # or, to use a UNIX socket
# control_host = unix:/var/run/tor/control # control_host = unix:/var/run/tor/control
tor_control_port = 9051 tor_control_port = 9051
# the host/port actually serving the hidden service
# (note the *virtual port*, that the client uses,
# is hardcoded to 80):
onion_serving_host = localhost
onion_serving_port = 8080
# in some exceptional case the HS may be SSL configured, # in some exceptional case the HS may be SSL configured,
# this feature is not yet implemented in code, but here for the # this feature is not yet implemented in code, but here for the

7
jmdaemon/jmdaemon/daemon_protocol.py

@ -274,6 +274,8 @@ class BIP78ServerProtocol(HTTPPassThrough):
self.serving_port = int(netconfig["port"]) self.serving_port = int(netconfig["port"])
self.tor_control_host = netconfig["tor_control_host"] self.tor_control_host = netconfig["tor_control_host"]
self.tor_control_port = int(netconfig["tor_control_port"]) self.tor_control_port = int(netconfig["tor_control_port"])
self.onion_serving_host=netconfig["onion_serving_host"]
self.onion_serving_port=int(netconfig["onion_serving_port"])
self.bip78_rr = BIP78ReceiverResource(self.info_callback, self.bip78_rr = BIP78ReceiverResource(self.info_callback,
self.shutdown_callback, self.shutdown_callback,
self.post_request_handler) self.post_request_handler)
@ -283,8 +285,9 @@ class BIP78ServerProtocol(HTTPPassThrough):
self.onion_hostname_callback, self.onion_hostname_callback,
self.tor_control_host, self.tor_control_host,
self.tor_control_port, self.tor_control_port,
self.serving_port, self.onion_serving_host,
self.shutdown_callback) self.onion_serving_port,
shutdown_callback=self.shutdown_callback)
# this call will start bringing up the HS; when it's finished, # this call will start bringing up the HS; when it's finished,
# it will fire the `onion_hostname_callback`, or if it fails, # it will fire the `onion_hostname_callback`, or if it fails,
# it'll fire the `setup_error_callback`. # it'll fire the `setup_error_callback`.

Loading…
Cancel
Save