You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Comrad/komrade/backend/operators.py

311 lines
10 KiB
Python

4 years ago
# internal imports
4 years ago
import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
4 years ago
from komrade import *
4 years ago
# from komrade.backend.crypt import *
# from komrade.backend.keymaker import *
# from komrade.backend.mazes import *
# from komrade.backend.switchboard import *
from komrade.backend import *
4 years ago
4 years ago
4 years ago
def locate_an_operator(name=None,pubkey=None):
4 years ago
global OPERATOR,TELEPHONE
from komrade.backend.the_operator import TheOperator
from komrade.backend.the_telephone import TheTelephone
from komrade.backend.callers import Caller
4 years ago
if not OPERATOR: OPERATOR = TheOperator()
if not TELEPHONE: TELEPHONE = TheTelephone()
if pubkey:
assert type(pubkey)==bytes
if not isBase64(pubkey): pubkey=b64encode(pubkey)
4 years ago
4 years ago
if name == OPERATOR_NAME:
4 years ago
return OPERATOR
4 years ago
if pubkey and pubkey == OPERATOR.pubkey:
4 years ago
return OPERATOR
4 years ago
4 years ago
if name==TELEPHONE_NAME:
return TELEPHONE
4 years ago
if pubkey and pubkey == TELEPHONE.pubkey:
4 years ago
return TELEPHONE
return Caller(name=name,pubkey=pubkey)
4 years ago
4 years ago
4 years ago
from komrade.constants import OPERATOR_ROUTES
4 years ago
class Operator(Keymaker):
4 years ago
ROUTES = OPERATOR_ROUTES
4 years ago
4 years ago
def __init__(self, name=None, passphrase=DEBUG_DEFAULT_PASSPHRASE, pubkey=None, keychain = {}, path_crypt_keys=PATH_CRYPT_CA_KEYS, path_crypt_data=PATH_CRYPT_CA_DATA):
4 years ago
# print('booting opertor with ...',name,pubkey,'??')
4 years ago
4 years ago
if pubkey:
4 years ago
print(pubkey,'pubkey !?')
4 years ago
assert type(pubkey)==bytes
if isBase64(pubkey): pubkey = b64decode(pubkey)
4 years ago
# print(pubkey,keychain,'??',name)
4 years ago
if keychain.get('pubkey'):
4 years ago
kcpubk=keychain.get('pubkey').data
# kcpubk = b64decode(kcpubk) if isBase64(kcpubk) else kcpubk
# assert kcpubk == pubkey
4 years ago
else:
4 years ago
keychain['pubkey']=pubkey #KomradeAsymmetricPublicKey(pubkey)
4 years ago
4 years ago
super().__init__(name=name,passphrase=passphrase, keychain=keychain,
path_crypt_keys=path_crypt_keys, path_crypt_data=path_crypt_data)
4 years ago
4 years ago
self.find_pubkey_and_name(name,pubkey)
4 years ago
# print('booted with operator with:',self.name,self.pubkey,self.find_pubkey(name),'??')
4 years ago
4 years ago
# def boot(self):
# ## get both name and pubkey somehow
# if not self.pubkey and self.name:
# self._keychain['pubkey'] = self.find_pubkey()
# elif self.pubkey and not self.name:
4 years ago
4 years ago
4 years ago
# def boot(self,create=False):
# # Do I have my keys?
# have_keys = self.exists()
4 years ago
# # If not, forge them -- only once!
# if not have_keys and create:
# self.get_new_keys()
4 years ago
4 years ago
@property
def phone(self):
4 years ago
from komrade.backend.the_telephone import TheTelephone
if type(self)==TheTelephone: return self
4 years ago
if hasattr(self,'_phone'): return self._phone
4 years ago
4 years ago
global TELEPHONE,TELEPHONE_KEYCHAIN
if TELEPHONE: return TELEPHONE
4 years ago
4 years ago
self._phone=TELEPHONE=TheTelephone()
4 years ago
4 years ago
return TELEPHONE
@property
def op(self):
4 years ago
from komrade.backend.the_operator import TheOperator
if type(self)==TheOperator: return self
if hasattr(self,'_op'): return self._op
4 years ago
global OPERATOR,OPERATOR_KEYCHAIN
if OPERATOR: return OPERATOR
4 years ago
self._op=OPERATOR=TheOperator()
4 years ago
return OPERATOR
4 years ago
4 years ago
def compose_msg_to(self,msg,another,incl_from_name=False,incl_to_name=False):
4 years ago
if not self.privkey or not self.pubkey:
4 years ago
raise KomradeException('why do I have no pub/privkey pair!?',self,self.name,self.pubkey,self.privkey,self.keychain())
4 years ago
if not another.name or not another.pubkey:
4 years ago
raise KomradeException('why do I not know whom I\'m writing to?')
4 years ago
4 years ago
# otherwise create msg
4 years ago
frompub = self.pubkey.data if hasattr(self.pubkey,'data') else self.pubkey
topub = another.pubkey.data if hasattr(another.pubkey,'data') else another.pubkey
4 years ago
msg_d = {
4 years ago
'from':frompub,
4 years ago
# 'from_name':self.name,
4 years ago
'to':topub,
4 years ago
# 'to_name':another.name,
'msg':msg
4 years ago
}
4 years ago
if incl_from_name: msg_d['from_name']=self.name
if incl_to_name: msg_d['to_name']=self.name
4 years ago
# self.log(f'I am {self} packaging a message to {another}: {msg_d}')
4 years ago
from komrade.backend.messages import Message
4 years ago
4 years ago
msg_obj = Message(msg_d,from_whom=self,to_whom=another)
4 years ago
4 years ago
# encrypt!
4 years ago
# msg_obj.encrypt()
4 years ago
return msg_obj
4 years ago
# def compose_reply(self,msg,another):
4 years ago
# def seal_msg(self,msg_d):
# msg_b = pickle.dumps(msg_d)
# self.log('Message has being sealed in a final binary package:',b64encode(msg_b))
# return msg_b
4 years ago
4 years ago
def unseal_msg(self,msg_b,from_whom=None,to_whom=None):
4 years ago
# default to assumption that I am the recipient
if not to_whom: to_whom=self
4 years ago
# decrypt by omega
4 years ago
# msg_b = self.omega_key.decrypt(msg_b_encr)
4 years ago
# msg_b = msg_b_encr
4 years ago
# unpackage from transmission
4 years ago
# msg_d = pickle.loads(msg_b)
4 years ago
# get message obj
4 years ago
# print('unsealed msg:',msg_d)
4 years ago
msg_d = {
4 years ago
'from':from_whom.pubkey.data,
'to':to_whom.pubkey.data,
4 years ago
'msg':msg_b
}
4 years ago
from komrade.backend.messages import Message
4 years ago
msg_obj = Message(msg_d,from_whom=from_whom,to_whom=to_whom)
4 years ago
# decrypt msg
return msg_obj
4 years ago
4 years ago
def __repr__(self):
clsname=(type(self)).__name__
4 years ago
#name = clsname+' '+
4 years ago
name = '@'+ (self.name if self.name else '?') # if self.name!=clsname else clsname
4 years ago
# try:
# keystr= 'on device: ' + ('+'.join(self.top_keys) if self.pubkey else '')
# except TypeError:
# keystr=''
# # if self.pubkey:
keystr=''
4 years ago
if False:
4 years ago
pubk=self.pubkey_b64.decode()
4 years ago
pubk=pubk[-5:]
4 years ago
pubk = f' ({pubk})'# if pubk else ''
else:
pubk = ''
4 years ago
return f'{name}' #' ({keystr})'
4 years ago
4 years ago
4 years ago
4 years ago
def route_msg(self,msg_obj,reencrypt=True):
4 years ago
# decrypt
4 years ago
self.log('got msg_obj!',msg_obj)
4 years ago
if msg_obj.is_encrypted:
msg_obj.decrypt()
4 years ago
# try route
4 years ago
if msg_obj.route:
4 years ago
data,route = msg_obj.data, msg_obj.route
4 years ago
if not hasattr(self,route) or route not in self.ROUTES:
4 years ago
raise KomradeException(f'Not a valid route!: {route}')
# route it!
func = getattr(self,route)
new_data = func(**data)
4 years ago
msg_obj.msg = msg_obj.msg_d['msg'] = new_data
4 years ago
# try passing it on?
if msg_obj.has_embedded_msg:
new_data = self.route_msg(msg_obj.msg)
4 years ago
msg_obj.msg = msg_obj.msg_d['msg'] = new_data
4 years ago
# time to turn around and encrypt
msg_obj.mark_return_to_sender()
self.log('returning to sender as:',msg_obj)
# encrypt
4 years ago
if reencrypt:
msg_obj.encrypt()
4 years ago
4 years ago
return msg_obj
4 years ago
4 years ago
def ring_ring(self,msg,to_whom,get_resp_from=None,route=None,caller=None):
4 years ago
# ring ring
4 years ago
from komrade.cli.artcode import ART_PHONE_SM1
4 years ago
import textwrap as tw
4 years ago
nxt=get_class_that_defined_method(get_resp_from).__name__
nxtfunc=get_resp_from.__name__
# if from_whom != self:
# self.status(f'''ring ring!
# @{self}: *picks up phone*
# @{from_whom}: I have a message I need you to send for me.
# @{self}: To whom?
# @{from_whom}: To @{to_whom}. But not directly.
# @{self}: Who should it I pass it through?
# @{from_whom}: Pass it to {nxt}. Tell them to use "{nxtfunc}".
# @{self}: Got it... So what's the message?
# @{from_whom}: The message is:
# {dict_format(msg,tab=4)}
# ''')
if caller!=self:
4 years ago
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} ')
4 years ago
else:
4 years ago
pass
# self.log(f'I ({self}) will now compose and send an encrypted message to {to_whom}.')
4 years ago
4 years ago
if route and type(msg)==dict and not ROUTE_KEYNAME in msg:
msg[ROUTE_KEYNAME] = route
4 years ago
4 years ago
# get encr msg obj
4 years ago
4 years ago
msg_obj = self.compose_msg_to(
msg,
4 years ago
to_whom
4 years ago
)
4 years ago
# 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)}')
4 years ago
# encrypting
msg_obj.encrypt()
4 years ago
# pass through the telephone wire by the get_resp_from function
4 years ago
if not get_resp_from: get_resp_from=to_whom.ring_ring
4 years ago
resp_msg_obj = get_resp_from(msg_obj.msg_d,caller=caller)
4 years ago
#self.log('resp_msg_obj <-',resp_msg_obj)
if not resp_msg_obj:
4 years ago
print('!! no response from op !!')
exit()
4 years ago
4 years ago
# decrypt
4 years ago
if resp_msg_obj.is_encrypted:
resp_msg_obj.decrypt()
4 years ago
# route back?
4 years ago
return self.route_msg(resp_msg_obj,reencrypt=False).msg
4 years ago
4 years ago
def pronto_pronto(self, msg_obj):
self.log(f'''
pronto pronto!
>> {msg_obj}
''')
4 years ago
return self.route_msg(msg_obj,reencrypt=True)
4 years ago
# route_response = self.route_msg(msg_obj)
# self.log('route_response',route_response)
# # set this to be the new msg
4 years ago
# #msg_obj.msg = msg_obj.msg_d['msg'] = response
4 years ago
# #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)
4 years ago
4 years ago
# # re-encrypt
# if not resp_msg_obj.is_encrypted:
# resp_msg_obj.encrypt()
# self.log(f're-encrypted: {resp_msg_obj}')
4 years ago
4 years ago
# # pass msg back the chain
# return resp_msg_obj
4 years ago