2023-01-10 15:58:26 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import nacl.bindings as sodium
|
|
|
|
from nacl.public import PrivateKey
|
|
|
|
from nacl.signing import SigningKey, VerifyKey
|
|
|
|
import nacl.encoding
|
|
|
|
import requests
|
|
|
|
import zmq
|
|
|
|
import zmq.utils.z85
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
import time
|
|
|
|
import random
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
|
|
|
|
context = zmq.Context()
|
|
|
|
socket = context.socket(zmq.DEALER)
|
|
|
|
socket.setsockopt(zmq.CONNECT_TIMEOUT, 5000)
|
|
|
|
socket.setsockopt(zmq.HANDSHAKE_IVL, 5000)
|
|
|
|
#socket.setsockopt(zmq.IMMEDIATE, 1)
|
|
|
|
|
|
|
|
if len(sys.argv) > 1 and any(sys.argv[1].startswith(x) for x in ("ipc://", "tcp://", "curve://")):
|
|
|
|
remote = sys.argv[1]
|
|
|
|
del sys.argv[1]
|
|
|
|
else:
|
|
|
|
remote = "ipc://./rpc.sock"
|
|
|
|
|
|
|
|
curve_pubkey = b''
|
|
|
|
my_privkey, my_pubkey = b'', b''
|
|
|
|
|
|
|
|
# If given a curve://whatever/pubkey argument then transform it into 'tcp://whatever' and put the
|
|
|
|
# 'pubkey' back into argv to be handled below.
|
|
|
|
if remote.startswith("curve://"):
|
|
|
|
pos = remote.rfind('/')
|
|
|
|
pkhex = remote[pos+1:]
|
|
|
|
remote = "tcp://" + remote[8:pos]
|
|
|
|
if len(pkhex) != 64 or not all(x in "0123456789abcdefABCDEF" for x in pkhex):
|
|
|
|
print("curve:// addresses must be in the form curve://HOST:PORT/REMOTE_PUBKEY_HEX", file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
sys.argv[1:0] = [pkhex]
|
|
|
|
|
|
|
|
if len(sys.argv) > 1 and len(sys.argv[1]) == 64 and all(x in "0123456789abcdefABCDEF" for x in sys.argv[1]):
|
|
|
|
curve_pubkey = bytes.fromhex(sys.argv[1])
|
|
|
|
del sys.argv[1]
|
|
|
|
socket.curve_serverkey = curve_pubkey
|
|
|
|
if len(sys.argv) > 1 and len(sys.argv[1]) == 64 and all(x in "0123456789abcdefABCDEF" for x in sys.argv[1]):
|
|
|
|
my_privkey = bytes.fromhex(sys.argv[1])
|
|
|
|
del sys.argv[1]
|
|
|
|
my_pubkey = zmq.utils.z85.decode(zmq.curve_public(zmq.utils.z85.encode(my_privkey)))
|
|
|
|
else:
|
|
|
|
my_privkey = PrivateKey.generate()
|
|
|
|
my_pubkey = my_privkey.public_key.encode()
|
|
|
|
my_privkey = my_privkey.encode()
|
|
|
|
|
|
|
|
print("No curve client privkey given; generated a random one (pubkey: {}, privkey: {})".format(
|
|
|
|
my_pubkey.hex(), my_privkey.hex()), file=sys.stderr)
|
|
|
|
socket.curve_secretkey = my_privkey
|
|
|
|
socket.curve_publickey = my_pubkey
|
|
|
|
|
|
|
|
if not 2 <= len(sys.argv) <= 3 or any(x in y for x in ("--help", "-h") for y in sys.argv[1:]):
|
|
|
|
print("Usage: {} [ipc:///path/to/sock|tcp://1.2.3.4:5678] [SERVER_CURVE_PUBKEY [LOCAL_CURVE_PRIVKEY]] COMMAND ['JSON']".format(
|
|
|
|
sys.argv[0]), file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
beginning_of_time = time.clock_gettime(time.CLOCK_MONOTONIC)
|
|
|
|
|
|
|
|
print("Connecting to {}".format(remote), file=sys.stderr)
|
|
|
|
socket.connect(remote)
|
|
|
|
to_send = [sys.argv[1].encode(), b'tagxyz123']
|
|
|
|
to_send += (x.encode() for x in sys.argv[2:])
|
|
|
|
print("Sending {}".format(to_send[0]), file=sys.stderr)
|
|
|
|
socket.send_multipart(to_send)
|
|
|
|
if socket.poll(timeout=5000):
|
|
|
|
m = socket.recv_multipart()
|
|
|
|
recv_time = time.clock_gettime(time.CLOCK_MONOTONIC)
|
|
|
|
if len(m) < 3 or m[0:2] != [b'REPLY', b'tagxyz123']:
|
|
|
|
print("Received unexpected {}-part reply:".format(len(m)), file=sys.stderr)
|
|
|
|
for x in m:
|
|
|
|
print("- {}".format(x))
|
|
|
|
else: # m[2] is numeric value, m[3] is data part, and will become m[2] <- changed
|
|
|
|
print("Received reply in {:.6f}s:".format(recv_time - beginning_of_time), file=sys.stderr)
|
|
|
|
if len(m) < 3:
|
|
|
|
print("(empty reply data)", file=sys.stderr)
|
|
|
|
else:
|
|
|
|
for x in m[2:]:
|
|
|
|
print("{} bytes data part:".format(len(x)), file=sys.stderr)
|
|
|
|
if any(x.startswith(y) for y in (b'd', b'l', b'i')) and x.endswith(b'e'):
|
|
|
|
sys.stdout.buffer.write(x)
|
|
|
|
else:
|
|
|
|
print(x.decode(), end="\n\n")
|
|
|
|
|
|
|
|
else:
|
|
|
|
print("Request timed out", file=sys.stderr)
|
|
|
|
socket.close(linger=0)
|
|
|
|
sys.exit(1)
|
|
|
|
|
2023-01-27 23:08:43 +00:00
|
|
|
# sample usage:
|
|
|
|
# ./omq-rpc.py ipc://$HOME/.oxen/testnet/oxend.sock 'llarp.get_service_nodes' | jq
|