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}
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)