2020-09-08 11:23:41 +00:00
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 *
from komrade . backend import *
2020-09-11 14:35:47 +00:00
from komrade . backend . keymaker import *
2020-09-08 11:23:41 +00:00
2020-09-13 07:15:44 +00:00
class Komrade ( Caller ) :
2020-09-08 11:23:41 +00:00
2020-09-10 17:52:07 +00:00
def __init__ ( self , name = None , passphrase = DEBUG_DEFAULT_PASSPHRASE ) :
2020-09-13 19:04:43 +00:00
super ( ) . __init__ ( name = name , passphrase = passphrase )
2020-09-13 19:03:29 +00:00
# if SHOW_STATUS:
# from komrade.cli import CLI
# self.cli = CLI(name=name, komrade=self)
# self.boot(create=False)
2020-09-13 19:04:43 +00:00
# self.name=name
# pass
2020-09-08 12:11:13 +00:00
2020-09-13 18:55:14 +00:00
def boot ( self , create = False , ping = False ) :
2020-09-13 18:47:25 +00:00
# Do I already have my keys?
# yes? -- login
2020-09-08 12:11:13 +00:00
2020-09-13 18:47:25 +00:00
keys = self . keychain ( )
if keys . get ( ' pubkey ' ) and keys . get ( ' privkey ' ) :
2020-09-13 18:55:14 +00:00
self . log ( ' already booted! @ ' + self . name )
2020-09-13 18:47:25 +00:00
return True
2020-09-09 14:38:37 +00:00
2020-09-13 18:55:14 +00:00
if self . exists_locally_as_account ( ) :
self . log ( f ' this account (@ { self . name } ) can be logged into ' )
return self . login ( )
elif self . exists_locally_as_contact ( ) :
self . log ( f ' this account (@ { self . name } ) is a contact ' )
return #pass #???
elif ping and self . exists_on_server ( ) :
self . log ( f ' this account exists on server. introduce? ' )
return
elif create :
self . log ( ' account is free: register? ' )
return self . register ( )
2020-09-09 14:38:37 +00:00
2020-09-09 17:34:19 +00:00
def exists_locally_as_contact ( self ) :
return self . pubkey and not self . privkey
2020-09-13 18:55:14 +00:00
def exists_locally_as_account ( self ) :
return self . pubkey and self . privkey_encr
2020-09-09 17:34:19 +00:00
def exists_on_server ( self ) :
2020-09-10 21:32:59 +00:00
answer = self . phone . ring_ring ( {
2020-09-09 18:31:36 +00:00
' _route ' : ' does_username_exist ' ,
' name ' : self . name
} )
2020-09-09 22:38:57 +00:00
self . log ( ' answer?? ' , answer )
2020-09-10 08:08:50 +00:00
return answer
2020-09-08 11:23:41 +00:00
2020-09-09 17:34:19 +00:00
# login?
2020-09-09 17:36:07 +00:00
# def login(self):
# if keys.get('pubkey') and keys.get('privkey')
2020-09-09 17:34:19 +00:00
2020-09-11 14:35:47 +00:00
def register ( self , name = None , passphrase = None , is_group = None , show_intro = 0 , show_body = True ) :
2020-09-13 14:15:06 +00:00
# print('got name:',name)
2020-09-12 13:11:39 +00:00
## Defaults
2020-09-10 17:52:07 +00:00
if name and not self . name : self . name = name
if not name and self . name : name = self . name
2020-09-13 13:57:06 +00:00
# if not name and not self.name: name=''
2020-09-13 14:15:06 +00:00
# print('got name',name)
2020-09-12 13:11:39 +00:00
## 1) Have name?
2020-09-13 13:57:06 +00:00
tolog = ' '
2020-09-11 14:35:47 +00:00
if SHOW_STATUS and show_intro :
2020-09-13 13:57:06 +00:00
self . name = name = self . cli . status_keymaker_part1 ( name )
2020-09-12 13:17:54 +00:00
elif not name :
2020-09-13 13:57:06 +00:00
self . name = name = input ( ' \n Hello, this is Komrade @ ' )
print ( ' \n I would like to sign up for the socialist network revolution. ' , flush = True )
do_pause ( )
else :
print ( f ' Hello, this is Komrade @ { name } . \n \n I would like to sign up for the socialist network revolution. ' )
do_pause ( )
clear_screen ( )
self . log ( f ' @Keymaker: Excellent. But to communicate with komrades securely, \n you must first cut your public & private encryption keys. ' )
# do_pause()
2020-09-12 13:11:39 +00:00
## 2) Make pub public/private keys
2020-09-11 14:35:47 +00:00
keypair = KomradeAsymmetricKey ( )
pubkey , privkey = keypair . pubkey_obj , keypair . privkey_obj
2020-09-13 13:57:06 +00:00
self . log ( f ' @Keymaker: I have cut for you a private and public asymmetric key pair \n using the Elliptic Curve algorithm from Themis cryptography library: \n \n (1) { pubkey } \n \n (2) { privkey } { ART_KEY_PAIR } ' , clear = False , pause = True )
2020-09-11 14:35:47 +00:00
2020-09-12 13:11:39 +00:00
## 3) Have passphrase?
2020-09-11 17:17:21 +00:00
if SHOW_STATUS and not passphrase :
2020-09-12 14:32:03 +00:00
passphrase = self . cli . status_keymaker_part2 ( name , passphrase , pubkey , privkey , hasher , self )
2020-09-11 14:35:47 +00:00
else :
2020-09-13 05:33:37 +00:00
if not passphrase : passphrase = DEBUG_DEFAULT_PASSPHRASE
2020-09-13 05:39:38 +00:00
while not passphrase :
2020-09-13 13:57:06 +00:00
passphrase = getpass ( f ' @Keymaker: Enter a memorable password to encrypt your private key with: \n \n @ { self . name } : ' )
2020-09-13 07:50:15 +00:00
clear_screen ( )
2020-09-12 13:11:39 +00:00
## 4) Get hashed password
2020-09-12 14:32:03 +00:00
passhash = hasher ( passphrase )
2020-09-13 07:57:40 +00:00
self . log ( f ''' @Keymaker: I have replaced your password with a disguised, hashed version \n using a salted SHA-256 algorithm from python ' s hashlib: \n \n \t { make_key_discreet_str ( passhash ) } ''' )
2020-09-12 13:11:39 +00:00
## 5) Encrypt private key
2020-09-12 14:32:03 +00:00
privkey_decr = KomradeSymmetricKeyWithPassphrase ( passphrase )
2020-09-11 17:17:21 +00:00
privkey_encr = privkey_decr . encrypt ( privkey . data )
2020-09-12 07:55:23 +00:00
privkey_encr_obj = KomradeEncryptedAsymmetricPrivateKey ( privkey_encr )
2020-09-13 13:57:06 +00:00
self . log ( f " @Keymaker: Store your private key on your device hardware ONLY \n as it was encrypted by your password-generated key: \n \n [Encrypted Private Key] \n ( { make_key_discreet_str ( privkey_encr_obj . data_b64 ) } ) " )
2020-09-12 07:55:23 +00:00
2020-09-12 13:17:54 +00:00
## 6) Test keychain works
2020-09-12 14:32:03 +00:00
privkey_decr2 = KomradeSymmetricKeyWithPassphrase ( passphrase )
assert privkey_decr2 . decrypt ( privkey_encr ) == privkey . data
2020-09-12 13:17:54 +00:00
2020-09-12 14:32:03 +00:00
self . _keychain [ ' pubkey ' ] = pubkey
self . _keychain [ ' privkey_encr ' ] = privkey_encr_obj
2020-09-12 19:31:29 +00:00
# self._keychain['privkey_decr']=privkey_decr
2020-09-12 14:32:03 +00:00
# we should be able to reassemble privkey now?
2020-09-12 19:31:29 +00:00
# self.log('this is my keychain now:')
2020-09-12 14:32:03 +00:00
assert ' privkey ' in self . keychain ( )
2020-09-12 13:17:54 +00:00
2020-09-12 18:43:50 +00:00
# self.log('My keychain now looks like:',dict_format(self.keychain()))
2020-09-12 13:17:54 +00:00
2020-09-12 13:11:39 +00:00
## 6) More narration?
2020-09-12 07:55:23 +00:00
if SHOW_STATUS :
2020-09-12 13:11:39 +00:00
self . cli . status_keymaker_part3 ( privkey , privkey_decr , privkey_encr , passphrase )
2020-09-10 09:00:11 +00:00
2020-09-12 13:11:39 +00:00
## 7) Save data to server
2020-09-10 10:59:37 +00:00
data = {
2020-09-12 07:55:23 +00:00
' name ' : name ,
2020-09-12 18:18:37 +00:00
' pubkey ' : pubkey . data ,
2020-09-10 10:59:37 +00:00
}
2020-09-13 07:49:54 +00:00
self . log ( ' @Keymaker: Store your public key both on your device hardware \n as well as register it with Komrade @Operator on the remote server: \n \n ' , dict_format ( data , tab = 2 ) )
2020-09-10 21:32:59 +00:00
2020-09-10 09:31:32 +00:00
# ring operator
2020-09-10 09:34:34 +00:00
# call from phone since I don't have pubkey on record on Op yet
2020-09-12 13:11:39 +00:00
# self.log('my keychain:',self._keychain,pubkey,self.op._keychain)
2020-09-13 09:42:22 +00:00
resp_msg_d = self . ring_ring (
2020-09-12 18:18:37 +00:00
{
' name ' : name ,
' pubkey ' : pubkey . data ,
} ,
route = ' register_new_user '
)
2020-09-13 09:42:22 +00:00
if not resp_msg_d . get ( ' success ' ) :
self . log ( f ' Registration failed. Message from operator was: \n \n { dict_format ( resp_msg_d ) } ' )
return
# otherwise, save things on our end
2020-09-13 09:44:13 +00:00
self . log ( f ' Registration successful. Message from operator was: \n \n { dict_format ( resp_msg_d ) } ' )
2020-09-13 10:57:06 +00:00
2020-09-13 09:42:22 +00:00
self . name = resp_msg_d . get ( ' name ' )
2020-09-13 13:04:44 +00:00
pubkey_b = resp_msg_d . get ( ' pubkey ' )
sec_login = resp_msg_d . get ( ' secret_login ' )
2020-09-13 10:57:06 +00:00
2020-09-13 09:42:22 +00:00
pubkey = self . _keychain [ ' pubkey ' ] = KomradeAsymmetricPublicKey ( pubkey_b )
2020-09-13 11:58:09 +00:00
uri_id = b64enc ( pubkey_b )
2020-09-13 09:42:22 +00:00
self . crypt_keys . set (
self . name ,
2020-09-13 09:43:15 +00:00
pubkey_b ,
2020-09-13 09:42:22 +00:00
prefix = ' /pubkey/ ' )
self . crypt_keys . set (
2020-09-13 10:57:06 +00:00
uri_id ,
2020-09-13 09:42:22 +00:00
self . name ,
prefix = ' /name/ ' )
2020-09-13 10:57:06 +00:00
self . crypt_keys . set (
uri_id ,
2020-09-13 13:04:10 +00:00
sec_login ,
2020-09-13 10:57:06 +00:00
prefix = ' /secret_login/ '
)
2020-09-13 12:27:45 +00:00
self . crypt_keys . set (
uri_id ,
privkey_encr_obj . data ,
prefix = ' /privkey_encr/ '
)
2020-09-13 09:42:22 +00:00
2020-09-13 11:36:03 +00:00
self . log ( f ''' Now saving name and public key on local device: ''' )
2020-09-10 09:34:34 +00:00
2020-09-13 09:42:22 +00:00
# save qr too:
2020-09-13 09:46:10 +00:00
uri_id = b64enc ( pubkey_b )
2020-09-13 09:47:30 +00:00
qr_str = self . qr_str ( uri_id )
2020-09-13 09:46:10 +00:00
fnfn = self . save_uri_as_qrcode ( uri_id )
2020-09-13 10:51:01 +00:00
# self.log(f'saved public key as QR code to:\n {fnfn}\n\n{qr_str}')
2020-09-13 09:43:15 +00:00
2020-09-13 14:18:36 +00:00
return resp_msg_d
2020-09-13 09:42:22 +00:00
# done!
2020-09-13 09:43:40 +00:00
self . log ( f ' Congratulations. Welcome, Komrade { self } . ' )
2020-09-08 15:14:48 +00:00
2020-09-13 11:18:04 +00:00
@property
def secret_login ( self ) :
return self . crypt_keys . get (
2020-09-13 12:31:33 +00:00
self . pubkey . data_b64 ,
prefix = ' /secret_login/ '
2020-09-13 11:18:04 +00:00
)
2020-09-13 12:27:45 +00:00
def login ( self , passphrase = None ) :
# check hardware
2020-09-13 11:18:04 +00:00
if not self . pubkey :
self . log ( ''' Login impossible. I do not have this komrade ' s public key, much less private one. ''' )
return
2020-09-13 12:27:45 +00:00
if not self . privkey_encr :
self . log ( ''' Login impossible. I do not have this komrade ' s private key on this hardware. ''' )
return
# check password
2020-09-13 12:46:36 +00:00
# while not passphrase:
# from getpass import getpass
# passphrase = getpass('@Keymaker: Enter password for {self} in order to decrypt the encrypted private key:\n\n')
2020-09-13 12:27:45 +00:00
# assemble privkey?
privkey = self . keychain ( passphrase = passphrase ) . get ( ' privkey ' )
if not privkey :
2020-09-13 11:18:04 +00:00
self . log ( ''' Login impossible. I do not have this komrade ' s private key on this hardware. ''' )
return
# compose message
msg = {
' name ' : self . name ,
' pubkey ' : self . pubkey . data ,
' secret_login ' : self . secret_login
}
# ask operator and get response
resp_msg = self . ring_ring (
msg ,
route = ' login '
)
# get result
self . log ( ' Got result back from operator: ' , resp_msg )
2020-09-13 12:28:29 +00:00
return resp_msg
2020-09-13 11:18:04 +00:00
2020-09-13 18:06:41 +00:00
## 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 ) )
2020-09-13 11:18:04 +00:00
2020-09-08 15:14:48 +00:00
2020-09-12 18:18:37 +00:00
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 )
2020-09-09 15:30:34 +00:00
2020-09-13 14:48:26 +00:00
2020-09-09 17:34:19 +00:00
def send_msg_to ( self , msg , to_whom ) :
2020-09-13 14:48:26 +00:00
msg_e2e = self . compose_msg_to ( msg , to_whom )
2020-09-09 22:26:48 +00:00
msg . encrypt ( )
2020-09-09 15:30:34 +00:00
2020-09-13 14:48:26 +00:00
{ ' _route ' : ' deliver_msg_to ' , ' msg ' : msg }
2020-09-09 15:30:34 +00:00
2020-09-09 17:34:19 +00:00
return self . ring_ring ( msg )
2020-09-09 15:30:34 +00:00
2020-09-09 17:34:19 +00:00
2020-09-09 15:30:34 +00:00
2020-09-10 14:00:55 +00:00
def test_register ( ) :
import random
num = random . choice ( list ( range ( 0 , 1000 ) ) )
2020-09-10 21:32:59 +00:00
botname = f ' marx { str ( num ) . zfill ( 3 ) } '
2020-09-13 07:15:44 +00:00
marxbot = Komrade ( botname )
# marxbot=Komrade()
2020-09-13 05:39:38 +00:00
marxbot . register ( passphrase = ' spectre ' )
2020-09-09 15:30:34 +00:00
2020-09-08 15:14:48 +00:00
if __name__ == ' __main__ ' :
2020-09-11 14:35:47 +00:00
test_register ( )
2020-09-13 07:15:44 +00:00
# marx = Komrade('marx')
# elon = Komrade('elon')
2020-09-08 15:14:48 +00:00
2020-09-11 14:35:47 +00:00
# marx.register()
# # elon.register()
# # person.register()
# # print(person.pubkey)
2020-09-09 15:41:33 +00:00
2020-09-11 14:35:47 +00:00
# # elon.send_msg_to('youre dumb',marx)
2020-09-12 18:18:37 +00:00
# #Caller('elon').ring_ring({'_route':'say_hello','msg':'my dumb message to operator'})
2020-09-09 17:39:30 +00:00
2020-09-11 14:35:47 +00:00
# # print(marx.exists_on_server())