* signer: introduce external signer command * cmd/signer, rpc: Implement new signer. Add info about remote user to Context * signer: refactored request/response, made use of urfave.cli * cmd/signer: Use common flags * cmd/signer: methods to validate calldata against abi * cmd/signer: work on abi parser * signer: add mutex around UI * cmd/signer: add json 4byte directory, remove passwords from api * cmd/signer: minor changes * cmd/signer: Use ErrRequestDenied, enable lightkdf * cmd/signer: implement tests * cmd/signer: made possible for UI to modify tx parameters * cmd/signer: refactors, removed channels in ui comms, added UI-api via stdin/out * cmd/signer: Made lowercase json-definitions, added UI-signer test functionality * cmd/signer: update documentation * cmd/signer: fix bugs, improve abi detection, abi argument display * cmd/signer: minor change in json format * cmd/signer: rework json communication * cmd/signer: implement mixcase addresses in API, fix json id bug * cmd/signer: rename fromaccount, update pythonpoc with new json encoding format * cmd/signer: make use of new abi interface * signer: documentation * signer/main: remove redundant option * signer: implement audit logging * signer: create package 'signer', minor changes * common: add 0x-prefix to mixcaseaddress in json marshalling + validation * signer, rules, storage: implement rules + ephemeral storage for signer rules * signer: implement OnApprovedTx, change signing response (API BREAKAGE) * signer: refactoring + documentation * signer/rules: implement dispatching to next handler * signer: docs * signer/rules: hide json-conversion from users, ensure context is cleaned * signer: docs * signer: implement validation rules, change signature of call_info * signer: fix log flaw with string pointer * signer: implement custom 4byte databsae that saves submitted signatures * signer/storage: implement aes-gcm-backed credential storage * accounts: implement json unmarshalling of url * signer: fix listresponse, fix gas->uint64 * node: make http/ipc start methods public * signer: add ipc capability+review concerns * accounts: correct docstring * signer: address review concerns * rpc: go fmt -s * signer: review concerns+ baptize Clef * signer,node: move Start-functions to separate file * signer: formatting
		
			
				
	
	
		
			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:])
 |