import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..'))) from comrad import * from comrad.backend import * def is_valid_msg_d(msg_d): if not type(msg_d)==dict: return False to_name=msg_d.get('to_name') to_pub=msg_d.get('to') from_name=msg_d.get('from_name') from_pub=msg_d.get('from') msg=msg_d.get('msg') # if to_name and to_pub and from_name and from_pub and msg: return True if to_pub and from_pub and msg: return True return False class Message(Logger): def __init__(self,msg_d={},from_whom=None,to_whom=None,msg=None): # check input self.msg_d=msg_d self.to_name=msg_d.get('to_name') if not to_whom else to_whom.name self.to_pubkey=msg_d.get('to') if not to_whom else to_whom.uri self.from_name=msg_d.get('from_name') if not from_whom else from_whom.name self.from_pubkey=msg_d.get('from') if not from_whom else from_whom.uri self.msg=msg_d.get('msg') if not msg else msg self.timestamp=msg_d.get('timestamp',time.time()) self._route=msg_d.get(ROUTE_KEYNAME) self._is_encrypted=None # reset msg_d self.msg_d = { 'msg':self.msg, 'to':self.to_pubkey, 'to_name':self.to_name, 'from':self.from_pubkey, 'from_name':self.from_name, 'timestamp':self.timestamp, } def __repr__(self): # self.log('my type??',type(self.msg),self.msg) if type(self.msg)==dict: if is_valid_msg_d(self.msg): import textwrap msg = textwrap.indent(repr(Message(self.msg)),' '*10) elif 'txt' in self.msg: msg=self.msg.get('txt') else: msg=dict_format(self.msg,tab=6) elif type(self.msg)==bytes: msg=b64enc_s(self.msg) else: msg=self.msg # return str(msg) msg_s = wrapp(str(msg)) hdr='#'*CLI_WIDTH from datetime import datetime self.log('msg_d',self.msg_d) if self.timestamp: dt_object = datetime.fromtimestamp(self.timestamp) timestr = dt_object.strftime("%-d %b %Y %H:%M") else: timestr = '?' return f""" {hdr} from: @{self.from_name if self.from_name else ''} to: @{self.to_name if self.to_name else ''} on: {timestr} {hdr} {msg_s} {hdr} """ @property def data(self): md={} msg_d=self.msg_d while msg_d: for k,v in msg_d.items(): md[k]=v msg_d = msg_d.get('msg',{}) if type(msg_d)!=dict: msg_d=None if 'msg' in md and type(md['msg']) == dict: del md['msg'] if ROUTE_KEYNAME in md: del md[ROUTE_KEYNAME] return md def return_to_sender(self,new_msg=None): self.log('making return to sender. v1:',self) new_msg = Message( { 'from':self.msg_d.get('to'), 'to':self.msg_d.get('from'), 'from_name':self.msg_d.get('to_name'), 'to_name':self.msg_d.get('from_name'), 'msg':new_msg if new_msg else self.msg_d.get('msg'), 'timestamp':time.time(), } ) self.log('returning:',new_msg) return new_msg @property def from_whom(self): # from comrad.backend.comrades import Comrad return Comrad(self.from_name, pubkey=self.from_pubkey) @property def to_whom(self): # from comrad.backend.comrades import Comrad return Comrad(self.to_name, pubkey=self.to_pubkey) def decrypt(self,recursive=False): # check if needs decryption if not self.is_encrypted: return # otherwise lets do it self.msg_encr = self.msg self.log(f'Attempting to decrypt:\n{self}') # decrypt msg # self.log('attempting to decrypt',self.msg,'from',self.from_pubkey,'to',self.to_pubkey, self.to_whom,dict_format(self.to_whom.keychain()),self.to_whom.assemble(self.to_whom.keychain())) if not self.to_whom.privkey: self.log(f'{self.to_whom} cannot decrypt this message! {dict_format(self.to_whom.keychain())}!\n\n{self.to_whom.name} {self.to_whom.pubkey} {self.to_name} {self.to_pubkey} {self.to_whom.keychain()}') return self.msg = self.msg_d['msg'] = decr_msg_b = SMessage( self.to_whom.privkey.data, b64dec(self.from_pubkey) ).unwrap(self.msg) # unpickle self.msg = self.msg_d['msg'] = decr_msg = pickle.loads(decr_msg_b) self.log('Message decrypted:\n',self) # now, is the decrypted message itself a message? if is_valid_msg_d(decr_msg): self.log('Once decrypted, I discovered that I contain an enclosed encrypted message!\n\n',self) # then ... make that, a message object and decrypt it too! self.msg = Message(decr_msg) if recursive and self.msg.is_encrypted: self.msg.decrypt() # self.log(f'done decrypting! {self}') return decr_msg @property def is_encrypted(self): return type(self.msg) == bytes # if self.msg._is_encrypted is not None: # return self.msg._is_encrypted def encrypt(self): # each child message should already be encrypted before coming to its parent message ,recursive=False): if self._is_encrypted: return # self.log(f'attempting to encrypt msg {self.msg} from {self.from_whom} to {self.to_whom}') # self.log(f'Before encrypting the message from @{self.from_name} to @{self.to_name}, it looks like:\n{self}') # make sure msg is not meeta if self.has_embedded_msg: self.msg = self.msg.msg_d # self.log('woops, first had to replace Message object with dict',self) # binarize msg msg_b = pickle.dumps(self.msg) # encrypt it! # self.log('from whom keychain:',self.from_whom.keychain()) # self.log('to pubkey:',self.to_pubkey) msg_encr = SMessage( self.from_whom.privkey.data, b64dec(self.to_pubkey) ).wrap(msg_b) self.msg_decr = self.msg self.msg_d['msg'] = self.msg = b64encode(msg_encr) # self.log(f'After encrypting the message from {self.from_whom} to {self.to_whom}, it looks like:\n{self}') self.msg_d['msg'] = self.msg = msg_encr self._is_encrypted = True @property def msg_b(self): return pickle.dumps(self.msg_d) ## msg properties @property def has_embedded_msg(self): return type(self.msg) == Message @property def messages(self): # move through msgs recursively def _msgs(): msg=self while True: yield msg if msg.has_embedded_msg: msg=msg.msg break return list(_msgs()) @property def route(self): if type(self.msg)==dict: rte=self.msg.get(ROUTE_KEYNAME) if rte: return rte if self.has_embedded_msg: return self.msg.route return None def delete_route(self): if type(self.msg)==dict: del self.msg[ROUTE_KEYNAME] if ROUTE_KEYNAME in self.msg_d['msg']: del self.msg_d['msg'][ROUTE_KEYNAME] if self.has_embedded_msg: self.msg.delete_route() def test_msg(): phone = TheTelephone() op = TheOperator() pprint(op.pubkey) print('?keychains?') pprint(phone.pubkey) msg={'_route':'forge_new_keys'} resp_msp_obj = phone.ring_ring(msg) print(resp_msp_obj) if __name__ == '__main__': test_msg()