Example #1
0
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)
Example #2
0
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)
Example #3
0
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()
Example #4
0
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)
Example #5
0
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)
Example #6
0
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()
Example #7
0
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)
Example #8
0
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)
Example #9
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)