2020-09-06 06:50:23 +00:00
"""
There is only one operator !
Running on node prime .
"""
# internal imports
import os , sys ; sys . path . append ( os . path . abspath ( os . path . join ( os . path . abspath ( os . path . join ( os . path . dirname ( __file__ ) , ' .. ' ) ) , ' .. ' ) ) )
from komrade import *
2020-09-06 20:17:47 +00:00
from komrade . backend import *
2020-09-06 06:50:23 +00:00
2020-09-07 13:33:47 +00:00
# print(PATH_OPERATOR_WEB_KEYS_URL)
2020-09-07 13:04:23 +00:00
2020-09-06 06:50:23 +00:00
class TheOperator ( Operator ) :
"""
2020-09-06 20:05:03 +00:00
The remote operator
2020-09-06 06:50:23 +00:00
"""
2020-09-06 20:17:47 +00:00
@property
def phone ( self ) :
2020-09-06 20:25:18 +00:00
global TELEPHONE
2020-09-06 20:30:36 +00:00
from komrade . backend . the_telephone import TheTelephone
2020-09-07 17:27:46 +00:00
if not TELEPHONE : TELEPHONE = TheTelephone ( )
2020-09-06 20:17:47 +00:00
return TELEPHONE
2020-09-06 06:50:23 +00:00
2020-09-12 19:17:07 +00:00
def __init__ ( self , name = OPERATOR_NAME , passphrase = None ) :
2020-09-06 06:50:23 +00:00
"""
Boot up the operator . Requires knowing or setting a password of memory .
"""
2020-09-12 19:17:07 +00:00
self . passphrase = passphrase
2020-09-07 17:27:46 +00:00
super ( ) . __init__ (
name ,
2020-09-12 19:12:17 +00:00
passphrase ,
2020-09-07 17:27:46 +00:00
path_crypt_keys = PATH_CRYPT_OP_KEYS ,
2020-09-09 14:38:37 +00:00
path_crypt_data = PATH_CRYPT_OP_DATA
)
2020-09-12 17:00:06 +00:00
from komrade . backend . phonelines import check_phonelines
keychain = check_phonelines ( ) [ OPERATOR_NAME ]
self . _keychain = self . load_keychain_from_bytes ( keychain )
2020-09-12 19:18:18 +00:00
self . _keychain = self . keychain ( )
2020-09-13 07:09:03 +00:00
# self.log('@Operator booted with keychain:',dict_format(self._keychain),'and passphrase',self.passphrase)
2020-09-12 19:15:58 +00:00
2020-09-08 12:11:13 +00:00
def ring ( self ,
2020-09-07 21:29:02 +00:00
from_caller = None ,
to_caller = None ,
json_phone2phone = { } ,
json_caller2phone = { } , # (person) -> operator or operator -> (person)
json_caller2caller = { } ) :
2020-09-08 12:11:13 +00:00
encr_msg_to_send = super ( ) . ring (
2020-09-07 21:29:02 +00:00
from_phone = self ,
to_phone = self . phone ,
from_caller = from_caller ,
to_caller = to_caller ,
json_phone2phone = json_phone2phone ,
json_caller2phone = json_caller2phone , # (person) -> operator
json_caller2caller = json_caller2caller )
return self . send ( encr_msg_to_send )
2020-09-08 15:44:17 +00:00
# ends the ring_ring() chain
2020-09-09 21:38:32 +00:00
def answer_phone ( self , data_b ) :
2020-09-08 15:44:17 +00:00
# route incoming call from the switchboard
2020-09-13 07:34:01 +00:00
from komrade . cli . artcode import ART_OLDPHONE4
2020-09-13 09:02:42 +00:00
from komrade . backend . messages import Message
2020-09-13 08:21:36 +00:00
self . log ( f ''' Hello, this is the Operator. { ART_OLDPHONE4 } I heard you say: \n \n { b64enc_s ( data_b ) } ''' )
2020-09-09 14:47:26 +00:00
# unseal
2020-09-13 09:42:22 +00:00
# self.log('got:',data_b)
2020-09-13 09:08:33 +00:00
msg_d = {
2020-09-13 09:09:28 +00:00
' msg ' : data_b ,
2020-09-13 09:10:34 +00:00
' from_name ' : self . phone . name ,
2020-09-13 09:09:28 +00:00
' from ' : self . phone . pubkey . data ,
' to_name ' : self . name ,
' to ' : self . pubkey . data ,
2020-09-13 09:08:33 +00:00
}
# msg_d = pickle.loads(data_b)
2020-09-13 09:42:22 +00:00
# self.log('msg_d',msg_d)
2020-09-13 09:09:28 +00:00
msg_obj = Message ( msg_d , from_whom = self . phone , to_whom = self )
2020-09-13 09:02:42 +00:00
2020-09-13 09:42:22 +00:00
self . log ( f ' Decoding the binary, I discovered an encrypted message from { self . phone } \n : { msg_obj } ' )
2020-09-09 19:31:57 +00:00
2020-09-09 23:01:08 +00:00
# decrypt?
msg_obj . decrypt ( )
2020-09-09 15:14:51 +00:00
# carry out message instructions
2020-09-13 10:21:59 +00:00
resp_msg_obj = self . route_msg ( msg_obj , reencrypt = True ) #,route=msg_obj.route)
2020-09-13 10:17:34 +00:00
self . log ( ' route_result <- ' , resp_msg_obj )
2020-09-09 15:14:51 +00:00
# send back down encrypted
2020-09-13 10:17:34 +00:00
self . log ( ' route msgd ' , resp_msg_obj . msg_d )
self . log ( ' route msg ' , resp_msg_obj . msg )
2020-09-13 10:21:59 +00:00
2020-09-13 07:07:39 +00:00
2020-09-13 10:24:19 +00:00
msg_sealed = pickle . dumps ( resp_msg_obj . msg_d )
self . log ( ' msg_sealed = ' , msg_sealed )
2020-09-09 15:14:51 +00:00
# return back to phone and back down to chain
return msg_sealed
2020-09-08 16:09:51 +00:00
2020-09-08 15:44:17 +00:00
2020-09-06 06:50:23 +00:00
2020-09-07 18:55:34 +00:00
def send ( self , encr_data_b ) :
2020-09-07 22:56:43 +00:00
self . log ( type ( encr_data_b ) , encr_data_b , ' sending! ' )
2020-09-07 22:53:56 +00:00
return encr_data_b
2020-09-07 08:44:40 +00:00
2020-09-09 17:34:19 +00:00
### ROUTES
2020-09-07 08:44:40 +00:00
2020-09-10 09:00:11 +00:00
def does_username_exist ( self , name , * * data ) :
2020-09-09 17:48:56 +00:00
pubkey = self . crypt_keys . get ( name , prefix = ' /pubkey/ ' )
2020-09-09 17:45:29 +00:00
self . log ( f ' looking for { name } , found { pubkey } as pubkey ' )
return bool ( pubkey )
2020-09-09 17:34:19 +00:00
2020-09-13 06:25:31 +00:00
def register_new_user ( self , name , pubkey , * * data ) :
2020-09-10 12:52:07 +00:00
# self.log('setting pubkey under name')
2020-09-10 15:28:54 +00:00
success , ck , cv_b64 = self . crypt_keys . set ( name , pubkey , prefix = ' /pubkey/ ' )
2020-09-13 06:25:31 +00:00
if not isBase64 ( pubkey ) : pubkey = b64encode ( pubkey )
2020-09-13 08:51:10 +00:00
# self.log(f'''
# got result from crypt:
# success = {success}
# ck = {ck}
# cv = {cv_b64}
# ''')
2020-09-13 06:25:31 +00:00
success , ck , cv_b64 = self . crypt_keys . set ( pubkey , name , prefix = ' /name/ ' )
2020-09-13 08:47:48 +00:00
# self.log(f'''
# got result from crypt:
# success = {success}
# ck = {ck}
# cv = {cv_b64}
# ''')
2020-09-10 12:52:07 +00:00
# check input back from crypt
2020-09-10 13:49:17 +00:00
# if success and b64decode(cv)!=pubkey: success=False
# if success and name!=self.crypt_keys.key2hash(name): success=False
2020-09-13 08:10:22 +00:00
from komrade . utils import b64dec
2020-09-10 12:52:07 +00:00
res = {
' success ' : success ,
2020-09-13 08:47:48 +00:00
' pubkey ' : pubkey ,
2020-09-10 12:52:07 +00:00
' name ' : name ,
}
2020-09-10 14:16:53 +00:00
if not success :
res [ ' status ' ] = self . status ( f " { OPERATOR_INTRO } I ' m sorry, but I can ' t register the name of { name } . " )
return res
2020-09-13 07:02:11 +00:00
self . log ( ' Operator returning result: ' , dict_format ( res , tab = 2 ) )
2020-09-13 08:47:25 +00:00
return res
2020-09-10 12:52:07 +00:00
2020-09-10 15:28:54 +00:00
# give back decryptor
2020-09-10 14:16:53 +00:00
2020-09-10 12:52:07 +00:00
## success msg
2020-09-10 14:16:53 +00:00
#
2020-09-10 15:28:54 +00:00
cvb64 = cv_b64 #b64encode(cv).decode()
2020-09-10 14:16:53 +00:00
qrstr = self . qr_str ( cvb64 )
res [ ' status ' ] = self . status ( f ''' { OPERATOR_INTRO } I have successfully registered Komrade { name } .
If you ' re interested, here ' s what I did . I stored the public key you gave me , { cvb64 } , under the name of " {name} " . However , I never save that name directly , but record it only in a disguised , " hashed " form : { ck } . I scrambled " {name} " by running it through a 1 - way hashing function , which will always yield the same result : provided you know which function I ' m using, and what the secret " salt " is that I add to all the input, a string of text which I keep protected and encrypted on my local hard drive.
2020-09-07 18:55:34 +00:00
2020-09-10 14:16:53 +00:00
The content of your data will therefore not only be encrypted , but its location in my database is obscured even to me . There ' s no way for me to reverse-engineer the name of {name} from the record I stored it under, {ck} . Unless you explictly ask me for the public key of {name} , I will have no way of accessing that information.
Your name ( { name } ) and your public key ( { cvb64 } ) are the first two pieces of information you ' ve given me about yourself. Your public key is your ' address ' in Komrade: in order for anyone to write to you, or for them to receive messages from you, they ' ll need to know your public key ( and vise versa ) . The Komrade app should store your public key on your device as a QR code , under ~ / . komrade / . contacts / { name } . png . It will look something like this : { qrstr } You can then send this image to anyone by a secure channel ( Signal , IRL , etc ) , or tell them the code directly ( { cvb64 } ) .
By default , if anyone asks me what your public key is , I won ' t tell them--though I won ' t be able to avoid hinting that a user exists under this name should someone try to register under that name and I deny them ) . Instead , if the person who requested your public key insists , I will send you a message ( encrypted end - to - end so only you can read it ) that the user who met someone would like to introduce themselves to you ; I will then send you their name and public key . It ' s now your move: up to you whether to save them back your public key.
2020-09-13 06:29:51 +00:00
If you ' d like to change this default behavior, e.g. by instead allowing anyone to request your public key, except for those whom you explcitly block, I have also created a super secret administrative record for you to change various settings on your account. This is protected by a separate encryption key which I have generated for you; and this key which is itself encrypted with the password you entered earlier. Don ' t worry : I never saw that password you typed , since it was given to me already hashed and disguised . Without that hashed passphrase , no one will be able to unlock the administration key ; and without the administration key , they won ' t be able to find the hashed record I stored your user settings under, since I also salted that hash with your own hashed passphrase. Even if someone found the record I stored them under, they wouldn ' t be able to decrypt the existing settings ; and if they can ' t do that, I won ' t let them overwrite the record . ''' )
2020-09-10 14:16:53 +00:00
self . log ( ' Operator returning result: ' , dict_format ( res , tab = 2 ) )
2020-09-07 08:44:40 +00:00
2020-09-06 06:50:23 +00:00
2020-09-07 13:04:23 +00:00
2020-09-06 06:50:23 +00:00
def test_op ( ) :
2020-09-06 19:39:44 +00:00
from komrade . backend . the_telephone import TheTelephone
2020-09-13 06:01:06 +00:00
from getpass import getpass
2020-09-13 07:00:21 +00:00
op = TheOperator ( )
2020-09-06 19:39:44 +00:00
# op.boot()
2020-09-13 06:00:28 +00:00
keychain_op = op . keychain ( )
2020-09-06 19:39:44 +00:00
2020-09-06 19:19:44 +00:00
2020-09-06 19:39:44 +00:00
phone = TheTelephone ( )
# phone.boot()
2020-09-13 06:00:28 +00:00
keychain_ph = phone . keychain ( )
2020-09-06 19:19:44 +00:00
2020-09-06 19:18:43 +00:00
from pprint import pprint
2020-09-06 19:19:44 +00:00
print ( ' REASSEMBLED OPERATOR KEYCHAIN ' )
pprint ( keychain_op )
# stop
2020-09-06 19:18:43 +00:00
print ( ' REASSEMBLED TELEPHONE KEYCHAIN ' )
2020-09-06 19:19:44 +00:00
pprint ( keychain_ph )
2020-09-06 19:18:43 +00:00
2020-09-06 17:44:08 +00:00
# print(op.pubkey(keychain=keychain))
2020-09-06 18:52:47 +00:00
# print(op.crypt_keys.get(op.pubkey(), prefix='/privkey_encr/'))
2020-09-06 18:51:25 +00:00
# print(op.crypt_keys.get(op.name, prefix='/pubkey_encr/'))
2020-09-06 19:18:43 +00:00
# print(op.pubkey_)
2020-09-06 18:52:47 +00:00
2020-09-06 17:42:57 +00:00
2020-09-06 19:18:43 +00:00
# stop
2020-09-06 06:50:23 +00:00
2020-09-06 19:18:43 +00:00
# pubkey = op.keychain()['pubkey']
# pubkey_b64 = b64encode(pubkey)
# print(pubkey)
2020-09-06 06:50:23 +00:00
if __name__ == ' __main__ ' : test_op ( )