Commit 36c7cb9e authored by Pascal Engélibert's avatar Pascal Engélibert

Add /idtysig

parent 84e1bc5d
Pipeline #7027 passed with stage
in 1 minute and 11 seconds
......@@ -207,6 +207,9 @@ Command: **/getconfirm/_sender\_pubkey_/_in\_seed1_** get mix confirmation
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)
* If "client": _sender_ is the sender pubkey
* Else: _sender_ is the sender peer hash
......
......@@ -350,10 +350,14 @@ Options:
--onion use proxy only when connecting to .onion
-d <path> config directory (default ~/.config/gmixer-client)
--no-tx Do not send transaction (for debug)
--idtysig <pubkey> <host> <port>
Update node's identity signature (no mixing)
Example:
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()
......@@ -364,6 +368,31 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
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", "")
if receiver == "":
print("Error: No receiver set (try option --help)")
......@@ -375,10 +404,6 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
port = int(utils.getargv("-h", "", 2))
amount = int(utils.getargv("-a", "1000"))
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
db_txs = plyvel.DB(DIR+"/client_db_txs", create_if_missing=True)
......
......@@ -221,7 +221,7 @@ def read_config(cdir, conf_overwrite={}):
return conf
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)
self.conf = conf
......@@ -232,6 +232,8 @@ class ServerThread(Thread):
self.tx_in_index = tx_in_index
self.tx_out_index = tx_out_index
self.db_txs = db_txs
self.timers = timers
self.client_th = client_th
self.sock = None
self.work = True
......@@ -470,6 +472,26 @@ class ServerThread(Thread):
resp["confirm_ok"] = tx.out_seeds[2]
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:
sender_pubkey = utils.getargv("getconfirm", "", 1, url)
try:
......@@ -539,7 +561,7 @@ class ServerThread(Thread):
self.sock.shutdown(socket.SHUT_WR)
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)
self.conf = conf
......@@ -550,6 +572,7 @@ class ClientThread(Thread):
self.tx_in_index = tx_in_index
self.tx_out_index = tx_out_index
self.db_txs = db_txs
self.timers = timers
self.bma_endpoints = conf["client"]["bma_hosts"].copy()
self.work = True
......@@ -740,7 +763,7 @@ class ClientThread(Thread):
t = time.time()
next_mix = t + self.conf["mix"]["mix_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()
local_peer = utils.Peer.generate(self.conf, self.keys, self.peers)
......@@ -819,11 +842,11 @@ class ClientThread(Thread):
utils.logprint("No peer for: "+tx.receiver_pubkey, utils.LOG_WARN)
# 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)
utils.logprint("Generated new peer info", utils.LOG_TRACE)
self.spread_peer_info()
next_peer_info = time.time() + self.conf["server"]["peer_info_interval"]
# Remove expired requests
expire_txs = []
......@@ -850,15 +873,6 @@ def get_credentials(conf):
password = getpass.getpass("Enter your 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
def main():
# Load conf
......@@ -888,9 +902,11 @@ def main():
# Generate peer info
local_peer = utils.Peer.generate(conf, keys, {})
timers = {"next_peer_info": 0}
# Start threads
clientThread = ClientThread(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)
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, timers, clientThread)
clientThread.start()
serverThread.start()
......@@ -965,8 +981,10 @@ if __name__ == "__main__":
)
print(idty_keys.pubkey)
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.sigtime"] = doc["sigtime"]
conf = read_config(DIR, conf_overwrite)
......
......@@ -132,19 +132,35 @@ def run_async(coro):
#-------- Ğ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:
raw = libnacl.sign.Verifier(PublicKey(idty_pubkey).hex_pk()).verify(raw)
data = ubjson.loadb(raw)
assert data["doctype"] == "gmixer/idtysig" , "Bad doctype"
assert data["docver"] == "1" , "Bad docver"
assert data["pubkey"] == peer_pubkey , "Bad pubkey"
t = time.time()
assert data["sigtime"] < t and data["sigtime"] + conf["server"]["idty_sig_age_max"] > t , "Bad sigtime"
assert checktime(conf, data) , "Bad sigtime"
except (ValueError, IndexError, ubjson.decoder.DecoderException, AssertionError) as e:
logprint("Bad idty sig: "+str(e), LOG_TRACE)
return False
return True
return None
return data
class Peer:
VERSION = "2"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment