From 00bcb8961c8a0b2b65bae6fa2dc8a23d29a630c2 Mon Sep 17 00:00:00 2001 From: quadrismegistus Date: Thu, 17 Sep 2020 13:23:11 +0100 Subject: [PATCH] almost done with posting??? --- komrade/backend/komrades.py | 335 +++++--------------------------- komrade/backend/operators.py | 6 +- komrade/backend/the_operator.py | 104 ++++++---- komrade/cli/cli.py | 35 ++-- 4 files changed, 135 insertions(+), 345 deletions(-) diff --git a/komrade/backend/komrades.py b/komrade/backend/komrades.py index be94245..35830cf 100644 --- a/komrade/backend/komrades.py +++ b/komrade/backend/komrades.py @@ -347,7 +347,7 @@ class KomradeX(Caller): res = self.ring_ring( msg_to_op, - route='introduce_komrades' + route='introduce' ) self.log('res from op <-',res) @@ -394,13 +394,14 @@ class KomradeX(Caller): if not someone.pubkey: self.log(f'''Don't know the public key of {someone}!''') + # write them message msg_obj = self.compose_msg_to( something, someone ) self.log('composed msg:',msg_obj) - # encrypting + # encrypt it msg_obj.encrypt() # attaching @@ -418,224 +419,77 @@ class KomradeX(Caller): } } - self.log('going to send msg to op?',msg_to_op) - return self.ring_ring( + # dial operator + res=self.ring_ring( msg_to_op, route='deliver_msg' ) + self.log('-->',res) + return res + def post(self,something): + return self.msg(WORLD_NAME,something) + + - - def download_inbox(self,uri=None): - if not self.pubkey and self.privkey: - return {'success':False,'status':'Need to be logged in'} - - # checking my own mail I presume? - uri=self.uri if not uri else uri - - # send info op needs - msg = { - 'secret_login':self.secret_login, - 'name':self.name, - 'pubkey':self.uri, - 'inbox':uri - } - self.log('sending msg to op:',msg) - - # Ring operator + ## Getting updates + def get_updates(self): res = self.ring_ring( - msg, - route='get_inbox' - ) - self.log('got back response:',res) - 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() - - # download new messages - inbox_post_ids = self.inbox_db.values - self.download_msgs( - post_ids = inbox_post_ids + { + 'seen':self.inbox_read_db.values + }, + route='get_updates' ) + self.log('<- Op.get_updates <-',res) - res = { - 'success':True, - 'status':'Messages refreshed', - 'unread':unread, - 'inbox':inbox - } - self.log('->',res) - return res - - def save_inbox(self, - post_ids, - uri=None, - encrypted=False): - self.log('<-',post_ids) - newval = BSEP.join(post_ids) - - res = self.crypt_keys.set( - self.uri if not uri else uri, - newval, - prefix='/inbox/', - override=True - ) - assert newval == self.crypt_keys.get( - self.uri, - prefix='/inbox/' - ) - self.log('->',res) - return res + # error? + if not res.get('success'): return res - def delete_msg(self,post_id): - return self.delete_msgs([post_id]) + # (1) save inbox + inbox=res.get('res_inbox').get('inbox',[]) + if inbox: self.inbox_db.prepend(inbox) - def delete_msgs(self,post_ids): - inbox_ids = self.get_inbox_ids().get('inbox',[]) - #print(inbox_ids,'v1',len(inbox_ids)) - deleted=[] - for post_id in post_ids: - #print('deleting post:',post_id) - self.crypt_data.delete( + # (2) save msgs + id2post=res.get('res_msgs').get('msgs',[]) + for post_id,post in id2post.items(): + post = self.crypt_data.set( post_id, - prefix='/post/', + post, + prefix='/post/' ) - deleted+=[post_id] - #print(post_id,inbox_ids,post_id in inbox_ids,'???') - # stop - if post_id in inbox_ids: - # print('removing from inbox...') - inbox_ids.remove(post_id) - self.save_inbox(inbox_ids) - #print(inbox_ids,'v2',len(inbox_ids)) - - res= { - 'success':not bool(set(post_ids) - set(deleted)), - 'status':f'Deleted {len(deleted)} messages.', - 'deleted':deleted - } - self.log('delete_msgs ->',res) - return res - - def inbox(self,topn=100,only_unread=False,delete_malformed=False,check_msgs=False): - # refreshing inbox - res = self.refresh(check_msgs=check_msgs) - # print('got from refresh',res) - if not res['success']: return res - - boxname = 'inbox' if not only_unread else 'unread' - post_ids = res[boxname] - msgs=[] - post_ids_malformed=[] - for post_id in post_ids: - malformed = False - try: - res = self.read_msg(post_id) - # print('GOT FROM READ_MSG',res) - except ThemisError as e: - print(f'!! Could not decrypt post {post_id}') - malformed = True - - #print(res,'ressss') - if not res.get('success'): - # return res - continue - - msg=res.get('msg') - if not msg: continue - # print(msg,'?!?!??!') - # stop - - if not msg.from_name or not msg.from_pubkey: - print('!! Invalid sender info!') - malformed = True - - msg.post_id=post_id - - if not malformed: - # print('good msg:',msg) - msgs.append(msg) - else: - post_ids_malformed.append(post_id) - - if len(msgs)>=topn: break - # print('!!',post_id,msg.from_whom, msg.to_whom, msg.from_whom is self) - - if delete_malformed: - self.delete_msgs(post_ids_malformed) - - #print(msgs,'msssgs') - return {'success':True, - 'msgs':msgs} - - # return all messages read? - - - def get_inbox_ids(self): - inbox = self.crypt_keys.get( - self.uri, - prefix='/inbox/', - ) - - # decrypt inbox? - if inbox: - inbox = b64enc(inbox).split(BSEP) - self.log('inbox_l',inbox) - else: - inbox=[] - - # find the unread ones - unread = [] - for post_id in inbox: - if not post_id: continue - if not self.crypt_data.get(post_id,prefix='/post/'): - unread.append(post_id) - - self.log(f'I {self} have {len(unread)} new messages') - res = { - 'success':True, - 'status':'Inbox retrieved.', - 'unread':unread, - 'inbox':inbox - } - self.log('->',res) - return res + # (3) save posts + # ... - def read_msg(self,post_id): + def messages(self,show_read=True,show_unread=True): + # meta inbox + inbox = self.inbox_db.values + # filter? + if not show_read: inbox = [x for x in inbox if not x in set(self.inbox_read_db.values)] + if not show_unread: inbox = [x for x in inbox if not x in set(self.inbox_unread_db.values)] + # decrypt and read all posts + results = [self.read_msg(post_id) for post_id in inbox] + msgs = [res.get('msg2me') for res in results if res.get('success')] + msgs = [x for x in msgs if x] + return msgs + + def read_msg(self,post_id=None,post_encr=None): # get post - post_encr = self.crypt_data.get(post_id,prefix='/post/') - # print(post_id,'????') if not post_encr: - self.download_msgs([post_id]) post_encr = self.crypt_data.get(post_id,prefix='/post/') - # print(post_id,'????') - - return { - 'success':False, - 'status':'Post not found.' - } self.log('found encrypted post store:',post_encr) - # self.log('unpickling?',pickle.loads(post_encr)) - - + # it should be twice decrypted msg_op2me_obj = Message( from_whom=self.op, to_whom=self, msg=post_encr ) + msg_op2me_obj.post_id=post_id self.log('assuming this is the message:',msg_op2me_obj) # decrypt @@ -667,46 +521,6 @@ class KomradeX(Caller): } - - def download_msgs(self,post_ids=[],inbox=None): - if not post_ids: - # get unerad - post_ids = self.get_inbox_ids().get('unread',[]) - if not post_ids: - return {'success':False,'status':'No messages requested'} - - # ask Op for them - res = self.ring_ring( - { - 'secret_login':self.secret_login, - 'name':self.name, - 'pubkey':self.uri, - 'post_ids':post_ids, - }, - route='download_msgs' - ) - - # print('got back from op!',res) - if not 'data_encr' or not res['data_encr'] or type(res['data_encr'])!=dict: - return {'success':False, 'status':'No valid data returned.'} - - # store -- encrypted! - posts_downloaded = [] - for post_id,post_encr in res['data_encr'].items(): - # print('storing...',post_id) - self.crypt_data.set( - post_id, - post_encr, - prefix='/post/' - ) - posts_downloaded.append(post_id) - return { - 'success':True, - 'status':'Messages downloaded', - 'downloaded':posts_downloaded, - } - - @@ -718,62 +532,7 @@ class KomradeX(Caller): - - - - - - 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/' - ) - 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) - - # 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) + diff --git a/komrade/backend/operators.py b/komrade/backend/operators.py index 69bcd1e..0d4036d 100644 --- a/komrade/backend/operators.py +++ b/komrade/backend/operators.py @@ -53,11 +53,9 @@ class Operator(Keymaker): 'register_new_user', 'login', 'deliver_msg', - 'get_inbox', - 'download_msgs', - 'introduce_komrades', + 'introduce', 'post', - 'fetch_posts' + 'get_updates' ] diff --git a/komrade/backend/the_operator.py b/komrade/backend/the_operator.py index 09f5ae0..970b4e6 100644 --- a/komrade/backend/the_operator.py +++ b/komrade/backend/the_operator.py @@ -504,32 +504,82 @@ class TheOperator(Operator): # (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 + def get_updates(self, + msg_to_op=None, + inbox_uri=None, + do_login=True, + include_posts=True): + self.log('<-',msg_to_op,inbox_uri) + + # uri? + if not inbox_uri and not msg_to_op: + return {'success':False, 'status':'Updates for whom?'} + uri = inbox_uri if inbox_uri else msg_to_op.from_pubkey + + # req login? + if do_login: + if not msg_to_op: + return {'success':False, 'status':'Cannot login outside of message context.'} + res_login=self.require_login(msg_to_op,do_login=do_login) + if not res_login.get('success'): return res_login # (1) get inbox - inbox_res = self.get_inbox() - if not inbox_res.get('success'): return inbox_res - inbox=inbox_res.get('inbox',[]) + res_inbox=self.get_inbox(uri) + if not res_inbox.get('success'): return res_inbox + inbox=res_inbox.get('inbox',[]) + + # (2) get msgs + res_msgs = self.get_msgs(inbox) + if not res_msgs.get('success'): return res_msgs + msgs=res_msgs.get('posts') + + # (3) get posts + posts=[] + if include_posts and self.name!=WORLD_NAME: + res_posts = self.get_posts() + if not res_posts.get('success'): return res_posts + posts=res.get('res_posts').get('posts',[]) + + # return + res={ + 'success': True, + 'status': f'You have {len(msgs)} new messages, and {len(posts)} new posts.', + 'posts': posts, + 'msgs': msgs, + } + self.log('-->',res) + return res + + ## posts + def get_posts(self): + world=Komrade(WORLD_NAME) + # (1) get inbox + res_inbox=self.get_inbox(world.uri) + if not res_inbox.get('success'): return res_inbox + inbox=res_inbox.get('inbox',[]) + + # (2) read msgs + id2post={} + for post_id in inbox: + res_read_msg = world.read_msg(post_id) + if res_read_msg.get('success'): + post=res_read_msg.get('msg2me') + if post: + post[post_id]=post + self.log('id2post for world',id2post) + return id2post - # (2) get posts + # (3) reencrypt for requester + # inbox=res_inbox.get('inbox',[]) # (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 - + def get_inbox(self,inbox_uri): # ok, then find the inbox? inbox=self.get_inbox_crypt( - pubkey_b=b64dec(msg_to_op.from_pubkey) + uri=inbox_uri, + pubkey_b=b64dec(inbox_uri) ) res = { @@ -541,7 +591,7 @@ class TheOperator(Operator): self.log(f'--> {res}') return res - def get_posts(self,post_ids): + def get_msgs(self,post_ids): posts={} for post_id in post_ids: post = self.crypt_data.get( @@ -554,7 +604,7 @@ class TheOperator(Operator): res = { 'status':'Succeeded in getting new messages and posts.', 'success':True, - 'posts':posts + 'msgs':posts } self.log(f'--> {res}') return res @@ -588,19 +638,7 @@ class TheOperator(Operator): - - - - - - - - - - ## posts - def fetch_posts(self,msg_to_op): - self.log('<-',msg_to_op) - + def get_posts(self): # get posts by personating world world = Komrade(WORLD_NAME) world_inbox_res = world.inbox() @@ -639,7 +677,7 @@ class TheOperator(Operator): # INTRODUCTIONS/MEETING ### - def introduce_komrades(self,msg_to_op): + def introduce(self,msg_to_op): # # logged in? # self.log('introduce got:',msg_to_op) # login_res = self.login(msg_to_op) diff --git a/komrade/cli/cli.py b/komrade/cli/cli.py index 6509dc1..91c4225 100644 --- a/komrade/cli/cli.py +++ b/komrade/cli/cli.py @@ -21,7 +21,7 @@ class CLI(Logger): 'meet':'meet a komrade', 'who':'show contacts or info', 'msg':'write people', - 'check':'check mail', + 'update':'check mail', 'read':'read mail', 'verbose':'show/hide log output', 'post':'post to world', @@ -210,11 +210,11 @@ class CLI(Logger): self.stat(res.get('status','?'),komrade_name='Operator') # also see if we got a msg update - if 'res_refresh' in res: - self.check( - res=res['res_refresh'], - statd={'use_prefix':False} - ) + # if 'res_refresh' in res: + # self.check( + # res=res['res_refresh'], + # statd={'use_prefix':False} + # ) @property def logged_in(self): @@ -289,21 +289,16 @@ class CLI(Logger): print() self.stat(f'Message successfully sent to @{name_or_pubkey}.',komrade_name='Operator',pause=True) - def check(self,dat=None,res=None,statd={}): + def update(self,dat=None,res=None,statd={}): self.log(f'<-- dat={dat}, res={res}') - if not res: - if self.with_required_login(): - res = self.komrade.refresh() - if not res['success']: - self.stat(res['status'],komrade_name='Operator') - return - - unr = res.get('unread',[]) - inb = res.get('inbox',[]) - print() - self.stat(f'You have {len(unr)} unread messages, with {len(inb)} total in your inbox.',komrade_name='Operator',**statd) - self.log(f'--> unr={unr}, inb={inb}') - # stop + if self.with_required_login(): + res = self.komrade.get_updates() + self.log('<-- get_updates',res) + if not res['success']: + self.stat(res['status'],komrade_name='Operator') + return + self.stat(res['status'],komrade_name='Operator',**statd) + def prompt_adduser(self,msg): # self.print('prompt got:',msg)