180 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			180 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import os,sys, subprocess | ||
|  | from tinyrpc.transports import ServerTransport | ||
|  | from tinyrpc.protocols.jsonrpc import JSONRPCProtocol | ||
|  | from tinyrpc.dispatch import public,RPCDispatcher | ||
|  | from tinyrpc.server import RPCServer | ||
|  | 
 | ||
|  | """ This is a POC example of how to write a custom UI for Clef. The UI starts the
 | ||
|  | clef process with the '--stdio-ui' option, and communicates with clef using standard input / output. | ||
|  | 
 | ||
|  | The standard input/output is a relatively secure way to communicate, as it does not require opening any ports | ||
|  | or IPC files. Needless to say, it does not protect against memory inspection mechanisms where an attacker | ||
|  | can access process memory."""
 | ||
|  | 
 | ||
|  | try: | ||
|  |     import urllib.parse as urlparse | ||
|  | except ImportError: | ||
|  |     import urllib as urlparse | ||
|  | 
 | ||
|  | class StdIOTransport(ServerTransport): | ||
|  |     """ Uses std input/output for RPC """ | ||
|  |     def receive_message(self): | ||
|  |         return None, urlparse.unquote(sys.stdin.readline()) | ||
|  | 
 | ||
|  |     def send_reply(self, context, reply): | ||
|  |         print(reply) | ||
|  | 
 | ||
|  | class PipeTransport(ServerTransport): | ||
|  |     """ Uses std a pipe for RPC """ | ||
|  | 
 | ||
|  |     def __init__(self,input, output): | ||
|  |         self.input = input | ||
|  |         self.output = output | ||
|  | 
 | ||
|  |     def receive_message(self): | ||
|  |         data = self.input.readline() | ||
|  |         print(">> {}".format( data)) | ||
|  |         return None, urlparse.unquote(data) | ||
|  | 
 | ||
|  |     def send_reply(self, context, reply): | ||
|  |         print("<< {}".format( reply)) | ||
|  |         self.output.write(reply) | ||
|  |         self.output.write("\n") | ||
|  | 
 | ||
|  | class StdIOHandler(): | ||
|  | 
 | ||
|  |     def __init__(self): | ||
|  |         pass | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveTx(self,req): | ||
|  |         """
 | ||
|  |         Example request: | ||
|  |         { | ||
|  |             "jsonrpc": "2.0", | ||
|  |             "method": "ApproveTx", | ||
|  |             "params": [{ | ||
|  |                 "transaction": { | ||
|  |                     "to": "0xae967917c465db8578ca9024c205720b1a3651A9", | ||
|  |                     "gas": "0x333", | ||
|  |                     "gasPrice": "0x123", | ||
|  |                     "value": "0x10", | ||
|  |                     "data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff", | ||
|  |                     "nonce": "0x0" | ||
|  |                 }, | ||
|  |                 "from": "0xAe967917c465db8578ca9024c205720b1a3651A9", | ||
|  |                 "call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658", | ||
|  |                 "meta": { | ||
|  |                     "remote": "127.0.0.1:34572", | ||
|  |                     "local": "localhost:8550", | ||
|  |                     "scheme": "HTTP/1.1" | ||
|  |                 } | ||
|  |             }], | ||
|  |             "id": 1 | ||
|  |         } | ||
|  | 
 | ||
|  |         :param transaction: transaction info | ||
|  |         :param call_info: info abou the call, e.g. if ABI info could not be | ||
|  |         :param meta: metadata about the request, e.g. where the call comes from | ||
|  |         :return:  | ||
|  |         """
 | ||
|  |         transaction = req.get('transaction') | ||
|  |         _from       = req.get('from') | ||
|  |         call_info   = req.get('call_info') | ||
|  |         meta        = req.get('meta') | ||
|  | 
 | ||
|  |         return { | ||
|  |             "approved" : False, | ||
|  |             #"transaction" : transaction, | ||
|  |   #          "from" : _from, | ||
|  | #            "password" : None, | ||
|  |         } | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveSignData(self, req): | ||
|  |         """ Example request
 | ||
|  | 
 | ||
|  |         """
 | ||
|  |         return {"approved": False, "password" : None} | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveExport(self, req): | ||
|  |         """ Example request
 | ||
|  | 
 | ||
|  |         """
 | ||
|  |         return {"approved" : False} | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveImport(self, req): | ||
|  |         """ Example request
 | ||
|  | 
 | ||
|  |         """
 | ||
|  |         return { "approved" : False, "old_password": "", "new_password": ""} | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveListing(self, req): | ||
|  |         """ Example request
 | ||
|  | 
 | ||
|  |         """
 | ||
|  |         return {'accounts': []} | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ApproveNewAccount(self, req): | ||
|  |         """
 | ||
|  |         Example request | ||
|  | 
 | ||
|  |         :return: | ||
|  |         """
 | ||
|  |         return {"approved": False, | ||
|  |                 #"password": "" | ||
|  |                 } | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ShowError(self,message = {}): | ||
|  |         """
 | ||
|  |         Example request: | ||
|  | 
 | ||
|  |         {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowError'"},"id":1} | ||
|  | 
 | ||
|  |         :param message: to show | ||
|  |         :return: nothing | ||
|  |         """
 | ||
|  |         if 'text' in message.keys(): | ||
|  |             sys.stderr.write("Error: {}\n".format( message['text'])) | ||
|  |         return | ||
|  | 
 | ||
|  |     @public | ||
|  |     def ShowInfo(self,message = {}): | ||
|  |         """
 | ||
|  |         Example request | ||
|  |         {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowInfo'"},"id":0} | ||
|  | 
 | ||
|  |         :param message: to display | ||
|  |         :return:nothing | ||
|  |         """
 | ||
|  | 
 | ||
|  |         if 'text' in message.keys(): | ||
|  |             sys.stdout.write("Error: {}\n".format( message['text'])) | ||
|  |         return | ||
|  | 
 | ||
|  | def main(args): | ||
|  | 
 | ||
|  |     cmd = ["./clef", "--stdio-ui"] | ||
|  |     if len(args) > 0 and args[0] == "test": | ||
|  |         cmd.extend(["--stdio-ui-test"]) | ||
|  |     print("cmd: {}".format(" ".join(cmd))) | ||
|  |     dispatcher = RPCDispatcher() | ||
|  |     dispatcher.register_instance(StdIOHandler(), '') | ||
|  |     # line buffered | ||
|  |     p = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | ||
|  | 
 | ||
|  |     rpc_server = RPCServer( | ||
|  |         PipeTransport(p.stdout, p.stdin), | ||
|  |         JSONRPCProtocol(), | ||
|  |         dispatcher | ||
|  |     ) | ||
|  |     rpc_server.serve_forever() | ||
|  | 
 | ||
|  | if __name__ == '__main__': | ||
|  |     main(sys.argv[1:]) |