def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Randomly create a new identity for our echo server server_identity = RNS.Identity() # We create a destination that clients can query. We want # to be able to verify echo replies to our clients, so we # create a "single" destination that can receive encrypted # messages. This way the client can send a request and be # certain that no-one else than this destination was able # to read it. echo_destination = RNS.Destination(server_identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "echo", "request") # We configure the destination to automatically prove all # packets adressed to it. By doing this, RNS will automatically # generate a proof for each incoming packet and transmit it # back to the sender of that packet. echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) # Tell the destination which function in our program to # run when a packet is received. We do this so we can # print a log message when the server receives a request echo_destination.packet_callback(server_callback) # Everything's ready! # Let's Wait for client requests or user input announceLoop(echo_destination)
def program_setup(configpath, channel=None): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # If the user did not select a "channel" we use # a default one called "public_information". # This "channel" is added to the destination name- # space, so the user can select different broadcast # channels. if channel == None: channel = "public_information" # We create a PLAIN destination. This is an uncencrypted endpoint # that anyone can listen to and send information to. broadcast_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, APP_NAME, "broadcast", channel) # We specify a callback that will get called every time # the destination receives data. broadcast_destination.packet_callback(packet_callback) # Everything's ready! # Let's hand over control to the main loop broadcastLoop(broadcast_destination)
def client(destination_hexhash, configpath): # We need a binary representation of the destination # hash that was entered on the command line try: if len(destination_hexhash) != 20: raise ValueError( "Destination length is invalid, must be 20 hexadecimal characters (10 bytes)" ) destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") exit() # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Check if we know a path to the destination if not RNS.Transport.has_path(destination_hash): RNS.log( "Destination is not yet known. Requesting path and waiting for announce to arrive..." ) RNS.Transport.request_path(destination_hash) while not RNS.Transport.has_path(destination_hash): time.sleep(0.1) # Recall the server identity server_identity = RNS.Identity.recall(destination_hash) # Inform the user that we'll begin connecting RNS.log("Establishing link with server...") # When the server identity is known, we set # up a destination server_destination = RNS.Destination(server_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "filetransfer", "server") # We also want to automatically prove incoming packets server_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) # And create a link link = RNS.Link(server_destination) # We expect any normal data packets on the link # to contain a list of served files, so we set # a callback accordingly link.set_packet_callback(filelist_received) # We'll also set up functions to inform the # user when the link is established or closed link.set_link_established_callback(link_established) link.set_link_closed_callback(link_closed) # And set the link to automatically begin # downloading advertised resources link.set_resource_strategy(RNS.Link.ACCEPT_ALL) link.set_resource_started_callback(download_began) link.set_resource_concluded_callback(download_concluded) menu()
def program_setup(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Randomly create a new identity for our example identity = RNS.Identity() # Using the identity we just created, we create a destination. # Destinations are endpoints in Reticulum, that can be addressed # and communicated with. Destinations can also announce their # existence, which will let the network know they are reachable # and autoomatically create paths to them, from anywhere else # in the network. destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "minimalsample") # We configure the destination to automatically prove all # packets adressed to it. By doing this, RNS will automatically # generate a proof for each incoming packet and transmit it # back to the sender of that packet. This will let anyone that # tries to communicate with the destination know whether their # communication was received correctly. destination.set_proof_strategy(RNS.Destination.PROVE_ALL) # Everything's ready! # Let's hand over control to the announce loop announceLoop(destination)
def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Randomly create a new identity for our link example server_identity = RNS.Identity() # We create a destination that clients can connect to. We # want clients to create links to this destination, so we # need to create a "single" destination type. server_destination = RNS.Destination( server_identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "linkexample" ) # We configure a function that will get called every time # a new client creates a link to this destination. server_destination.set_link_established_callback(client_connected) # Everything's ready! # Let's Wait for client requests or user input server_loop(server_destination)
def client(destination_hexhash, configpath): # We need a binary representation of the destination # hash that was entered on the command line try: if len(destination_hexhash) != 20: raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)") destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") exit() # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Check if we know a path to the destination if not RNS.Transport.has_path(destination_hash): RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...") RNS.Transport.request_path(destination_hash) while not RNS.Transport.has_path(destination_hash): time.sleep(0.1) # Recall the server identity server_identity = RNS.Identity.recall(destination_hash) # Inform the user that we'll begin connecting RNS.log("Establishing link with server...") # When the server identity is known, we set # up a destination server_destination = RNS.Destination( server_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "linkexample" ) # And create a link link = RNS.Link(server_destination) # We set a callback that will get executed # every time a packet is received over the # link link.set_packet_callback(client_packet_received) # We'll also set up functions to inform the # user when the link is established or closed link.set_link_established_callback(link_established) link.set_link_closed_callback(link_closed) # Everything is set up, so let's enter a loop # for the user to interact with the example client_loop()
def program_setup(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Randomly create a new identity for our example identity = RNS.Identity() # Using the identity we just created, we create two destinations # in the "example_utilities.announcesample" application space. # # Destinations are endpoints in Reticulum, that can be addressed # and communicated with. Destinations can also announce their # existence, which will let the network know they are reachable # and autoomatically create paths to them, from anywhere else # in the network. destination_1 = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "announcesample", "fruits") destination_2 = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "announcesample", "noble_gases") # We configure the destinations to automatically prove all # packets adressed to it. By doing this, RNS will automatically # generate a proof for each incoming packet and transmit it # back to the sender of that packet. This will let anyone that # tries to communicate with the destination know whether their # communication was received correctly. destination_1.set_proof_strategy(RNS.Destination.PROVE_ALL) destination_2.set_proof_strategy(RNS.Destination.PROVE_ALL) # We create an announce handler and configure it to only ask for # announces from "example_utilities.announcesample.fruits". # Try changing the filter and see what happens. announce_handler = ExampleAnnounceHandler( aspect_filter="example_utilities.announcesample.fruits") # We register the announce handler with Reticulum RNS.Transport.register_announce_handler(announce_handler) # Everything's ready! # Let's hand over control to the announce loop announceLoop(destination_1, destination_2)
def client(destination_hexhash, configpath, timeout=None): # We need a binary representation of the destination # hash that was entered on the command line try: if len(destination_hexhash) != 20: raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)") destination_hash = destination_hexhash.decode("hex") except: RNS.log("Invalid destination entered. Check your input!\n") exit() # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # We override the loglevel to provide feedback when # an announce is received RNS.loglevel = RNS.LOG_INFO # Tell the user that the client is ready! RNS.log("Echo client ready, hit enter to send echo request to "+destination_hexhash+" (Ctrl-C to quit)") # We enter a loop that runs until the user exits. # If the user hits enter, we will try to send an # echo request to the destination specified on the # command line. while True: raw_input() # Let's first check if RNS knows a path to the destination. # If it does, we'll load the server identity and create a packet if RNS.Transport.hasPath(destination_hash): # To address the server, we need to know it's public # key, so we check if Reticulum knows this destination. # This is done by calling the "recall" method of the # Identity module. If the destination is known, it will # return an Identity instance that can be used in # outgoing destinations. server_identity = RNS.Identity.recall(destination_hash) # We got the correct identity instance from the # recall method, so let's create an outgoing # destination. We use the naming convention: # example_utilities.echo.request # This matches the naming we specified in the # server part of the code. request_destination = RNS.Destination(server_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "echo", "request") # The destination is ready, so let's create a packet. # We set the destination to the request_destination # that was just created, and the only data we add # is a random hash. echo_request = RNS.Packet(request_destination, RNS.Identity.getRandomHash()) # Send the packet! If the packet is successfully # sent, it will return a PacketReceipt instance. packet_receipt = echo_request.send() # If the user specified a timeout, we set this # timeout on the packet receipt, and configure # a callback function, that will get called if # the packet times out. if timeout != None: packet_receipt.set_timeout(timeout) packet_receipt.timeout_callback(packet_timed_out) # We can then set a delivery callback on the receipt. # This will get automatically called when a proof for # this specific packet is received from the destination. packet_receipt.delivery_callback(packet_delivered) # Tell the user that the echo request was sent RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) else: # If we do not know this destination, tell the # user to wait for an announce to arrive. RNS.log("Destination is not yet known. Requesting path...") RNS.Transport.requestPath(destination_hash)
def __init__(self, configdir=None, rnsconfigdir=None, daemon=False, force_console=False): self.version = __version__ self.enable_client = False self.enable_node = False self.identity = None self.uimode = None if configdir == None: self.configdir = NomadNetworkApp.configdir else: self.configdir = configdir if force_console: self.force_console_log = True else: self.force_console_log = False if NomadNetworkApp._shared_instance == None: NomadNetworkApp._shared_instance = self self.rns = RNS.Reticulum(configdir=rnsconfigdir) self.configpath = self.configdir + "/config" self.ignoredpath = self.configdir + "/ignored" self.logfilepath = self.configdir + "/logfile" self.errorfilepath = self.configdir + "/errors" self.storagepath = self.configdir + "/storage" self.identitypath = self.configdir + "/storage/identity" self.cachepath = self.configdir + "/storage/cache" self.resourcepath = self.configdir + "/storage/resources" self.conversationpath = self.configdir + "/storage/conversations" self.directorypath = self.configdir + "/storage/directory" self.peersettingspath = self.configdir + "/storage/peersettings" self.pagespath = self.configdir + "/storage/pages" self.filespath = self.configdir + "/storage/files" self.cachepath = self.configdir + "/storage/cache" self.downloads_path = os.path.expanduser("~/Downloads") self.firstrun = False self.should_run_jobs = True self.job_interval = 5 self.defer_jobs = 90 self.peer_announce_at_start = True self.try_propagation_on_fail = True self.periodic_lxmf_sync = True self.lxmf_sync_interval = 360 * 60 self.lxmf_sync_limit = 8 if not os.path.isdir(self.storagepath): os.makedirs(self.storagepath) if not os.path.isdir(self.cachepath): os.makedirs(self.cachepath) if not os.path.isdir(self.resourcepath): os.makedirs(self.resourcepath) if not os.path.isdir(self.conversationpath): os.makedirs(self.conversationpath) if not os.path.isdir(self.pagespath): os.makedirs(self.pagespath) if not os.path.isdir(self.filespath): os.makedirs(self.filespath) if not os.path.isdir(self.cachepath): os.makedirs(self.cachepath) if os.path.isfile(self.configpath): try: self.config = ConfigObj(self.configpath) try: self.applyConfig() except Exception as e: RNS.log( "The configuration file is invalid. The contained exception was: " + str(e), RNS.LOG_ERROR) nomadnet.panic() RNS.log("Configuration loaded from " + self.configpath) except Exception as e: RNS.log( "Could not parse the configuration at " + self.configpath, RNS.LOG_ERROR) RNS.log("Check your configuration file for errors!", RNS.LOG_ERROR) nomadnet.panic() else: RNS.log( "Could not load config file, creating default configuration file..." ) self.createDefaultConfig() self.firstrun = True if os.path.isfile(self.identitypath): try: self.identity = RNS.Identity.from_file(self.identitypath) if self.identity != None: RNS.log("Loaded Primary Identity %s from %s" % (str(self.identity), self.identitypath)) else: RNS.log( "Could not load the Primary Identity from " + self.identitypath, RNS.LOG_ERROR) nomadnet.panic() except Exception as e: RNS.log( "Could not load the Primary Identity from " + self.identitypath, RNS.LOG_ERROR) RNS.log("The contained exception was: %s" % (str(e)), RNS.LOG_ERROR) nomadnet.panic() else: try: RNS.log("No Primary Identity file found, creating new...") self.identity = RNS.Identity() self.identity.to_file(self.identitypath) RNS.log("Created new Primary Identity %s" % (str(self.identity))) except Exception as e: RNS.log("Could not create and save a new Primary Identity", RNS.LOG_ERROR) RNS.log("The contained exception was: %s" % (str(e)), RNS.LOG_ERROR) nomadnet.panic() if os.path.isfile(self.peersettingspath): try: file = open(self.peersettingspath, "rb") self.peer_settings = msgpack.unpackb(file.read()) file.close() if not "node_last_announce" in self.peer_settings: self.peer_settings["node_last_announce"] = None if not "propagation_node" in self.peer_settings: self.peer_settings["propagation_node"] = None if not "last_lxmf_sync" in self.peer_settings: self.peer_settings["last_lxmf_sync"] = 0 if not "node_connects" in self.peer_settings: self.peer_settings["node_connects"] = 0 if not "served_page_requests" in self.peer_settings: self.peer_settings["served_page_requests"] = 0 if not "served_file_requests" in self.peer_settings: self.peer_settings["served_file_requests"] = 0 except Exception as e: RNS.log( "Could not load local peer settings from " + self.peersettingspath, RNS.LOG_ERROR) RNS.log("The contained exception was: %s" % (str(e)), RNS.LOG_ERROR) nomadnet.panic() else: try: RNS.log("No peer settings file found, creating new...") self.peer_settings = { "display_name": "Anonymous Peer", "announce_interval": None, "last_announce": None, "node_last_announce": None, "propagation_node": None, "last_lxmf_sync": 0, } self.save_peer_settings() RNS.log("Created new peer settings file") except Exception as e: RNS.log("Could not create and save a new peer settings file", RNS.LOG_ERROR) RNS.log("The contained exception was: %s" % (str(e)), RNS.LOG_ERROR) nomadnet.panic() self.ignored_list = [] if os.path.isfile(self.ignoredpath): try: fh = open(self.ignoredpath, "rb") ignored_input = fh.read() fh.close() ignored_hash_strs = ignored_input.splitlines() for hash_str in ignored_hash_strs: if len(hash_str ) == RNS.Identity.TRUNCATED_HASHLENGTH // 8 * 2: try: ignored_hash = bytes.fromhex( hash_str.decode("utf-8")) self.ignored_list.append(ignored_hash) except Exception as e: RNS.log( "Could not decode RNS Identity hash from: " + str(hash_str), RNS.LOG_DEBUG) RNS.log("The contained exception was: " + str(e), RNS.LOG_DEBUG) except Exception as e: RNS.log( "Error while fetching loading list of ignored destinations: " + str(e), RNS.LOG_ERROR) self.directory = nomadnet.Directory(self) self.message_router = LXMF.LXMRouter(identity=self.identity, storagepath=self.storagepath, autopeer=True) self.message_router.register_delivery_callback(self.lxmf_delivery) for destination_hash in self.ignored_list: self.message_router.ignore_destination(destination_hash) self.lxmf_destination = self.message_router.register_delivery_identity( self.identity, display_name=self.peer_settings["display_name"]) self.lxmf_destination.set_default_app_data(self.get_display_name_bytes) RNS.Identity.remember(packet_hash=None, destination_hash=self.lxmf_destination.hash, public_key=self.identity.get_public_key(), app_data=None) RNS.log("LXMF Router ready to receive on: " + RNS.prettyhexrep(self.lxmf_destination.hash)) if self.enable_node: self.message_router.enable_propagation() RNS.log("LXMF Propagation Node started on: " + RNS.prettyhexrep( self.message_router.propagation_destination.hash)) self.node = nomadnet.Node(self) else: self.node = None RNS.Transport.register_announce_handler(nomadnet.Conversation) RNS.Transport.register_announce_handler(nomadnet.Directory) self.autoselect_propagation_node() if self.peer_announce_at_start: def delayed_announce(): time.sleep(NomadNetworkApp.START_ANNOUNCE_DELAY) self.announce_now() da_thread = threading.Thread(target=delayed_announce) da_thread.setDaemon(True) da_thread.start() atexit.register(self.exit_handler) sys.excepthook = self.exception_handler job_thread = threading.Thread(target=self.__jobs) job_thread.setDaemon(True) job_thread.start() # Override UI choice from config on --daemon switch if daemon: self.uimode = nomadnet.ui.UI_NONE # This stderr redirect is needed to stop urwid # from spewing KeyErrors to the console and thus, # messing up the UI. A pull request to fix the # bug in urwid was submitted, but until it is # merged, this hack will mitigate it. strio = io.StringIO() with contextlib.redirect_stderr(strio): nomadnet.ui.spawn(self.uimode) if strio.tell() > 0: try: strio.seek(0) err_file = open(self.errorfilepath, "w") err_file.write(strio.read()) err_file.close() except Exception as e: RNS.log( "Could not write stderr output to error log file at " + str(self.errorfilepath) + ".", RNS.LOG_ERROR) RNS.log("The contained exception was: " + str(e), RNS.LOG_ERROR)