From 850f5592224ef03bfd78e32d3021cec4eef5a753 Mon Sep 17 00:00:00 2001 From: Andres Vargas Date: Mon, 14 Apr 2014 11:58:47 -0500 Subject: [PATCH 1/5] fix the daemon --- INSTALL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 289c5fe..fdaa31e 100644 --- a/INSTALL +++ b/INSTALL @@ -4,6 +4,6 @@ Dependencies (Debian): # pip install tornado - $ cd gateway/txrad/ + $ cd daemon/txrad/ $ make From e69ada6c962c837d1ceb8403ad171c7bc87ab720 Mon Sep 17 00:00:00 2001 From: Andres Vargas Date: Thu, 8 May 2014 15:50:41 -0500 Subject: [PATCH 2/5] reoranize to run with libs --- daemon/lib/__init__.py | 0 daemon/lib/crypto2crypto.py | 131 ++++++++++++++++++++++++++++ daemon/lib/p2p.py | 169 ++++++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 daemon/lib/__init__.py create mode 100644 daemon/lib/crypto2crypto.py create mode 100644 daemon/lib/p2p.py diff --git a/daemon/lib/__init__.py b/daemon/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/daemon/lib/crypto2crypto.py b/daemon/lib/crypto2crypto.py new file mode 100644 index 0000000..0623506 --- /dev/null +++ b/daemon/lib/crypto2crypto.py @@ -0,0 +1,131 @@ +import json +import sys +import pyelliptic as ec + +from p2p import PeerConnection, TransportLayer +from multiprocessing import Process +import traceback + +from protocol import hello, response_pubkey +import obelisk + +#if len(sys.argv) < 2: +# print >> sys.stderr, "Error, you need the filename of your crypto stuff." +# sys.exit(-1) + +def load_crypto_details(): + with open(sys.argv[1]) as f: + data = json.loads(f.read()) + assert "nickname" in data + assert "secret" in data + assert "pubkey" in data + assert len(data["secret"]) == 2 * 32 + assert len(data["pubkey"]) == 2 * 33 + return data["nickname"], data["secret"].decode("hex"), data["pubkey"].decode("hex") + +#NICKNAME, SECRET, PUBKEY = load_crypto_details() + +class CryptoPeerConnection(PeerConnection): + def __init__(self, address, transport, pub): + self._priv = transport._myself + self._pub = pub + PeerConnection.__init__(self, transport, address) + + def encrypt(self, data): + return self._priv.encrypt(data, self._pub) + + def send(self, data): + self.send_raw(self.encrypt(json.dumps(data))) + + def on_message(self, msg): + # this are just acks + pass + + +class CryptoTransportLayer(TransportLayer): + def __init__(self, port=None, my_ip=None): + TransportLayer.__init__(self, port, my_ip) + self._myself = ec.ECC(curve='secp256k1') + + self.nick_mapping = {} + + def get_profile(self): + peers = {} + for uri, peer in self._peers.iteritems(): + if peer._pub: + peers[uri] = peer._pub.encode('hex') + return {'uri': self._uri, 'pub': self._myself.get_pubkey().encode('hex'), 'peers': peers} + + def respond_pubkey_if_mine(self, nickname, ident_pubkey): + if ident_pubkey != PUBKEY: + print "Not my ident." + return + pubkey = self._myself.get_pubkey() + ec_key = obelisk.EllipticCurveKey() + ec_key.set_secret(SECRET) + digest = obelisk.Hash(pubkey) + signature = ec_key.sign(digest) + self.send(response_pubkey(nickname, pubkey, signature)) + + def create_peer(self, uri, pub): + if pub: + self.log("init peer " + uri + " " + pub[0:8], '*') + pub = pub.decode('hex') + else: + self.log("init peer [seed] " + uri, '*') + + # create the peer + self._peers[uri] = CryptoPeerConnection(uri, self, pub) + + # call 'peer' callbacks on listeners + self.trigger_callbacks('peer', self._peers[uri]) + + # now send a hello message to the peer + if pub: + self.log("sending encrypted profile to %s" % uri) + self._peers[uri].send(hello(self.get_profile())) + else: + # this is needed for the first connection + self.log("sending normal profile to %s" % uri) + profile = hello(self.get_profile()) + self._peers[uri].send_raw(json.dumps(profile)) + + def init_peer(self, msg): + uri = msg['uri'] + pub = msg.get('pub') + if uri == self._uri: + return + if not uri in self._peers: + self.create_peer(uri, pub) + elif pub: # and not self._peers[uri]._pub: + if self._peers[uri]._pub: + self.log("updating peer pubkey " + uri) + else: + self.log("setting pub for seed node " + uri) + if not self._peers[uri]._pub or not pub == self._peers[uri]._pub.encode('hex'): + self._peers[uri]._pub = pub.decode('hex') + self._peers[uri].send(hello(self.get_profile())) + + def on_raw_message(self, serialized): + try: + msg = json.loads(serialized) + self.log("receive [%s]" % msg.get('type', 'unknown')) + except ValueError: + try: + msg = json.loads(self._myself.decrypt(serialized)) + self.log("decrypted [%s]" % msg.get('type', 'unknown')) + except: + self.log("incorrect msg ! %s...") + traceback.print_exc() + return + + msg_type = msg.get('type') + if msg_type == 'hello' and msg.get('uri'): + self.init_peer(msg) + for uri, pub in msg.get('peers', {}).iteritems(): + self.init_peer({'uri': uri, 'pub': pub}) + self.log("Update peer table [%s peers]" % len(self._peers)) + else: + self.on_message(msg) + + diff --git a/daemon/lib/p2p.py b/daemon/lib/p2p.py new file mode 100644 index 0000000..1bc5889 --- /dev/null +++ b/daemon/lib/p2p.py @@ -0,0 +1,169 @@ +import sys +import json +from collections import defaultdict + +import pyelliptic as ec + +from zmq.eventloop import ioloop, zmqstream +import zmq +from multiprocessing import Process +from threading import Thread +#ioloop.install() +import traceback + +# Default port +DEFAULT_PORT=8889 + +# Get some command line pars +MY_IP = "127.0.0.1" + + +# Connection to one peer +class PeerConnection(object): + def __init__(self, transport, address): + # timeout in seconds + self._timeout = 10 + self._address = address + self._transport = transport + + def create_socket(self): + self._ctx = zmq.Context() + self._socket = self._ctx.socket(zmq.REQ) + self._socket.connect(self._address) + + def cleanup_socket(self): + self._socket.close() + + def send(self, data): + self.send_raw(json.dumps(data)) + + def send_raw(self, serialized): + Process(target=self._send_raw, args=(serialized,)).start() + + def _send_raw(self, serialized): + self.create_socket() + + self._socket.send(serialized) + + poller = zmq.Poller() + poller.register(self._socket, zmq.POLLIN) + if poller.poll(self._timeout * 1000): + msg = self._socket.recv() + self.on_message(msg) + self.cleanup_socket() + + else: + self._transport.log("Peer " + self._address + " timed out.") + self.cleanup_socket() + self._transport.remove_peer(self._address) + + def on_message(self, msg): + print "message received!", msg + + def closed(self, *args): + print " - peer disconnected" + +# Transport layer manages a list of peers +class TransportLayer(object): + def __init__(self, port=DEFAULT_PORT, my_ip=MY_IP): + print "init as " + my_ip + self._peers = {} + self._callbacks = defaultdict(list) + self._id = my_ip[-1] # hack for logging + self._port = port + self._uri = 'tcp://%s:%s' % (my_ip, self._port) + + def add_callback(self, section, callback): + self._callbacks[section].append(callback) + + def trigger_callbacks(self, section, *data): + for cb in self._callbacks[section]: + cb(*data) + if not section == 'all': + for cb in self._callbacks['all']: + cb(*data) + + def get_profile(self): + return {'type': 'hello', 'uri': self._uri} + + def join_network(self, seeds=[]): + self.listen() + for seed in seeds: + self.init_peer({'uri': seed}) + + def listen(self): + Thread(target=self._listen).start() + + def _listen(self): + self.log("init server %s" % self._uri) + self._ctx = zmq.Context() + self._socket = self._ctx.socket(zmq.REP) + self._socket.bind(self._uri) + while True: + try: + message = self._socket.recv() + except: + message = None + if message: + self.on_raw_message(message) + self._socket.send(json.dumps({'type': "ok"})) + + def closed(self, *args): + print "client left" + + def init_peer(self, msg): + uri = msg['uri'] + self.log("init peer %s" % msg) + if not uri in self._peers: + self._peers[uri] = PeerConnection(uri, self) + + def remove_peer(self, uri): + self.log("Removing peer " + uri ) + del self._peers[uri] + + self.log.debug("Peers " + str(self._peers) ) + + def log(self, msg, pointer='-'): + print " %s [%s] %s" % (pointer, self._id, msg) + + def send(self, data, send_to=None, secure=False): + self.log("sending %s..." % data.keys()) + # directed message + if send_to: + for peer in self._peers.values(): + if peer._pub == send_to: + peer.send(data) + return + print "peer not found!", send_to, self._myself.get_pubkey() + return + # broadcast + for peer in self._peers.values(): + try: + if peer._pub: + peer.send(data) + elif not secure: + serialized = json.dumps(data) + peer.send_raw(serialized) + except: + print "error sending over peer!" + traceback.print_exc() + + def on_message(self, msg): + # here goes the application callbacks + # we get a "clean" msg which is a dict holding whatever + self.trigger_callbacks(msg.get('type'), msg) + + def on_raw_message(self, serialized): + self.log("connected " +str(len(serialized))) + try: + msg = json.loads(serialized[0]) + except: + self.log("incorrect msg! " + serialized) + return + + msg_type = msg.get('type') + if msg_type == 'hello' and msg.get('uri'): + self.init_peer(msg) + else: + self.on_message(msg) + From 1679d9ab06405f9359dab41c46eba0562725717a Mon Sep 17 00:00:00 2001 From: Andres Vargas Date: Thu, 8 May 2014 15:56:03 -0500 Subject: [PATCH 3/5] make works with lib --- .gitignore | 1 + daemon/gateway.py | 2 +- lib/crypto2crypto.py | 131 --------------------------------- lib/p2p.py | 169 ------------------------------------------- 4 files changed, 2 insertions(+), 301 deletions(-) delete mode 100644 lib/crypto2crypto.py delete mode 100644 lib/p2p.py diff --git a/.gitignore b/.gitignore index 1a9d961..cac4866 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.pyc *.o *.so +config.json diff --git a/daemon/gateway.py b/daemon/gateway.py index 96c075c..4c2d6ea 100755 --- a/daemon/gateway.py +++ b/daemon/gateway.py @@ -18,7 +18,7 @@ from tornado.platform.twisted import TwistedIOLoop from twisted.internet import reactor TwistedIOLoop().install() -from crypto2crypto import CryptoTransportLayer +from lib.crypto2crypto import CryptoTransportLayer from tornado.options import define, options, parse_command_line diff --git a/lib/crypto2crypto.py b/lib/crypto2crypto.py deleted file mode 100644 index 0623506..0000000 --- a/lib/crypto2crypto.py +++ /dev/null @@ -1,131 +0,0 @@ -import json -import sys -import pyelliptic as ec - -from p2p import PeerConnection, TransportLayer -from multiprocessing import Process -import traceback - -from protocol import hello, response_pubkey -import obelisk - -#if len(sys.argv) < 2: -# print >> sys.stderr, "Error, you need the filename of your crypto stuff." -# sys.exit(-1) - -def load_crypto_details(): - with open(sys.argv[1]) as f: - data = json.loads(f.read()) - assert "nickname" in data - assert "secret" in data - assert "pubkey" in data - assert len(data["secret"]) == 2 * 32 - assert len(data["pubkey"]) == 2 * 33 - return data["nickname"], data["secret"].decode("hex"), data["pubkey"].decode("hex") - -#NICKNAME, SECRET, PUBKEY = load_crypto_details() - -class CryptoPeerConnection(PeerConnection): - def __init__(self, address, transport, pub): - self._priv = transport._myself - self._pub = pub - PeerConnection.__init__(self, transport, address) - - def encrypt(self, data): - return self._priv.encrypt(data, self._pub) - - def send(self, data): - self.send_raw(self.encrypt(json.dumps(data))) - - def on_message(self, msg): - # this are just acks - pass - - -class CryptoTransportLayer(TransportLayer): - def __init__(self, port=None, my_ip=None): - TransportLayer.__init__(self, port, my_ip) - self._myself = ec.ECC(curve='secp256k1') - - self.nick_mapping = {} - - def get_profile(self): - peers = {} - for uri, peer in self._peers.iteritems(): - if peer._pub: - peers[uri] = peer._pub.encode('hex') - return {'uri': self._uri, 'pub': self._myself.get_pubkey().encode('hex'), 'peers': peers} - - def respond_pubkey_if_mine(self, nickname, ident_pubkey): - if ident_pubkey != PUBKEY: - print "Not my ident." - return - pubkey = self._myself.get_pubkey() - ec_key = obelisk.EllipticCurveKey() - ec_key.set_secret(SECRET) - digest = obelisk.Hash(pubkey) - signature = ec_key.sign(digest) - self.send(response_pubkey(nickname, pubkey, signature)) - - def create_peer(self, uri, pub): - if pub: - self.log("init peer " + uri + " " + pub[0:8], '*') - pub = pub.decode('hex') - else: - self.log("init peer [seed] " + uri, '*') - - # create the peer - self._peers[uri] = CryptoPeerConnection(uri, self, pub) - - # call 'peer' callbacks on listeners - self.trigger_callbacks('peer', self._peers[uri]) - - # now send a hello message to the peer - if pub: - self.log("sending encrypted profile to %s" % uri) - self._peers[uri].send(hello(self.get_profile())) - else: - # this is needed for the first connection - self.log("sending normal profile to %s" % uri) - profile = hello(self.get_profile()) - self._peers[uri].send_raw(json.dumps(profile)) - - def init_peer(self, msg): - uri = msg['uri'] - pub = msg.get('pub') - if uri == self._uri: - return - if not uri in self._peers: - self.create_peer(uri, pub) - elif pub: # and not self._peers[uri]._pub: - if self._peers[uri]._pub: - self.log("updating peer pubkey " + uri) - else: - self.log("setting pub for seed node " + uri) - if not self._peers[uri]._pub or not pub == self._peers[uri]._pub.encode('hex'): - self._peers[uri]._pub = pub.decode('hex') - self._peers[uri].send(hello(self.get_profile())) - - def on_raw_message(self, serialized): - try: - msg = json.loads(serialized) - self.log("receive [%s]" % msg.get('type', 'unknown')) - except ValueError: - try: - msg = json.loads(self._myself.decrypt(serialized)) - self.log("decrypted [%s]" % msg.get('type', 'unknown')) - except: - self.log("incorrect msg ! %s...") - traceback.print_exc() - return - - msg_type = msg.get('type') - if msg_type == 'hello' and msg.get('uri'): - self.init_peer(msg) - for uri, pub in msg.get('peers', {}).iteritems(): - self.init_peer({'uri': uri, 'pub': pub}) - self.log("Update peer table [%s peers]" % len(self._peers)) - else: - self.on_message(msg) - - diff --git a/lib/p2p.py b/lib/p2p.py deleted file mode 100644 index 1bc5889..0000000 --- a/lib/p2p.py +++ /dev/null @@ -1,169 +0,0 @@ -import sys -import json -from collections import defaultdict - -import pyelliptic as ec - -from zmq.eventloop import ioloop, zmqstream -import zmq -from multiprocessing import Process -from threading import Thread -#ioloop.install() -import traceback - -# Default port -DEFAULT_PORT=8889 - -# Get some command line pars -MY_IP = "127.0.0.1" - - -# Connection to one peer -class PeerConnection(object): - def __init__(self, transport, address): - # timeout in seconds - self._timeout = 10 - self._address = address - self._transport = transport - - def create_socket(self): - self._ctx = zmq.Context() - self._socket = self._ctx.socket(zmq.REQ) - self._socket.connect(self._address) - - def cleanup_socket(self): - self._socket.close() - - def send(self, data): - self.send_raw(json.dumps(data)) - - def send_raw(self, serialized): - Process(target=self._send_raw, args=(serialized,)).start() - - def _send_raw(self, serialized): - self.create_socket() - - self._socket.send(serialized) - - poller = zmq.Poller() - poller.register(self._socket, zmq.POLLIN) - if poller.poll(self._timeout * 1000): - msg = self._socket.recv() - self.on_message(msg) - self.cleanup_socket() - - else: - self._transport.log("Peer " + self._address + " timed out.") - self.cleanup_socket() - self._transport.remove_peer(self._address) - - def on_message(self, msg): - print "message received!", msg - - def closed(self, *args): - print " - peer disconnected" - -# Transport layer manages a list of peers -class TransportLayer(object): - def __init__(self, port=DEFAULT_PORT, my_ip=MY_IP): - print "init as " + my_ip - self._peers = {} - self._callbacks = defaultdict(list) - self._id = my_ip[-1] # hack for logging - self._port = port - self._uri = 'tcp://%s:%s' % (my_ip, self._port) - - def add_callback(self, section, callback): - self._callbacks[section].append(callback) - - def trigger_callbacks(self, section, *data): - for cb in self._callbacks[section]: - cb(*data) - if not section == 'all': - for cb in self._callbacks['all']: - cb(*data) - - def get_profile(self): - return {'type': 'hello', 'uri': self._uri} - - def join_network(self, seeds=[]): - self.listen() - for seed in seeds: - self.init_peer({'uri': seed}) - - def listen(self): - Thread(target=self._listen).start() - - def _listen(self): - self.log("init server %s" % self._uri) - self._ctx = zmq.Context() - self._socket = self._ctx.socket(zmq.REP) - self._socket.bind(self._uri) - while True: - try: - message = self._socket.recv() - except: - message = None - if message: - self.on_raw_message(message) - self._socket.send(json.dumps({'type': "ok"})) - - def closed(self, *args): - print "client left" - - def init_peer(self, msg): - uri = msg['uri'] - self.log("init peer %s" % msg) - if not uri in self._peers: - self._peers[uri] = PeerConnection(uri, self) - - def remove_peer(self, uri): - self.log("Removing peer " + uri ) - del self._peers[uri] - - self.log.debug("Peers " + str(self._peers) ) - - def log(self, msg, pointer='-'): - print " %s [%s] %s" % (pointer, self._id, msg) - - def send(self, data, send_to=None, secure=False): - self.log("sending %s..." % data.keys()) - # directed message - if send_to: - for peer in self._peers.values(): - if peer._pub == send_to: - peer.send(data) - return - print "peer not found!", send_to, self._myself.get_pubkey() - return - # broadcast - for peer in self._peers.values(): - try: - if peer._pub: - peer.send(data) - elif not secure: - serialized = json.dumps(data) - peer.send_raw(serialized) - except: - print "error sending over peer!" - traceback.print_exc() - - def on_message(self, msg): - # here goes the application callbacks - # we get a "clean" msg which is a dict holding whatever - self.trigger_callbacks(msg.get('type'), msg) - - def on_raw_message(self, serialized): - self.log("connected " +str(len(serialized))) - try: - msg = json.loads(serialized[0]) - except: - self.log("incorrect msg! " + serialized) - return - - msg_type = msg.get('type') - if msg_type == 'hello' and msg.get('uri'): - self.init_peer(msg) - else: - self.on_message(msg) - From 0aa0b33998ade7d4f46eb8baf433db540487337f Mon Sep 17 00:00:00 2001 From: Andres Vargas Date: Thu, 8 May 2014 15:58:10 -0500 Subject: [PATCH 4/5] ignore ctags --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cac4866..4ad1a0f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.o *.so config.json +tags From 1fc632e1a468b108deccf8fe820c9643ac9014bd Mon Sep 17 00:00:00 2001 From: Andres Vargas Date: Thu, 8 May 2014 16:20:57 -0500 Subject: [PATCH 5/5] fix documentation --- INSTALL | 2 +- README.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index fdaa31e..0847e65 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Dependencies (Debian): python-obelisk from https://github.com/darkwallet/python-obelisk - # pip install tornado + # pip install tornado pyellyptic $ cd daemon/txrad/ $ make diff --git a/README.md b/README.md index 847b3bf..d95ce5e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ The darkwallet gateway is a daemon providing the following services to wallets: Generally the gateway tries to provide all services a wallet may need acting as a proxy to mask the user address so as to not compromise it in many services. +Install: +------------- + +see INSTALL file + Running: -----------