Skip to content
Snippets Groups Projects
Commit 36c7cb9e authored by Pascal Engélibert's avatar Pascal Engélibert :bicyclist:
Browse files

Add /idtysig

parent 84e1bc5d
No related branches found
No related tags found
No related merge requests found
Pipeline #7027 passed
...@@ -207,6 +207,9 @@ Command: **/getconfirm/_sender\_pubkey_/_in\_seed1_** get mix confirmation ...@@ -207,6 +207,9 @@ Command: **/getconfirm/_sender\_pubkey_/_in\_seed1_** get mix confirmation
CONFIRMS // Each confirm is preceded by its length, as above CONFIRMS // Each confirm is preceded by its length, as above
) )
Command: **/idtysig** update identity signature
Content: Identity signature (must be signed by current server idty)
Command: **/mix/_sender_/_amount_/_base_[/client]** mix a transaction (set "client" option if request is sent to entry node) Command: **/mix/_sender_/_amount_/_base_[/client]** mix a transaction (set "client" option if request is sent to entry node)
* If "client": _sender_ is the sender pubkey * If "client": _sender_ is the sender pubkey
* Else: _sender_ is the sender peer hash * Else: _sender_ is the sender peer hash
......
...@@ -350,10 +350,14 @@ Options: ...@@ -350,10 +350,14 @@ Options:
--onion use proxy only when connecting to .onion --onion use proxy only when connecting to .onion
-d <path> config directory (default ~/.config/gmixer-client) -d <path> config directory (default ~/.config/gmixer-client)
--no-tx Do not send transaction (for debug) --no-tx Do not send transaction (for debug)
--idtysig <pubkey> <host> <port>
Update node's identity signature (no mixing)
Example: Example:
python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8 -p 127.0.0.1 9050 --onion python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPgjMunYfLiCfUCySkM8 -p 127.0.0.1 9050 --onion
⤷ send 10Ğ1 to Duniter developers ⤷ send 10Ğ1 to Duniter developers (through a Tor peer)
python3 client.py -h txmn.tk 10951 -r HVXB7mrnrLDfJVALZiZknFg8FgPPi5k4y1md6GCLYGEK -a 5000
⤷ send 50Ğ1 to ĞMixer contributors
""") """)
exit() exit()
...@@ -364,6 +368,31 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg ...@@ -364,6 +368,31 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
conf = read_config(DIR) conf = read_config(DIR)
proxy = None
if "-p" in sys.argv:
proxy = (utils.getargv("-p", "127.0.0.1", 1), int(utils.getargv("-p", 9050, 2)))
proxy_onion_only = "--onion" in sys.argv
if "--idtysig" in sys.argv:
loop = True
while loop:
idty_keys = SigningKey.from_credentials(
getpass.getpass("Identity passphrase (salt):"),
getpass.getpass("Identity password:")
)
print(idty_keys.pubkey)
loop = input("Is that the right pubkey? [yn]: ").lower() != "y"
print(utils.sdata(
(utils.getargv("--idtysig", n=2), int(utils.getargv("--idtysig", n=3))),
"POST",
"/idtysig",
utils.gen_idty_sig(PublicKey(utils.getargv("--idtysig", n=1)), idty_keys)[0],
proxy=proxy,
proxy_onion_only=proxy_onion_only
))
exit()
receiver = utils.getargv("-r", "") receiver = utils.getargv("-r", "")
if receiver == "": if receiver == "":
print("Error: No receiver set (try option --help)") print("Error: No receiver set (try option --help)")
...@@ -375,10 +404,6 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg ...@@ -375,10 +404,6 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
port = int(utils.getargv("-h", "", 2)) port = int(utils.getargv("-h", "", 2))
amount = int(utils.getargv("-a", "1000")) amount = int(utils.getargv("-a", "1000"))
layers = int(utils.getargv("-l", "3")) layers = int(utils.getargv("-l", "3"))
proxy = None
if "-p" in sys.argv:
proxy = (utils.getargv("-p", "127.0.0.1", 1), int(utils.getargv("-p", 9050, 2)))
proxy_onion_only = "--onion" in sys.argv
send_tx = not "--no-tx" in sys.argv send_tx = not "--no-tx" in sys.argv
db_txs = plyvel.DB(DIR+"/client_db_txs", create_if_missing=True) db_txs = plyvel.DB(DIR+"/client_db_txs", create_if_missing=True)
......
...@@ -221,7 +221,7 @@ def read_config(cdir, conf_overwrite={}): ...@@ -221,7 +221,7 @@ def read_config(cdir, conf_overwrite={}):
return conf return conf
class ServerThread(Thread): class ServerThread(Thread):
def __init__(self, conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs): def __init__(self, conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs, timers, client_th):
Thread.__init__(self) Thread.__init__(self)
self.conf = conf self.conf = conf
...@@ -232,6 +232,8 @@ class ServerThread(Thread): ...@@ -232,6 +232,8 @@ class ServerThread(Thread):
self.tx_in_index = tx_in_index self.tx_in_index = tx_in_index
self.tx_out_index = tx_out_index self.tx_out_index = tx_out_index
self.db_txs = db_txs self.db_txs = db_txs
self.timers = timers
self.client_th = client_th
self.sock = None self.sock = None
self.work = True self.work = True
...@@ -470,6 +472,26 @@ class ServerThread(Thread): ...@@ -470,6 +472,26 @@ class ServerThread(Thread):
resp["confirm_ok"] = tx.out_seeds[2] resp["confirm_ok"] = tx.out_seeds[2]
peer.up_in = True peer.up_in = True
elif "idtysig" in url:
doc = utils.verify_idty_sig(self.conf, content, self.conf["idty"]["pubkey"], self.keys.pubkey, utils.self_checktime)
if not doc:
send_response(client, "403 Forbidden", {"error": "bad_idty_sig"}, resp_format)
continue
self.conf = read_config(DIR, {
"idty.sig": content.hex(),
"idty.sigtime": doc["sigtime"]
})
utils.logprint("Updated idty sig: sigtime= {}".format(doc["sigtime"]), utils.LOG_INFO)
self.timers["next_peer_info"] = time.time() + self.conf["server"]["peer_info_interval"]
self.local_peer = utils.Peer.generate(self.conf, self.keys, self.peers)
utils.logprint("Generated new peer info", utils.LOG_TRACE)
self.client_th.spread_peer_info()
resp["idtysig_ok"] = doc
if "getconfirm" in url: if "getconfirm" in url:
sender_pubkey = utils.getargv("getconfirm", "", 1, url) sender_pubkey = utils.getargv("getconfirm", "", 1, url)
try: try:
...@@ -539,7 +561,7 @@ class ServerThread(Thread): ...@@ -539,7 +561,7 @@ class ServerThread(Thread):
self.sock.shutdown(socket.SHUT_WR) self.sock.shutdown(socket.SHUT_WR)
class ClientThread(Thread): class ClientThread(Thread):
def __init__(self, conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs): def __init__(self, conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs, timers):
Thread.__init__(self) Thread.__init__(self)
self.conf = conf self.conf = conf
...@@ -550,6 +572,7 @@ class ClientThread(Thread): ...@@ -550,6 +572,7 @@ class ClientThread(Thread):
self.tx_in_index = tx_in_index self.tx_in_index = tx_in_index
self.tx_out_index = tx_out_index self.tx_out_index = tx_out_index
self.db_txs = db_txs self.db_txs = db_txs
self.timers = timers
self.bma_endpoints = conf["client"]["bma_hosts"].copy() self.bma_endpoints = conf["client"]["bma_hosts"].copy()
self.work = True self.work = True
...@@ -740,7 +763,7 @@ class ClientThread(Thread): ...@@ -740,7 +763,7 @@ class ClientThread(Thread):
t = time.time() t = time.time()
next_mix = t + self.conf["mix"]["mix_interval"] next_mix = t + self.conf["mix"]["mix_interval"]
next_peers_detection = t + self.conf["server"]["peer_detect_interval"] next_peers_detection = t + self.conf["server"]["peer_detect_interval"]
next_peer_info = t + self.conf["server"]["peer_info_interval"] self.timers["next_peer_info"] = t + self.conf["server"]["peer_info_interval"]
self.detect_peers() self.detect_peers()
local_peer = utils.Peer.generate(self.conf, self.keys, self.peers) local_peer = utils.Peer.generate(self.conf, self.keys, self.peers)
...@@ -819,11 +842,11 @@ class ClientThread(Thread): ...@@ -819,11 +842,11 @@ class ClientThread(Thread):
utils.logprint("No peer for: "+tx.receiver_pubkey, utils.LOG_WARN) utils.logprint("No peer for: "+tx.receiver_pubkey, utils.LOG_WARN)
# Generate peer info # Generate peer info
if t > next_peer_info: if t > self.timers["next_peer_info"]:
self.timers["next_peer_info"] = time.time() + self.conf["server"]["peer_info_interval"]
self.local_peer = utils.Peer.generate(self.conf, self.keys, self.peers) self.local_peer = utils.Peer.generate(self.conf, self.keys, self.peers)
utils.logprint("Generated new peer info", utils.LOG_TRACE) utils.logprint("Generated new peer info", utils.LOG_TRACE)
self.spread_peer_info() self.spread_peer_info()
next_peer_info = time.time() + self.conf["server"]["peer_info_interval"]
# Remove expired requests # Remove expired requests
expire_txs = [] expire_txs = []
...@@ -850,15 +873,6 @@ def get_credentials(conf): ...@@ -850,15 +873,6 @@ def get_credentials(conf):
password = getpass.getpass("Enter your password: ") password = getpass.getpass("Enter your password: ")
return salt, password return salt, password
def gen_idty_sig(keys, idty_keys):
doc = {
"doctype": "gmixer/idtysig",
"docver": "1",
"pubkey": keys.pubkey,
"sigtime": time.time()
}
return idty_keys.sign(ubjson.dumpb(doc))
# Main function # Main function
def main(): def main():
# Load conf # Load conf
...@@ -888,9 +902,11 @@ def main(): ...@@ -888,9 +902,11 @@ def main():
# Generate peer info # Generate peer info
local_peer = utils.Peer.generate(conf, keys, {}) local_peer = utils.Peer.generate(conf, keys, {})
timers = {"next_peer_info": 0}
# Start threads # Start threads
clientThread = ClientThread(conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs) clientThread = ClientThread(conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs, timers)
serverThread = ServerThread(conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs) serverThread = ServerThread(conf, peers, keys, local_peer, pool, tx_in_index, tx_out_index, db_txs, timers, clientThread)
clientThread.start() clientThread.start()
serverThread.start() serverThread.start()
...@@ -965,8 +981,10 @@ if __name__ == "__main__": ...@@ -965,8 +981,10 @@ if __name__ == "__main__":
) )
print(idty_keys.pubkey) print(idty_keys.pubkey)
loop = input("Is that the right pubkey? [yn]: ").lower() != "y" loop = input("Is that the right pubkey? [yn]: ").lower() != "y"
conf_overwrite["idty.sig"] = gen_idty_sig(keys, idty_keys).hex() sig, doc = utils.gen_idty_sig(keys, idty_keys)
conf_overwrite["idty.sig"] = sig.hex()
conf_overwrite["idty.pubkey"] = idty_keys.pubkey conf_overwrite["idty.pubkey"] = idty_keys.pubkey
conf_overwrite["idty.sigtime"] = doc["sigtime"]
conf = read_config(DIR, conf_overwrite) conf = read_config(DIR, conf_overwrite)
......
...@@ -132,19 +132,35 @@ def run_async(coro): ...@@ -132,19 +132,35 @@ def run_async(coro):
#-------- ĞMixer #-------- ĞMixer
def verify_idty_sig(conf, raw, idty_pubkey, peer_pubkey): def gen_idty_sig(keys, idty_keys):
doc = {
"doctype": "gmixer/idtysig",
"docver": "1",
"pubkey": keys.pubkey if isinstance(keys, SigningKey) else keys.base58(),
"sigtime": int(time.time())
}
return idty_keys.sign(ubjson.dumpb(doc)), doc
def default_checktime(conf, data):
t = time.time()
return data["sigtime"] < t and data["sigtime"] + conf["server"]["idty_sig_age_max"] > t
def self_checktime(conf, data):
t = time.time()
return data["sigtime"] > conf["idty"]["sigtime"] and data["sigtime"] < t and data["sigtime"] + conf["server"]["idty_sig_age_max"] > t
def verify_idty_sig(conf, raw, idty_pubkey, peer_pubkey, checktime=default_checktime):
try: try:
raw = libnacl.sign.Verifier(PublicKey(idty_pubkey).hex_pk()).verify(raw) raw = libnacl.sign.Verifier(PublicKey(idty_pubkey).hex_pk()).verify(raw)
data = ubjson.loadb(raw) data = ubjson.loadb(raw)
assert data["doctype"] == "gmixer/idtysig" , "Bad doctype" assert data["doctype"] == "gmixer/idtysig" , "Bad doctype"
assert data["docver"] == "1" , "Bad docver" assert data["docver"] == "1" , "Bad docver"
assert data["pubkey"] == peer_pubkey , "Bad pubkey" assert data["pubkey"] == peer_pubkey , "Bad pubkey"
t = time.time() assert checktime(conf, data) , "Bad sigtime"
assert data["sigtime"] < t and data["sigtime"] + conf["server"]["idty_sig_age_max"] > t , "Bad sigtime"
except (ValueError, IndexError, ubjson.decoder.DecoderException, AssertionError) as e: except (ValueError, IndexError, ubjson.decoder.DecoderException, AssertionError) as e:
logprint("Bad idty sig: "+str(e), LOG_TRACE) logprint("Bad idty sig: "+str(e), LOG_TRACE)
return False return None
return True return data
class Peer: class Peer:
VERSION = "2" VERSION = "2"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment