def filelist_received(filelist_data, packet): global server_files, menu_mode try: # Unpack the list and extend our # local list of available files filelist = umsgpack.unpackb(filelist_data) for file in filelist: if not file in server_files: server_files.append(file) # If the menu is already visible, # we'll update it with what was # just received if menu_mode == "main": print_menu() except: RNS.log("Invalid file list data received, closing link") packet.link.teardown()
def unpack_from_file(lxmf_file_handle): try: container = msgpack.unpackb(lxmf_file_handle.read()) lxm = LXMessage.unpack_from_bytes(container["lxmf_bytes"]) if "state" in container: lxm.state = container["state"] if "transport_encrypted" in container: lxm.transport_encrypted = container["transport_encrypted"] if "transport_encryption" in container: lxm.transport_encryption = container["transport_encryption"] return lxm except Exception as e: RNS.log( "Could not unpack LXMessage from file. The contained exception was: " + str(e), RNS.LOG_ERROR) return None
def load_from_disk(self): if os.path.isfile(self.app.directorypath): try: file = open(self.app.directorypath, "rb") unpacked_directory = msgpack.unpackb(file.read()) unpacked_list = unpacked_directory["entry_list"] file.close() entries = {} for e in unpacked_list: if len(e) > 3: hosts_node = e[3] else: hosts_node = False if len(e) > 4: preferred_delivery = e[4] else: preferred_delivery = None if len(e) > 5: identify = e[5] else: identify = False entries[e[0]] = DirectoryEntry( e[0], e[1], e[2], hosts_node, preferred_delivery=preferred_delivery, identify_on_connect=identify) self.directory_entries = entries self.announce_stream = unpacked_directory["announce_stream"] except Exception as e: RNS.log( "Could not load directory from disk. The contained exception was: " + str(e), RNS.LOG_ERROR)
def unpack_from_bytes(lxmf_bytes): destination_hash = lxmf_bytes[:LXMessage.DESTINATION_LENGTH] source_hash = lxmf_bytes[LXMessage.DESTINATION_LENGTH:2 * LXMessage.DESTINATION_LENGTH] signature = lxmf_bytes[2 * LXMessage.DESTINATION_LENGTH:2 * LXMessage.DESTINATION_LENGTH + LXMessage.SIGNATURE_LENGTH] packed_payload = lxmf_bytes[2 * LXMessage.DESTINATION_LENGTH + LXMessage.SIGNATURE_LENGTH:] hashed_part = b"" + destination_hash + source_hash + packed_payload message_hash = RNS.Identity.full_hash(hashed_part) signed_part = b"" + hashed_part + message_hash unpacked_payload = msgpack.unpackb(packed_payload) timestamp = unpacked_payload[0] title_bytes = unpacked_payload[1] content_bytes = unpacked_payload[2] fields = unpacked_payload[3] destination_identity = RNS.Identity.recall(destination_hash) if destination_identity != None: destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "delivery") else: destination = None source_identity = RNS.Identity.recall(source_hash) if source_identity != None: source = RNS.Destination(source_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "delivery") else: source = None message = LXMessage(destination=destination, source=source, content="", title="", fields=fields, destination_hash=destination_hash, source_hash=source_hash) message.hash = message_hash message.signature = signature message.incoming = True message.timestamp = timestamp message.packed = lxmf_bytes message.packed_size = len(lxmf_bytes) message.set_title_from_bytes(title_bytes) message.set_content_from_bytes(content_bytes) try: if source: if source.identity.validate(signature, signed_part): message.signature_validated = True else: message.signature_validated = False message.unverified_reason = LXMessage.SIGNATURE_INVALID else: signature_validated = False message.unverified_reason = LXMessage.SOURCE_UNKNOWN RNS.log( "Unpacked LXMF message signature could not be validated, since source identity is unknown", RNS.LOG_DEBUG) except Exception as e: message.signature_validated = False RNS.log( "Error while validating LXMF message signature. The contained exception was: " + str(e), RNS.LOG_ERROR) return message
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)