From a20f380284a728fa704fd16bc4504200eb386ece Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Sun, 8 Sep 2024 14:52:54 +0200 Subject: [PATCH] Get message ratchet IDs --- LXMF/LXMRouter.py | 21 +++++++++++++++++---- LXMF/LXMessage.py | 26 +++++++++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/LXMF/LXMRouter.py b/LXMF/LXMRouter.py index 49793cb..659c47b 100644 --- a/LXMF/LXMRouter.py +++ b/LXMF/LXMRouter.py @@ -1260,9 +1260,14 @@ class LXMRouter: ### Message Routing & Delivery ######################## ####################################################### - def lxmf_delivery(self, lxmf_data, destination_type = None, phy_stats = None): + def lxmf_delivery(self, lxmf_data, destination_type = None, phy_stats = None, ratchet_id = None, method = None): try: message = LXMessage.unpack_from_bytes(lxmf_data) + if ratchet_id and not message.ratchet_id: + message.ratchet_id = ratchet_id + + if method: + message.method = method if message.signature_validated and FIELD_TICKET in message.fields: ticket_entry = message.fields[FIELD_TICKET] @@ -1299,6 +1304,7 @@ class LXMRouter: if "snr" in phy_stats: message.snr = phy_stats["snr"] if "q" in phy_stats: message.q = phy_stats["q"] + # TODO: Update these descriptions to account for ratchets if destination_type == RNS.Destination.SINGLE: message.transport_encrypted = True message.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_EC @@ -1339,11 +1345,14 @@ class LXMRouter: def delivery_packet(self, data, packet): packet.prove() try: + method = None if packet.destination_type != RNS.Destination.LINK: + method = LXMessage.OPPORTUNISTIC lxmf_data = b"" lxmf_data += packet.destination.hash lxmf_data += data else: + method = LXMessage.DIRECT lxmf_data = data try: @@ -1356,7 +1365,7 @@ class LXMRouter: phy_stats = {"rssi": packet.rssi, "snr": packet.snr, "q": packet.q} - self.lxmf_delivery(lxmf_data, packet.destination_type, phy_stats=phy_stats) + self.lxmf_delivery(lxmf_data, packet.destination_type, phy_stats=phy_stats, ratchet_id=packet.ratchet_id, method=method) except Exception as e: RNS.log("Exception occurred while parsing incoming LXMF data.", RNS.LOG_ERROR) @@ -1388,8 +1397,12 @@ class LXMRouter: def delivery_resource_concluded(self, resource): RNS.log("Transfer concluded for LXMF delivery resource "+str(resource), RNS.LOG_DEBUG) if resource.status == RNS.Resource.COMPLETE: + ratchet_id = None + # Set ratchet ID to link ID if available + if resource.link and hasattr(resource.link, "link_id"): + ratchet_id = resource.link.link_id phy_stats = {"rssi": resource.link.rssi, "snr": resource.link.snr, "q": resource.link.q} - self.lxmf_delivery(resource.data.read(), resource.link.type, phy_stats=phy_stats) + self.lxmf_delivery(resource.data.read(), resource.link.type, phy_stats=phy_stats, ratchet_id=ratchet_id, method=LXMessage.DIRECT) ### Peer Sync & Propagation ########################### @@ -1598,7 +1611,7 @@ class LXMRouter: decrypted_lxmf_data = delivery_destination.decrypt(encrypted_lxmf_data) if decrypted_lxmf_data != None: delivery_data = lxmf_data[:LXMessage.DESTINATION_LENGTH]+decrypted_lxmf_data - self.lxmf_delivery(delivery_data, delivery_destination.type) + self.lxmf_delivery(delivery_data, delivery_destination.type, ratchet_id=delivery_destination.latest_ratchet_id, method=LXMessage.PROPAGATED) self.locally_delivered_transient_ids[transient_id] = time.time() if signal_local_delivery != None: diff --git a/LXMF/LXMessage.py b/LXMF/LXMessage.py index adbac64..a41560f 100644 --- a/LXMF/LXMessage.py +++ b/LXMF/LXMessage.py @@ -159,6 +159,7 @@ class LXMessage: self.incoming = False self.signature_validated = False self.unverified_reason = None + self.ratchet_id = None self.representation = LXMessage.UNKNOWN self.desired_method = desired_method @@ -310,11 +311,13 @@ class LXMessage: # generating a valid stamp. if self.outbound_ticket != None and type(self.outbound_ticket) == bytes and len(self.outbound_ticket) == LXMessage.TICKET_LENGTH: RNS.log(f"Generating stamp with outbound ticket for {self}", RNS.LOG_DEBUG) # TODO: Remove at some point + self.stamp_value = LXMessage.COST_TICKET return RNS.Identity.truncated_hash(self.outbound_ticket+self.message_id) # If no stamp cost is required, we can just # return immediately. elif self.stamp_cost == None: + self.stamp_value = None return None # If a stamp was already generated, return @@ -504,6 +507,9 @@ class LXMessage: RNS.log(f"Stamp generated in {RNS.prettytime(duration)}, {rounds} rounds, {int(speed)} rounds per second", RNS.LOG_DEBUG) + self.stamp_value = LXMessage.stamp_value(RNS.Identity.full_hash(workblock+stamp)) + self.stamp_valid = True + return stamp def pack(self): @@ -575,6 +581,7 @@ class LXMessage: single_packet_content_limit = LXMessage.LINK_PACKET_MAX_CONTENT encrypted_data = self.__destination.encrypt(self.packed[LXMessage.DESTINATION_LENGTH:]) + self.ratchet_id = self.__destination.latest_ratchet_id self.propagation_packed = msgpack.packb([time.time(), [self.packed[:LXMessage.DESTINATION_LENGTH]+encrypted_data]]) content_size = len(self.propagation_packed) @@ -589,6 +596,7 @@ class LXMessage: paper_content_limit = LXMessage.PAPER_MDU encrypted_data = self.__destination.encrypt(self.packed[LXMessage.DESTINATION_LENGTH:]) + self.ratchet_id = self.__destination.latest_ratchet_id self.paper_packed = self.packed[:LXMessage.DESTINATION_LENGTH]+encrypted_data content_size = len(self.paper_packed) @@ -605,14 +613,18 @@ class LXMessage: self.determine_transport_encryption() if self.method == LXMessage.OPPORTUNISTIC: - self.__as_packet().send().set_delivery_callback(self.__mark_delivered) + lxm_packet = self.__as_packet() + lxm_packet.send().set_delivery_callback(self.__mark_delivered) + self.ratchet_id = lxm_packet.ratchet_id self.state = LXMessage.SENT elif self.method == LXMessage.DIRECT: self.state = LXMessage.SENDING if self.representation == LXMessage.PACKET: - receipt = self.__as_packet().send() + lxm_packet = self.__as_packet() + receipt = lxm_packet.send() + self.ratchet_id = self.__delivery_destination.link_id if receipt: receipt.set_delivery_callback(self.__mark_delivered) receipt.set_timeout_callback(self.__link_packet_timed_out) @@ -623,6 +635,7 @@ class LXMessage: elif self.representation == LXMessage.RESOURCE: self.resource_representation = self.__as_resource() + self.ratchet_id = self.__delivery_destination.link_id self.progress = 0.10 elif self.method == LXMessage.PROPAGATED: @@ -692,7 +705,8 @@ class LXMessage: try: self.__delivery_callback(self) except Exception as e: - RNS.log("An error occurred in the external delivery callback for "+str(message), RNS.LOG_ERROR) + RNS.log("An error occurred in the external delivery callback for "+str(self), RNS.LOG_ERROR) + RNS.trace_exception(e) def __mark_propagated(self, receipt = None): RNS.log("Received propagation success notification for "+str(self), RNS.LOG_DEBUG) @@ -703,7 +717,8 @@ class LXMessage: try: self.__delivery_callback(self) except Exception as e: - RNS.log("An error occurred in the external delivery callback for "+str(message), RNS.LOG_ERROR) + RNS.log("An error occurred in the external delivery callback for "+str(self), RNS.LOG_ERROR) + RNS.trace_exception(e) def __mark_paper_generated(self, receipt = None): RNS.log("Paper message generation succeeded for "+str(self), RNS.LOG_DEBUG) @@ -714,7 +729,8 @@ class LXMessage: try: self.__delivery_callback(self) except Exception as e: - RNS.log("An error occurred in the external delivery callback for "+str(message), RNS.LOG_ERROR) + RNS.log("An error occurred in the external delivery callback for "+str(self), RNS.LOG_ERROR) + RNS.trace_exception(e) def __resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: