Add personal_newAccount handler for socket server

This commit is contained in:
nolash 2020-08-05 21:30:08 +02:00
parent e71b5ef4ea
commit acaff79ad2
Signed by: lash
GPG Key ID: 93EC1C676274C889
3 changed files with 105 additions and 24 deletions

View File

@ -1,12 +1,44 @@
import socket import socket
import json import json
import logging import logging
import sys
import os
from jsonrpc.exceptions import JSONRPCParseError from jsonrpc.exceptions import *
from signer import ReferenceSigner
from keystore import ReferenceDatabase
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger() logg = logging.getLogger()
db = None
signer = None
def personal_new_account(p):
if p.__class__.__name__ != 'list':
e = JSONRPCInvalidParams()
e.data = 'parameter must be list containing one string'
raise ValueError(e )
if len(p) != 1:
e = JSONRPCInvalidParams()
e.data = 'parameter must be list containing one string'
raise ValueError(e)
if p[0].__class__.__name__ != 'str':
e = JSONRPCInvalidParams()
e.data = 'parameter must be list containing one string'
raise ValueError(e)
r = db.new(p[0])
return [r]
methods = {
'personal_newAccount': personal_new_account,
}
def jsonrpc_error(id, err): def jsonrpc_error(id, err):
return { return {
@ -22,23 +54,61 @@ def jsonrpc_ok(rpc_id, response):
return { return {
'json-rpc': '2.0', 'json-rpc': '2.0',
'id': rpc_id, 'id': rpc_id,
'response': response, 'result': response,
} }
s = socket.socket(family = socket.AF_UNIX, type = socket.SOCK_STREAM) def process_input(j):
s.bind('/tmp/foo.ipc')
s.listen(10)
while True:
(csock, caddr) = s.accept()
d = csock.recv(4096)
try:
logg.debug('{}'.format(d.decode('utf-8')))
json.loads(d)
csock.send(json.dumps(jsonrpc_ok(0, [])).encode('utf-8'))
except:
csock.send(json.dumps(jsonrpc_error(None, JSONRPCParseError)).encode('utf-8'))
csock.close()
s.close()
os.unlink('/tmp/foo.ipc') rpc_id = j['id']
m = j['method']
p = j['params']
return (rpc_id, methods[m](p))
def start_server():
os.unlink('/tmp/foo.ipc')
s = socket.socket(family = socket.AF_UNIX, type = socket.SOCK_STREAM)
s.bind('/tmp/foo.ipc')
s.listen(10)
while True:
(csock, caddr) = s.accept()
d = csock.recv(4096)
try:
j = json.loads(b)
process_input(j)
logg.debug('{}'.format(d.decode('utf-8')))
csock.send(json.dumps(jsonrpc_ok(0, [])).encode('utf-8'))
except:
csock.send(json.dumps(jsonrpc_error(None, JSONRPCParseError)).encode('utf-8'))
csock.close()
s.close()
os.unlink('/tmp/foo.ipc')
def init():
global db, signer
secret_hex = os.environ.get('SIGNER_SECRET')
secret = bytes.fromhex(secret_hex)
kw = {
'symmetric_key': secret,
}
db = ReferenceDatabase('cic_signer', **kw)
signer = ReferenceSigner(db.get)
if __name__ == '__main__':
init()
arg = None
try:
arg = json.loads(sys.argv[1])
except:
logg.info('no json rpc command detected, starting socket server')
start_server()
sys.exit(0)
(rpc_id, response) = process_input(arg)
r = jsonrpc_ok(rpc_id, response)
sys.stdout.write(json.dumps(r))

View File

@ -9,6 +9,8 @@ from eth_keys import KeyAPI
from eth_keys.backends import NativeECCBackend from eth_keys.backends import NativeECCBackend
import sha3 import sha3
from common import strip_hex_prefix
keyapi = KeyAPI(NativeECCBackend) keyapi = KeyAPI(NativeECCBackend)
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
@ -24,7 +26,7 @@ class ReferenceDatabase:
def __init__(self, dbname, **kwargs): def __init__(self, dbname, **kwargs):
self.conn = psycopg2.connect('dbname='+dbname) self.conn = psycopg2.connect('dbname=' + dbname)
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
self.symmetric_key = kwargs.get('symmetric_key') self.symmetric_key = kwargs.get('symmetric_key')
@ -36,12 +38,20 @@ class ReferenceDatabase:
return self._decrypt(k, password) return self._decrypt(k, password)
def new(self, address, password=None): def new(self, password=None):
b = os.urandom(32) b = os.urandom(32)
pk = keyapi.PrivateKey(b) pk = keyapi.PrivateKey(b)
pubk = keyapi.private_key_to_public_key(pk)
address_hex = pubk.to_checksum_address()
address_hex_clean = strip_hex_prefix(address_hex)
logg.debug('address {}'.format(address_hex_clean))
c = self._encrypt(pk.to_bytes(), password) c = self._encrypt(pk.to_bytes(), password)
s = sql.SQL('INSERT INTO ethereum (wallet_address_hex, key_ciphertext) VALUES (%s, %s)') s = sql.SQL('INSERT INTO ethereum (wallet_address_hex, key_ciphertext) VALUES (%s, %s)')
self.cur.execute(s, [ address, c.decode('utf-8') ]) self.cur.execute(s, [ address_hex_clean, c.decode('utf-8') ])
self.conn.commit()
return address_hex
def _encrypt(self, private_key, password): def _encrypt(self, private_key, password):
@ -64,7 +74,8 @@ class ReferenceDatabase:
return f.decrypt(c.encode('utf-8')) return f.decrypt(c.encode('utf-8'))
def __exit__(self): def __del__(self):
self.conn logg.debug('closing database')
self.conn.commit()
self.cur.close() self.cur.close()
self.conn.close() self.conn.close()

View File

@ -27,12 +27,12 @@ class ReferenceSigner(Signer):
super(ReferenceSigner, self).__init__(keyGetter) super(ReferenceSigner, self).__init__(keyGetter)
def signTransaction(self, tx): def signTransaction(self, tx, password=None):
s = tx.serialize() s = tx.serialize()
h = sha3.keccak_256() h = sha3.keccak_256()
h.update(s) h.update(s)
g = h.digest() g = h.digest()
k = keys.PrivateKey(self.keyGetter(tx.sender)) k = keys.PrivateKey(self.keyGetter(tx.sender, password))
z = keys.ecdsa_sign(message_hash=g, private_key=k) z = keys.ecdsa_sign(message_hash=g, private_key=k)
tx.v = (tx.v * 2) + 35 + z[64] tx.v = (tx.v * 2) + 35 + z[64]
tx.r = z[:32] tx.r = z[:32]