Esempio n. 1
0
 def on_BIP78_RECEIVER_INIT(self, netconfig):
     netconfig = json.loads(netconfig)
     self.serving_port = int(netconfig["port"])
     self.tor_control_host = netconfig["tor_control_host"]
     self.tor_control_port = int(netconfig["tor_control_port"])
     self.bip78_rr = BIP78ReceiverResource(self.info_callback,
                                           self.shutdown_callback,
                                           self.post_request_handler)
     self.hs = JMHiddenService(self.bip78_rr, self.info_callback,
                               self.setup_error_callback,
                               self.onion_hostname_callback,
                               self.tor_control_host, self.tor_control_port,
                               self.serving_port, 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`.
     self.hs.start_tor()
     return {"accepted": True}
Esempio n. 2
0
class BIP78ServerProtocol(HTTPPassThrough):
    @BIP78ReceiverInit.responder
    def on_BIP78_RECEIVER_INIT(self, netconfig):
        netconfig = json.loads(netconfig)
        self.serving_port = int(netconfig["port"])
        self.tor_control_host = netconfig["tor_control_host"]
        self.tor_control_port = int(netconfig["tor_control_port"])
        self.bip78_rr = BIP78ReceiverResource(self.info_callback,
                                              self.shutdown_callback,
                                              self.post_request_handler)
        self.hs = JMHiddenService(self.bip78_rr, self.info_callback,
                                  self.setup_error_callback,
                                  self.onion_hostname_callback,
                                  self.tor_control_host, self.tor_control_port,
                                  self.serving_port, 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`.
        self.hs.start_tor()
        return {"accepted": True}

    def setup_error_callback(self, errormsg):
        d = self.callRemote(BIP78ReceiverOnionSetupFailed, reason=errormsg)
        self.defaultCallbacks(d)

    def shutdown_callback(self):
        d = self.callRemote(BIP78ReceiverHiddenServiceShutdown)
        self.defaultCallbacks(d)

    def info_callback(self, msg):
        """ Informational messages are all passed
	to the client. TODO makes sense to log locally
	too, in case daemon is isolated?.
	"""
        d = self.callRemote(BIP78InfoMsg, infomsg=msg)
        self.defaultCallbacks(d)

    def onion_hostname_callback(self, hostname):
        """ On successful start of HS, we pass hostname
	to client, who can use this to build the full URI.
	"""
        d = self.callRemote(BIP78ReceiverUp, hostname=hostname)
        self.defaultCallbacks(d)

    def post_request_handler(self, request, body, params):
        """ Fired when a sender has sent a POST request
	to our hidden service. Argument `body` should be a base64
        string and params should be a dict.
	"""
        self.post_request = request
        d = self.callRemote(BIP78ReceiverOriginalPSBT,
                            body=body,
                            params=json.dumps(bdict_sdict_convert(params)))
        self.defaultCallbacks(d)

    @BIP78ReceiverSendProposal.responder
    def on_BIP78_RECEIVER_SEND_PROPOSAL(self, psbt):
        content = psbt.encode("utf-8")
        self.post_request.setHeader(b"content-length", ("%d" % len(content)))
        self.post_request.write(content)
        self.post_request.finish()
        return {"accepted": True}

    @BIP78ReceiverSendError.responder
    def on_BIP78_RECEIVER_SEND_ERROR(self, errormsg, errorcode):
        self.post_request.write(
            self.bip78_rr.bip78_error(self.post_request, errormsg, errorcode))
        self.post_request.finish()
        return {"accepted": True}

    @BIP78SenderInit.responder
    def on_BIP78_SENDER_INIT(self, netconfig):
        self.on_INIT(netconfig)
        d = self.callRemote(BIP78SenderUp)
        self.defaultCallbacks(d)
        return {"accepted": True}

    @BIP78SenderOriginalPSBT.responder
    def on_BIP78_SENDER_ORIGINAL_PSBT(self, body, params):
        self.postRequest(body,
                         self.servers[0],
                         self.bip78_receiver_response,
                         params=json.loads(params),
                         headers=Headers({"Content-Type": ["text/plain"]}))
        return {"accepted": True}

    def bip78_receiver_response(self, response, server):
        d = readBody(response)
        # if the response code is not 200 OK, we must assume payjoin
        # attempt has failed, and revert to standard payment.
        if int(response.code) != 200:
            d.addCallback(self.process_receiver_errormsg, response.code)
            return
        d.addCallback(self.process_receiver_psbt)

    def process_receiver_errormsg(self, response, errorcode):
        d = self.callRemote(BIP78SenderReceiveError,
                            errormsg=response.decode("utf-8"),
                            errorcode=errorcode)
        self.defaultCallbacks(d)

    def process_receiver_psbt(self, response):
        d = self.callRemote(BIP78SenderReceiveProposal,
                            psbt=response.decode("utf-8"))
        self.defaultCallbacks(d)