mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-26 15:30:18 +00:00
Compare commits
19 Commits
1aa3a0230a
...
5cf4869eda
Author | SHA1 | Date | |
---|---|---|---|
|
5cf4869eda | ||
|
d2feb8b136 | ||
|
f595648a9b | ||
|
b06f5285c5 | ||
|
8330f70a27 | ||
|
e47dcae54e | ||
|
15e10b9435 | ||
|
b91c852330 | ||
|
75acdf5902 | ||
|
acd893a6e6 | ||
|
c032a2e438 | ||
|
1f6a494e14 | ||
|
059c2381b5 | ||
|
541d3cde48 | ||
|
87ff1808a2 | ||
|
8d1a000378 | ||
|
794a5f4401 | ||
|
7159e6a523 | ||
|
cf41187e2f |
@ -168,16 +168,19 @@ class Link:
|
|||||||
self.type = RNS.Destination.LINK
|
self.type = RNS.Destination.LINK
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
|
self.expected_hops = None
|
||||||
self.attached_interface = None
|
self.attached_interface = None
|
||||||
self.__remote_identity = None
|
self.__remote_identity = None
|
||||||
self.__track_phy_stats = False
|
self.__track_phy_stats = False
|
||||||
self._channel = None
|
self._channel = None
|
||||||
|
|
||||||
if self.destination == None:
|
if self.destination == None:
|
||||||
self.initiator = False
|
self.initiator = False
|
||||||
self.prv = X25519PrivateKey.generate()
|
self.prv = X25519PrivateKey.generate()
|
||||||
self.sig_prv = self.owner.identity.sig_prv
|
self.sig_prv = self.owner.identity.sig_prv
|
||||||
else:
|
else:
|
||||||
self.initiator = True
|
self.initiator = True
|
||||||
|
self.expected_hops = RNS.Transport.hops_to(self.destination.hash)
|
||||||
self.establishment_timeout = RNS.Reticulum.get_instance().get_first_hop_timeout(destination.hash)
|
self.establishment_timeout = RNS.Reticulum.get_instance().get_first_hop_timeout(destination.hash)
|
||||||
self.establishment_timeout += Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, RNS.Transport.hops_to(destination.hash))
|
self.establishment_timeout += Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, RNS.Transport.hops_to(destination.hash))
|
||||||
self.prv = X25519PrivateKey.generate()
|
self.prv = X25519PrivateKey.generate()
|
||||||
|
@ -64,8 +64,8 @@ class Transport:
|
|||||||
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
|
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
|
||||||
|
|
||||||
PATH_REQUEST_TIMEOUT = 15 # Default timuout for client path requests in seconds
|
PATH_REQUEST_TIMEOUT = 15 # Default timuout for client path requests in seconds
|
||||||
PATH_REQUEST_GRACE = 0.35 # Grace time before a path announcement is made, allows directly reachable peers to respond first
|
PATH_REQUEST_GRACE = 0.4 # Grace time before a path announcement is made, allows directly reachable peers to respond first
|
||||||
PATH_REQUEST_RW = 2 # Path request random window
|
PATH_REQUEST_RG = 0.6 # Extra grace time for roaming-mode interfaces to allow more suitable peers to respond first
|
||||||
PATH_REQUEST_MI = 20 # Minimum interval in seconds for automated path requests
|
PATH_REQUEST_MI = 20 # Minimum interval in seconds for automated path requests
|
||||||
|
|
||||||
STATE_UNKNOWN = 0x00
|
STATE_UNKNOWN = 0x00
|
||||||
@ -746,7 +746,8 @@ class Transport:
|
|||||||
packet.receipt = RNS.PacketReceipt(packet)
|
packet.receipt = RNS.PacketReceipt(packet)
|
||||||
Transport.receipts.append(packet.receipt)
|
Transport.receipts.append(packet.receipt)
|
||||||
|
|
||||||
Transport.cache(packet)
|
# TODO: Enable when caching has been redesigned
|
||||||
|
# Transport.cache(packet)
|
||||||
|
|
||||||
# Check if we have a known path for the destination in the path table
|
# Check if we have a known path for the destination in the path table
|
||||||
if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination.type != RNS.Destination.PLAIN and packet.destination.type != RNS.Destination.GROUP and packet.destination_hash in Transport.destination_table:
|
if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination.type != RNS.Destination.PLAIN and packet.destination.type != RNS.Destination.GROUP and packet.destination_hash in Transport.destination_table:
|
||||||
@ -972,6 +973,13 @@ class Transport:
|
|||||||
# TODO: Think long and hard about this.
|
# TODO: Think long and hard about this.
|
||||||
# Is it even strictly necessary with the current
|
# Is it even strictly necessary with the current
|
||||||
# transport rules?
|
# transport rules?
|
||||||
|
|
||||||
|
# Filter packets intended for other transport instances
|
||||||
|
if packet.transport_id != None and packet.packet_type != RNS.Packet.ANNOUNCE:
|
||||||
|
if packet.transport_id != Transport.identity.hash:
|
||||||
|
RNS.log("Ignored packet "+RNS.prettyhexrep(packet.packet_hash)+" in transport for other transport instance", RNS.LOG_EXTREME)
|
||||||
|
return False
|
||||||
|
|
||||||
if packet.context == RNS.Packet.KEEPALIVE:
|
if packet.context == RNS.Packet.KEEPALIVE:
|
||||||
return True
|
return True
|
||||||
if packet.context == RNS.Packet.RESOURCE_REQ:
|
if packet.context == RNS.Packet.RESOURCE_REQ:
|
||||||
@ -1136,10 +1144,31 @@ class Transport:
|
|||||||
elif Transport.interface_to_shared_instance(interface):
|
elif Transport.interface_to_shared_instance(interface):
|
||||||
packet.hops -= 1
|
packet.hops -= 1
|
||||||
|
|
||||||
|
|
||||||
if Transport.packet_filter(packet):
|
if Transport.packet_filter(packet):
|
||||||
Transport.packet_hashlist.append(packet.packet_hash)
|
# By default, remember packet hashes to avoid routing
|
||||||
Transport.cache(packet)
|
# loops in the network, using the packet filter.
|
||||||
|
remember_packet_hash = True
|
||||||
|
|
||||||
|
# If this packet belongs to a link in our link table,
|
||||||
|
# we'll have to defer adding it to the filter list.
|
||||||
|
# In some cases, we might see a packet over a shared-
|
||||||
|
# medium interface, belonging to a link that transports
|
||||||
|
# or terminates with this instance, but before it would
|
||||||
|
# normally reach us. If the packet is appended to the
|
||||||
|
# filter list at this point, link transport will break.
|
||||||
|
if packet.destination_hash in Transport.link_table:
|
||||||
|
remember_packet_hash = False
|
||||||
|
|
||||||
|
# If this is a link request proof, don't add it until
|
||||||
|
# we are sure it's not actually somewhere else in the
|
||||||
|
# routing chain.
|
||||||
|
if packet.packet_type == RNS.Packet.PROOF and packet.context == RNS.Packet.LRPROOF:
|
||||||
|
remember_packet_hash = False
|
||||||
|
|
||||||
|
if remember_packet_hash:
|
||||||
|
Transport.packet_hashlist.append(packet.packet_hash)
|
||||||
|
# TODO: Enable when caching has been redesigned
|
||||||
|
# Transport.cache(packet)
|
||||||
|
|
||||||
# Check special conditions for local clients connected
|
# Check special conditions for local clients connected
|
||||||
# through a shared Reticulum instance
|
# through a shared Reticulum instance
|
||||||
@ -1260,7 +1289,7 @@ class Transport:
|
|||||||
link_entry = Transport.link_table[packet.destination_hash]
|
link_entry = Transport.link_table[packet.destination_hash]
|
||||||
# If receiving and outbound interface is
|
# If receiving and outbound interface is
|
||||||
# the same for this link, direction doesn't
|
# the same for this link, direction doesn't
|
||||||
# matter, and we simply send the packet on.
|
# matter, and we simply repeat the packet.
|
||||||
outbound_interface = None
|
outbound_interface = None
|
||||||
if link_entry[2] == link_entry[4]:
|
if link_entry[2] == link_entry[4]:
|
||||||
# But check that taken hops matches one
|
# But check that taken hops matches one
|
||||||
@ -1281,6 +1310,11 @@ class Transport:
|
|||||||
outbound_interface = link_entry[2]
|
outbound_interface = link_entry[2]
|
||||||
|
|
||||||
if outbound_interface != None:
|
if outbound_interface != None:
|
||||||
|
# Add this packet to the filter hashlist if we
|
||||||
|
# have determined that it's actually our turn
|
||||||
|
# to process it.
|
||||||
|
Transport.packet_hashlist.append(packet.packet_hash)
|
||||||
|
|
||||||
new_raw = packet.raw[0:1]
|
new_raw = packet.raw[0:1]
|
||||||
new_raw += struct.pack("!B", packet.hops)
|
new_raw += struct.pack("!B", packet.hops)
|
||||||
new_raw += packet.raw[2:]
|
new_raw += packet.raw[2:]
|
||||||
@ -1712,7 +1746,24 @@ class Transport:
|
|||||||
# pending link
|
# pending link
|
||||||
for link in Transport.pending_links:
|
for link in Transport.pending_links:
|
||||||
if link.link_id == packet.destination_hash:
|
if link.link_id == packet.destination_hash:
|
||||||
link.validate_proof(packet)
|
# We need to also allow an expected hops value of
|
||||||
|
# PATHFINDER_M, since in some cases, the number of hops
|
||||||
|
# to the destination will be unknown at link creation
|
||||||
|
# time. The real chance of this occuring is likely to be
|
||||||
|
# extremely small, and this allowance could probably
|
||||||
|
# be discarded without major issues, but it is kept
|
||||||
|
# for now to ensure backwards compatibility.
|
||||||
|
|
||||||
|
# TODO: Probably reset check back to
|
||||||
|
# if packet.hops == link.expected_hops:
|
||||||
|
# within one of the next releases
|
||||||
|
|
||||||
|
if packet.hops == link.expected_hops or link.expected_hops == RNS.Transport.PATHFINDER_M:
|
||||||
|
# Add this packet to the filter hashlist if we
|
||||||
|
# have determined that it's actually destined
|
||||||
|
# for this system, and then validate the proof
|
||||||
|
Transport.packet_hashlist.append(packet.packet_hash)
|
||||||
|
link.validate_proof(packet)
|
||||||
|
|
||||||
elif packet.context == RNS.Packet.RESOURCE_PRF:
|
elif packet.context == RNS.Packet.RESOURCE_PRF:
|
||||||
for link in Transport.active_links:
|
for link in Transport.active_links:
|
||||||
@ -1729,7 +1780,7 @@ class Transport:
|
|||||||
else:
|
else:
|
||||||
proof_hash = None
|
proof_hash = None
|
||||||
|
|
||||||
# Check if this proof neds to be transported
|
# Check if this proof needs to be transported
|
||||||
if (RNS.Reticulum.transport_enabled() or from_local_client or proof_for_local_client) and packet.destination_hash in Transport.reverse_table:
|
if (RNS.Reticulum.transport_enabled() or from_local_client or proof_for_local_client) and packet.destination_hash in Transport.reverse_table:
|
||||||
reverse_entry = Transport.reverse_table.pop(packet.destination_hash)
|
reverse_entry = Transport.reverse_table.pop(packet.destination_hash)
|
||||||
if packet.receiving_interface == reverse_entry[1]:
|
if packet.receiving_interface == reverse_entry[1]:
|
||||||
@ -2124,6 +2175,7 @@ class Transport:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def path_is_unresponsive(destination_hash):
|
def path_is_unresponsive(destination_hash):
|
||||||
if destination_hash in Transport.path_states:
|
if destination_hash in Transport.path_states:
|
||||||
if Transport.path_states[destination_hash] == Transport.STATE_UNRESPONSIVE:
|
if Transport.path_states[destination_hash] == Transport.STATE_UNRESPONSIVE:
|
||||||
@ -2288,8 +2340,18 @@ class Transport:
|
|||||||
if is_from_local_client:
|
if is_from_local_client:
|
||||||
retransmit_timeout = now
|
retransmit_timeout = now
|
||||||
else:
|
else:
|
||||||
# TODO: Look at this timing
|
if Transport.is_local_client_interface(Transport.next_hop_interface(destination_hash)):
|
||||||
retransmit_timeout = now + Transport.PATH_REQUEST_GRACE # + (RNS.rand() * Transport.PATHFINDER_RW)
|
RNS.log("Path request destination "+RNS.prettyhexrep(destination_hash)+" is on a local client interface, rebroadcasting immediately", RNS.LOG_EXTREME)
|
||||||
|
retransmit_timeout = now
|
||||||
|
|
||||||
|
else:
|
||||||
|
retransmit_timeout = now + Transport.PATH_REQUEST_GRACE
|
||||||
|
|
||||||
|
# If we are answering on a roaming-mode interface, wait a
|
||||||
|
# little longer, to allow potential more well-connected
|
||||||
|
# peers to answer first.
|
||||||
|
if attached_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING:
|
||||||
|
retransmit_timeout += Transport.PATH_REQUEST_RG
|
||||||
|
|
||||||
# This handles an edge case where a peer sends a past
|
# This handles an edge case where a peer sends a past
|
||||||
# request for a destination just after an announce for
|
# request for a destination just after an announce for
|
||||||
|
@ -37,26 +37,48 @@ SIG_EXT = "rsg"
|
|||||||
ENCRYPT_EXT = "rfe"
|
ENCRYPT_EXT = "rfe"
|
||||||
CHUNK_SIZE = 16*1024*1024
|
CHUNK_SIZE = 16*1024*1024
|
||||||
|
|
||||||
def spin(until=None, msg=None, timeout=None):
|
|
||||||
|
def spin(until=None, msg="", timeout=None):
|
||||||
i = 0
|
i = 0
|
||||||
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
||||||
if timeout != None:
|
if timeout is not None:
|
||||||
timeout = time.time()+timeout
|
timeout = time.time()+timeout
|
||||||
|
|
||||||
print(msg+" ", end=" ")
|
print(msg, end=" ")
|
||||||
while (timeout == None or time.time()<timeout) and not until():
|
while (timeout is None or time.time()<timeout) and not until():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
print(("\b\b"+syms[i]+" "), end="")
|
print(("\b\b", syms[i]), end=" ", sep="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
print("\r"+" "*len(msg)+" \r", end="")
|
print("\r", *len(msg), "\r", end="", sep="")
|
||||||
|
|
||||||
if timeout != None and time.time() > timeout:
|
if timeout is not None and time.time() > timeout:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_keys(args: argparse.Namespace, identity) -> None:
|
||||||
|
"""Get public or/and private keys"""
|
||||||
|
|
||||||
|
if args.base64:
|
||||||
|
RNS.log("Public Key : " + base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8"))
|
||||||
|
elif args.base32:
|
||||||
|
RNS.log("Public Key : " + base64.b32encode(identity.get_public_key()).decode("utf-8"))
|
||||||
|
else:
|
||||||
|
RNS.log("Public Key : " + RNS.hexrep(identity.get_public_key(), delimit=False))
|
||||||
|
if identity.prv:
|
||||||
|
if args.print_private:
|
||||||
|
if args.base64:
|
||||||
|
RNS.log("Private Key : " + base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8"))
|
||||||
|
elif args.base32:
|
||||||
|
RNS.log("Private Key : " + base64.b32encode(identity.get_private_key()).decode("utf-8"))
|
||||||
|
else:
|
||||||
|
RNS.log("Private Key : " + RNS.hexrep(identity.get_private_key(), delimit=False))
|
||||||
|
else:
|
||||||
|
RNS.log("Private Key : Hidden")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
parser = argparse.ArgumentParser(description="Reticulum Identity & Encryption Utility")
|
parser = argparse.ArgumentParser(description="Reticulum Identity & Encryption Utility")
|
||||||
@ -82,7 +104,7 @@ def main():
|
|||||||
parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str)
|
parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str)
|
||||||
parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files")
|
parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files")
|
||||||
parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file"
|
parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file"
|
||||||
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
||||||
|
|
||||||
parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network")
|
parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network")
|
||||||
parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
||||||
@ -93,14 +115,10 @@ def main():
|
|||||||
parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output")
|
parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output")
|
||||||
|
|
||||||
parser.add_argument("--version", action="version", version="rnid {version}".format(version=__version__))
|
parser.add_argument("--version", action="version", version="rnid {version}".format(version=__version__))
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
ops = 0;
|
ops = sum(1 for t in [args.encrypt, args.decrypt, args.validate, args.sign] if t)
|
||||||
for t in [args.encrypt, args.decrypt, args.validate, args.sign]:
|
|
||||||
if t:
|
|
||||||
ops += 1
|
|
||||||
|
|
||||||
if ops > 1:
|
if ops > 1:
|
||||||
RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
|
RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -134,22 +152,8 @@ def main():
|
|||||||
exit(42)
|
exit(42)
|
||||||
|
|
||||||
RNS.log("Identity imported")
|
RNS.log("Identity imported")
|
||||||
if args.base64:
|
|
||||||
RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8"))
|
get_keys(args, identity)
|
||||||
elif args.base32:
|
|
||||||
RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8"))
|
|
||||||
else:
|
|
||||||
RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False))
|
|
||||||
if identity.prv:
|
|
||||||
if args.print_private:
|
|
||||||
if args.base64:
|
|
||||||
RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8"))
|
|
||||||
elif args.base32:
|
|
||||||
RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8"))
|
|
||||||
else:
|
|
||||||
RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False))
|
|
||||||
else:
|
|
||||||
RNS.log("Private Key : Hidden")
|
|
||||||
|
|
||||||
if args.write:
|
if args.write:
|
||||||
try:
|
try:
|
||||||
@ -179,7 +183,7 @@ def main():
|
|||||||
quietness = args.quiet
|
quietness = args.quiet
|
||||||
if verbosity != 0 or quietness != 0:
|
if verbosity != 0 or quietness != 0:
|
||||||
targetloglevel = targetloglevel+verbosity-quietness
|
targetloglevel = targetloglevel+verbosity-quietness
|
||||||
|
|
||||||
# Start Reticulum
|
# Start Reticulum
|
||||||
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
|
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
|
||||||
RNS.compact_log_fmt = True
|
RNS.compact_log_fmt = True
|
||||||
@ -208,7 +212,7 @@ def main():
|
|||||||
destination_hash = bytes.fromhex(identity_str)
|
destination_hash = bytes.fromhex(identity_str)
|
||||||
identity = RNS.Identity.recall(destination_hash)
|
identity = RNS.Identity.recall(destination_hash)
|
||||||
|
|
||||||
if identity == None:
|
if identity is None:
|
||||||
if not args.request:
|
if not args.request:
|
||||||
RNS.log("Could not recall Identity for "+RNS.prettyhexrep(destination_hash)+".", RNS.LOG_ERROR)
|
RNS.log("Could not recall Identity for "+RNS.prettyhexrep(destination_hash)+".", RNS.LOG_ERROR)
|
||||||
RNS.log("You can query the network for unknown Identities with the -R option.", RNS.LOG_ERROR)
|
RNS.log("You can query the network for unknown Identities with the -R option.", RNS.LOG_ERROR)
|
||||||
@ -216,7 +220,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
RNS.Transport.request_path(destination_hash)
|
RNS.Transport.request_path(destination_hash)
|
||||||
def spincheck():
|
def spincheck():
|
||||||
return RNS.Identity.recall(destination_hash) != None
|
return RNS.Identity.recall(destination_hash) is not None
|
||||||
spin(spincheck, "Requesting unknown Identity for "+RNS.prettyhexrep(destination_hash), args.t)
|
spin(spincheck, "Requesting unknown Identity for "+RNS.prettyhexrep(destination_hash), args.t)
|
||||||
|
|
||||||
if not spincheck():
|
if not spincheck():
|
||||||
@ -224,17 +228,15 @@ def main():
|
|||||||
exit(6)
|
exit(6)
|
||||||
else:
|
else:
|
||||||
identity = RNS.Identity.recall(destination_hash)
|
identity = RNS.Identity.recall(destination_hash)
|
||||||
RNS.log("Received Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)+" from the network")
|
RNS.log(" ".join(["Received Identity", str(identity), "for destination", RNS.prettyhexrep(destination_hash), "from the network"]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log("Recalled Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash))
|
RNS.log(" ".join(["Recalled Identity", str(identity), "for destination", RNS.prettyhexrep(destination_hash)]))
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
|
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
|
||||||
exit(7)
|
exit(7)
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Try loading Identity from file
|
# Try loading Identity from file
|
||||||
if not os.path.isfile(identity_str):
|
if not os.path.isfile(identity_str):
|
||||||
@ -243,13 +245,13 @@ def main():
|
|||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
identity = RNS.Identity.from_file(identity_str)
|
identity = RNS.Identity.from_file(identity_str)
|
||||||
RNS.log("Loaded Identity "+str(identity)+" from "+str(identity_str))
|
RNS.log(" ".join(["Loaded Identity", str(identity), "from", str(identity_str)]))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Could not decode Identity from specified file")
|
RNS.log("Could not decode Identity from specified file")
|
||||||
exit(9)
|
exit(9)
|
||||||
|
|
||||||
if identity != None:
|
if identity is not None:
|
||||||
if args.hash:
|
if args.hash:
|
||||||
try:
|
try:
|
||||||
aspects = args.hash.split(".")
|
aspects = args.hash.split(".")
|
||||||
@ -259,9 +261,9 @@ def main():
|
|||||||
else:
|
else:
|
||||||
app_name = aspects[0]
|
app_name = aspects[0]
|
||||||
aspects = aspects[1:]
|
aspects = aspects[1:]
|
||||||
if identity.pub != None:
|
if identity.pub is not None:
|
||||||
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects)
|
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects)
|
||||||
RNS.log("The "+str(args.hash)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash))
|
RNS.log(" ".join(["The", str(args.hash), "destination for this Identity is", RNS.prettyhexrep(destination.hash)]))
|
||||||
RNS.log("The full destination specifier is "+str(destination))
|
RNS.log("The full destination specifier is "+str(destination))
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -282,7 +284,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
app_name = aspects[0]
|
app_name = aspects[0]
|
||||||
aspects = aspects[1:]
|
aspects = aspects[1:]
|
||||||
if identity.prv != None:
|
if identity.prv is not None:
|
||||||
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects)
|
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects)
|
||||||
RNS.log("Created destination "+str(destination))
|
RNS.log("Created destination "+str(destination))
|
||||||
RNS.log("Announcing destination "+RNS.prettyhexrep(destination.hash))
|
RNS.log("Announcing destination "+RNS.prettyhexrep(destination.hash))
|
||||||
@ -291,7 +293,7 @@ def main():
|
|||||||
exit(0)
|
exit(0)
|
||||||
else:
|
else:
|
||||||
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects)
|
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects)
|
||||||
RNS.log("The "+str(args.announce)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash))
|
RNS.log(" ".join(["The", str(args.announce), "destination for this Identity is", RNS.prettyhexrep(destination.hash)]))
|
||||||
RNS.log("The full destination specifier is "+str(destination))
|
RNS.log("The full destination specifier is "+str(destination))
|
||||||
RNS.log("Cannot announce this destination, since the private key is not held")
|
RNS.log("Cannot announce this destination, since the private key is not held")
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
@ -303,22 +305,7 @@ def main():
|
|||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
if args.print_identity:
|
if args.print_identity:
|
||||||
if args.base64:
|
get_keys(args, identity)
|
||||||
RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8"))
|
|
||||||
elif args.base32:
|
|
||||||
RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8"))
|
|
||||||
else:
|
|
||||||
RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False))
|
|
||||||
if identity.prv:
|
|
||||||
if args.print_private:
|
|
||||||
if args.base64:
|
|
||||||
RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8"))
|
|
||||||
elif args.base32:
|
|
||||||
RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8"))
|
|
||||||
else:
|
|
||||||
RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False))
|
|
||||||
else:
|
|
||||||
RNS.log("Private Key : Hidden")
|
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
if args.export:
|
if args.export:
|
||||||
@ -373,7 +360,7 @@ def main():
|
|||||||
if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith("."+ENCRYPT_EXT):
|
if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith("."+ENCRYPT_EXT):
|
||||||
args.write = str(args.read).replace("."+ENCRYPT_EXT, "")
|
args.write = str(args.read).replace("."+ENCRYPT_EXT, "")
|
||||||
|
|
||||||
if args.sign and identity.prv == None:
|
if args.sign and identity.prv is None:
|
||||||
RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR)
|
RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR)
|
||||||
exit(14)
|
exit(14)
|
||||||
|
|
||||||
@ -391,7 +378,7 @@ def main():
|
|||||||
RNS.log("Could not open output file for writing", RNS.LOG_ERROR)
|
RNS.log("Could not open output file for writing", RNS.LOG_ERROR)
|
||||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
exit(15)
|
exit(15)
|
||||||
|
|
||||||
# TODO: Actually expand this to a good solution
|
# TODO: Actually expand this to a good solution
|
||||||
# probably need to create a wrapper that takes
|
# probably need to create a wrapper that takes
|
||||||
# into account not closing stdout when done
|
# into account not closing stdout when done
|
||||||
@ -399,7 +386,7 @@ def main():
|
|||||||
# data_output = sys.stdout
|
# data_output = sys.stdout
|
||||||
|
|
||||||
if args.sign:
|
if args.sign:
|
||||||
if identity.prv == None:
|
if identity.prv is None:
|
||||||
RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR)
|
RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR)
|
||||||
exit(16)
|
exit(16)
|
||||||
|
|
||||||
@ -415,15 +402,15 @@ def main():
|
|||||||
|
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Signing "+str(args.read))
|
RNS.log("Signing "+str(args.read))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data_output.write(identity.sign(data_input.read()))
|
data_output.write(identity.sign(data_input.read()))
|
||||||
data_output.close()
|
data_output.close()
|
||||||
data_input.close()
|
data_input.close()
|
||||||
|
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
if args.read:
|
if args.read:
|
||||||
RNS.log("File "+str(args.read)+" signed with "+str(identity)+" to "+str(args.write))
|
RNS.log(" ".join([ "File", str(args.read), "signed with", str(identity), "to", str(args.write) ]))
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -448,7 +435,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
# if not args.stdout:
|
# if not args.stdout:
|
||||||
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
|
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
sig_input = open(args.validate, "rb")
|
sig_input = open(args.validate, "rb")
|
||||||
@ -457,18 +444,17 @@ def main():
|
|||||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
exit(21)
|
exit(21)
|
||||||
|
|
||||||
|
|
||||||
validated = identity.validate(sig_input.read(), data_input.read())
|
validated = identity.validate(sig_input.read(), data_input.read())
|
||||||
sig_input.close()
|
sig_input.close()
|
||||||
data_input.close()
|
data_input.close()
|
||||||
|
|
||||||
if not validated:
|
if not validated:
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" is invalid", RNS.LOG_ERROR)
|
RNS.log(" ".join(["Signature", str(args.validate), "for file", str(args.read), "is invalid"]), RNS.LOG_ERROR)
|
||||||
exit(22)
|
exit(22)
|
||||||
else:
|
else:
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" made by Identity "+str(identity)+" is valid")
|
RNS.log(" ".join(["Signature", str(args.validate), "for file", str(args.read), "made by Identity", str(identity), "is valid"]))
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -498,7 +484,7 @@ def main():
|
|||||||
|
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Encrypting "+str(args.read))
|
RNS.log("Encrypting "+str(args.read))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
more_data = True
|
more_data = True
|
||||||
while more_data:
|
while more_data:
|
||||||
@ -511,7 +497,7 @@ def main():
|
|||||||
data_input.close()
|
data_input.close()
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
if args.read:
|
if args.read:
|
||||||
RNS.log("File "+str(args.read)+" encrypted for "+str(identity)+" to "+str(args.write))
|
RNS.log(" ".join(["File", str(args.read), "encrypted for", str(identity), "to", str(args.write)]))
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -529,7 +515,7 @@ def main():
|
|||||||
exit(26)
|
exit(26)
|
||||||
|
|
||||||
if args.decrypt:
|
if args.decrypt:
|
||||||
if identity.prv == None:
|
if identity.prv is None:
|
||||||
RNS.log("Specified Identity does not hold a private key. Cannot decrypt.", RNS.LOG_ERROR)
|
RNS.log("Specified Identity does not hold a private key. Cannot decrypt.", RNS.LOG_ERROR)
|
||||||
exit(27)
|
exit(27)
|
||||||
|
|
||||||
@ -544,15 +530,15 @@ def main():
|
|||||||
exit(29)
|
exit(29)
|
||||||
|
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Decrypting "+str(args.read)+"...")
|
RNS.log("".join(["Decrypting ", str(args.read), "..."]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
more_data = True
|
more_data = True
|
||||||
while more_data:
|
while more_data:
|
||||||
chunk = data_input.read(CHUNK_SIZE)
|
chunk = data_input.read(CHUNK_SIZE)
|
||||||
if chunk:
|
if chunk:
|
||||||
plaintext = identity.decrypt(chunk)
|
plaintext = identity.decrypt(chunk)
|
||||||
if plaintext == None:
|
if plaintext is None:
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
RNS.log("Data could not be decrypted with the specified Identity")
|
RNS.log("Data could not be decrypted with the specified Identity")
|
||||||
exit(30)
|
exit(30)
|
||||||
@ -564,7 +550,7 @@ def main():
|
|||||||
data_input.close()
|
data_input.close()
|
||||||
if not args.stdout:
|
if not args.stdout:
|
||||||
if args.read:
|
if args.read:
|
||||||
RNS.log("File "+str(args.read)+" decrypted with "+str(identity)+" to "+str(args.write))
|
RNS.log(" ".join(["File", str(args.read), "decrypted with", str(identity), "to", str(args.write)]))
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -581,20 +567,10 @@ def main():
|
|||||||
pass
|
pass
|
||||||
exit(31)
|
exit(31)
|
||||||
|
|
||||||
if True:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif False:
|
|
||||||
pass
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("")
|
|
||||||
parser.print_help()
|
|
||||||
print("")
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("")
|
print("")
|
||||||
exit(255)
|
exit(255)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -24,23 +24,23 @@
|
|||||||
|
|
||||||
import RNS
|
import RNS
|
||||||
import argparse
|
import argparse
|
||||||
import time
|
|
||||||
|
|
||||||
from RNS._version import __version__
|
from RNS._version import __version__
|
||||||
|
|
||||||
|
|
||||||
def program_setup(configdir, verbosity = 0, quietness = 0, service = False):
|
def program_setup(configdir, verbosity=0, quietness=0, service=False):
|
||||||
targetverbosity = verbosity-quietness
|
targetverbosity = verbosity - quietness
|
||||||
|
|
||||||
if service:
|
if service:
|
||||||
targetlogdest = RNS.LOG_FILE
|
targetlogdest = RNS.LOG_FILE
|
||||||
targetverbosity = None
|
targetverbosity = None
|
||||||
else:
|
else:
|
||||||
targetlogdest = RNS.LOG_STDOUT
|
targetlogdest = RNS.LOG_STDOUT
|
||||||
|
|
||||||
reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest)
|
RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest)
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
parser = argparse.ArgumentParser(description="Reticulum Distributed Identity Resolver")
|
parser = argparse.ArgumentParser(description="Reticulum Distributed Identity Resolver")
|
||||||
@ -49,24 +49,23 @@ def main():
|
|||||||
parser.add_argument('-q', '--quiet', action='count', default=0)
|
parser.add_argument('-q', '--quiet', action='count', default=0)
|
||||||
parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit")
|
parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit")
|
||||||
parser.add_argument("--version", action="version", version="ir {version}".format(version=__version__))
|
parser.add_argument("--version", action="version", version="ir {version}".format(version=__version__))
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.exampleconfig:
|
if args.exampleconfig:
|
||||||
print(__example_rns_config__)
|
print(__example_rns_config__)
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
configarg = None
|
||||||
if args.config:
|
if args.config:
|
||||||
configarg = args.config
|
configarg = args.config
|
||||||
else:
|
|
||||||
configarg = None
|
|
||||||
|
|
||||||
program_setup(configdir = configarg, verbosity=args.verbose, quietness=args.quiet)
|
program_setup(configdir=configarg, verbosity=args.verbose, quietness=args.quiet)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("")
|
print("")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
__example_rns_config__ = '''# This is an example Identity Resolver file.
|
__example_rns_config__ = '''# This is an example Identity Resolver file.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -56,12 +56,14 @@ fw_filename = None
|
|||||||
fw_url = None
|
fw_url = None
|
||||||
mapped_model = None
|
mapped_model = None
|
||||||
|
|
||||||
|
# TODO: Create and use constants for megas, kilos, etc (Avoid using magic numbers)
|
||||||
|
|
||||||
class KISS():
|
class KISS():
|
||||||
FEND = 0xC0
|
FEND = 0xC0
|
||||||
FESC = 0xDB
|
FESC = 0xDB
|
||||||
TFEND = 0xDC
|
TFEND = 0xDC
|
||||||
TFESC = 0xDD
|
TFESC = 0xDD
|
||||||
|
|
||||||
CMD_UNKNOWN = 0xFE
|
CMD_UNKNOWN = 0xFE
|
||||||
CMD_DATA = 0x00
|
CMD_DATA = 0x00
|
||||||
CMD_FREQUENCY = 0x01
|
CMD_FREQUENCY = 0x01
|
||||||
@ -102,11 +104,11 @@ class KISS():
|
|||||||
|
|
||||||
DETECT_REQ = 0x73
|
DETECT_REQ = 0x73
|
||||||
DETECT_RESP = 0x46
|
DETECT_RESP = 0x46
|
||||||
|
|
||||||
RADIO_STATE_OFF = 0x00
|
RADIO_STATE_OFF = 0x00
|
||||||
RADIO_STATE_ON = 0x01
|
RADIO_STATE_ON = 0x01
|
||||||
RADIO_STATE_ASK = 0xFF
|
RADIO_STATE_ASK = 0xFF
|
||||||
|
|
||||||
CMD_ERROR = 0x90
|
CMD_ERROR = 0x90
|
||||||
ERROR_INITRADIO = 0x01
|
ERROR_INITRADIO = 0x01
|
||||||
ERROR_TXFAILED = 0x02
|
ERROR_TXFAILED = 0x02
|
||||||
@ -166,7 +168,7 @@ class ROM():
|
|||||||
MODEL_E9 = 0xE9
|
MODEL_E9 = 0xE9
|
||||||
MODEL_E3 = 0xE3
|
MODEL_E3 = 0xE3
|
||||||
MODEL_E8 = 0xE8
|
MODEL_E8 = 0xE8
|
||||||
|
|
||||||
PRODUCT_HMBRW = 0xF0
|
PRODUCT_HMBRW = 0xF0
|
||||||
MODEL_FF = 0xFF
|
MODEL_FF = 0xFF
|
||||||
MODEL_FE = 0xFE
|
MODEL_FE = 0xFE
|
||||||
@ -280,7 +282,7 @@ try:
|
|||||||
os.makedirs(ROM_DIR)
|
os.makedirs(ROM_DIR)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("No access to directory "+str(CNF_DIR)+". This utility needs file system access to store firmware and data files. Cannot continue.")
|
print("".join(["No access to directory ", str(CNF_DIR), ". This utility needs file system access to store firmware and data files. Cannot continue."]))
|
||||||
print("The contained exception was:")
|
print("The contained exception was:")
|
||||||
print(str(e))
|
print(str(e))
|
||||||
exit(99)
|
exit(99)
|
||||||
@ -411,7 +413,7 @@ class RNode():
|
|||||||
command_buffer = command_buffer+bytes([byte])
|
command_buffer = command_buffer+bytes([byte])
|
||||||
if (len(command_buffer) == 4):
|
if (len(command_buffer) == 4):
|
||||||
self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3]
|
self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3]
|
||||||
RNS.log("Radio reporting frequency is "+str(self.r_frequency/1000000.0)+" MHz")
|
RNS.log("".join(["Radio reporting frequency is ", str(self.r_frequency/1000000.0), " MHz"]))
|
||||||
self.updateBitrate()
|
self.updateBitrate()
|
||||||
|
|
||||||
elif (command == KISS.CMD_BANDWIDTH):
|
elif (command == KISS.CMD_BANDWIDTH):
|
||||||
@ -427,7 +429,7 @@ class RNode():
|
|||||||
command_buffer = command_buffer+bytes([byte])
|
command_buffer = command_buffer+bytes([byte])
|
||||||
if (len(command_buffer) == 4):
|
if (len(command_buffer) == 4):
|
||||||
self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3]
|
self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3]
|
||||||
RNS.log("Radio reporting bandwidth is "+str(self.r_bandwidth/1000.0)+" KHz")
|
RNS.log("".join(["Radio reporting bandwidth is ", str(self.r_bandwidth/1000.0), " KHz"]))
|
||||||
self.updateBitrate()
|
self.updateBitrate()
|
||||||
|
|
||||||
elif (command == KISS.CMD_BT_PIN):
|
elif (command == KISS.CMD_BT_PIN):
|
||||||
@ -501,7 +503,7 @@ class RNode():
|
|||||||
|
|
||||||
elif (command == KISS.CMD_TXPOWER):
|
elif (command == KISS.CMD_TXPOWER):
|
||||||
self.r_txpower = byte
|
self.r_txpower = byte
|
||||||
RNS.log("Radio reporting TX power is "+str(self.r_txpower)+" dBm")
|
RNS.log("".join(["Radio reporting TX power is ", str(self.r_txpower), " dBm"]))
|
||||||
elif (command == KISS.CMD_SF):
|
elif (command == KISS.CMD_SF):
|
||||||
self.r_sf = byte
|
self.r_sf = byte
|
||||||
RNS.log("Radio reporting spreading factor is "+str(self.r_sf))
|
RNS.log("Radio reporting spreading factor is "+str(self.r_sf))
|
||||||
@ -549,17 +551,17 @@ class RNode():
|
|||||||
self.r_random = byte
|
self.r_random = byte
|
||||||
elif (command == KISS.CMD_ERROR):
|
elif (command == KISS.CMD_ERROR):
|
||||||
if (byte == KISS.ERROR_INITRADIO):
|
if (byte == KISS.ERROR_INITRADIO):
|
||||||
RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")")
|
RNS.log("".join([str(self), " hardware initialisation error (code ", RNS.hexrep(byte), ")"]))
|
||||||
elif (byte == KISS.ERROR_TXFAILED):
|
elif (byte == KISS.ERROR_TXFAILED):
|
||||||
RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")")
|
RNS.log("".join([str(self), " hardware TX error (code ", RNS.hexrep(byte), ")"]))
|
||||||
else:
|
else:
|
||||||
RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")")
|
RNS.log("".join([str(self), " hardware error (code ", RNS.hexrep(byte), ")"]))
|
||||||
elif (command == KISS.CMD_DETECT):
|
elif (command == KISS.CMD_DETECT):
|
||||||
if byte == KISS.DETECT_RESP:
|
if byte == KISS.DETECT_RESP:
|
||||||
self.detected = True
|
self.detected = True
|
||||||
else:
|
else:
|
||||||
self.detected = False
|
self.detected = False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
time_since_last = int(time.time()*1000) - last_read_ms
|
time_since_last = int(time.time()*1000) - last_read_ms
|
||||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||||
@ -816,7 +818,7 @@ class RNode():
|
|||||||
from cryptography.hazmat.primitives.serialization import load_der_private_key
|
from cryptography.hazmat.primitives.serialization import load_der_private_key
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
|
||||||
# Try loading local signing key for
|
# Try loading local signing key for
|
||||||
# validation of self-signed devices
|
# validation of self-signed devices
|
||||||
if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"):
|
if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"):
|
||||||
private_bytes = None
|
private_bytes = None
|
||||||
@ -852,7 +854,7 @@ class RNode():
|
|||||||
RNS.log("Could not deserialize local signing key")
|
RNS.log("Could not deserialize local signing key")
|
||||||
RNS.log(str(e))
|
RNS.log(str(e))
|
||||||
|
|
||||||
# Try loading trusted signing key for
|
# Try loading trusted signing key for
|
||||||
# validation of devices
|
# validation of devices
|
||||||
if os.path.isdir(TK_DIR):
|
if os.path.isdir(TK_DIR):
|
||||||
for f in os.listdir(TK_DIR):
|
for f in os.listdir(TK_DIR):
|
||||||
@ -930,7 +932,7 @@ class RNode():
|
|||||||
print(" ")
|
print(" ")
|
||||||
print(" To initialise this device to a verifiable state, please run:")
|
print(" To initialise this device to a verifiable state, please run:")
|
||||||
print(" ")
|
print(" ")
|
||||||
print(" rnodeconf "+str(self.serial.name)+" --autoinstall")
|
print("".join([" rnodeconf ", str(self.serial.name), " --autoinstall"]))
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
|
||||||
@ -965,7 +967,7 @@ class RNode():
|
|||||||
|
|
||||||
selected_version = None
|
selected_version = None
|
||||||
selected_hash = None
|
selected_hash = None
|
||||||
firmware_version_url = "https://unsigned.io/firmware/latest/?v="+program_version+"&variant="
|
firmware_version_url = "".join(["https://unsigned.io/firmware/latest/?v=", program_version, "&variant="])
|
||||||
fallback_firmware_version_url = "https://github.com/markqvist/rnode_firmware/releases/latest/download/release.json"
|
fallback_firmware_version_url = "https://github.com/markqvist/rnode_firmware/releases/latest/download/release.json"
|
||||||
def ensure_firmware_file(fw_filename):
|
def ensure_firmware_file(fw_filename):
|
||||||
global selected_version, selected_hash, upd_nocheck
|
global selected_version, selected_hash, upd_nocheck
|
||||||
@ -981,7 +983,7 @@ def ensure_firmware_file(fw_filename):
|
|||||||
]
|
]
|
||||||
parts_missing = False
|
parts_missing = False
|
||||||
for rf in required_files:
|
for rf in required_files:
|
||||||
if not os.path.isfile(EXT_DIR+"/"+rf):
|
if not os.path.isfile("".join([EXT_DIR, "/", rf])):
|
||||||
parts_missing = True
|
parts_missing = True
|
||||||
|
|
||||||
if parts_missing:
|
if parts_missing:
|
||||||
@ -994,7 +996,7 @@ def ensure_firmware_file(fw_filename):
|
|||||||
release_info = vf.read().decode("utf-8").strip()
|
release_info = vf.read().decode("utf-8").strip()
|
||||||
selected_version = release_info.split()[0]
|
selected_version = release_info.split()[0]
|
||||||
selected_hash = release_info.split()[1]
|
selected_hash = release_info.split()[1]
|
||||||
RNS.log("Using existing firmware file: "+fw_filename+" for version "+selected_version)
|
RNS.log("".join(["Using existing firmware file: ", fw_filename, " for version ", selected_version]))
|
||||||
else:
|
else:
|
||||||
RNS.log("No extracted firmware is available, cannot continue.")
|
RNS.log("No extracted firmware is available, cannot continue.")
|
||||||
RNS.log("Extract a firmware from an existing RNode first, using the --extract-firmware option.")
|
RNS.log("Extract a firmware from an existing RNode first, using the --extract-firmware option.")
|
||||||
@ -1006,17 +1008,19 @@ def ensure_firmware_file(fw_filename):
|
|||||||
try:
|
try:
|
||||||
# if custom firmware url, download latest release
|
# if custom firmware url, download latest release
|
||||||
if selected_version == None and fw_url == None:
|
if selected_version == None and fw_url == None:
|
||||||
version_url = firmware_version_url+fw_filename
|
version_url = firmware_version_url + fw_filename
|
||||||
RNS.log("Retrieving latest version info from "+version_url)
|
RNS.log("Retrieving latest version info from "+version_url)
|
||||||
urlretrieve(firmware_version_url+fw_filename, UPD_DIR+"/"+fw_filename+".version.latest")
|
urlretrieve(version_url, "".join([UPD_DIR, "/", fw_filename, ".version.latest"]))
|
||||||
else:
|
else:
|
||||||
if fw_url != None:
|
if fw_url != None:
|
||||||
if selected_version == None:
|
if selected_version == None:
|
||||||
version_url = fw_url+"latest/download/release.json"
|
version_url = fw_url+"latest/download/release.json"
|
||||||
else:
|
else:
|
||||||
version_url = fw_url+"download/"+selected_version+"/release.json"
|
version_url = "".join([fw_url, "download/", selected_version, "/release.json"])
|
||||||
else:
|
else:
|
||||||
version_url = firmware_update_url+selected_version+"/release.json"
|
if selected_version is None:
|
||||||
|
selected_version = ""
|
||||||
|
version_url = "".join([firmware_update_url, selected_version, "/release.json"])
|
||||||
try:
|
try:
|
||||||
RNS.log("Retrieving specified version info from "+version_url)
|
RNS.log("Retrieving specified version info from "+version_url)
|
||||||
urlretrieve(version_url, UPD_DIR+"/version_release_info.json")
|
urlretrieve(version_url, UPD_DIR+"/version_release_info.json")
|
||||||
@ -1024,8 +1028,9 @@ def ensure_firmware_file(fw_filename):
|
|||||||
with open(UPD_DIR+"/version_release_info.json", "rb") as rif:
|
with open(UPD_DIR+"/version_release_info.json", "rb") as rif:
|
||||||
rdat = json.loads(rif.read())
|
rdat = json.loads(rif.read())
|
||||||
variant = rdat[fw_filename]
|
variant = rdat[fw_filename]
|
||||||
with open(UPD_DIR+"/"+fw_filename+".version.latest", "wb") as verf:
|
with open("".join([UPD_DIR, "/", fw_filename, ".version.latest"]), "wb") as verf:
|
||||||
inf_str = str(variant["version"])+" "+str(variant["hash"])
|
inf_str = str(variant["version"])+" "+str(variant["hash"])
|
||||||
|
inf_str = "".join([str(variant["version"]), " ", str(variant["hash"])])
|
||||||
verf.write(inf_str.encode("utf-8"))
|
verf.write(inf_str.encode("utf-8"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Failed to retrive version information for your board.")
|
RNS.log("Failed to retrive version information for your board.")
|
||||||
@ -1055,7 +1060,7 @@ def ensure_firmware_file(fw_filename):
|
|||||||
with open(UPD_DIR+"/fallback_release_info.json", "rb") as rif:
|
with open(UPD_DIR+"/fallback_release_info.json", "rb") as rif:
|
||||||
rdat = json.loads(rif.read())
|
rdat = json.loads(rif.read())
|
||||||
variant = rdat[fw_filename]
|
variant = rdat[fw_filename]
|
||||||
with open(UPD_DIR+"/"+fw_filename+".version.latest", "wb") as verf:
|
with open("".join([UPD_DIR, "/", fw_filename, ".version.latest"]), "wb") as verf:
|
||||||
inf_str = str(variant["version"])+" "+str(variant["hash"])
|
inf_str = str(variant["version"])+" "+str(variant["hash"])
|
||||||
verf.write(inf_str.encode("utf-8"))
|
verf.write(inf_str.encode("utf-8"))
|
||||||
|
|
||||||
@ -1064,7 +1069,7 @@ def ensure_firmware_file(fw_filename):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
file = open(UPD_DIR+"/"+fw_filename+".version.latest", "rb")
|
file = open("".join([UPD_DIR, "/", fw_filename, ".version.latest"]), "rb")
|
||||||
release_info = file.read().decode("utf-8").strip()
|
release_info = file.read().decode("utf-8").strip()
|
||||||
selected_version = release_info.split()[0]
|
selected_version = release_info.split()[0]
|
||||||
if selected_version == "not":
|
if selected_version == "not":
|
||||||
@ -1074,7 +1079,7 @@ def ensure_firmware_file(fw_filename):
|
|||||||
selected_hash = release_info.split()[1]
|
selected_hash = release_info.split()[1]
|
||||||
if not os.path.isdir(UPD_DIR+"/"+selected_version):
|
if not os.path.isdir(UPD_DIR+"/"+selected_version):
|
||||||
os.makedirs(UPD_DIR+"/"+selected_version)
|
os.makedirs(UPD_DIR+"/"+selected_version)
|
||||||
shutil.copy(UPD_DIR+"/"+fw_filename+".version.latest", UPD_DIR+"/"+selected_version+"/"+fw_filename+".version")
|
shutil.copy("".join([UPD_DIR, "/", fw_filename, ".version.latest"]), "".join([UPD_DIR, "/", selected_version, "/", fw_filename, ".version"]))
|
||||||
RNS.log("The selected firmware for this board is version "+selected_version)
|
RNS.log("The selected firmware for this board is version "+selected_version)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1084,32 +1089,32 @@ def ensure_firmware_file(fw_filename):
|
|||||||
|
|
||||||
# if custom firmware url, use it
|
# if custom firmware url, use it
|
||||||
if fw_url != None:
|
if fw_url != None:
|
||||||
update_target_url = fw_url+"download/"+selected_version+"/"+fw_filename
|
update_target_url = "".join([fw_url, "download/", selected_version, "/", fw_filename])
|
||||||
RNS.log("Retrieving firmware from custom url "+update_target_url)
|
RNS.log("Retrieving firmware from custom url "+update_target_url)
|
||||||
else:
|
else:
|
||||||
update_target_url = firmware_update_url+selected_version+"/"+fw_filename
|
update_target_url = "".join([firmware_update_url, selected_version, "/", fw_filename])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not os.path.isdir(UPD_DIR+"/"+selected_version):
|
if not os.path.isdir(UPD_DIR+"/"+selected_version):
|
||||||
os.makedirs(UPD_DIR+"/"+selected_version)
|
os.makedirs(UPD_DIR+"/"+selected_version)
|
||||||
|
|
||||||
if not os.path.isfile(UPD_DIR+"/"+selected_version+"/"+fw_filename):
|
if not os.path.isfile("".join([UPD_DIR, "/", selected_version, "/", fw_filename])):
|
||||||
RNS.log("Firmware "+UPD_DIR+"/"+selected_version+"/"+fw_filename+" not found.")
|
RNS.log("".join(["Firmware ", UPD_DIR, "/", selected_version, "/", fw_filename, " not found."]))
|
||||||
RNS.log("Downloading missing firmware file: "+fw_filename+" for version "+selected_version)
|
RNS.log("".join(["Downloading missing firmware file: ", fw_filename, " for version ", selected_version]))
|
||||||
urlretrieve(update_target_url, UPD_DIR+"/"+selected_version+"/"+fw_filename)
|
urlretrieve(update_target_url, "".join([UPD_DIR, "/", selected_version, "/", fw_filename]))
|
||||||
RNS.log("Firmware file downloaded")
|
RNS.log("Firmware file downloaded")
|
||||||
else:
|
else:
|
||||||
RNS.log("Using existing firmware file: "+fw_filename+" for version "+selected_version)
|
RNS.log("".join(["Using existing firmware file: ", fw_filename, " for version ", selected_version]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if selected_hash == None:
|
if selected_hash == None:
|
||||||
try:
|
try:
|
||||||
file = open(UPD_DIR+"/"+selected_version+"/"+fw_filename+".version", "rb")
|
file = open("".join([UPD_DIR, "/", selected_version, "/", fw_filename, ".version"]), "rb")
|
||||||
release_info = file.read().decode("utf-8").strip()
|
release_info = file.read().decode("utf-8").strip()
|
||||||
selected_hash = release_info.split()[1]
|
selected_hash = release_info.split()[1]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Could not read locally cached release information.")
|
RNS.log("Could not read locally cached release information.")
|
||||||
RNS.log("Ensure "+UPD_DIR+"/"+selected_version+"/"+fw_filename+".version exists and has the correct format and hash.")
|
RNS.log("".join(["Ensure ", UPD_DIR, "/", selected_version, "/", fw_filename, ".version exists and has the correct format and hash."]))
|
||||||
RNS.log("You can clear the cache with the --clear-cache option and try again.")
|
RNS.log("You can clear the cache with the --clear-cache option and try again.")
|
||||||
|
|
||||||
if selected_hash == None:
|
if selected_hash == None:
|
||||||
@ -1117,7 +1122,8 @@ def ensure_firmware_file(fw_filename):
|
|||||||
exit(97)
|
exit(97)
|
||||||
|
|
||||||
RNS.log("Verifying firmware integrity...")
|
RNS.log("Verifying firmware integrity...")
|
||||||
fw_file = open(UPD_DIR+"/"+selected_version+"/"+fw_filename, "rb")
|
fw_file = open("".join([UPD_DIR, "/", selected_version, "/", fw_filename]), "rb")
|
||||||
|
# TODO: Remove unused variable
|
||||||
expected_hash = bytes.fromhex(selected_hash)
|
expected_hash = bytes.fromhex(selected_hash)
|
||||||
file_hash = hashlib.sha256(fw_file.read()).hexdigest()
|
file_hash = hashlib.sha256(fw_file.read()).hexdigest()
|
||||||
if file_hash == selected_hash:
|
if file_hash == selected_hash:
|
||||||
@ -1230,11 +1236,11 @@ def main():
|
|||||||
|
|
||||||
parser.add_argument("-f", "--flash", action="store_true", help="Flash firmware and bootstrap EEPROM")
|
parser.add_argument("-f", "--flash", action="store_true", help="Flash firmware and bootstrap EEPROM")
|
||||||
parser.add_argument("-r", "--rom", action="store_true", help="Bootstrap EEPROM without flashing firmware")
|
parser.add_argument("-r", "--rom", action="store_true", help="Bootstrap EEPROM without flashing firmware")
|
||||||
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
|
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
|
||||||
parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key")
|
parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key")
|
||||||
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash")
|
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash")
|
||||||
parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap")
|
parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap")
|
||||||
parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") #
|
parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") #
|
||||||
parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap")
|
parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap")
|
||||||
parser.add_argument("--hwrev", action="store", metavar="revision", type=int, default=None, help="Hardware revision for device bootstrap")
|
parser.add_argument("--hwrev", action="store", metavar="revision", type=int, default=None, help="Hardware revision for device bootstrap")
|
||||||
|
|
||||||
@ -1263,7 +1269,7 @@ def main():
|
|||||||
|
|
||||||
if args.fw_version != None:
|
if args.fw_version != None:
|
||||||
selected_version = args.fw_version
|
selected_version = args.fw_version
|
||||||
try:
|
try:
|
||||||
check_float = float(selected_version)
|
check_float = float(selected_version)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.")
|
RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.")
|
||||||
@ -1277,7 +1283,7 @@ def main():
|
|||||||
|
|
||||||
if args.nocheck:
|
if args.nocheck:
|
||||||
upd_nocheck = True
|
upd_nocheck = True
|
||||||
|
|
||||||
if args.public or args.key or args.flash or args.rom or args.autoinstall or args.trust_key:
|
if args.public or args.key or args.flash or args.rom or args.autoinstall or args.trust_key:
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
@ -1296,7 +1302,7 @@ def main():
|
|||||||
public_key = load_der_public_key(public_bytes, backend=default_backend())
|
public_key = load_der_public_key(public_bytes, backend=default_backend())
|
||||||
key_hash = hashlib.sha256(public_bytes).hexdigest()
|
key_hash = hashlib.sha256(public_bytes).hexdigest()
|
||||||
RNS.log("Trusting key: "+str(key_hash))
|
RNS.log("Trusting key: "+str(key_hash))
|
||||||
f = open(TK_DIR+"/"+str(key_hash)+".pubkey", "wb")
|
f = open("".join([TK_DIR, "/", str(key_hash), ".pubkey"]), "wb")
|
||||||
f.write(public_bytes)
|
f.write(public_bytes)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
@ -1328,12 +1334,12 @@ def main():
|
|||||||
ports = list_ports.comports()
|
ports = list_ports.comports()
|
||||||
portlist = []
|
portlist = []
|
||||||
for port in ports:
|
for port in ports:
|
||||||
portlist.insert(0, port)
|
portlist.insert(0, port)
|
||||||
|
|
||||||
pi = 1
|
pi = 1
|
||||||
print("Detected serial ports:")
|
print("Detected serial ports:")
|
||||||
for port in portlist:
|
for port in portlist:
|
||||||
print(" ["+str(pi)+"] "+str(port.device)+" ("+str(port.product)+", "+str(port.serial_number)+")")
|
print("".join([" [", str(pi), "] ", str(port.device), " (", str(port.product), ", ", str(port.serial_number), ")"]))
|
||||||
pi += 1
|
pi += 1
|
||||||
|
|
||||||
print("\nEnter the number of the serial port your device is connected to:\n? ", end="")
|
print("\nEnter the number of the serial port your device is connected to:\n? ", end="")
|
||||||
@ -1355,7 +1361,7 @@ def main():
|
|||||||
port_product = selected_port.product
|
port_product = selected_port.product
|
||||||
port_serialno = selected_port.serial_number
|
port_serialno = selected_port.serial_number
|
||||||
|
|
||||||
print("\nOk, using device on "+str(port_path)+" ("+str(port_product)+", "+str(port_serialno)+")")
|
print("".join(["\nOk, using device on ", str(port_path), " (", str(port_product), ", ", str(port_serialno), ")"]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ports = list_ports.comports()
|
ports = list_ports.comports()
|
||||||
@ -1423,11 +1429,11 @@ def main():
|
|||||||
hash_f.close()
|
hash_f.close()
|
||||||
|
|
||||||
extraction_parts = [
|
extraction_parts = [
|
||||||
("bootloader", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x1000 0x4650 \""+EXT_DIR+"/extracted_rnode_firmware.bootloader\""),
|
("bootloader", "".join(["python \"", CNF_DIR, "/recovery_esptool.py\" --chip esp32 --port ", port_path, " --baud ", args.baud_flash, " --before default_reset --after hard_reset read_flash 0x1000 0x4650 \"", EXT_DIR, "/extracted_rnode_firmware.bootloader\""])),
|
||||||
("partition table", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x8000 0xC00 \""+EXT_DIR+"/extracted_rnode_firmware.partitions\""),
|
("partition table", "".join(["python \"", CNF_DIR, "/recovery_esptool.py\" --chip esp32 --port ", port_path, " --baud ", args.baud_flash, " --before default_reset --after hard_reset read_flash 0x8000 0xC00 \"", EXT_DIR, "/extracted_rnode_firmware.partitions\""])),
|
||||||
("app boot", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0xe000 0x2000 \""+EXT_DIR+"/extracted_rnode_firmware.boot_app0\""),
|
("app boot", "".join(["python \"", CNF_DIR, "/recovery_esptool.py\" --chip esp32 --port ", port_path, " --baud ", args.baud_flash, " --before default_reset --after hard_reset read_flash 0xe000 0x2000 \"", EXT_DIR, "/extracted_rnode_firmware.boot_app0\""])),
|
||||||
("application image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x10000 0x200000 \""+EXT_DIR+"/extracted_rnode_firmware.bin\""),
|
("application image", "".join(["python \"", CNF_DIR, "/recovery_esptool.py\" --chip esp32 --port ", port_path, " --baud ", args.baud_flash, " --before default_reset --after hard_reset read_flash 0x10000 0x200000 \"", EXT_DIR, "/extracted_rnode_firmware.bin\""])),
|
||||||
("console image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x210000 0x1F0000 \""+EXT_DIR+"/extracted_console_image.bin\""),
|
("console image", "".join(["python \"", CNF_DIR, "/recovery_esptool.py\" --chip esp32 --port ", port_path, " --baud ", args.baud_flash, " --before default_reset --after hard_reset read_flash 0x210000 0x1F0000 \"", EXT_DIR, "/extracted_console_image.bin\""])),
|
||||||
]
|
]
|
||||||
import subprocess, shlex
|
import subprocess, shlex
|
||||||
for part, command in extraction_parts:
|
for part, command in extraction_parts:
|
||||||
@ -1460,12 +1466,12 @@ def main():
|
|||||||
ports = list_ports.comports()
|
ports = list_ports.comports()
|
||||||
portlist = []
|
portlist = []
|
||||||
for port in ports:
|
for port in ports:
|
||||||
portlist.insert(0, port)
|
portlist.insert(0, port)
|
||||||
|
|
||||||
pi = 1
|
pi = 1
|
||||||
print("Detected serial ports:")
|
print("Detected serial ports:")
|
||||||
for port in portlist:
|
for port in portlist:
|
||||||
print(" ["+str(pi)+"] "+str(port.device)+" ("+str(port.product)+", "+str(port.serial_number)+")")
|
print("".join([" [", str(pi), "] ", str(port.device), " (", str(port.product), ", ", str(port.serial_number), ")"]))
|
||||||
pi += 1
|
pi += 1
|
||||||
|
|
||||||
print("\nEnter the number of the serial port your device is connected to:\n? ", end="")
|
print("\nEnter the number of the serial port your device is connected to:\n? ", end="")
|
||||||
@ -1488,7 +1494,7 @@ def main():
|
|||||||
port_serialno = selected_port.serial_number
|
port_serialno = selected_port.serial_number
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
print("\nOk, using device on "+str(port_path)+" ("+str(port_product)+", "+str(port_serialno)+")")
|
print("".join(["\nOk, using device on ", str(port_path), " (", str(port_product), ", ", str(port_serialno), ")"]))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ports = list_ports.comports()
|
ports = list_ports.comports()
|
||||||
@ -1541,7 +1547,7 @@ def main():
|
|||||||
print("correct firmware and provision it.")
|
print("correct firmware and provision it.")
|
||||||
else:
|
else:
|
||||||
print("\nIt looks like this is a fresh device with no RNode firmware.")
|
print("\nIt looks like this is a fresh device with no RNode firmware.")
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("What kind of device is this?\n")
|
print("What kind of device is this?\n")
|
||||||
print("[1] A specific kind of RNode")
|
print("[1] A specific kind of RNode")
|
||||||
@ -1981,7 +1987,7 @@ def main():
|
|||||||
fw_filename = "rnode_firmware.hex"
|
fw_filename = "rnode_firmware.hex"
|
||||||
elif selected_mcu == ROM.MCU_2560:
|
elif selected_mcu == ROM.MCU_2560:
|
||||||
fw_filename = "rnode_firmware_m2560.hex"
|
fw_filename = "rnode_firmware_m2560.hex"
|
||||||
|
|
||||||
elif selected_platform == ROM.PLATFORM_ESP32:
|
elif selected_platform == ROM.PLATFORM_ESP32:
|
||||||
fw_filename = None
|
fw_filename = None
|
||||||
print("\nWhat kind of ESP32 board is this?\n")
|
print("\nWhat kind of ESP32 board is this?\n")
|
||||||
@ -2094,7 +2100,7 @@ def main():
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Could not load device signing key")
|
RNS.log("Could not load device signing key")
|
||||||
|
|
||||||
|
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
@ -2177,7 +2183,7 @@ def main():
|
|||||||
if platform == "unzip":
|
if platform == "unzip":
|
||||||
flasher = "unzip"
|
flasher = "unzip"
|
||||||
if which(flasher) is not None:
|
if which(flasher) is not None:
|
||||||
return [flasher, "-o", UPD_DIR+"/"+selected_version+"/"+fw_filename, "-d", UPD_DIR+"/"+selected_version]
|
return [flasher, "-o", "".join([UPD_DIR, "/", selected_version, "/", fw_filename]), "-d", UPD_DIR+"/"+selected_version]
|
||||||
else:
|
else:
|
||||||
RNS.log("")
|
RNS.log("")
|
||||||
RNS.log("You do not currently have the \""+flasher+"\" program installed on your system.")
|
RNS.log("You do not currently have the \""+flasher+"\" program installed on your system.")
|
||||||
@ -2194,9 +2200,9 @@ def main():
|
|||||||
# avrdude -C/home/markqvist/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -q -q -V -patmega2560 -cwiring -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino-sketch-0E260F46C421A84A7CBAD48E859C8E64/RNode_Firmware.ino.hex:i
|
# avrdude -C/home/markqvist/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -q -q -V -patmega2560 -cwiring -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino-sketch-0E260F46C421A84A7CBAD48E859C8E64/RNode_Firmware.ino.hex:i
|
||||||
# avrdude -q -q -V -patmega2560 -cwiring -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino-sketch-0E260F46C421A84A7CBAD48E859C8E64/RNode_Firmware.ino.hex:i
|
# avrdude -q -q -V -patmega2560 -cwiring -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino-sketch-0E260F46C421A84A7CBAD48E859C8E64/RNode_Firmware.ino.hex:i
|
||||||
if fw_filename == "rnode_firmware.hex":
|
if fw_filename == "rnode_firmware.hex":
|
||||||
return [flasher, "-P", args.port, "-p", "m1284p", "-c", "arduino", "-b", "115200", "-U", "flash:w:"+UPD_DIR+"/"+selected_version+"/"+fw_filename+":i"]
|
return [flasher, "-P", args.port, "-p", "m1284p", "-c", "arduino", "-b", "115200", "-U", "".join(["flash:w:", UPD_DIR, "/", selected_version, "/", fw_filename, ":i"])]
|
||||||
elif fw_filename == "rnode_firmware_m2560.hex":
|
elif fw_filename == "rnode_firmware_m2560.hex":
|
||||||
return [flasher, "-P", args.port, "-p", "atmega2560", "-c", "wiring", "-D", "-b", "115200", "-U", "flash:w:"+UPD_DIR+"/"+selected_version+"/"+fw_filename]
|
return [flasher, "-P", args.port, "-p", "atmega2560", "-c", "wiring", "-D", "-b", "115200", "-U", "".join(["flash:w:", UPD_DIR, "/", selected_version, "/", fw_filename])]
|
||||||
else:
|
else:
|
||||||
RNS.log("")
|
RNS.log("")
|
||||||
RNS.log("You do not currently have the \""+flasher+"\" program installed on your system.")
|
RNS.log("You do not currently have the \""+flasher+"\" program installed on your system.")
|
||||||
@ -2224,6 +2230,7 @@ def main():
|
|||||||
os.chmod(flasher, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
|
os.chmod(flasher, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
|
||||||
|
|
||||||
if which(flasher) is not None:
|
if which(flasher) is not None:
|
||||||
|
# TODO: Simplify this returns with a list and add or remove arguments
|
||||||
if fw_filename == "rnode_firmware_tbeam.zip":
|
if fw_filename == "rnode_firmware_tbeam.zip":
|
||||||
if numeric_version >= 1.55:
|
if numeric_version >= 1.55:
|
||||||
return [
|
return [
|
||||||
@ -2237,11 +2244,11 @@ def main():
|
|||||||
"--flash_mode", "dio",
|
"--flash_mode", "dio",
|
||||||
"--flash_freq", "80m",
|
"--flash_freq", "80m",
|
||||||
"--flash_size", "4MB",
|
"--flash_size", "4MB",
|
||||||
"0xe000", UPD_DIR+"/"+selected_version+"/rnode_firmware_tbeam.boot_app0",
|
"0xe000", "".join([UPD_DIR, "/", selected_version, "/rnode_firmware_tbeam.boot_app0"]),
|
||||||
"0x1000", UPD_DIR+"/"+selected_version+"/rnode_firmware_tbeam.bootloader",
|
"0x1000", "".join([UPD_DIR, "/", selected_version, "/rnode_firmware_tbeam.bootloader"]),
|
||||||
"0x10000", UPD_DIR+"/"+selected_version+"/rnode_firmware_tbeam.bin",
|
"0x10000", "".join([UPD_DIR, "/", selected_version, "/rnode_firmware_tbeam.bin"]),
|
||||||
"0x210000",UPD_DIR+"/"+selected_version+"/console_image.bin",
|
"0x210000","".join([UPD_DIR, "/", selected_version, "/console_image.bin"]),
|
||||||
"0x8000", UPD_DIR+"/"+selected_version+"/rnode_firmware_tbeam.partitions",
|
"0x8000", "".join([UPD_DIR, "/", selected_version, "/rnode_firmware_tbeam.partitions"]),
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
return [
|
return [
|
||||||
@ -2672,7 +2679,7 @@ def main():
|
|||||||
wants_fw_provision = False
|
wants_fw_provision = False
|
||||||
if args.flash:
|
if args.flash:
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
|
|
||||||
if fw_filename == None:
|
if fw_filename == None:
|
||||||
fw_filename = "rnode_firmware.hex"
|
fw_filename = "rnode_firmware.hex"
|
||||||
|
|
||||||
@ -2703,9 +2710,9 @@ def main():
|
|||||||
RNS.log("Error while flashing")
|
RNS.log("Error while flashing")
|
||||||
RNS.log(str(e))
|
RNS.log(str(e))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
fw_src = UPD_DIR+"/"+selected_version+"/"
|
fw_src = "".join([UPD_DIR, "/", selected_version, "/"])
|
||||||
if os.path.isfile(fw_src+fw_filename):
|
if os.path.isfile(fw_src+fw_filename):
|
||||||
try:
|
try:
|
||||||
if fw_filename.endswith(".zip"):
|
if fw_filename.endswith(".zip"):
|
||||||
@ -2862,7 +2869,7 @@ def main():
|
|||||||
update_full_path = EXT_DIR+"/extracted_rnode_firmware.version"
|
update_full_path = EXT_DIR+"/extracted_rnode_firmware.version"
|
||||||
else:
|
else:
|
||||||
update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename
|
update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename
|
||||||
if os.path.isfile(update_full_path):
|
if os.path.isfile(update_full_path):
|
||||||
try:
|
try:
|
||||||
args.info = False
|
args.info = False
|
||||||
RNS.log("Updating RNode firmware for device on "+args.port)
|
RNS.log("Updating RNode firmware for device on "+args.port)
|
||||||
@ -3017,13 +3024,13 @@ def main():
|
|||||||
|
|
||||||
RNS.log("")
|
RNS.log("")
|
||||||
RNS.log("Device info:")
|
RNS.log("Device info:")
|
||||||
RNS.log("\tProduct : "+products[rnode.product]+" "+models[rnode.model][3]+" ("+bytes([rnode.product]).hex()+":"+bytes([rnode.model]).hex()+board_string+")")
|
RNS.log("".join(["\tProduct : ", products[rnode.product], " ", models[rnode.model][3], " (", bytes([rnode.product]).hex(), ":", bytes([rnode.model]).hex(), board_string, ")"]))
|
||||||
RNS.log("\tDevice signature : "+sigstring)
|
RNS.log("\tDevice signature : "+sigstring)
|
||||||
RNS.log("\tFirmware version : "+rnode.version)
|
RNS.log("\tFirmware version : "+rnode.version)
|
||||||
RNS.log("\tHardware revision : "+str(int(rnode.hw_rev)))
|
RNS.log("\tHardware revision : "+str(int(rnode.hw_rev)))
|
||||||
RNS.log("\tSerial number : "+RNS.hexrep(rnode.serialno))
|
RNS.log("\tSerial number : "+RNS.hexrep(rnode.serialno))
|
||||||
RNS.log("\tModem chip : "+str(models[rnode.model][5]))
|
RNS.log("\tModem chip : "+str(models[rnode.model][5]))
|
||||||
RNS.log("\tFrequency range : "+str(rnode.min_freq/1e6)+" MHz - "+str(rnode.max_freq/1e6)+" MHz")
|
RNS.log("".join(["\tFrequency range : ", str(rnode.min_freq/1e6), " MHz - ", str(rnode.max_freq/1e6), " MHz"]))
|
||||||
RNS.log("\tMax TX power : "+str(rnode.max_output)+" dBm")
|
RNS.log("\tMax TX power : "+str(rnode.max_output)+" dBm")
|
||||||
RNS.log("\tManufactured : "+timestring)
|
RNS.log("\tManufactured : "+timestring)
|
||||||
|
|
||||||
@ -3040,7 +3047,7 @@ def main():
|
|||||||
RNS.log("\tDevice mode : TNC")
|
RNS.log("\tDevice mode : TNC")
|
||||||
RNS.log("\t Frequency : "+str((rnode.conf_frequency/1000000.0))+" MHz")
|
RNS.log("\t Frequency : "+str((rnode.conf_frequency/1000000.0))+" MHz")
|
||||||
RNS.log("\t Bandwidth : "+str(rnode.conf_bandwidth/1000.0)+" KHz")
|
RNS.log("\t Bandwidth : "+str(rnode.conf_bandwidth/1000.0)+" KHz")
|
||||||
RNS.log("\t TX power : "+str(rnode.conf_txpower)+" dBm ("+str(txp_mw)+" mW)")
|
RNS.log("".join(["\t TX power : ", str(rnode.conf_txpower), " dBm (", str(txp_mw), " mW)"]))
|
||||||
RNS.log("\t Spreading factor : "+str(rnode.conf_sf))
|
RNS.log("\t Spreading factor : "+str(rnode.conf_sf))
|
||||||
RNS.log("\t Coding rate : "+str(rnode.conf_cr))
|
RNS.log("\t Coding rate : "+str(rnode.conf_cr))
|
||||||
RNS.log("\t On-air bitrate : "+str(rnode.bitrate_kbps)+" kbps")
|
RNS.log("\t On-air bitrate : "+str(rnode.bitrate_kbps)+" kbps")
|
||||||
@ -3070,7 +3077,7 @@ def main():
|
|||||||
if args.autoinstall:
|
if args.autoinstall:
|
||||||
RNS.log("Clearing old EEPROM, this will take about 15 seconds...")
|
RNS.log("Clearing old EEPROM, this will take about 15 seconds...")
|
||||||
rnode.wipe_eeprom()
|
rnode.wipe_eeprom()
|
||||||
|
|
||||||
if rnode.platform == ROM.PLATFORM_ESP32:
|
if rnode.platform == ROM.PLATFORM_ESP32:
|
||||||
RNS.log("Waiting for ESP32 reset...")
|
RNS.log("Waiting for ESP32 reset...")
|
||||||
time.sleep(6)
|
time.sleep(6)
|
||||||
@ -3241,7 +3248,7 @@ def main():
|
|||||||
vf.close()
|
vf.close()
|
||||||
else:
|
else:
|
||||||
partition_filename = fw_filename.replace(".zip", ".bin")
|
partition_filename = fw_filename.replace(".zip", ".bin")
|
||||||
partition_hash = get_partition_hash(UPD_DIR+"/"+selected_version+"/"+partition_filename)
|
partition_hash = get_partition_hash("".join([UPD_DIR, "/", selected_version, "/", partition_filename]))
|
||||||
|
|
||||||
if partition_hash != None:
|
if partition_hash != None:
|
||||||
time.sleep(0.75)
|
time.sleep(0.75)
|
||||||
|
@ -27,13 +27,14 @@ import argparse
|
|||||||
|
|
||||||
from RNS._version import __version__
|
from RNS._version import __version__
|
||||||
|
|
||||||
|
|
||||||
def size_str(num, suffix='B'):
|
def size_str(num, suffix='B'):
|
||||||
units = ['','K','M','G','T','P','E','Z']
|
units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
||||||
last_unit = 'Y'
|
last_unit = 'Y'
|
||||||
|
|
||||||
if suffix == 'b':
|
if suffix == 'b':
|
||||||
num *= 8
|
num *= 8
|
||||||
units = ['','K','M','G','T','P','E','Z']
|
units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
||||||
last_unit = 'Y'
|
last_unit = 'Y'
|
||||||
|
|
||||||
for unit in units:
|
for unit in units:
|
||||||
@ -46,6 +47,14 @@ def size_str(num, suffix='B'):
|
|||||||
|
|
||||||
return "%.2f%s%s" % (num, last_unit, suffix)
|
return "%.2f%s%s" % (num, last_unit, suffix)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_bytes_to_hex(value_obj):
|
||||||
|
if isinstance(value_obj, bytes):
|
||||||
|
return RNS.hexrep(value_obj, delimit=False)
|
||||||
|
elif isinstance(value_obj, dict):
|
||||||
|
return {key: convert_bytes_to_hex(value) for key, value in value_obj.items()}
|
||||||
|
return value_obj
|
||||||
|
|
||||||
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False, sorting=None, sort_reverse=False):
|
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False, sorting=None, sort_reverse=False):
|
||||||
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
|
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
|
||||||
|
|
||||||
@ -55,169 +64,159 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if stats != None:
|
if stats is None:
|
||||||
if json:
|
|
||||||
import json
|
|
||||||
for s in stats:
|
|
||||||
if isinstance(stats[s], bytes):
|
|
||||||
stats[s] = RNS.hexrep(stats[s], delimit=False)
|
|
||||||
|
|
||||||
if isinstance(stats[s], dict):
|
|
||||||
for i in stats[s]:
|
|
||||||
if isinstance(i, dict):
|
|
||||||
for k in i:
|
|
||||||
if isinstance(i[k], bytes):
|
|
||||||
i[k] = RNS.hexrep(i[k], delimit=False)
|
|
||||||
|
|
||||||
print(json.dumps(stats))
|
|
||||||
exit()
|
|
||||||
|
|
||||||
interfaces = stats["interfaces"]
|
|
||||||
if sorting != None and isinstance(sorting, str):
|
|
||||||
sorting = sorting.lower()
|
|
||||||
if sorting == "rate" or sorting == "bitrate":
|
|
||||||
interfaces.sort(key=lambda i: i["bitrate"], reverse=not sort_reverse)
|
|
||||||
if sorting == "rx":
|
|
||||||
interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse)
|
|
||||||
if sorting == "tx":
|
|
||||||
interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse)
|
|
||||||
if sorting == "traffic":
|
|
||||||
interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse)
|
|
||||||
if sorting == "announces" or sorting == "announce":
|
|
||||||
interfaces.sort(key=lambda i: i["incoming_announce_frequency"]+i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
|
||||||
if sorting == "arx":
|
|
||||||
interfaces.sort(key=lambda i: i["incoming_announce_frequency"], reverse=not sort_reverse)
|
|
||||||
if sorting == "atx":
|
|
||||||
interfaces.sort(key=lambda i: i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
|
||||||
if sorting == "held":
|
|
||||||
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
|
||||||
|
|
||||||
|
|
||||||
for ifstat in interfaces:
|
|
||||||
name = ifstat["name"]
|
|
||||||
|
|
||||||
if dispall or not (
|
|
||||||
name.startswith("LocalInterface[") or
|
|
||||||
name.startswith("TCPInterface[Client") or
|
|
||||||
name.startswith("I2PInterfacePeer[Connected peer") or
|
|
||||||
(name.startswith("I2PInterface[") and ("i2p_connectable" in ifstat and ifstat["i2p_connectable"] == False))
|
|
||||||
):
|
|
||||||
|
|
||||||
if not (name.startswith("I2PInterface[") and ("i2p_connectable" in ifstat and ifstat["i2p_connectable"] == False)):
|
|
||||||
if name_filter == None or name_filter.lower() in name.lower():
|
|
||||||
print("")
|
|
||||||
|
|
||||||
if ifstat["status"]:
|
|
||||||
ss = "Up"
|
|
||||||
else:
|
|
||||||
ss = "Down"
|
|
||||||
|
|
||||||
if ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT:
|
|
||||||
modestr = "Access Point"
|
|
||||||
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_POINT_TO_POINT:
|
|
||||||
modestr = "Point-to-Point"
|
|
||||||
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_ROAMING:
|
|
||||||
modestr = "Roaming"
|
|
||||||
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY:
|
|
||||||
modestr = "Boundary"
|
|
||||||
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_GATEWAY:
|
|
||||||
modestr = "Gateway"
|
|
||||||
else:
|
|
||||||
modestr = "Full"
|
|
||||||
|
|
||||||
|
|
||||||
if ifstat["clients"] != None:
|
|
||||||
clients = ifstat["clients"]
|
|
||||||
if name.startswith("Shared Instance["):
|
|
||||||
cnum = max(clients-1,0)
|
|
||||||
if cnum == 1:
|
|
||||||
spec_str = " program"
|
|
||||||
else:
|
|
||||||
spec_str = " programs"
|
|
||||||
|
|
||||||
clients_string = "Serving : "+str(cnum)+spec_str
|
|
||||||
elif name.startswith("I2PInterface["):
|
|
||||||
if "i2p_connectable" in ifstat and ifstat["i2p_connectable"] == True:
|
|
||||||
cnum = clients
|
|
||||||
if cnum == 1:
|
|
||||||
spec_str = " connected I2P endpoint"
|
|
||||||
else:
|
|
||||||
spec_str = " connected I2P endpoints"
|
|
||||||
|
|
||||||
clients_string = "Peers : "+str(cnum)+spec_str
|
|
||||||
else:
|
|
||||||
clients_string = ""
|
|
||||||
else:
|
|
||||||
clients_string = "Clients : "+str(clients)
|
|
||||||
|
|
||||||
else:
|
|
||||||
clients = None
|
|
||||||
|
|
||||||
print(" {n}".format(n=ifstat["name"]))
|
|
||||||
|
|
||||||
if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None:
|
|
||||||
print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
|
|
||||||
|
|
||||||
print(" Status : {ss}".format(ss=ss))
|
|
||||||
|
|
||||||
if clients != None and clients_string != "":
|
|
||||||
print(" "+clients_string)
|
|
||||||
|
|
||||||
if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")):
|
|
||||||
print(" Mode : {mode}".format(mode=modestr))
|
|
||||||
|
|
||||||
if "bitrate" in ifstat and ifstat["bitrate"] != None:
|
|
||||||
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
|
|
||||||
|
|
||||||
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
|
||||||
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
|
||||||
|
|
||||||
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
|
||||||
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
|
||||||
|
|
||||||
if "peers" in ifstat and ifstat["peers"] != None:
|
|
||||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
|
||||||
|
|
||||||
if "tunnelstate" in ifstat and ifstat["tunnelstate"] != None:
|
|
||||||
print(" I2P : {ts}".format(ts=ifstat["tunnelstate"]))
|
|
||||||
|
|
||||||
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
|
|
||||||
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
|
|
||||||
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
|
||||||
|
|
||||||
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
|
||||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
|
||||||
|
|
||||||
if astats and "announce_queue" in ifstat and ifstat["announce_queue"] != None and ifstat["announce_queue"] > 0:
|
|
||||||
aqn = ifstat["announce_queue"]
|
|
||||||
if aqn == 1:
|
|
||||||
print(" Queued : {np} announce".format(np=aqn))
|
|
||||||
else:
|
|
||||||
print(" Queued : {np} announces".format(np=aqn))
|
|
||||||
|
|
||||||
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
|
|
||||||
aqn = ifstat["held_announces"]
|
|
||||||
if aqn == 1:
|
|
||||||
print(" Held : {np} announce".format(np=aqn))
|
|
||||||
else:
|
|
||||||
print(" Held : {np} announces".format(np=aqn))
|
|
||||||
|
|
||||||
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None:
|
|
||||||
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
|
|
||||||
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
|
|
||||||
|
|
||||||
print(" Traffic : {txb}↑\n {rxb}↓".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
|
|
||||||
|
|
||||||
if "transport_id" in stats and stats["transport_id"] != None:
|
|
||||||
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
|
|
||||||
if "probe_responder" in stats and stats["probe_responder"] != None:
|
|
||||||
print(" Probe responder at "+RNS.prettyhexrep(stats["probe_responder"])+ " active")
|
|
||||||
print(" Uptime is "+RNS.prettytime(stats["transport_uptime"]))
|
|
||||||
|
|
||||||
print("")
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("Could not get RNS status")
|
print("Could not get RNS status")
|
||||||
|
return
|
||||||
|
|
||||||
|
if json:
|
||||||
|
import json
|
||||||
|
for s, value in stats.items():
|
||||||
|
stats[s] = convert_bytes_to_hex(value)
|
||||||
|
print(json.dumps(stats))
|
||||||
|
exit()
|
||||||
|
|
||||||
|
interfaces = stats["interfaces"]
|
||||||
|
if sorting is not None and isinstance(sorting, str):
|
||||||
|
sorting = sorting.lower()
|
||||||
|
if sorting == "rate" or sorting == "bitrate":
|
||||||
|
interfaces.sort(key=lambda i: i["bitrate"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "rx":
|
||||||
|
interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "tx":
|
||||||
|
interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "traffic":
|
||||||
|
interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "announces" or sorting == "announce":
|
||||||
|
interfaces.sort(key=lambda i: i["incoming_announce_frequency"]+i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "arx":
|
||||||
|
interfaces.sort(key=lambda i: i["incoming_announce_frequency"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "atx":
|
||||||
|
interfaces.sort(key=lambda i: i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
||||||
|
elif sorting == "held":
|
||||||
|
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
||||||
|
|
||||||
|
for ifstat in interfaces:
|
||||||
|
name = ifstat["name"]
|
||||||
|
|
||||||
|
if dispall or not (
|
||||||
|
name.startswith("LocalInterface[") or
|
||||||
|
name.startswith("TCPInterface[Client") or
|
||||||
|
name.startswith("I2PInterfacePeer[Connected peer") or
|
||||||
|
(name.startswith("I2PInterface[") and ("i2p_connectable" in ifstat and ifstat["i2p_connectable"] == False))
|
||||||
|
):
|
||||||
|
|
||||||
|
if not (name.startswith("I2PInterface[") and ("i2p_connectable" in ifstat and ifstat["i2p_connectable"] == False)):
|
||||||
|
if name_filter == None or name_filter.lower() in name.lower():
|
||||||
|
print("")
|
||||||
|
|
||||||
|
if ifstat["status"]:
|
||||||
|
ss = "Up"
|
||||||
|
else:
|
||||||
|
ss = "Down"
|
||||||
|
|
||||||
|
if ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT:
|
||||||
|
modestr = "Access Point"
|
||||||
|
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_POINT_TO_POINT:
|
||||||
|
modestr = "Point-to-Point"
|
||||||
|
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_ROAMING:
|
||||||
|
modestr = "Roaming"
|
||||||
|
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY:
|
||||||
|
modestr = "Boundary"
|
||||||
|
elif ifstat["mode"] == RNS.Interfaces.Interface.Interface.MODE_GATEWAY:
|
||||||
|
modestr = "Gateway"
|
||||||
|
else:
|
||||||
|
modestr = "Full"
|
||||||
|
|
||||||
|
if ifstat["clients"] is not None:
|
||||||
|
clients = ifstat["clients"]
|
||||||
|
if name.startswith("Shared Instance["):
|
||||||
|
cnum = max(clients-1,0)
|
||||||
|
if cnum == 1:
|
||||||
|
spec_str = " program"
|
||||||
|
else:
|
||||||
|
spec_str = " programs"
|
||||||
|
|
||||||
|
clients_string = "Serving : "+str(cnum)+spec_str
|
||||||
|
elif name.startswith("I2PInterface["):
|
||||||
|
if "i2p_connectable" in ifstat and ifstat["i2p_connectable"] == True:
|
||||||
|
cnum = clients
|
||||||
|
if cnum == 1:
|
||||||
|
spec_str = " connected I2P endpoint"
|
||||||
|
else:
|
||||||
|
spec_str = " connected I2P endpoints"
|
||||||
|
|
||||||
|
clients_string = "Peers : "+str(cnum)+spec_str
|
||||||
|
else:
|
||||||
|
clients_string = ""
|
||||||
|
else:
|
||||||
|
clients_string = "Clients : "+str(clients)
|
||||||
|
|
||||||
|
else:
|
||||||
|
clients = None
|
||||||
|
|
||||||
|
print(" {n}".format(n=ifstat["name"]))
|
||||||
|
|
||||||
|
if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None:
|
||||||
|
print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
|
||||||
|
|
||||||
|
print(" Status : {ss}".format(ss=ss))
|
||||||
|
|
||||||
|
if clients != None and clients_string != "":
|
||||||
|
print(" "+clients_string)
|
||||||
|
|
||||||
|
if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")):
|
||||||
|
print(" Mode : {mode}".format(mode=modestr))
|
||||||
|
|
||||||
|
if "bitrate" in ifstat and ifstat["bitrate"] != None:
|
||||||
|
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
|
||||||
|
|
||||||
|
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
||||||
|
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
||||||
|
|
||||||
|
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
||||||
|
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
||||||
|
|
||||||
|
if "peers" in ifstat and ifstat["peers"] != None:
|
||||||
|
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||||
|
|
||||||
|
if "tunnelstate" in ifstat and ifstat["tunnelstate"] != None:
|
||||||
|
print(" I2P : {ts}".format(ts=ifstat["tunnelstate"]))
|
||||||
|
|
||||||
|
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
|
||||||
|
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
|
||||||
|
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
||||||
|
|
||||||
|
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||||
|
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||||
|
|
||||||
|
if astats and "announce_queue" in ifstat and ifstat["announce_queue"] != None and ifstat["announce_queue"] > 0:
|
||||||
|
aqn = ifstat["announce_queue"]
|
||||||
|
if aqn == 1:
|
||||||
|
print(" Queued : {np} announce".format(np=aqn))
|
||||||
|
else:
|
||||||
|
print(" Queued : {np} announces".format(np=aqn))
|
||||||
|
|
||||||
|
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
|
||||||
|
aqn = ifstat["held_announces"]
|
||||||
|
if aqn == 1:
|
||||||
|
print(" Held : {np} announce".format(np=aqn))
|
||||||
|
else:
|
||||||
|
print(" Held : {np} announces".format(np=aqn))
|
||||||
|
|
||||||
|
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None:
|
||||||
|
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
|
||||||
|
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
|
||||||
|
|
||||||
|
print(" Traffic : {txb}↑\n {rxb}↓".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
|
||||||
|
|
||||||
|
if "transport_id" in stats and stats["transport_id"] != None:
|
||||||
|
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
|
||||||
|
if "probe_responder" in stats and stats["probe_responder"] != None:
|
||||||
|
print(" Probe responder at "+RNS.prettyhexrep(stats["probe_responder"])+ " active")
|
||||||
|
print(" Uptime is "+RNS.prettytime(stats["transport_uptime"]))
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
@ -232,7 +231,7 @@ def main():
|
|||||||
help="show all interfaces",
|
help="show all interfaces",
|
||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-A",
|
"-A",
|
||||||
"--announce-stats",
|
"--announce-stats",
|
||||||
@ -240,7 +239,7 @@ def main():
|
|||||||
help="show announce stats",
|
help="show announce stats",
|
||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
"--sort",
|
"--sort",
|
||||||
@ -249,7 +248,7 @@ def main():
|
|||||||
default=None,
|
default=None,
|
||||||
type=str
|
type=str
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-r",
|
"-r",
|
||||||
"--reverse",
|
"--reverse",
|
||||||
@ -257,7 +256,7 @@ def main():
|
|||||||
help="reverse sorting",
|
help="reverse sorting",
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-j",
|
"-j",
|
||||||
"--json",
|
"--json",
|
||||||
@ -269,7 +268,7 @@ def main():
|
|||||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||||
|
|
||||||
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
|
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.config:
|
if args.config:
|
||||||
@ -292,6 +291,7 @@ def main():
|
|||||||
print("")
|
print("")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
def speed_str(num, suffix='bps'):
|
def speed_str(num, suffix='bps'):
|
||||||
units = ['','k','M','G','T','P','E','Z']
|
units = ['','k','M','G','T','P','E','Z']
|
||||||
last_unit = 'Y'
|
last_unit = 'Y'
|
||||||
@ -308,5 +308,6 @@ def speed_str(num, suffix='bps'):
|
|||||||
|
|
||||||
return "%.2f %s%s" % (num, last_unit, suffix)
|
return "%.2f %s%s" % (num, last_unit, suffix)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -28,7 +28,7 @@ import argparse
|
|||||||
import shlex
|
import shlex
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
import tty
|
# import tty # Commented this because commented lines below use it
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from RNS._version import __version__
|
from RNS._version import __version__
|
||||||
@ -39,25 +39,27 @@ reticulum = None
|
|||||||
allow_all = False
|
allow_all = False
|
||||||
allowed_identity_hashes = []
|
allowed_identity_hashes = []
|
||||||
|
|
||||||
|
|
||||||
def prepare_identity(identity_path):
|
def prepare_identity(identity_path):
|
||||||
global identity
|
global identity
|
||||||
if identity_path == None:
|
if identity_path is None:
|
||||||
identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME
|
identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME
|
||||||
|
|
||||||
if os.path.isfile(identity_path):
|
if os.path.isfile(identity_path):
|
||||||
identity = RNS.Identity.from_file(identity_path)
|
identity = RNS.Identity.from_file(identity_path)
|
||||||
|
|
||||||
if identity == None:
|
if identity == None:
|
||||||
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||||
identity = RNS.Identity()
|
identity = RNS.Identity()
|
||||||
identity.to_file(identity_path)
|
identity.to_file(identity_path)
|
||||||
|
|
||||||
|
|
||||||
def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed = [], print_identity = False, disable_auth = None, disable_announce=False):
|
def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed = [], print_identity = False, disable_auth = None, disable_announce=False):
|
||||||
global identity, allow_all, allowed_identity_hashes, reticulum
|
global identity, allow_all, allowed_identity_hashes, reticulum
|
||||||
|
|
||||||
targetloglevel = 3+verbosity-quietness
|
targetloglevel = 3+verbosity-quietness
|
||||||
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
||||||
|
|
||||||
prepare_identity(identitypath)
|
prepare_identity(identitypath)
|
||||||
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute")
|
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute")
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
|
|||||||
if disable_auth:
|
if disable_auth:
|
||||||
allow_all = True
|
allow_all = True
|
||||||
else:
|
else:
|
||||||
if allowed != None:
|
if allowed is not None:
|
||||||
for a in allowed:
|
for a in allowed:
|
||||||
try:
|
try:
|
||||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||||
@ -107,7 +109,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
|
|||||||
|
|
||||||
if not disable_announce:
|
if not disable_announce:
|
||||||
destination.announce()
|
destination.announce()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
@ -297,6 +299,7 @@ def remote_execution_progress(request_receipt):
|
|||||||
link = None
|
link = None
|
||||||
listener_destination = None
|
listener_destination = None
|
||||||
remote_exec_grace = 2.0
|
remote_exec_grace = 2.0
|
||||||
|
|
||||||
def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detailed = False, mirror = False, noid = False, destination = None, command = None, stdin = None, stdoutl = None, stderrl = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, result_timeout = None, interactive = False):
|
def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detailed = False, mirror = False, noid = False, destination = None, command = None, stdin = None, stdoutl = None, stderrl = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, result_timeout = None, interactive = False):
|
||||||
global identity, reticulum, link, listener_destination, remote_exec_grace
|
global identity, reticulum, link, listener_destination, remote_exec_grace
|
||||||
|
|
||||||
@ -338,7 +341,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
|
|||||||
if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
|
if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
|
||||||
link = RNS.Link(listener_destination)
|
link = RNS.Link(listener_destination)
|
||||||
link.did_identify = False
|
link.did_identify = False
|
||||||
|
|
||||||
if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg="Establishing link with "+RNS.prettyhexrep(destination_hash), timeout=timeout):
|
if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg="Establishing link with "+RNS.prettyhexrep(destination_hash), timeout=timeout):
|
||||||
print("Could not establish link with "+RNS.prettyhexrep(destination_hash))
|
print("Could not establish link with "+RNS.prettyhexrep(destination_hash))
|
||||||
exit(243)
|
exit(243)
|
||||||
@ -467,7 +470,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
|
|||||||
else:
|
else:
|
||||||
tstr = ""
|
tstr = ""
|
||||||
print("Remote wrote "+str(outlen)+" bytes to stdout"+tstr)
|
print("Remote wrote "+str(outlen)+" bytes to stdout"+tstr)
|
||||||
|
|
||||||
if errlen != None and stderr != None:
|
if errlen != None and stderr != None:
|
||||||
if len(stderr) < errlen:
|
if len(stderr) < errlen:
|
||||||
tstr = ", "+str(len(stderr))+" bytes displayed"
|
tstr = ", "+str(len(stderr))+" bytes displayed"
|
||||||
@ -548,7 +551,6 @@ def main():
|
|||||||
parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int)
|
parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int)
|
||||||
parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int)
|
parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int)
|
||||||
parser.add_argument("--version", action="version", version="rnx {version}".format(version=__version__))
|
parser.add_argument("--version", action="version", version="rnx {version}".format(version=__version__))
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.listen or args.print_identity:
|
if args.listen or args.print_identity:
|
||||||
@ -600,8 +602,8 @@ def main():
|
|||||||
# while True:
|
# while True:
|
||||||
# ch = sys.stdin.read(1)
|
# ch = sys.stdin.read(1)
|
||||||
# cmdbuf += ch.encode("utf-8")
|
# cmdbuf += ch.encode("utf-8")
|
||||||
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
||||||
|
|
||||||
command = input()
|
command = input()
|
||||||
if command.lower() == "exit" or command.lower() == "quit":
|
if command.lower() == "exit" or command.lower() == "quit":
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -668,6 +670,7 @@ def size_str(num, suffix='B'):
|
|||||||
|
|
||||||
return "%.2f%s%s" % (num, last_unit, suffix)
|
return "%.2f%s%s" % (num, last_unit, suffix)
|
||||||
|
|
||||||
|
|
||||||
def pretty_time(time, verbose=False):
|
def pretty_time(time, verbose=False):
|
||||||
days = int(time // (24 * 3600))
|
days = int(time // (24 * 3600))
|
||||||
time = time % (24 * 3600)
|
time = time % (24 * 3600)
|
||||||
@ -676,7 +679,7 @@ def pretty_time(time, verbose=False):
|
|||||||
minutes = int(time // 60)
|
minutes = int(time // 60)
|
||||||
time %= 60
|
time %= 60
|
||||||
seconds = round(time, 2)
|
seconds = round(time, 2)
|
||||||
|
|
||||||
ss = "" if seconds == 1 else "s"
|
ss = "" if seconds == 1 else "s"
|
||||||
sm = "" if minutes == 1 else "s"
|
sm = "" if minutes == 1 else "s"
|
||||||
sh = "" if hours == 1 else "s"
|
sh = "" if hours == 1 else "s"
|
||||||
@ -684,31 +687,24 @@ def pretty_time(time, verbose=False):
|
|||||||
|
|
||||||
components = []
|
components = []
|
||||||
if days > 0:
|
if days > 0:
|
||||||
components.append(str(days)+" day"+sd if verbose else str(days)+"d")
|
components.append("".join([str(days), " day", sd if verbose else str(days), "d"]))
|
||||||
|
|
||||||
if hours > 0:
|
if hours > 0:
|
||||||
components.append(str(hours)+" hour"+sh if verbose else str(hours)+"h")
|
components.append("".join([str(hours), " hour", sh if verbose else str(hours), "h"]))
|
||||||
|
|
||||||
if minutes > 0:
|
if minutes > 0:
|
||||||
components.append(str(minutes)+" minute"+sm if verbose else str(minutes)+"m")
|
components.append("".join([str(minutes), " minute", sm if verbose else str(minutes), "m"]))
|
||||||
|
|
||||||
if seconds > 0:
|
if seconds > 0:
|
||||||
components.append(str(seconds)+" second"+ss if verbose else str(seconds)+"s")
|
components.append("".join([str(seconds), " second", ss if verbose else str(seconds), "s"]))
|
||||||
|
|
||||||
i = 0
|
if len(components) > 1:
|
||||||
tstr = ""
|
time_string = "".join([", ".join(components[:-1]), " and ", components[-1]])
|
||||||
for c in components:
|
else:
|
||||||
i += 1
|
time_string = components[0] if components else ""
|
||||||
if i == 1:
|
|
||||||
pass
|
|
||||||
elif i < len(components):
|
|
||||||
tstr += ", "
|
|
||||||
elif i == len(components):
|
|
||||||
tstr += " and "
|
|
||||||
|
|
||||||
tstr += c
|
return time_string
|
||||||
|
|
||||||
return tstr
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "0.7.3"
|
__version__ = "0.7.4"
|
||||||
|
@ -99,6 +99,9 @@ class TestLink(unittest.TestCase):
|
|||||||
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
||||||
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
||||||
|
|
||||||
|
RNS.Transport.request_path(bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
@ -120,6 +123,9 @@ class TestLink(unittest.TestCase):
|
|||||||
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
||||||
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
||||||
|
|
||||||
|
RNS.Transport.request_path(bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
@ -400,6 +406,9 @@ class TestLink(unittest.TestCase):
|
|||||||
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
||||||
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
||||||
|
|
||||||
|
RNS.Transport.request_path(bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
@ -449,6 +458,9 @@ class TestLink(unittest.TestCase):
|
|||||||
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
||||||
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
||||||
|
|
||||||
|
RNS.Transport.request_path(bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
@ -502,6 +514,9 @@ class TestLink(unittest.TestCase):
|
|||||||
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0]))
|
||||||
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
self.assertEqual(id1.hash, bytes.fromhex(fixed_keys[0][1]))
|
||||||
|
|
||||||
|
RNS.Transport.request_path(bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
@ -9,4 +9,4 @@
|
|||||||
loglevel = 1
|
loglevel = 1
|
||||||
|
|
||||||
[interfaces]
|
[interfaces]
|
||||||
# No interfaces, only local traffic
|
# No interfaces, only local traffic
|
||||||
|
Loading…
Reference in New Issue
Block a user