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. 56
      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

56
jmbase/jmbase/twisted_utils.py

@ -2,7 +2,8 @@
from zope.interface import implementer
from twisted.internet.error import ReactorNotRunning
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
import txtorcon
from txtorcon.web import tor_agent
@ -105,6 +106,12 @@ def get_nontor_agent(tls_whitelist=[]):
contextFactory=WhitelistContextFactory(tls_whitelist))
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):
""" Wrapper class around the actions needed to
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,
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):
self.site = Site(resource)
self.site.displayTracebacks = False
@ -124,26 +132,29 @@ class JMHiddenService(object):
# known and is 80 by default)
self.onion_hostname_callback = onion_hostname_callback
self.shutdown_callback = shutdown_callback
if not serving_port:
self.port = 80
if not virtual_port:
self.virtual_port = 80
else:
self.port = serving_port
self.virtual_port = virtual_port
self.tor_control_host = tor_control_host
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):
""" This function executes the workflow
of starting the hidden service and returning its hostname
"""
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:'):
control_endpoint = UNIXClientEndpoint(reactor,
self.tor_control_host[5:])
else:
control_endpoint = TCP4ClientEndpoint(reactor,
self.tor_control_host,self.tor_control_port)
self.tor_control_host, self.tor_control_port)
d = txtorcon.connect(reactor, control_endpoint)
d.addCallback(self.create_onion_ep)
d.addErrback(self.setup_failed)
@ -158,20 +169,27 @@ class JMHiddenService(object):
def create_onion_ep(self, t):
self.tor_connection = t
return t.create_onion_endpoint(self.port, private_key=txtorcon.DISCARD)
def onion_listen(self, onion_ep):
return onion_ep.listen(self.site)
portmap_string = config_to_hs_ports(self.virtual_port,
self.serving_host, self.serving_port)
return t.create_onion_service(
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):
""" Callback fired once the HS is available;
we let the caller know the hidden service onion hostname,
which is not otherwise available to them:
""" Callback fired once the HS is available
and the site is up ready to receive requests.
The hidden service hostname will be used in the BIP21 uri.
"""
# Note that ep,getHost().onion_port must return the same
# 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)
self.onion_hostname_callback(self.onion.hostname)
def shutdown(self):
self.tor_connection.protocol.transport.loseConnection()

4
jmclient/jmclient/client_protocol.py

@ -86,7 +86,9 @@ class BIP78ClientProtocol(BaseClientProtocol):
else:
netconfig = {"port": 80,
"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,
netconfig=netconfig)
self.defaultCallbacks(d)

11
jmclient/jmclient/configure.py

@ -374,15 +374,22 @@ max_additional_fee_contribution = default
# transaction; note it is decimal, not integer.
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_port = 9050
# for payjoin onion service creation, the tor control configuration:
# for payjoin onion service creation:
# the tor control configuration:
tor_control_host = localhost
# or, to use a UNIX socket
# control_host = unix:/var/run/tor/control
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,
# 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.tor_control_host = netconfig["tor_control_host"]
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.shutdown_callback,
self.post_request_handler)
@ -283,8 +285,9 @@ class BIP78ServerProtocol(HTTPPassThrough):
self.onion_hostname_callback,
self.tor_control_host,
self.tor_control_port,
self.serving_port,
self.shutdown_callback)
self.onion_serving_host,
self.onion_serving_port,
shutdown_callback=self.shutdown_callback)
# this call will start bringing up the HS; when it's finished,
# it will fire the `onion_hostname_callback`, or if it fails,
# it'll fire the `setup_error_callback`.

Loading…
Cancel
Save