Beispiel #1
0
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()
Beispiel #2
0
    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
Beispiel #3
0
    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)
Beispiel #4
0
    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
Beispiel #5
0
    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)