pythonsigner.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import os,sys, subprocess
  2. from tinyrpc.transports import ServerTransport
  3. from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
  4. from tinyrpc.dispatch import public,RPCDispatcher
  5. from tinyrpc.server import RPCServer
  6. """ This is a POC example of how to write a custom UI for Clef. The UI starts the
  7. clef process with the '--stdio-ui' option, and communicates with clef using standard input / output.
  8. The standard input/output is a relatively secure way to communicate, as it does not require opening any ports
  9. or IPC files. Needless to say, it does not protect against memory inspection mechanisms where an attacker
  10. can access process memory."""
  11. try:
  12. import urllib.parse as urlparse
  13. except ImportError:
  14. import urllib as urlparse
  15. class StdIOTransport(ServerTransport):
  16. """ Uses std input/output for RPC """
  17. def receive_message(self):
  18. return None, urlparse.unquote(sys.stdin.readline())
  19. def send_reply(self, context, reply):
  20. print(reply)
  21. class PipeTransport(ServerTransport):
  22. """ Uses std a pipe for RPC """
  23. def __init__(self,input, output):
  24. self.input = input
  25. self.output = output
  26. def receive_message(self):
  27. data = self.input.readline()
  28. print(">> {}".format( data))
  29. return None, urlparse.unquote(data)
  30. def send_reply(self, context, reply):
  31. print("<< {}".format( reply))
  32. self.output.write(reply)
  33. self.output.write("\n")
  34. class StdIOHandler():
  35. def __init__(self):
  36. pass
  37. @public
  38. def ApproveTx(self,req):
  39. """
  40. Example request:
  41. {
  42. "jsonrpc": "2.0",
  43. "method": "ApproveTx",
  44. "params": [{
  45. "transaction": {
  46. "to": "0xae967917c465db8578ca9024c205720b1a3651A9",
  47. "gas": "0x333",
  48. "gasPrice": "0x123",
  49. "value": "0x10",
  50. "data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff",
  51. "nonce": "0x0"
  52. },
  53. "from": "0xAe967917c465db8578ca9024c205720b1a3651A9",
  54. "call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658",
  55. "meta": {
  56. "remote": "127.0.0.1:34572",
  57. "local": "localhost:8550",
  58. "scheme": "HTTP/1.1"
  59. }
  60. }],
  61. "id": 1
  62. }
  63. :param transaction: transaction info
  64. :param call_info: info abou the call, e.g. if ABI info could not be
  65. :param meta: metadata about the request, e.g. where the call comes from
  66. :return:
  67. """
  68. transaction = req.get('transaction')
  69. _from = req.get('from')
  70. call_info = req.get('call_info')
  71. meta = req.get('meta')
  72. return {
  73. "approved" : False,
  74. #"transaction" : transaction,
  75. # "from" : _from,
  76. # "password" : None,
  77. }
  78. @public
  79. def ApproveSignData(self, req):
  80. """ Example request
  81. """
  82. return {"approved": False, "password" : None}
  83. @public
  84. def ApproveExport(self, req):
  85. """ Example request
  86. """
  87. return {"approved" : False}
  88. @public
  89. def ApproveImport(self, req):
  90. """ Example request
  91. """
  92. return { "approved" : False, "old_password": "", "new_password": ""}
  93. @public
  94. def ApproveListing(self, req):
  95. """ Example request
  96. """
  97. return {'accounts': []}
  98. @public
  99. def ApproveNewAccount(self, req):
  100. """
  101. Example request
  102. :return:
  103. """
  104. return {"approved": False,
  105. #"password": ""
  106. }
  107. @public
  108. def ShowError(self,message = {}):
  109. """
  110. Example request:
  111. {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowError'"},"id":1}
  112. :param message: to show
  113. :return: nothing
  114. """
  115. if 'text' in message.keys():
  116. sys.stderr.write("Error: {}\n".format( message['text']))
  117. return
  118. @public
  119. def ShowInfo(self,message = {}):
  120. """
  121. Example request
  122. {"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowInfo'"},"id":0}
  123. :param message: to display
  124. :return:nothing
  125. """
  126. if 'text' in message.keys():
  127. sys.stdout.write("Error: {}\n".format( message['text']))
  128. return
  129. def main(args):
  130. cmd = ["clef", "--stdio-ui"]
  131. if len(args) > 0 and args[0] == "test":
  132. cmd.extend(["--stdio-ui-test"])
  133. print("cmd: {}".format(" ".join(cmd)))
  134. dispatcher = RPCDispatcher()
  135. dispatcher.register_instance(StdIOHandler(), '')
  136. # line buffered
  137. p = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  138. rpc_server = RPCServer(
  139. PipeTransport(p.stdout, p.stdin),
  140. JSONRPCProtocol(),
  141. dispatcher
  142. )
  143. rpc_server.serve_forever()
  144. if __name__ == '__main__':
  145. main(sys.argv[1:])