Commit df8c5d7f authored by Pascal Engélibert's avatar Pascal Engélibert

Fixes, client config

parent 0b638808
Pipeline #6673 passed with stage
in 2 minutes and 11 seconds
......@@ -32,10 +32,10 @@ Install the following packages: `libleveldb-dev` `libsodium-dev` `python3` `pyth
## How to use it
Create config & data dir: (change `~/.gmixer-g1`, so you can run different
Create config & data dir: (change `~/.config/gmixer-g1`, so you can run different
servers with different configs) (note that each server must have different dir)
python3 server.py -i -d ~/.gmixer-g1
python3 server.py -i -d ~/.config/gmixer-g1
Edit config and set your values. If you are not using any proxy, `bind_` and `public_` addresses should be the same.
If `salt` or `password` are empty, they will be asked at runtime. For security reasons, it is not a good idea to write them in commandline.
......
......@@ -22,14 +22,55 @@ Sources:
https://www.ietf.org/rfc/rfc3092.txt <- Very important RFC, please read it
"""
import sys, os, asyncio, getpass, random, time, secrets, socket
import sys, os, asyncio, getpass, random, time, secrets, socket, json
import ubjson
import plyvel
import libnacl.sign
from duniterpy.key import SigningKey, PublicKey
import utils
DIR = "~/.gmixer"
DIR = "~/.config/gmixer-client"
BMA_HOSTS = ["g1.duniter.fr 443", "g1.duniter.org 443", "g1.presles.fr 443", "g1.cgeek.fr 443", "ts.g1.librelois.fr 443"]
PEER_SIG_AGE_MAX = 604800 # max age of a peer document signature
IDTY_SIG_AGE_MAX = 2592000 # max age of a idty document signature
CURRENCY = "g1"
# Read json config file
def read_config(cdir, conf_overwrite={}):
if not os.path.isfile(cdir+"/config.json"):
configfile = open(cdir+"/config.json", "w")
configfile.write("{}")
configfile.close()
with open(cdir+"/config.json", "r") as configfile:
try:
conf = json.load(configfile)
except json.JSONDecodeError:
utils.logprint("Config: bad JSON => abort", utils.LOG_ERROR)
exit(1)
conf.setdefault("currency", CURRENCY)
conf.setdefault("server", {})
conf["server"].setdefault("peer_sig_age_max", PEER_SIG_AGE_MAX)
conf["server"].setdefault("idty_sig_age_max", IDTY_SIG_AGE_MAX)
conf.setdefault("client", {})
conf["client"].setdefault("bma_hosts", BMA_HOSTS)
conf["client"].setdefault("proxy", None)
conf["client"].setdefault("proxy_onion_only", False)
conf.setdefault("idty", {})
conf["idty"].setdefault("needed", True)
for key in conf_overwrite:
c = conf
k = key.split(".")
for i in k[:len(k)-1]:
c = conf[i]
c[k[len(k)-1]] = conf_overwrite[key]
with open(cdir+"/config.json", "w") as configfile:
json.dump(conf, configfile, indent=1)
return conf
class Confirmation():
def __init__(self, client_pubkey, node_pubkey, raw):
......@@ -63,7 +104,8 @@ class Confirmation():
"out_base": self.out_base
}
def get_peers(host, proxy=None, proxy_onion_only=False):
def get_peers(conf, host, proxy=None, proxy_onion_only=False):
header, content = utils.sdata(host, "GET", "/peers/info", proxy=proxy, proxy_onion_only=proxy_onion_only)
try:
......@@ -74,7 +116,7 @@ def get_peers(host, proxy=None, proxy_onion_only=False):
print("Error: bad UBJSON")
return
peers = [utils.Peer(data["info"]), *[utils.Peer(p) for p in data["peers"]]]
peers = [utils.Peer(conf, data["info"]), *[utils.Peer(conf, p["raw"]) for p in data["peers"]]]
#peers = [utils.Peer(p) for p in data["peers"]]
print([p.pubkey for p in peers])
......@@ -239,7 +281,7 @@ async def mix(db_txs, amount, base, sender, path, host, proxy=None, proxy_onion_
if not send_tx:
print("Remind: no-tx mode")
if input("OK? [yn]: ").lower() == "y":
if input("OK? [yN]: ").lower() == "y":
message = {
"sender": sender.pubkey,
"path": path,
......@@ -252,7 +294,10 @@ async def mix(db_txs, amount, base, sender, path, host, proxy=None, proxy_onion_
if send_tx:
try:
await utils.send_transaction(sender, path[0], amount, utils.gen_comment(comment_seeds[0]))
authfile = "/tmp/gmixer-client-authfile-"+secrets.token_urlsafe(8)
sender.save_seedhex_file(authfile)
#await utils.send_transaction(sender, path[0], amount, utils.gen_comment(comment_seeds[0]))
utils.send_transaction(authfile, path[0], amount, utils.gen_comment(comment_seeds[0]))
message["sent"] = True
db_txs.put(comment_seeds[0][1], PublicKey(sender.pubkey).encrypt_seal(ubjson.dumpb(message)))
......@@ -262,10 +307,10 @@ async def mix(db_txs, amount, base, sender, path, host, proxy=None, proxy_onion_
print("Error when sending tx: " + str(e))
return
async def main(db_txs, host, receiver, amount=1000, layers=3, proxy=None, proxy_onion_only=False, send_tx=True):
async def main(conf, db_txs, host, receiver, amount=1000, layers=3, proxy=None, proxy_onion_only=False, send_tx=True):
if amount < 100:
print("!! Warning !!\nYou are going to send less than 1.00, all this money will be destroyed by Duniter.\nPlease always send 1.00 or more.")
if input("Do it anyway? [yn]: ").lower() != "y":
if input("Do it anyway? [yN]: ").lower() != "y":
return
print("IDs of the expeditor account:")
......@@ -273,10 +318,10 @@ async def main(db_txs, host, receiver, amount=1000, layers=3, proxy=None, proxy_
password = getpass.getpass("Psw: ")
keys = SigningKey.from_credentials(salt, password) # sender
print(keys.pubkey)
if input("Is that the right pubkey? [yn]: ").lower() != "y":
if input("Is that the right pubkey? [yN]: ").lower() != "y":
return
peers = get_peers(host, proxy, proxy_onion_only)
peers = get_peers(conf, host, proxy, proxy_onion_only)
if peers == None:
print("Error getting peer list")
exit(1)
......@@ -287,7 +332,7 @@ async def main(db_txs, host, receiver, amount=1000, layers=3, proxy=None, proxy_
exit(1)
for peer in path:
print(peer)
if input("OK? [yn]: ").lower() == "y":
if input("OK? [yN]: ").lower() == "y":
break
await mix(db_txs, amount, 0, keys, path, host1, proxy, proxy_onion_only, send_tx)
......@@ -303,7 +348,7 @@ Options:
-h <host> <port> host for sync peer list
-p <host> <port> SOCKS5 proxy
--onion use proxy only when connecting to .onion
-d <path> config directory (default ~/.gmixer)
-d <path> config directory (default ~/.config/gmixer-client)
--no-tx Do not send transaction (for debug)
Example:
......@@ -317,6 +362,8 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
DIR = DIR[:len(DIR)-1] # Remove last slash
os.makedirs(DIR, exist_ok=True)
conf = read_config(DIR)
receiver = utils.getargv("-r", "")
if receiver == "":
print("Error: No receiver set (try option --help)")
......@@ -336,4 +383,4 @@ python3 client.py -h svetsae7j3usrycn.onion 10951 -r 78ZwwgpgdH5uLZLbThUQH7LKwPg
db_txs = plyvel.DB(DIR+"/client_db_txs", create_if_missing=True)
asyncio.get_event_loop().run_until_complete(main(db_txs, (host, port), receiver, amount, layers, proxy, proxy_onion_only, send_tx))
asyncio.get_event_loop().run_until_complete(main(conf, db_txs, (host, port), receiver, amount, layers, proxy, proxy_onion_only, send_tx))
......@@ -38,7 +38,7 @@ in_ = something that a node sent to me
out_ = something I'm sending to a node
"""
DIR = "~/.gmixer"
DIR = "~/.config/gmixer"
BIND_HOST = socket.gethostname()
try:
BIND_HOST = socket.gethostbyname(BIND_HOST)
......@@ -716,7 +716,8 @@ class ClientThread(Thread):
random.shuffle(txs)
for tx in txs:
try:
await utils.send_transaction(self.keys, tx.receiver_pubkey, tx.out_amount, utils.gen_comment(tx.out_seeds))
#await utils.send_transaction(self.keys, tx.receiver_pubkey, tx.out_amount, utils.gen_comment(tx.out_seeds))
utils.send_transaction(DIR+"/authfile", tx.receiver_pubkey, tx.out_amount, utils.gen_comment(tx.out_seeds))
tx.tx_sent = True
tx.export_ubjson(self.db_txs)
except socket.timeout:
......@@ -881,6 +882,9 @@ def main():
keys = SigningKey.from_credentials(salt, password)
utils.logprint("Pubkey: "+keys.pubkey, utils.LOG_INFO)
# Generate authfile
keys.save_seedhex_file(DIR+"/authfile")
# Generate peer info
local_peer = utils.Peer.generate(conf, keys, {})
......@@ -904,6 +908,12 @@ def main():
serverThread.join()
clientThread.join()
# Wipe authfile
f = open(DIR+"/authfile", "w")
f.write(secrets.token_hex(32))
f.close()
os.remove(DIR+"/authfile")
# Save
utils.save_peers(db_peers, peers)
db_peers.close()
......@@ -1033,7 +1043,7 @@ Options:\n\
--help Display help\n\
\n\
-d <path> Change config & data dir\n\
default: ~/.gmixer\n\
default: ~/.config/gmixer\n\
-v Verbose\n\
-P Auto set public address (overwrites config)\n\
-g (with -i or -I only) Generate identity signature\n\
......
......@@ -17,7 +17,7 @@
along with ĞMixer-py. If not, see <https://www.gnu.org/licenses/>.
"""
import sys, os, re, socket, time, secrets, hashlib, base64, asyncio
import sys, os, re, socket, time, secrets, hashlib, base64, asyncio, subprocess
import socks
import ubjson
import libnacl.sign
......@@ -275,8 +275,11 @@ async def check_idty(bma_endpoints:list, pubkey:str):
await client.close()
return "identities" in result and len(result["identities"]) > 0 and result["identities"][0]["pubkey"] == pubkey and result["identities"][0]["membershipExpiresIn"] > 0
async def send_transaction(sender_keys:SigningKey, receiver_pubkey:str, amount:int, comment:str):
#async def send_transaction(sender_keys:SigningKey, receiver_pubkey:str, amount:int, comment:str):
#sender_amount = silkaj.money.get_amount_from_pubkey(sender_keys.pubkey)[0]
#assert sender_amount >= amount, "not enough money"
await silkaj.tx.handle_intermediaries_transactions(sender_keys, sender_keys.pubkey, amount, [receiver_pubkey], comment)
#await silkaj.tx.handle_intermediaries_transactions(sender_keys, sender_keys.pubkey, amount, [receiver_pubkey], comment)
def send_transaction(authfile:str, receiver_pubkey:str, amount:int, comment:str):
subprocess.Popen(["silkaj", "--auth-file", "--file", authfile, "tx", "--output", receiver_pubkey, "--amount", str(amount/100), "--comment", comment, "-y"])
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