Added page authentication

This commit is contained in:
Mark Qvist 2022-04-06 20:34:49 +02:00
parent 886c23c21f
commit 3eaeb42bf6
4 changed files with 97 additions and 16 deletions

View File

@ -32,7 +32,7 @@ class Directory:
packed_list = [] packed_list = []
for source_hash in self.directory_entries: for source_hash in self.directory_entries:
e = self.directory_entries[source_hash] e = self.directory_entries[source_hash]
packed_list.append((e.source_hash, e.display_name, e.trust_level, e.hosts_node, e.preferred_delivery)) packed_list.append((e.source_hash, e.display_name, e.trust_level, e.hosts_node, e.preferred_delivery, e.identify))
directory = { directory = {
"entry_list": packed_list, "entry_list": packed_list,
@ -65,7 +65,12 @@ class Directory:
else: else:
preferred_delivery = None preferred_delivery = None
entries[e[0]] = DirectoryEntry(e[0], e[1], e[2], hosts_node, preferred_delivery=preferred_delivery) 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.directory_entries = entries
@ -183,6 +188,18 @@ class Directory:
except Exception as e: except Exception as e:
return False return False
def should_identify_on_connect(self, source_hash):
if source_hash in self.directory_entries:
entry = self.directory_entries[source_hash]
return entry.identify
else:
return False
def set_identify_on_connect(self, source_hash, state):
if source_hash in self.directory_entries:
entry = self.directory_entries[source_hash]
entry.identify = state
def known_nodes(self): def known_nodes(self):
node_list = [] node_list = []
for eh in self.directory_entries: for eh in self.directory_entries:
@ -214,7 +231,7 @@ class DirectoryEntry:
DIRECT = 0x01 DIRECT = 0x01
PROPAGATED = 0x02 PROPAGATED = 0x02
def __init__(self, source_hash, display_name=None, trust_level=UNKNOWN, hosts_node=False, preferred_delivery=None): 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: if len(source_hash) == RNS.Identity.TRUNCATED_HASHLENGTH//8:
self.source_hash = source_hash self.source_hash = source_hash
self.display_name = display_name self.display_name = display_name
@ -228,5 +245,6 @@ class DirectoryEntry:
self.trust_level = trust_level self.trust_level = trust_level
self.hosts_node = hosts_node self.hosts_node = hosts_node
self.identify = identify_on_connect
else: else:
raise TypeError("Attempt to add invalid source hash to directory") raise TypeError("Attempt to add invalid source hash to directory")

View File

@ -79,7 +79,8 @@ class Node:
directories = [file for file in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, file)) and file[:1] != "."] directories = [file for file in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, file)) and file[:1] != "."]
for file in files: for file in files:
self.servedpages.append(base_path+"/"+file) if not file.endswith(".allowed"):
self.servedpages.append(base_path+"/"+file)
for directory in directories: for directory in directories:
self.scan_pages(base_path+"/"+directory) self.scan_pages(base_path+"/"+directory)
@ -96,17 +97,63 @@ class Node:
def serve_page(self, path, data, request_id, remote_identity, requested_at): def serve_page(self, path, data, request_id, remote_identity, requested_at):
RNS.log("Page request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE) RNS.log("Page request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_VERBOSE)
file_path = path.replace("/page", self.app.pagespath, 1) file_path = path.replace("/page", self.app.pagespath, 1)
try:
RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE) allowed_path = file_path+".allowed"
if os.access(file_path, os.X_OK): request_allowed = False
generated = subprocess.run([file_path], stdout=subprocess.PIPE)
return generated.stdout if os.path.isfile(allowed_path):
allowed_list = []
try:
if os.access(allowed_path, os.X_OK):
allowed_result = subprocess.run([allowed_path], stdout=subprocess.PIPE)
allowed_input = allowed_result.stdout
else:
fh = open(allowed_path, "rb")
allowed_input = fh.read()
fh.close()
allowed_hash_strs = allowed_input.splitlines()
for hash_str in allowed_hash_strs:
if len(hash_str) == RNS.Identity.TRUNCATED_HASHLENGTH//8*2:
try:
allowed_hash = bytes.fromhex(hash_str.decode("utf-8"))
allowed_list.append(allowed_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 list of allowed identities for request: "+str(e), RNS.LOG_ERROR)
if remote_identity.hash in allowed_list:
request_allowed = True
else: else:
fh = open(file_path, "rb") request_allowed = False
response_data = fh.read() RNS.log("Denying request, remote identity was not in list of allowed identities", RNS.LOG_VERBOSE)
fh.close()
return response_data else:
request_allowed = True
try:
if request_allowed:
RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE)
if os.access(file_path, os.X_OK):
generated = subprocess.run([file_path], stdout=subprocess.PIPE)
return generated.stdout
else:
fh = open(file_path, "rb")
response_data = fh.read()
fh.close()
return response_data
else:
RNS.log("Request denied", RNS.LOG_VERBOSE)
return DEFAULT_NOTALLOWED.encode("utf-8")
except Exception as e: except Exception as e:
RNS.log("Error occurred while handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_ERROR) RNS.log("Error occurred while handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_ERROR)
@ -160,4 +207,9 @@ DEFAULT_INDEX = '''>Default Home Page
This node is serving pages, but the home page file (index.mu) was not found in the page storage directory. This is an auto-generated placeholder. This node is serving pages, but the home page file (index.mu) was not found in the page storage directory. This is an auto-generated placeholder.
If you are the node operator, you can define your own home page by creating a file named `*index.mu`* in the page storage directory. If you are the node operator, you can define your own home page by creating a file named `*index.mu`* in the page storage directory.
'''
DEFAULT_NOTALLOWED = '''>Request Not Allowed
You are not authorised to carry out the request.
''' '''

View File

@ -643,6 +643,10 @@ class Browser:
def link_established(self, link): def link_established(self, link):
self.status = Browser.LINK_ESTABLISHED self.status = Browser.LINK_ESTABLISHED
if self.app.directory.should_identify_on_connect(self.destination_hash):
RNS.log("Link established, identifying to remote system...", RNS.LOG_VERBOSE)
self.link.identify(self.app.identity)
def link_closed(self, link): def link_closed(self, link):
if self.status == Browser.DISCONECTED or self.status == Browser.DONE: if self.status == Browser.DISCONECTED or self.status == Browser.DONE:

View File

@ -443,7 +443,11 @@ class KnownNodeInfo(urwid.WidgetWrap):
def pn_change(sender, userdata): def pn_change(sender, userdata):
self.pn_changed = True self.pn_changed = True
def ident_change(sender, userdata):
pass
propagation_node_checkbox = urwid.CheckBox("Use as default propagation node", state=(self.app.get_user_selected_propagation_node() == source_hash), on_state_change=pn_change) propagation_node_checkbox = urwid.CheckBox("Use as default propagation node", state=(self.app.get_user_selected_propagation_node() == source_hash), on_state_change=pn_change)
connect_identify_checkbox = urwid.CheckBox("Identify when connecting", state=self.app.directory.should_identify_on_connect(source_hash), on_state_change=ident_change)
def save_node(sender): def save_node(sender):
if self.pn_changed: if self.pn_changed:
@ -461,7 +465,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
display_str = e_name.get_edit_text() display_str = e_name.get_edit_text()
node_entry = DirectoryEntry(source_hash, display_name=display_str, trust_level=trust_level, hosts_node=True) node_entry = DirectoryEntry(source_hash, display_name=display_str, trust_level=trust_level, hosts_node=True, identify_on_connect=connect_identify_checkbox.get_state())
self.app.directory.remember(node_entry) self.app.directory.remember(node_entry)
self.app.ui.main_display.sub_displays.network_display.directory_change_callback() self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
show_known_nodes(None) show_known_nodes(None)
@ -479,6 +483,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
# urwid.Text(["Trust : ", (style, trust_str)], align="left"), # urwid.Text(["Trust : ", (style, trust_str)], align="left"),
urwid.Divider(g["divider1"]), urwid.Divider(g["divider1"]),
propagation_node_checkbox, propagation_node_checkbox,
connect_identify_checkbox,
urwid.Divider(g["divider1"]), urwid.Divider(g["divider1"]),
r_untrusted, r_untrusted,
r_unknown, r_unknown,
@ -793,8 +798,9 @@ class LocalPeer(urwid.WidgetWrap):
if display_name == None: if display_name == None:
display_name = "" display_name = ""
t_id = urwid.Text("Addr : "+RNS.hexrep(self.app.lxmf_destination.hash, delimit=False)) t_id = urwid.Text("LXMF Addr : "+RNS.prettyhexrep(self.app.lxmf_destination.hash))
e_name = urwid.Edit(caption="Name : ", edit_text=display_name) i_id = urwid.Text("Identity : "+RNS.prettyhexrep(self.app.identity.hash))
e_name = urwid.Edit(caption="Name : ", edit_text=display_name)
def save_query(sender): def save_query(sender):
def dismiss_dialog(sender): def dismiss_dialog(sender):
@ -858,6 +864,7 @@ class LocalPeer(urwid.WidgetWrap):
self.display_widget = urwid.Pile( self.display_widget = urwid.Pile(
[ [
t_id, t_id,
i_id,
e_name, e_name,
urwid.Divider(g["divider1"]), urwid.Divider(g["divider1"]),
self.t_last_announce, self.t_last_announce,