mirror of
https://github.com/markqvist/LXMF.git
synced 2024-12-26 23:59:34 -05:00
Added paper message generator
This commit is contained in:
parent
f75ea842d9
commit
3d31620160
@ -2,6 +2,7 @@ import RNS
|
||||
import RNS.vendor.umsgpack as msgpack
|
||||
|
||||
import time
|
||||
import base64
|
||||
|
||||
from .LXMF import APP_NAME
|
||||
|
||||
@ -22,7 +23,8 @@ class LXMessage:
|
||||
OPPORTUNISTIC = 0x01
|
||||
DIRECT = 0x02
|
||||
PROPAGATED = 0x03
|
||||
valid_methods = [OPPORTUNISTIC, DIRECT, PROPAGATED]
|
||||
PAPER = 0x05
|
||||
valid_methods = [OPPORTUNISTIC, DIRECT, PROPAGATED, PAPER]
|
||||
|
||||
SOURCE_UNKNOWN = 0x01
|
||||
SIGNATURE_INVALID = 0x02
|
||||
@ -76,6 +78,12 @@ class LXMessage:
|
||||
ENCRYPTION_DESCRIPTION_EC = "Curve25519"
|
||||
ENCRYPTION_DESCRIPTION_UNENCRYPTED = "Unencrypted"
|
||||
|
||||
# Constants for QR/URL encoding LXMs
|
||||
URL_PROTO_SPECIFIER = "lxm"
|
||||
QR_ERROR_CORRECTION = "ERROR_CORRECT_L"
|
||||
QR_MAX_STORAGE = 2953
|
||||
PAPER_MDU = ((QR_MAX_STORAGE-(len(URL_PROTO_SPECIFIER)+len("://")))*6)//8
|
||||
|
||||
def __str__(self):
|
||||
if self.hash != None:
|
||||
return "<LXMessage "+RNS.hexrep(self.hash, delimit=False)+">"
|
||||
@ -196,6 +204,7 @@ class LXMessage:
|
||||
self.timestamp = time.time()
|
||||
|
||||
self.propagation_packed = None
|
||||
self.paper_packed = None
|
||||
|
||||
self.payload = [self.timestamp, self.title, self.content, self.fields]
|
||||
|
||||
@ -263,6 +272,19 @@ class LXMessage:
|
||||
self.method = self.desired_method
|
||||
self.representation = LXMessage.RESOURCE
|
||||
|
||||
elif self.desired_method == LXMessage.PAPER:
|
||||
paper_content_limit = LXMessage.PAPER_MDU
|
||||
|
||||
encrypted_data = self.__destination.encrypt(self.packed[LXMessage.DESTINATION_LENGTH:])
|
||||
self.paper_packed = msgpack.packb(self.packed[:LXMessage.DESTINATION_LENGTH]+encrypted_data)
|
||||
|
||||
content_size = len(self.paper_packed)
|
||||
if content_size <= paper_content_limit:
|
||||
self.method = self.desired_method
|
||||
self.representation = LXMessage.PAPER
|
||||
else:
|
||||
raise TypeError("LXMessage desired paper delivery method, but content exceeds paper message maximum size.")
|
||||
|
||||
else:
|
||||
raise ValueError("Attempt to re-pack LXMessage "+str(self)+" that was already packed")
|
||||
|
||||
@ -327,6 +349,16 @@ class LXMessage:
|
||||
else:
|
||||
self.transport_encrypted = False
|
||||
self.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_UNENCRYPTED
|
||||
elif self.method == LXMessage.PAPER:
|
||||
if self.__destination.type == RNS.Destination.SINGLE:
|
||||
self.transport_encrypted = True
|
||||
self.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_EC
|
||||
elif self.__destination.type == RNS.Destination.GROUP:
|
||||
self.transport_encrypted = True
|
||||
self.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_AES
|
||||
else:
|
||||
self.transport_encrypted = False
|
||||
self.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_UNENCRYPTED
|
||||
else:
|
||||
self.transport_encrypted = False
|
||||
self.transport_encryption = LXMessage.ENCRYPTION_DESCRIPTION_UNENCRYPTED
|
||||
@ -351,6 +383,16 @@ class LXMessage:
|
||||
except Exception as e:
|
||||
RNS.log("An error occurred in the external delivery callback for "+str(message), RNS.LOG_ERROR)
|
||||
|
||||
def __mark_paper_generated(self, receipt = None):
|
||||
RNS.log("Paper message generation succeeded for "+str(self), RNS.LOG_DEBUG)
|
||||
self.state = LXMessage.PAPER
|
||||
|
||||
if self.__delivery_callback != None and callable(self.__delivery_callback):
|
||||
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)
|
||||
|
||||
def __resource_concluded(self, resource):
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
self.__mark_delivered()
|
||||
@ -441,6 +483,56 @@ class LXMessage:
|
||||
RNS.log("Error while writing LXMF message to file \""+str(file_path)+"\". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
return None
|
||||
|
||||
def as_url(self, finalise=True):
|
||||
self.determine_transport_encryption()
|
||||
if not self.packed:
|
||||
self.pack()
|
||||
|
||||
if self.desired_method == LXMessage.PAPER and self.paper_packed != None:
|
||||
# Encode packed LXM with URL-safe base64 and remove padding
|
||||
encoded_bytes = base64.urlsafe_b64encode(self.paper_packed)
|
||||
|
||||
# Add protocol specifier and return
|
||||
lxm_url = LXMessage.URL_PROTO_SPECIFIER+"://"+encoded_bytes.decode("utf-8").replace("=","")
|
||||
|
||||
# TODO: Remove
|
||||
# RNS.log(str(len(lxm_url))+" byte LXM URL: "+str(lxm_url), RNS.LOG_EXTREME)
|
||||
|
||||
if finalise:
|
||||
self.__mark_paper_generated()
|
||||
|
||||
return lxm_url
|
||||
|
||||
else:
|
||||
raise TypeError("Attempt to represent LXM with non-paper delivery method as URL")
|
||||
|
||||
def as_qr(self):
|
||||
self.determine_transport_encryption()
|
||||
if not self.packed:
|
||||
self.pack()
|
||||
|
||||
if self.desired_method == LXMessage.PAPER and self.paper_packed != None:
|
||||
import importlib
|
||||
if importlib.util.find_spec('qrcode') != None:
|
||||
import qrcode
|
||||
|
||||
qr = qrcode.make(
|
||||
error_correction = qrcode.constants.__dict__[LXMessage.QR_ERROR_CORRECTION],
|
||||
border = 1,
|
||||
data = self.as_url(finalise=False),
|
||||
)
|
||||
|
||||
self.__mark_paper_generated()
|
||||
|
||||
return qr
|
||||
|
||||
else:
|
||||
RNS.log("Generating QR-code representanions of LXMs requires the \"qrcode\" module to be installed.", RNS.LOG_CRITICAL)
|
||||
RNS.log("You can install it with the command: python3 -m pip install qrcode", RNS.LOG_CRITICAL)
|
||||
return None
|
||||
|
||||
else:
|
||||
raise TypeError("Attempt to represent LXM with non-paper delivery method as QR-code")
|
||||
|
||||
@staticmethod
|
||||
def unpack_from_bytes(lxmf_bytes):
|
||||
|
Loading…
Reference in New Issue
Block a user