Compare commits

...

5 Commits
0.2.5 ... 0.2.6

Author SHA1 Message Date
Mark Qvist
6a8a146d6a Updated dependencies and version 2022-11-03 12:23:44 +01:00
Mark Qvist
70d0b0a32a Updated dependencies and version 2022-11-03 12:23:00 +01:00
Mark Qvist
fe0437a2fd Updated guide 2022-11-03 12:22:29 +01:00
Mark Qvist
4fcf37ac86 Implemented support for standalone LXMF propagation nodes 2022-10-25 12:52:02 +02:00
Mark Qvist
fe257a63c0 Fixed typo 2022-10-22 22:32:49 +02:00
7 changed files with 124 additions and 51 deletions

View File

@@ -5,6 +5,29 @@ import time
import nomadnet
import RNS.vendor.umsgpack as msgpack
class PNAnnounceHandler:
def __init__(self, owner):
self.aspect_filter = "lxmf.propagation"
self.owner = owner
def received_announce(self, destination_hash, announced_identity, app_data):
try:
if type(app_data) == bytes:
data = msgpack.unpackb(app_data)
if data[0] == True:
RNS.log("Received active propagation node announce from "+RNS.prettyhexrep(destination_hash))
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
associated_node = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", announced_identity)
self.owner.app.directory.pn_announce_received(destination_hash, app_data, associated_peer, associated_node)
self.owner.app.autoselect_propagation_node()
except Exception as e:
RNS.log("Error while evaluating propagation node announce, ignoring announce.", RNS.LOG_DEBUG)
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
class Directory:
ANNOUNCE_STREAM_MAXLENGTH = 64
@@ -14,8 +37,6 @@ class Directory:
app = nomadnet.NomadNetworkApp.get_shared_instance()
if not destination_hash in app.ignored_list:
destination_hash_text = RNS.hexrep(destination_hash, delimit=False)
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
app.directory.node_announce_received(destination_hash, app_data, associated_peer)
@@ -31,6 +52,9 @@ class Directory:
self.app = app
self.load_from_disk()
self.pn_announce_handler = PNAnnounceHandler(self)
RNS.Transport.register_announce_handler(self.pn_announce_handler)
def save_to_disk(self):
try:
@@ -90,7 +114,7 @@ class Directory:
def lxmf_announce_received(self, source_hash, app_data):
if app_data != None:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, False))
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
@@ -100,7 +124,7 @@ class Directory:
def node_announce_received(self, source_hash, app_data, associated_peer):
if app_data != None:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, True))
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
@@ -113,6 +137,27 @@ class Directory:
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def pn_announce_received(self, source_hash, app_data, associated_peer, associated_node):
found_node = None
for sh in self.directory_entries:
if sh == associated_node:
found_node = True
break
for e in self.announce_stream:
if e[1] == associated_node:
found_node = True
break
if not found_node:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def remove_announce_with_timestamp(self, timestamp):
selected_announce = None
for announce in self.announce_stream:
@@ -250,11 +295,6 @@ class DirectoryEntry:
def __init__(self, source_hash, display_name=None, trust_level=UNKNOWN, hosts_node=False, preferred_delivery=None, identify_on_connect=False):
if len(source_hash) == RNS.Identity.TRUNCATED_HASHLENGTH//8:
self.source_hash = source_hash
# TODO: Clean
# if display_name == None:
# display_name = source_hash
self.display_name = display_name
if preferred_delivery == None:

View File

@@ -256,7 +256,7 @@ class NomadNetworkApp:
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)
RNS.log("Error while loading list of ignored destinations: "+str(e), RNS.LOG_ERROR)
self.directory = nomadnet.Directory(self)
@@ -436,8 +436,9 @@ class NomadNetworkApp:
def autoselect_propagation_node(self):
selected_node = None
if "propagation_node" in self.peer_settings and self.directory.find(self.peer_settings["propagation_node"]):
selected_node = self.directory.find(self.peer_settings["propagation_node"])
if "propagation_node" in self.peer_settings:
selected_node = self.peer_settings["propagation_node"]
else:
nodes = self.directory.known_nodes()
trusted_nodes = []
@@ -450,19 +451,14 @@ class NomadNetworkApp:
if hops < best_hops:
best_hops = hops
selected_node = node
selected_node = node.source_hash
if selected_node == None:
RNS.log("Could not autoselect a propagation node! LXMF propagation will not be available until a trusted node announces on the network.", RNS.LOG_WARNING)
RNS.log("Could not autoselect a propagation node! LXMF propagation will not be available until a trusted node announces on the network, or a propagation node is manually selected.", RNS.LOG_WARNING)
else:
node_identity = RNS.Identity.recall(selected_node.source_hash)
if node_identity != None:
propagation_hash = RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_identity)
RNS.log("Selecting "+selected_node.display_name+" "+RNS.prettyhexrep(propagation_hash)+" as default LXMF propagation node", RNS.LOG_INFO)
self.message_router.set_outbound_propagation_node(propagation_hash)
else:
RNS.log("Could not recall identity for autoselected LXMF propagation node "+RNS.prettyhexrep(selected_node.source_hash), RNS.LOG_WARNING)
RNS.log("LXMF propagation will not be available until a trusted node announces on the network.", RNS.LOG_WARNING)
pn_name_str = ""
RNS.log("Selecting "+RNS.prettyhexrep(selected_node)+pn_name_str+" as default LXMF propagation node", RNS.LOG_INFO)
self.message_router.set_outbound_propagation_node(selected_node)
def get_user_selected_propagation_node(self):
if "propagation_node" in self.peer_settings:

View File

@@ -1 +1 @@
__version__ = "0.2.5"
__version__ = "0.2.6"

View File

@@ -398,10 +398,15 @@ class ConversationsDisplay():
if pn_ident != None:
node_hash = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", pn_ident)
pn_entry = self.app.directory.find(node_hash)
pn_display_str = " "
if pn_entry != None:
pn_display_str += " "+str(pn_entry.display_name)
else:
pn_display_str += " "+RNS.prettyhexrep(pn_hash)
dialog = DialogLineBox(
urwid.Pile([
urwid.Text(""+g["node"]+" "+str(pn_entry.display_name), align="center"),
urwid.Text(""+g["node"]+pn_display_str, align="center"),
urwid.Divider(g["divider1"]),
sync_progress,
urwid.Divider(g["divider1"]),
@@ -417,7 +422,7 @@ class ConversationsDisplay():
urwid.Pile([
urwid.Text(""),
urwid.Text("No trusted nodes found, cannot sync!\n", align="center"),
urwid.Text("To syncronise messages from the network, one or more nodes must be marked as trusted in the Known Nodes list. Nomad Network will then automatically sync from the nearest trusted node.", align="left"),
urwid.Text("To syncronise messages from the network, one or more nodes must be marked as trusted in the Known Nodes list, or a node must manually be selected as the default propagation node. Nomad Network will then automatically sync from the nearest trusted node, or the manually selected one.", align="left"),
urwid.Text(""),
button_columns
]), title="Message Sync"

View File

@@ -272,7 +272,7 @@ In the `![ Conversations ]`! part of the program you can view and interact with
By default, Nomad Network will attempt to deliver messages to a peer directly. This happens by first establishing an encrypted link directly to the peer, and then delivering the message over it.
If the desired peer is not available because it has disconnected from the network, this method will obviously fail. In this case, Nomad Network will attempt to deliver the message to a node, which will store and forward it over the network, for later retrieval by the destination peer. The message is encrypted with an ephemeral key before being transmitted to the network, and is only readable by the intended recipient.
If the desired peer is not available because it has disconnected from the network, this method will obviously fail. In this case, Nomad Network will attempt to deliver the message to a node, which will store and forward it over the network, for later retrieval by the destination peer. The message is encrypted before being transmitted to the network, and is only readable by the intended recipient.
For propagated delivery to work, one or more nodes must be available on the network. If one or more trusted nodes are available, Nomad Network will automatically select the most suitable node to send the message via, but you can also manually specify what node to use.

View File

@@ -71,11 +71,17 @@ class AnnounceInfo(urwid.WidgetWrap):
trust_str = ""
display_str = self.app.directory.simplest_display_str(source_hash)
addr_str = "<"+RNS.hexrep(source_hash, delimit=False)+">"
is_node = announce[3]
info_type = announce[3]
if is_node:
type_string = "Node " + g["node"]
else:
is_node = False
is_pn = False
if info_type == "node" or info_type == True:
type_string = "Nomad Network Node " + g["node"]
is_node = True
elif info_type == "pn":
type_string = "LXMF Propagation Node " + g["sent"]
is_pn = True
elif info_type == "peer" or info_type == False:
type_string = "Peer " + g["peer"]
try:
@@ -174,10 +180,20 @@ class AnnounceInfo(urwid.WidgetWrap):
except Exception as e:
RNS.log("Error while starting conversation from announce. The contained exception was: "+str(e), RNS.LOG_ERROR)
def use_pn(sender):
show_announce_stream(None)
try:
self.app.set_user_selected_propagation_node(source_hash)
except Exception as e:
RNS.log("Error while setting active propagation node from announce. The contained exception was: "+str(e), RNS.LOG_ERROR)
if is_node:
type_button = ("weight", 0.45, urwid.Button("Connect", on_press=connect))
msg_button = ("weight", 0.45, urwid.Button("Msg Op", on_press=msg_op))
save_button = ("weight", 0.45, urwid.Button("Save", on_press=save_node))
elif is_pn:
type_button = ("weight", 0.45, urwid.Button("Use as default", on_press=use_pn))
save_button = None
else:
type_button = ("weight", 0.45, urwid.Button("Converse", on_press=converse))
save_button = None
@@ -187,21 +203,33 @@ class AnnounceInfo(urwid.WidgetWrap):
else:
button_columns = urwid.Columns([("weight", 0.45, urwid.Button("Back", on_press=show_announce_stream)), ("weight", 0.1, urwid.Text("")), type_button])
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Text("Name : "+display_str, align="left"),
urwid.Text(["Trust : ", (style, trust_str)], align="left"),
urwid.Divider(g["divider1"]),
urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
pile_widgets = []
if is_node:
operator_entry = urwid.Text("Oprtr : "+op_str, align="left")
pile_widgets.insert(4, operator_entry)
if is_pn:
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
else:
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Text("Name : "+display_str, align="left"),
urwid.Text(["Trust : ", (style, trust_str)], align="left"),
urwid.Divider(g["divider1"]),
urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
if is_node:
operator_entry = urwid.Text("Oprtr : "+op_str, align="left")
pile_widgets.insert(4, operator_entry)
pile = urwid.Pile(pile_widgets)
@@ -220,7 +248,7 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
timestamp = announce[0]
source_hash = announce[1]
is_node = announce[3]
announce_type = announce[3]
self.app = app
self.timestamp = timestamp
time_format = app.time_format
@@ -257,10 +285,12 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
style = "list_untrusted"
focus_style = "list_focus_untrusted"
if is_node:
if announce_type == "node" or announce_type == True:
type_symbol = g["node"]
else:
elif announce_type == "peer" or announce_type == False:
type_symbol = g["peer"]
elif announce_type == "pn":
type_symbol = g["sent"]
widget = ListEntry(ts_string+" "+type_symbol+" "+display_str)
urwid.connect_signal(widget, "click", self.display_announce, announce)
@@ -425,13 +455,15 @@ class KnownNodeInfo(urwid.WidgetWrap):
if display_str == None:
display_str = addr_str
pn_hash = RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_ident)
if node_ident != None:
lxmf_addr_str = g["sent"]+" LXMF Propagation Node Address is "+RNS.prettyhexrep(RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_ident))
lxmf_addr_str = g["sent"]+" LXMF Propagation Node Address is "+RNS.prettyhexrep(pn_hash)
else:
lxmf_addr_str = "No associated Propagation Node known"
type_string = "Node " + g["node"]
type_string = "Nomad Network Node " + g["node"]
if trust_level == DirectoryEntry.UNTRUSTED:
trust_str = "Untrusted"
@@ -525,7 +557,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
def save_node(sender):
if self.pn_changed:
if propagation_node_checkbox.get_state():
self.app.set_user_selected_propagation_node(source_hash)
self.app.set_user_selected_propagation_node(pn_hash)
else:
self.app.set_user_selected_propagation_node(None)

View File

@@ -23,6 +23,6 @@ setuptools.setup(
entry_points= {
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
},
install_requires=['rns>=0.3.16', 'lxmf>=0.2.1', 'urwid>=2.1.2'],
install_requires=['rns>=0.4.0', 'lxmf>=0.2.3', 'urwid>=2.1.2'],
python_requires='>=3.6',
)