2
0
mirror of https://github.com/ComradCollective/Comrad synced 2024-11-17 21:25:37 +00:00
Comrad/komrade/backend/operators.py

307 lines
9.4 KiB
Python
Raw Normal View History

2020-09-05 16:26:37 +00:00
# internal imports
2020-09-04 15:50:08 +00:00
import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
2020-09-05 16:26:37 +00:00
from komrade import *
2020-09-09 14:38:37 +00:00
from komrade.backend import *
2020-09-14 06:25:43 +00:00
# BEGIN PHONE BOOK (in memory singleton mapping)
PHONEBOOK = {}
# Factory constructor
2020-09-14 07:58:26 +00:00
def Komrade(name=None,pubkey=None,*x,**y):
if issubclass(type(name),Operator): return name
if name and not pubkey and type(name)==bytes:
pubkey=b64enc(name)
2020-09-14 13:06:50 +00:00
name=None
2020-09-14 07:58:26 +00:00
2020-09-14 06:25:43 +00:00
from komrade.backend.the_operator import TheOperator
from komrade.backend.the_telephone import TheTelephone
from komrade.backend.komrades import KomradeX
global PHONEBOOK
# already have?
if not name and not pubkey: return KomradeX()
if name in PHONEBOOK: return PHONEBOOK[name]
pk64 = None if not pubkey else b64enc(pubkey)
if pk64 in PHONEBOOK: return PHONEBOOK[pk64]
# print(f'finding Komrade {name} / {pubkey} for the first time!')
# operator?
if name==OPERATOR_NAME:
kommie = TheOperator() #(*x,**y)
if name==TELEPHONE_NAME:
kommie = TheTelephone() #(*x,**y)
else:
2020-09-14 08:49:25 +00:00
# print('booting new kommie')
2020-09-14 06:25:43 +00:00
kommie = KomradeX(name,*x,**y)
# print('found!',name,PHONEBOOK[name],PHONEBOOK[name].keychain())
PHONEBOOK[name] = kommie
if kommie.pubkey:
PHONEBOOK[kommie.pubkey.data_b64] = kommie
return kommie
2020-09-06 06:50:23 +00:00
2020-09-13 20:15:29 +00:00
2020-09-04 15:50:08 +00:00
2020-09-15 11:25:15 +00:00
# from komrade.constants import OPERATOR_ROUTES
2020-09-04 15:50:08 +00:00
class Operator(Keymaker):
2020-09-15 11:24:46 +00:00
ROUTES = [
2020-09-15 11:24:15 +00:00
'register_new_user',
'login',
'deliver_msg',
'check_msgs',
'download_msgs',
'introduce_komrades'
]
2020-09-14 06:02:17 +00:00
2020-09-14 07:58:26 +00:00
def __eq__(self,other):
return self.pubkey.data == other.pubkey.data
2020-09-14 06:02:17 +00:00
2020-09-14 07:58:26 +00:00
def __init__(self,
name=None,
pubkey=None,
keychain = {},
path_crypt_keys=PATH_CRYPT_CA_KEYS,
path_crypt_data=PATH_CRYPT_CA_DATA
):
2020-09-14 06:25:43 +00:00
global PHONEBOOK
2020-09-12 20:19:53 +00:00
2020-09-14 07:58:26 +00:00
# call Keymaker's intro
super().__init__(
name=name,
keychain=keychain,
path_crypt_keys=path_crypt_keys,
path_crypt_data=path_crypt_data
)
2020-09-14 06:25:43 +00:00
# add to phonebook
2020-09-14 07:58:26 +00:00
if name: PHONEBOOK[name]=self
2020-09-14 20:10:31 +00:00
if self.pubkey: PHONEBOOK[self.pubkey.data_b64]=self
2020-09-12 16:33:54 +00:00
2020-09-12 20:20:27 +00:00
2020-09-07 17:11:52 +00:00
@property
def phone(self):
2020-09-07 20:00:21 +00:00
from komrade.backend.the_telephone import TheTelephone
if type(self)==TheTelephone: return self
2020-09-07 17:50:58 +00:00
if hasattr(self,'_phone'): return self._phone
2020-09-07 20:00:21 +00:00
2020-09-07 17:11:52 +00:00
global TELEPHONE,TELEPHONE_KEYCHAIN
if TELEPHONE: return TELEPHONE
2020-09-07 20:00:21 +00:00
2020-09-07 17:50:58 +00:00
self._phone=TELEPHONE=TheTelephone()
2020-09-07 20:00:21 +00:00
2020-09-07 17:11:52 +00:00
return TELEPHONE
@property
def op(self):
2020-09-07 20:00:21 +00:00
from komrade.backend.the_operator import TheOperator
if type(self)==TheOperator: return self
if hasattr(self,'_op'): return self._op
2020-09-07 17:11:52 +00:00
global OPERATOR,OPERATOR_KEYCHAIN
if OPERATOR: return OPERATOR
2020-09-07 20:00:21 +00:00
self._op=OPERATOR=TheOperator()
2020-09-07 17:11:52 +00:00
return OPERATOR
2020-09-09 14:38:37 +00:00
2020-09-14 07:58:26 +00:00
def compose_msg_to(self,msg,another,incl_from_name=True,incl_to_name=True):
2020-09-08 15:14:48 +00:00
if not self.privkey or not self.pubkey:
2020-09-15 08:51:52 +00:00
raise KomradeException('I appear not yet to have an encryption keypair.',self,self.name,self.pubkey,self.privkey,self.keychain())
2020-09-08 15:14:48 +00:00
if not another.name or not another.pubkey:
2020-09-14 03:55:22 +00:00
self.log(f'I {self} failed to compose a message to {another} ?')
2020-09-15 08:51:52 +00:00
raise KomradeException('I do not know the Komrade I am writing to.')
2020-09-08 15:14:48 +00:00
2020-09-09 14:38:37 +00:00
# otherwise create msg
2020-09-12 20:51:27 +00:00
frompub = self.pubkey.data if hasattr(self.pubkey,'data') else self.pubkey
topub = another.pubkey.data if hasattr(another.pubkey,'data') else another.pubkey
2020-09-09 11:01:27 +00:00
msg_d = {
2020-09-12 20:51:27 +00:00
'from':frompub,
2020-09-12 18:18:37 +00:00
# 'from_name':self.name,
2020-09-12 20:51:27 +00:00
'to':topub,
2020-09-12 18:18:37 +00:00
# 'to_name':another.name,
'msg':msg
2020-09-08 11:23:41 +00:00
}
2020-09-12 18:18:37 +00:00
if incl_from_name: msg_d['from_name']=self.name
2020-09-13 08:43:59 +00:00
if incl_to_name: msg_d['to_name']=another.name
2020-09-09 18:31:36 +00:00
# self.log(f'I am {self} packaging a message to {another}: {msg_d}')
2020-09-09 22:10:58 +00:00
from komrade.backend.messages import Message
2020-09-09 14:38:37 +00:00
2020-09-14 06:02:17 +00:00
msg_obj = Message(msg_d)
2020-09-09 18:31:36 +00:00
2020-09-09 19:15:35 +00:00
# encrypt!
2020-09-09 22:26:48 +00:00
# msg_obj.encrypt()
2020-09-09 14:38:37 +00:00
return msg_obj
2020-09-13 09:00:25 +00:00
2020-09-07 20:00:21 +00:00
2020-09-09 18:31:36 +00:00
def __repr__(self):
clsname=(type(self)).__name__
2020-09-12 18:18:37 +00:00
#name = clsname+' '+
2020-09-13 06:18:52 +00:00
name = '@'+ (self.name if self.name else '?') # if self.name!=clsname else clsname
2020-09-12 18:18:37 +00:00
# try:
# keystr= 'on device: ' + ('+'.join(self.top_keys) if self.pubkey else '')
# except TypeError:
# keystr=''
# # if self.pubkey:
keystr=''
2020-09-10 08:23:44 +00:00
if False:
2020-09-10 08:22:21 +00:00
pubk=self.pubkey_b64.decode()
2020-09-10 08:23:05 +00:00
pubk=pubk[-5:]
2020-09-10 08:22:21 +00:00
pubk = f' ({pubk})'# if pubk else ''
else:
pubk = ''
2020-09-12 18:18:37 +00:00
return f'{name}' #' ({keystr})'
2020-09-09 18:31:36 +00:00
2020-09-12 20:19:53 +00:00
2020-09-09 21:30:14 +00:00
2020-09-13 09:25:38 +00:00
def route_msg(self,msg_obj,reencrypt=True,new_data=None):
2020-09-09 21:30:14 +00:00
# decrypt
2020-09-13 08:34:32 +00:00
# self.log('got msg_obj!',msg_obj)
2020-09-10 07:53:40 +00:00
if msg_obj.is_encrypted:
msg_obj.decrypt()
2020-09-10 11:57:53 +00:00
# try route
2020-09-10 11:58:17 +00:00
if msg_obj.route:
2020-09-10 11:57:53 +00:00
data,route = msg_obj.data, msg_obj.route
2020-09-10 11:59:06 +00:00
if not hasattr(self,route) or route not in self.ROUTES:
2020-09-10 11:57:53 +00:00
raise KomradeException(f'Not a valid route!: {route}')
# route it!
2020-09-13 11:27:26 +00:00
self.log(f'Routing msg to {self}.{route}():\n\n{dict_format(msg_obj.data,tab=4)}')
2020-09-10 11:57:53 +00:00
func = getattr(self,route)
2020-09-14 07:58:26 +00:00
# new_data = func(**data)
new_data = func(msg_obj)
2020-09-14 22:05:08 +00:00
self.log(f'New data was received back from {self}.{route}() route:\b\b{new_data}')
2020-09-13 09:49:19 +00:00
msg_obj.msg = msg_obj.msg_d['msg'] = new_data
2020-09-10 11:57:53 +00:00
# try passing it on?
if msg_obj.has_embedded_msg:
new_data = self.route_msg(msg_obj.msg)
2020-09-13 09:49:19 +00:00
msg_obj.msg = msg_obj.msg_d['msg'] = new_data
2020-09-10 11:57:53 +00:00
2020-09-13 10:33:43 +00:00
if not new_data or not reencrypt:
2020-09-13 09:25:38 +00:00
# end of the line?
return msg_obj
2020-09-10 11:57:53 +00:00
# time to turn around and encrypt
2020-09-14 22:22:50 +00:00
# @unsure?``
2020-09-13 10:28:57 +00:00
# from komrade.backend.komrades import Komrade
# if self != self.phone and type(self)!=Komrade:
# # if client, let the request rest
# return msg_obj
2020-09-13 10:14:52 +00:00
2020-09-14 04:07:06 +00:00
# # if remote operator, keep going?
# self.log('time to flip msg around and return to sender. v1:',msg_obj,dict_format(msg_obj.msg_d))#,new_data,reencrypt,msg_obj.route)
2020-09-14 03:58:43 +00:00
2020-09-14 04:07:06 +00:00
# new_msg_obj = msg_obj.to_whom.compose_msg_to(
# msg=new_data,
# another=msg_obj.from_whom
# ) #msg_obj.mark_return_to_sender()
# self.log('returning to sender as:',new_msg_obj)
new_msg_obj = msg_obj.return_to_sender(new_data)
2020-09-10 11:57:53 +00:00
# encrypt
2020-09-10 12:04:12 +00:00
if reencrypt:
2020-09-13 10:37:47 +00:00
# self.log('reencrypting v1',new_msg_obj)
2020-09-13 09:15:44 +00:00
new_msg_obj.encrypt()
2020-09-13 10:37:47 +00:00
# self.log('reencrypting v2',new_msg_obj)
2020-09-13 10:19:54 +00:00
2020-09-10 11:57:53 +00:00
2020-09-13 09:15:44 +00:00
return new_msg_obj
2020-09-10 11:57:53 +00:00
2020-09-12 18:18:37 +00:00
def ring_ring(self,msg,to_whom,get_resp_from=None,route=None,caller=None):
2020-09-09 23:23:27 +00:00
# ring ring
2020-09-12 13:11:39 +00:00
from komrade.cli.artcode import ART_PHONE_SM1
2020-09-12 14:32:03 +00:00
import textwrap as tw
2020-09-14 06:02:17 +00:00
2020-09-12 18:18:37 +00:00
if caller!=self:
2020-09-12 18:43:50 +00:00
from komrade.cli.artcode import ART_PHONE_SM1
self.log(f'ring ring! I the {self} have received a message from {caller},\n which I will now encrypt and send along to {to_whom}.\n {ART_PHONE_SM1} ')
2020-09-12 18:18:37 +00:00
else:
2020-09-12 18:43:50 +00:00
pass
2020-09-13 08:01:10 +00:00
self.log(f'I ({self}) will now compose and send an encrypted message to {to_whom}.')
2020-09-12 14:32:03 +00:00
2020-09-12 18:18:37 +00:00
if route and type(msg)==dict and not ROUTE_KEYNAME in msg:
msg[ROUTE_KEYNAME] = route
2020-09-12 14:32:03 +00:00
2020-09-09 23:23:27 +00:00
# get encr msg obj
2020-09-12 18:18:37 +00:00
2020-09-09 23:23:27 +00:00
msg_obj = self.compose_msg_to(
msg,
2020-09-12 18:18:37 +00:00
to_whom
2020-09-09 23:23:27 +00:00
)
2020-09-13 08:01:10 +00:00
self.log(f'Here is the message I will now encrypt and to send to {to_whom}:\n\n {dict_format(msg_obj.msg,tab = 2)}')
2020-09-09 23:23:27 +00:00
# encrypting
msg_obj.encrypt()
2020-09-10 11:57:53 +00:00
# pass through the telephone wire by the get_resp_from function
2020-09-09 23:23:27 +00:00
if not get_resp_from: get_resp_from=to_whom.ring_ring
2020-09-13 10:24:19 +00:00
resp_msg_obj = get_resp_from(msg_obj.msg_d,caller=caller)
2020-09-13 05:59:03 +00:00
#self.log('resp_msg_obj <-',resp_msg_obj)
if not resp_msg_obj:
2020-09-13 05:59:47 +00:00
print('!! no response from op !!')
exit()
2020-09-09 23:23:27 +00:00
2020-09-10 11:57:53 +00:00
# decrypt
2020-09-10 08:08:50 +00:00
if resp_msg_obj.is_encrypted:
resp_msg_obj.decrypt()
2020-09-09 23:23:27 +00:00
# route back?
2020-09-10 12:05:03 +00:00
return self.route_msg(resp_msg_obj,reencrypt=False).msg
2020-09-09 23:23:27 +00:00
2020-09-09 23:18:22 +00:00
def pronto_pronto(self, msg_obj):
2020-09-13 08:33:14 +00:00
self.log(f'''*ring *ring*
...
2020-09-13 08:04:56 +00:00
{self}: pronto?
2020-09-13 08:54:01 +00:00
{msg_obj.from_whom}: Ciao ciao. I have a message for you:\n{msg_obj}\n''')
2020-09-09 23:18:22 +00:00
2020-09-10 12:04:12 +00:00
return self.route_msg(msg_obj,reencrypt=True)
2020-09-10 11:57:53 +00:00
# route_response = self.route_msg(msg_obj)
# self.log('route_response',route_response)
# # set this to be the new msg
2020-09-12 18:18:37 +00:00
# #msg_obj.msg = msg_obj.msg_d['msg'] = response
2020-09-10 11:57:53 +00:00
# #self.log('what msg_obj looks like now:',msg_obj)
# # send new content back
# # from komrade.backend.messages import Message
# # if type(route_response)==Message:
# # resp_msg_obj = route_response
# # else:
# resp_msg_obj = msg_obj.to_whom.compose_msg_to(
# route_response,
# msg_obj.from_whom
# )
# self.log('resp_msg_obj',resp_msg_obj)
2020-09-09 22:23:51 +00:00
2020-09-10 11:57:53 +00:00
# # re-encrypt
# if not resp_msg_obj.is_encrypted:
# resp_msg_obj.encrypt()
# self.log(f're-encrypted: {resp_msg_obj}')
2020-09-09 21:30:14 +00:00
2020-09-10 11:57:53 +00:00
# # pass msg back the chain
# return resp_msg_obj
2020-09-09 14:38:37 +00:00