From cc01f7413f1fd98805d304f1f532370841d0f561 Mon Sep 17 00:00:00 2001 From: quadrismegistus Date: Thu, 17 Sep 2020 11:37:58 +0100 Subject: [PATCH] cleaning up komrades.py --- komrade/backend/crypt.py | 17 +- komrade/backend/komrades.py | 355 ++++++++++++++++---------------- komrade/backend/operators.py | 26 ++- komrade/backend/the_operator.py | 285 ++++++++++++------------- 4 files changed, 340 insertions(+), 343 deletions(-) diff --git a/komrade/backend/crypt.py b/komrade/backend/crypt.py index ea0936d..bf85b42 100644 --- a/komrade/backend/crypt.py +++ b/komrade/backend/crypt.py @@ -210,17 +210,20 @@ class CryptList(Crypt): # like inbox if not val_b: return [] return pickle.loads(val_b) - def prepend(self,x): + def prepend(self,x_l): return self.append(x,insert=0) - def append(self,x,insert=None): + def append(self,x_l,insert=None): + if type(x_l)!=list: x_l=[x_l] val_l = self.values + x_l = [x for x in x_l if not x in set(val_l)] # print('val_l =',val_l) - if insert is not None: - val_l.insert(insert,x) - else: - val_l.append(x) - # print('val_l2 =',val_l) + for x in x_l: + if insert is not None: + val_l.insert(insert,x) + else: + val_l.append(x) + # print('val_l2 =',val_l) return self.set(val_l) diff --git a/komrade/backend/komrades.py b/komrade/backend/komrades.py index d8c5c1f..be94245 100644 --- a/komrade/backend/komrades.py +++ b/komrade/backend/komrades.py @@ -70,6 +70,24 @@ class KomradeX(Caller): return answer + + ## Talking with Operator + def ring_ring(self,msg,route=None,**y): + if type(msg)==dict and not ROUTE_KEYNAME in msg: + msg[ROUTE_KEYNAME]=route + return super().ring_ring(msg,caller=self,**y) + + + + + + + #################################### + ## (1) Logging in and registering ## + #################################### + + + def register(self, name = None, passphrase = None, is_group=None, show_intro=0,show_body=True,logfunc=None): # global PHONEBOOK @@ -278,122 +296,92 @@ class KomradeX(Caller): - ## MEETING PEOPLE - def find(self,someone): - if type(someone)==str: - return Komrade(name=someone) - if type(someone)==bytes: - return Komrade(pubkey=someone) - self.log('what is type of someoen here?',type(someone)) - return someone - # def meet(self,someone): - # # get person obj - # someone = self.find(someone) - # self.log('got someone =',someone,type(someone)) + + + + + + + + + ######################## + ## (2) MEETING PEOPLE ## + ######################## + def contacts(self): # who do I know? return sorted([fn.split('.png')[0] for fn in os.listdir(PATH_QRCODES)]) + ### MEETING PEOLPE + def meet(self,name=None,pubkey=None,returning=False): + if not name and not pubkey: + return {'success':False,'status':'Meet whom?'} + + # already met this person? + keystr=self.name+'->'+name + if self.crypt_keys.get( + keystr, + prefix='/met/' + ): + return { + 'success':False, + 'status':f'You have already sent an introduction to @{name}. It would be rude to send another.' + } + # send msg to op + msg_to_op = { + 'name':self.name, + 'secret_login':self.secret_login, + 'pubkey':self.uri, - def ring_ring(self,msg,route=None,**y): - if type(msg)==dict and not ROUTE_KEYNAME in msg: - msg[ROUTE_KEYNAME]=route - return super().ring_ring(msg,caller=self,**y) - + 'meet_name':name, + 'meet_pubkey':pubkey, + 'returning':returning + } + self.log('msg_to_op',msg_to_op) - def fetch_posts(self,n=100,only_from=[],not_from=[]): - # already seen? - seen_post_ids_b = self.crypt_keys.get( - 'seen_post_ids', - prefix='/cache/' + res = self.ring_ring( + msg_to_op, + route='introduce_komrades' ) - if seen_post_ids_b: - seen_post_ids=pickle.loads(seen_post_ids_b) - else: - seen_post_ids=[] - self.log('seen_post_ids =',seen_post_ids) + self.log('res from op <-',res) - # ring operator - res_b = self.ring_ring( - { - 'seen_post_ids':seen_post_ids, - 'only_from':only_from, - 'not_from':not_from, - 'n':n - }, - route='fetch_posts' + # record that I've already tried this + self.crypt_keys.set( + keystr, + b'y', + prefix='/met/' ) - self.log('res_b <-',res_b) - # msg from world? - msg_from_world = Message( - from_whom=self.op,#Komrade(WORLD_NAME), - to_whom=self, - msg=res_b - ) - self.log('converted to msg:',msg_from_world.msg_d) - msg_from_world.decrypt() - self.log('decrypted msg:',msg_from_world) + # return result + return res + + + + + - # get binary blob for all fetched posts - msgs_d = msg_from_world.msg - self.log('msgs_d??',msgs_d) - msgs = msgs_d['msg'].split(BSEP) if msgs_d['msg'] else [] - res = { - 'status':f'Fetched {len(msgs)} poss.', - 'success':True, - 'msgs':msgs - } - self.log('->',res) - return res - - # def post(self,something,to_name=WORLD_NAME): - # self.log('<-',something,to_name) - # # encryption chain: - # # me -> world - # # me -> op - # # op <- me - # # op -> others - # to_komrade = Komrade(to_name) - # self.log('posting to',to_name,to_komrade,to_komrade.uri) - # # make post data - - # # encrypt - # something_encr = SMessage( - # self.privkey.data, - # to_komrade.pubkey.data - # ).wrap(something) - - # # make dict (do not use normal msg_d key names!) - # post_d = { - # 'post':{ - # 'from':self.uri, - # 'from_name':self.name, - # 'to_name':to_name, - # 'to':to_komrade.uri, - # 'msg':something_encr - # } - # } - # self.log('post_d =',post_d) - # # enclose as message to operator - # self.ring_ring( - # post_d, - # route='post' - # ) - def post(self,something): - return self.msg(WORLD_NAME,something) - + + + + + + + ################### + ## (3) MESSAGING ## + ################### + + @@ -439,28 +427,6 @@ class KomradeX(Caller): ) - @property - def inbox_db(self): - if not hasattr(self,'_inbox_db'): - self._inbox_db=self.get_inbox_crypt( - prefix='/inbox/' - ) - return self._inbox_db - @property - def inbox_unread_db(self): - if not hasattr(self,'_inbox_unread_db'): - self._inbox_unread_db=self.get_inbox_crypt( - prefix='/inbox/unread/', - ) - return self._inbox_unread_db - @property - def inbox_read_db(self): - if not hasattr(self,'_inbox_read_db'): - self._inbox_read_db=self.get_inbox_crypt( - prefix='/inbox/read/', - ) - return self._inbox_read_db - def download_inbox(self,uri=None): @@ -485,44 +451,22 @@ class KomradeX(Caller): route='get_inbox' ) self.log('got back response:',res) - stop - - return self.do_check_msgs(res) - - def do_check_msgs(self,res): - # decrypt? - if not res.get('data_encr'): - return {'success':False, 'status':'No data'} - inbox_encr = res['data_encr'] - - inbox = SMessage( - self.privkey.data, - self.op.pubkey.data - ).unwrap(inbox_encr) - self.log('inbox decrypted:',inbox) - - # overwrite my local inbox with encrypted one from op? - return self.crypt_keys.set( - self.uri, - inbox, - prefix='/inbox/', - override=True - ) + if not res.get('success'): return res + inbox=res.get('inbox',[]) + if inbox: + res['res_inbox']=self.inbox_db.prepend(inbox) + return res def refresh(self,check_msgs=True): # refresh inbox if check_msgs: self.download_inbox() - # status? - inbox_status = self.get_inbox_ids() - if not inbox_status['success']: return inbox_status - - unread=inbox_status.get('unread',[]) - inbox=inbox_status.get('inbox',[]) - # download new messages - self.download_msgs(post_ids = inbox) + inbox_post_ids = self.inbox_db.values + self.download_msgs( + post_ids = inbox_post_ids + ) res = { 'success':True, @@ -764,48 +708,103 @@ class KomradeX(Caller): - ### MEETING PEOLPE - def meet(self,name=None,pubkey=None,returning=False): - if not name and not pubkey: - return {'success':False,'status':'Meet whom?'} - keystr=self.name+'->'+name - # if self.crypt_keys.get( - # keystr, - # prefix='/met/' - # ): - # return { - # 'success':False, - # 'status':f'You have already sent an introduction to @{name}. It would be rude to send another.' - # } - msg_to_op = { - 'name':self.name, - 'secret_login':self.secret_login, - 'pubkey':self.uri, - 'meet_name':name, - 'meet_pubkey':pubkey, - 'returning':returning - } - # print('msg_to_op',msg_to_op) - res = self.ring_ring( - msg_to_op, - route='introduce_komrades' + + + + + + + + + + def fetch_posts(self,n=100,only_from=[],not_from=[]): + # already seen? + seen_post_ids_b = self.crypt_keys.get( + 'seen_post_ids', + prefix='/cache/' ) - # print('res from op',res) + if seen_post_ids_b: + seen_post_ids=pickle.loads(seen_post_ids_b) + else: + seen_post_ids=[] + self.log('seen_post_ids =',seen_post_ids) - # record that I've already tried this - self.crypt_keys.set( - keystr, - b'y', - prefix='/met/' + # ring operator + res_b = self.ring_ring( + { + 'seen_post_ids':seen_post_ids, + 'only_from':only_from, + 'not_from':not_from, + 'n':n + }, + route='fetch_posts' ) + self.log('res_b <-',res_b) + + # msg from world? + msg_from_world = Message( + from_whom=self.op,#Komrade(WORLD_NAME), + to_whom=self, + msg=res_b + ) + self.log('converted to msg:',msg_from_world.msg_d) + msg_from_world.decrypt() + self.log('decrypted msg:',msg_from_world) + + # get binary blob for all fetched posts + msgs_d = msg_from_world.msg + self.log('msgs_d??',msgs_d) + msgs = msgs_d['msg'].split(BSEP) if msgs_d['msg'] else [] + res = { + 'status':f'Fetched {len(msgs)} poss.', + 'success':True, + 'msgs':msgs + } + + self.log('->',res) return res + + + def post(self,something): + return self.msg(WORLD_NAME,something) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + def test_register(): diff --git a/komrade/backend/operators.py b/komrade/backend/operators.py index dfa36a4..69bcd1e 100644 --- a/komrade/backend/operators.py +++ b/komrade/backend/operators.py @@ -325,4 +325,28 @@ class Operator(Keymaker): ) self.log('-->',inbox_crypt) - return inbox_crypt \ No newline at end of file + return inbox_crypt + + + + @property + def inbox_db(self): + if not hasattr(self,'_inbox_db'): + self._inbox_db=self.get_inbox_crypt( + prefix='/inbox/' + ) + return self._inbox_db + @property + def inbox_unread_db(self): + if not hasattr(self,'_inbox_unread_db'): + self._inbox_unread_db=self.get_inbox_crypt( + prefix='/inbox/unread/', + ) + return self._inbox_unread_db + @property + def inbox_read_db(self): + if not hasattr(self,'_inbox_read_db'): + self._inbox_read_db=self.get_inbox_crypt( + prefix='/inbox/read/', + ) + return self._inbox_read_db diff --git a/komrade/backend/the_operator.py b/komrade/backend/the_operator.py index d40a9a1..09f5ae0 100644 --- a/komrade/backend/the_operator.py +++ b/komrade/backend/the_operator.py @@ -328,69 +328,7 @@ class TheOperator(Operator): # self.log('Operator returning result:',dict_format(res,tab=2)) - def fetch_posts(self,msg_to_op): - self.log('<-',msg_to_op) - # get posts by personating world - world = Komrade(WORLD_NAME) - world_inbox_res = world.inbox() - self.log('world_inbox_res',world_inbox_res) - if not world_inbox_res.get('success'): - return world_inbox_res - world_msgs = world_inbox_res.get('msgs') - self.log('world_msgs',world_msgs) - - # encrypt to sender from world - world_msgs_b = BSEP.join([msg.msg_b for msg in world_msgs]) - world_msg_to_sender = Message( - from_whom=world, - to_whom=msg_to_op.from_whom, - msg=world_msgs_b - ) - self.log(world_msg_to_sender,'<- world_msg_to_sender') - # encrypt - world_msg_to_sender.encrypt() - self.log(world_msg_to_sender,'<- world_msg_to_sender encrypted') - - return world_msg_to_sender.msg_d - - - # def post1(self,msg_to_op): - # self.log('post <-',msg_to_op.msg_d) - # self.log('post data <-',msg_to_op.data) - # post_d = msg_to_op.data.get('post') - # self.log('post_d =',post_d) - - # # need to decrypt this first -- it's to World, - # # which I on the server have access to private key. - # # I need to decrypt and re-encrypt/reroute - # #msg_to_world = Message(post_d) - # #self.log('msg to world',dict_format(msg_to_world.msg_d)) - - # # decrypt - # encr_txt = post_d.get('msg') - # txt = SMessage( - # Komrade(post_d.get('to_name')).privkey.data, # requires we have this privkey!!! - # Komrade(post_d.get('from_name')).pubkey.data - # ).unwrap(encr_txt) - # self.log('unencr txt',txt) - - # post - - # # normally we'd deliver it to the person - # # but here we need to deliver it to... - # # everyone? - # contacts = sorted([fn.split('.png')[0] for fn in os.listdir(PATH_QRCODES)]) - # self.log('contacts =',contacts) - - # # mass send! - # res = self.mass_deliver_msg(txt,contacts) - - # return { - # 'status':'Hold your horses.', - # 'success':False, - # 'res_mass_deliver_msg':res - # } def mass_deliver_msg(self,post_msg_d,contacts): def do_mass_deliver_msg(contact,post_msg_d=post_msg_d): @@ -538,20 +476,56 @@ class TheOperator(Operator): self.log('->',res) return res - def get_inbox(self, - msg_to_op, - required_fields = [ - 'secret_login', - 'name', - 'pubkey', - 'inbox', - ],do_login=True): + + + + + + + + ### + # LETS SIMPLIFY THIS + # Komrade -> Op: get_updates() + # gets new DMs, new posts, + # both index/inbox and content/body + ### + + def require_login(self,msg_to_op,do_login=True): # logged in? if do_login: login_res = self.login(msg_to_op) if not login_res.get('success'): return login_res + return {'success':True,'status':'Logged in.'} + else: + return {'success':True,'status':'Login not required.'} + + + # (0) get updates + # user enters here + def get_updates(self,msg_to_op,do_login=True): + # req login + login_res=self.require_login(msg_to_op,do_login=do_login) + if not login_res.get('success'): return login_res + + # (1) get inbox + inbox_res = self.get_inbox() + if not inbox_res.get('success'): return inbox_res + inbox=inbox_res.get('inbox',[]) + + # (2) get posts + + + + # (1) get inbox + def get_inbox(self, + msg_to_op, + do_login=True, + delete_afterward=False): + # req login + login_res=self.require_login(msg_to_op,do_login=do_login) + if not login_res.get('success'): return login_res # ok, then find the inbox? inbox=self.get_inbox_crypt( @@ -561,112 +535,109 @@ class TheOperator(Operator): res = { 'status':'Succeeded in getting inbox.', 'success':True, - 'inbox':inbox.values if inbox else None + 'inbox':inbox.values if inbox else [] } - self.log(f'returning from Op.get_inbox --> {res}') + + self.log(f'--> {res}') return res - - def download_msgs(self, - msg_to_op, - required_fields = [ - 'secret_login', - 'name', - 'pubkey', - 'post_ids', - ], - delete_afterward=True): - # logged in? - login_res = self.login(msg_to_op) - if not login_res.get('success'): - return login_res - - # ok, then find the posts? - post_ids=msg_to_op.data.get('post_ids',[]) - if not post_ids: return {'success':False, 'status':'No post_ids specified'} - - posts = {} + def get_posts(self,post_ids): + posts={} for post_id in post_ids: - - post = self.crypt_data.get(b64enc(post_id),prefix='/post/') - if post: - posts[post_id] = post - self.log('looking for:',post_id,post) + post = self.crypt_data.get( + post_id, + prefix='/post/' + ) + if post: posts[post_id] = post self.log(f'I {self} found {len(posts)} for {msg_to_op.from_name}') - - # delete? + res = { - 'status':'Succeeded in downloading new messages.' + (' I\'ve already deleted these messages from the server.' if delete_afterward else ''), + 'status':'Succeeded in getting new messages and posts.', 'success':True, - 'data_encr':posts + 'posts':posts } - - # delete? - if delete_afterward: - res['res_delete_msgs'] = self.delete_msgs( - post_ids, - inbox_uri = b64enc( - msg_to_op.data.get('pubkey') - ) - ) - - # show res - self.log('->',res) + self.log(f'--> {res}') return res - - - def delete_msgs(self,post_ids,inbox_uri=None): - # @hack: this a bit dangerous? + def delete_posts(self,post_ids,inbox_uri=None): + # delete from posts + deleted_post_ids=[] for post_id in post_ids: - self.crypt_data.delete( + if self.crypt_data.delete( post_id, prefix='/post/' - ) - self.log('deleting post id',post_id,'...') + ): + deleted_post_ids.append(post_id) + self.log('deleted_post_ids',deleted_post_ids,'...') + res = { + 'deleted':post_ids, + } - # if inbox, remove these posts from it + # delete from inbox if inbox_uri: - # unwrap - inbox = self.crypt_keys.get( - inbox_uri, - prefix='/inbox/' + inbox_db=self.get_inbox_crypt( + uri=inbox_uri, + pubkey_b=b64dec(inbox_uri) ) - if inbox: - inbox = SMessage( - self.privkey.data, - b64dec(inbox_uri) - ).unwrap(inbox) - self.log('unwrapped inbox_encr:',inbox) - inbox_l = inbox.split(BSEP) - self.log('length v1:',len(inbox_l)) - - # alter - inbox_l = [pid for pid in inbox_l if pid not in post_ids] - self.log('length v2:',len(inbox_l)) - - # rewrap - inbox = BSEP.join(inbox_l) - if inbox: - #print('inboxxx',inbox) - inbox = SMessage( - self.privkey.data, - b64dec(inbox_uri) - ).wrap(inbox) - - # overwrite! - self.crypt_keys.set( - inbox_uri, - inbox, - prefix='/inbox/', - override=True + res['deleted_from_inbox']=inbox_db.remove( + deleted_post_ids ) + + self.log('-->',res) + return res + + + + + + + + + + + + + ## posts + def fetch_posts(self,msg_to_op): + self.log('<-',msg_to_op) + + # get posts by personating world + world = Komrade(WORLD_NAME) + world_inbox_res = world.inbox() + self.log('world_inbox_res',world_inbox_res) + if not world_inbox_res.get('success'): + return world_inbox_res + world_msgs = world_inbox_res.get('msgs') + self.log('world_msgs',world_msgs) + + # encrypt to sender from world + world_msgs_b = BSEP.join([msg.msg_b for msg in world_msgs]) + world_msg_to_sender = Message( + from_whom=world, + to_whom=msg_to_op.from_whom, + msg=world_msgs_b + ) + self.log(world_msg_to_sender,'<- world_msg_to_sender') + # encrypt + world_msg_to_sender.encrypt() + self.log(world_msg_to_sender,'<- world_msg_to_sender encrypted') + + return world_msg_to_sender.msg_d + + + + + + + + + + - return { - 'success':True, - 'deleted':post_ids, - } + ### + # INTRODUCTIONS/MEETING + ### def introduce_komrades(self,msg_to_op): # # logged in?