lots of cli work

keys-on-cli
quadrismegistus 4 years ago
parent db46ee8a65
commit c15c3afeb9

@ -1,6 +1,7 @@
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 *
from komrade.cli import *
# from komrade.backend.the_telephone import *
# from komrade.backend.the_telephone import *
@ -18,3 +19,8 @@ class Caller(Operator):
to_whom=self.op,
get_resp_from=self.phone.ring_ring
)
# @hack: repurposing this for now as a narrator
e

@ -2,6 +2,15 @@ import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.p
from komrade import *
from komrade.backend.crypt import *
from abc import ABC, abstractmethod
# common external imports
from pythemis.skeygen import KEY_PAIR_TYPE, GenerateKeyPair
from pythemis.smessage import SMessage, ssign, sverify
from pythemis.skeygen import GenerateSymmetricKey
from pythemis.scell import SCellSeal
from pythemis.exception import ThemisError
class KomradeKey(ABC,Logger):
@abstractmethod
@ -14,7 +23,8 @@ class KomradeKey(ABC,Logger):
def data_b64(self):return b64encode(self.data)
@property
def discreet(self): return make_key_discreet(self.data)
def __str__(self):
return repr(self)
class KomradeSymmetricKey(KomradeKey):
@ -32,6 +42,7 @@ class KomradeSymmetricKey(KomradeKey):
def decrypt(self,msg,**kwargs):
return self.cell.decrypt(msg,**kwargs)
def getpass_status(passphrase=None):
while not passphrase:
passphrase1 = getpass(f'@Keymaker: What is a *memorable* pass word or phrase? Do not write it down.\n@{name}: ')
@ -41,13 +52,14 @@ def getpass_status(passphrase=None):
else:
return passphrase1
get_pass_func = getpass_status if SHOW_STATUS else getpass
class KomradeSymmetricKeyWithPassphrase(KomradeSymmetricKey):
def __init__(self,passphrase=DEBUG_DEFAULT_PASSPHRASE, why=WHY_MSG):
self.passphrase=passphrase
if not self.passphrase:
self.passphrase=getpass_status if SHOW_LOG else getpass.getpass(why)
self.passphrase=getpass(why)
#return self.passphrase
@property
def data(self): return KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE.encode('utf-8')
@ -63,9 +75,16 @@ class KomradeSymmetricKeyWithoutPassphrase(KomradeSymmetricKey):
class KomradeAsymmetricKey(KomradeKey):
def __init__(self,pubkey,privkey):
def __init__(self,pubkey=None,privkey=None):
if not pubkey or not privkey:
keypair = GenerateKeyPair(KEY_PAIR_TYPE.EC)
privkey = keypair.export_private_key()
pubkey = keypair.export_public_key()
self.pubkey=pubkey
self.privkey=privkey
self.privkey=privkey
self.privkey_obj = KomradeAsymmetricPrivateKey(privkey,pubkey)
self.pubkey_obj = KomradeAsymmetricPublicKey(pubkey,privkey)
def encrypt(self,msg,pubkey=None,privkey=None):
if issubclass(type(msg), KomradeKey): msg=msg.data
pubkey=pubkey if pubkey else self.pubkey
@ -107,6 +126,11 @@ def make_key_discreet(data,chance_bowdlerize=0.5):
return ''.join((k if random.random()<chance_bowdlerize else '-') for k in key)
def make_key_discreet_str(string,chance_bowdlerize=0.5):
import random
if not string: return '?'
return ''.join((k if random.random()<chance_bowdlerize else '-') for k in string)
def make_key_discreet1(data,len_start=10,len_end=10,ellipsis='.',show_len=True):
if not data: return '?'
@ -124,6 +148,8 @@ class KomradeEncryptedKey(Logger):
def __repr__(self): return f'[Encrypted Key] ({self.discreet})'
@property
def discreet(self): return make_key_discreet(self.data)
def __str__(self):
return repr(self)
class KomradeEncryptedAsymmetricPrivateKey(KomradeEncryptedKey):
def __repr__(self): return f'[Encrypted Asymmetric Private Key] ({self.discreet})'
@ -211,7 +237,7 @@ class Keymaker(Logger):
for keyname in look_for:
if keyname in keys and keys[keyname]: continue
key = self.crypt_keys.get(uri,prefix=f'/{keyname}/')
if key: keys[keyname]=key
if key: keys[keyname]=key #get_encrypted_key_obj(key,keyname)
# try to assemble
keys = self.assemble(self.assemble(keys))
@ -222,6 +248,12 @@ class Keymaker(Logger):
#return
return keys
def keychain_obj(self,look_for=KEYMAKER_DEFAULT_ALL_KEY_NAMES):
keychain = self.keychain()
for keyname,key_b in keychain.items():
keychain[keyname] = get_encrypted_key_obj(key_b,keyname)
return keychain
@property
def pubkey(self): return self.keychain().get('pubkey')
@property
@ -301,26 +333,37 @@ class Keymaker(Logger):
"""
Get new asymmetric/symmetric keys, given a dictionary of constants describing their type
"""
# print('bbbbb')
asymmetric_pubkey=None
asymmetric_privkey=None
keychain = {}
# print('hello?')
for key_name,key_type_desc in key_types.items():
# print(key_name,key_type_desc)
if key_type_desc in {KEY_TYPE_ASYMMETRIC_PUBKEY,KEY_TYPE_ASYMMETRIC_PRIVKEY}:
if not asymmetric_privkey or not asymmetric_pubkey:
keypair = GenerateKeyPair(KEY_PAIR_TYPE.EC)
asymmetric_privkey = keypair.export_private_key()
asymmetric_pubkey = keypair.export_public_key()
if key_type_desc==KEY_TYPE_ASYMMETRIC_PRIVKEY:
keychain[key_name] = KomradeAsymmetricPrivateKey(asymmetric_pubkey,asymmetric_privkey)
elif key_type_desc==KEY_TYPE_ASYMMETRIC_PUBKEY:
keychain[key_name] = KomradeAsymmetricPublicKey(asymmetric_pubkey,asymmetric_privkey)
elif key_type_desc==KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE:
keychain[key_name]=KomradeSymmetricKeyWithoutPassphrase()
elif key_type_desc==KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE:
if not passphrase and not self.passphrase: self.passphrase=getpass.getpass(WHY_MSG)
if not passphrase and not self.passphrase:
self.passphrase=getpass(WHY_MSG)
passphrase=passphrase if passphrase else self.passphrase
keychain[key_name]=KomradeSymmetricKeyWithPassphrase(passphrase=passphrase)
return keychain
@ -346,6 +389,7 @@ class Keymaker(Logger):
_key_encr_obj = get_encrypted_key_obj(_key_encr, name_of_what_to_encrypt)
# self.log(f'{_key}\n-- encrypting ----->\n{_key_encr}')
# keychain[key_name]=_key_encr
keychain[key_name]=_key_encr_obj
return keychain
@ -356,52 +400,68 @@ class Keymaker(Logger):
keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER,
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT,
keys_to_gen = KEYMAKER_DEFAULT_KEYS_TO_GEN,
key_types = KEYMAKER_DEFAULT_KEY_TYPES):
key_types = KEYMAKER_DEFAULT_KEY_TYPES,
save_keychain=True,
return_keychain=True,
return_all_keys=False):
# setup
keys_to_gen = set(keys_to_gen) | set(keys_to_save) | set(keys_to_return)
keys_to_gen = sorted(list(keys_to_gen),key=lambda x: x.count('_'))
key_types = dict([(k,key_types[k]) for k in keys_to_gen])
if not name: name=self.name
print('forging!')
# show user what's happening
self.log(f'''
Keymaker ({self}) is forging new keys for {name}
I will save these keys in this crypt:
{keys_to_save}
I will also save this user's pubkey (as b64 URI) to:
{self.get_path_qrcode(name=name)}
I will return these keys to you:
{keys_to_return}
which means I will end up generating these keys:
{keys_to_gen}
I will also be using these key types to do so:
{dict_format(key_types,tab=4)}
''')
''' + ('''
* I will save these keys in this crypt: {', '.join(keys_to_save)}
''' if save_keychain else '') #+ #'''
# * I will also save this user's pubkey (as b64 URI) to:
# {self.get_path_qrcode(name=name)}
# ''' + (f'''
+ (f'''
* I will return these keys to you: {', '.join(keys_to_return)}
''' if return_keychain else '')
+ f'''
* I will forge these keys for you: {', '.join(keys_to_gen)}
* I will be using these key types to do so:
{dict_format(key_types,tab=4)}
''')
# gen decryptor keys!
keychain = self.gen_keys_from_types(key_types,passphrase=passphrase)
# gen encrypted keys!
# self.log('I built this keychain v1!',dict_format(keychain,tab=2))
keychain = self.gen_encr_keys(keychain,keys_to_gen,passphrase=passphrase)
self.log('I built this keychain!',dict_format(keychain,tab=2))
# self.log('I built this keychain!',dict_format(keychain,tab=2))
# self.status('@Keymaker: I ended up building these keys:',keychain)
# save keys!
# get URI id to save under (except for pubkeys, accessible by name)
uri_id,keys_saved_d,keychain = self.save_keychain(name,keychain,keys_to_save)
self.log('I saved this keychain:',dict_format(keys_saved_d,tab=2),'using the generated-from-pubkey URI ID',uri_id)
if save_keychain:
# get URI id to save under (except for pubkeys, accessible by name)
uri_id,keys_saved_d,keychain = self.save_keychain(name,keychain,keys_to_save)
# self.log('I saved this keychain:',dict_format(keys_saved_d,tab=2),'using the generated-from-pubkey URI ID',uri_id)
# return keys!
keys_returned = self.return_keychain(keychain,keys_to_return)
self.log('I am returning this keychain:',dict_format(keys_returned,tab=2))
if return_all_keys:
return keychain
if return_keychain:
keys_returned = self.return_keychain(keychain,keys_to_return)
# self.log('I am returning this keychain:',dict_format(keys_returned,tab=2))
# return (uri_id,keys_returned)
return keys_returned
print('done forging!')
return (uri_id,keys_returned)
raise KomradeException('What did you want me to do here?')
def return_keychain(self,keychain,keys_to_return=None):
@ -422,11 +482,9 @@ Keymaker ({self}) is forging new keys for {name}
def qr(self): return self.qr_str(data=self.uri_id)
def qr_str(self,data=None):
import qrcode
qr=qrcode.QRCode()
qr.add_data(self.uri_id if not data else data)
ascii = capture_stdout(qr.print_ascii)
return ascii
data = self.uri_id if not data else data
return get_qr_str(data)
def save_uri_as_qrcode(self,uri_id=None,name=None):
if not uri_id: uri_id = self.uri_id
@ -458,7 +516,7 @@ Keymaker ({self}) is forging new keys for {name}
keys_saved_d={}
for keyname in keys_to_save:
if not '_' in keyname and keyname!='pubkey':
raise KomradeException('there is no private property in a socialist network! all keys must be split between komrades')
self.log('there is no private property in a socialist network! all keys must be split between komrades',keyname)
if keyname in keychain:
# uri = uri_id
uri = uri_id if keyname!='pubkey' else name
@ -533,7 +591,7 @@ Keymaker ({self}) is forging new keys for {name}
# self.log('assembled_key built:',key)
return key
except ThemisError as e:
# self.log('!! decryption failed:',e)
self.log('!! decryption failed:',e)
return
def get_cell(self, str_or_key_or_cell):

@ -1,12 +1,15 @@
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 *
from komrade.backend.keymaker import *
class Persona(Caller):
def __init__(self, name=None, passphrase=DEBUG_DEFAULT_PASSPHRASE):
super().__init__(name=name,passphrase=passphrase)
if SHOW_STATUS:
from komrade.cli import CLI
self.cli = CLI()
# self.boot(create=False)
# def boot(self,create=False):
@ -42,22 +45,38 @@ class Persona(Caller):
# def login(self):
# if keys.get('pubkey') and keys.get('privkey')
def register(self, name = None, passphrase = None, is_group=None):
def register(self, name = None, passphrase = None, is_group=None, show_intro=0,show_body=True):
# defaults
if name and not self.name: self.name=name
if not name and self.name: name=self.name
if not name and not self.name: name=''
clear_screen()
# intro narration?
if SHOW_STATUS and show_intro:
name = self.cli.status_keymaker_intro(name)
# forge public/private keys
keypair = KomradeAsymmetricKey()
pubkey,privkey = keypair.pubkey_obj,keypair.privkey_obj
# make sure we have passphrase
if SHOW_STATUS:
passphrase = self.cli.status_keymaker_body(
name,
passphrase,
pubkey,
privkey,
self.crypt_keys.hash
)
else:
if not passphrase: passphrase=getpass('Enter a memorable password to encrypt your private key with: ')
if not passphrase: passphrase=getpass('Enter a memorable password: ')
# encrypt private key
exit()
# make and save keys locally
uri_id,keys_returned = self.forge_new_keys(
name=name,
passphrase=passphrase,
keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT,
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER
)
self.log(f'my new uri is {uri_id} and I got new keys!: {dict_format(keys_returned)}')
# save the ones we should on server
data = {
@ -96,15 +115,16 @@ def test_register():
marxbot.register()
if __name__=='__main__':
marx = Persona('marx')
elon = Persona('elon')
test_register()
# marx = Persona('marx')
# elon = Persona('elon')
marx.register()
# elon.register()
# person.register()
# print(person.pubkey)
# marx.register()
# # elon.register()
# # person.register()
# # print(person.pubkey)
# elon.send_msg_to('youre dumb',marx)
#Caller('elon').ring_ring({'_route':'say_hello','_msg':'my dumb message to operator'})
# # elon.send_msg_to('youre dumb',marx)
# #Caller('elon').ring_ring({'_route':'say_hello','_msg':'my dumb message to operator'})
# print(marx.exists_on_server())
# # print(marx.exists_on_server())

@ -0,0 +1,2 @@
from .artcode import *
from .cli import *

@ -2,19 +2,19 @@ ART_TELEPHONE = '''
..--""""----..
.-" ..--""""--.j-.
.-" .-" .--.""--..
.-" .-" ..--"-. \/ ;
.-" .-" ..--"-. \\/ ;
.-" .-"_.--..--"" ..--' "-. :
.' .' / `. \..--"" __ _ \ ;
:.__.-" \ / .' ( )"-. Y
; ;: ( ) ( ). \
.': /:: : \ \
.'.-"\._ _.-" ; ; ( ) .-. ( ) \
" `.""" .j" : : \ ; ; \
bug /"""""/ ; ( ) "" :.( ) \
/\ / : \ \`.: _ \
: `. / ; `( ) (\/ :" \ \
\ `. : "-.(_)_.' t-' ;
\ `. ; ..--":
.' .' / `. \\..--"" __ _ \\ ;
:.__.-" \\ / .' ( )"-. Y
; ;: ( ) ( ). \\
.': /:: : \\ \\
.'.-"\\._ _.-" ; ; ( ) .-. ( ) \\
" `.""" .j" : : \\ ; ; \\
bug /"""""/ ; ( ) "" :.( ) \\
/\\ / : \\ \\`.: _ \\
: `. / ; `( ) (\\/ :" \\ \\
\\ `. : "-.(_)_.' t-' ;
\\ `. ; ..--":
`. `. : ..--"" :
`. "-. ; ..--"" ;
`. "-.:_..--"" ..--"
@ -25,30 +25,30 @@ ART_TELEPHONE = '''
'''
ART_PHONE_SM1 = """
.----------------.
/ _H______H_ \@,
\____/ \____/ @,
/ \ `@
/ _H______H_ \\@,
\\____/ \\____/ @,
/ \\ `@
| LI LI LI | ,@
| LI LI LI | ,@'
| LI LI LI | ,@'
| LI LI LI |@@'
jgs \ /'
jgs \\ /'
`----------'
"""
ART_ROTARY2="""
_______________
/ \
/ \\
| .---------. |@
'---' .-----. '---'@
.' /6 5_4 3\ '. @
| |7 /...\ 2| | @
| |8 \___/ 1| | @
| \_9_0_)\/ | @@
.' /6 5_4 3\\ '. @
| |7 /...\\ 2| | @
| |8 \\___/ 1| | @
| \\_9_0_)\\/ | @@
/==|_____________|@@@@
H-------------------@@
H ) || || ( @@
H / || || \ @
H / || || \\ @
H |----''---''----|
=/ |_______________|
"""
@ -64,16 +64,16 @@ ART_KEY = """
ART_OLDPHONE = """
__
/` _`\
/` _`\\
| (_()| .-.
\_ _/_/ \
\\_ _/_/ \\
||=[_] |
|| | | |
||/ \ |
||/ \\ |
||`---' /
.--'||-.___.'
/` .-||-.
'-/`.____.`\
'-/`.____.`\\
jgs '.______.'
"""
@ -81,13 +81,13 @@ ART_OLDPHONE2="""
_|~|/|
( | | |
/_|_|\|
/_|_|\\|
| |
| |~|
| | |
| | |
| |-|
| | \
| | \\
| |__|
|_|_
/ ~-_
@ -101,16 +101,16 @@ ART_ROTARY = """
,-' ,-. `-.
,' ,-. ( 4 ) ,-. `.
,' ( 5 ) `-' ( 3 ) `.
/ ,-. `-',-'' ``-.`-' ,-. \
/ ( 6 ) ,' `. ( 2 ) \
: `-' / FEUER \ `-' :
/ ,-. `-',-'' ``-.`-' ,-. \\
/ ( 6 ) ,' `. ( 2 ) \\
: `-' / FEUER \\ `-' :
| ,-. : ________ : ,-. |
|( 7 ) | |________| | ( 1 )|
| `-' : ; `-' |
: ,-. \ NOTRUF / ;
\ ( 8 ) `. ,'(`. /
\ `-' ,-.`-..__..-' \ `-./
`. ( 9 ) ,-. \ ,'
: ,-. \\ NOTRUF / ;
\\ ( 8 ) `. ,'(`. /
\\ `-' ,-.`-..__..-' \\ `-./
`. ( 9 ) ,-. \\ ,'
`. `-' ( 0 ) ,'`
`-._ `-' _.-'
```----''' SSt
@ -124,17 +124,17 @@ ART_PHONE_DIAGRAM = """
/ `--' / |
/__ __ __ / |
//_//_//_// / __
//_//_//_// / \`.___ Listening end
//_//_//_// / \\`.___ Listening end
//_//_//_// /
//_//_//_// /__
/ / / \`.___ Buttons
/ / / \\`.___ Buttons
/ .-. / /
/ /#/ / /
/ `-' / /__
/ .====. / / \`.___ Speaking end
/ .====. / / \\`.___ Speaking end
|`--------' /
\ , .'__
`-//----' \`.___ Disconnect button
\\ , .'__
`-//----' \\`.___ Disconnect button
//
"""
@ -142,14 +142,14 @@ ART_OLDPHONE3 = """
__ _
.: .' '.
/: / \_
;: ; ,-'/`:\
/: / \\_
;: ; ,-'/`:\\
|: | | |():|
;: ; '-.\_:/
\: \ /`
;: ; '-.\\_:/
\\: \\ /`
':_'._.'
||
/__\
/__\\
.---. {====}
.' _,"-,__|:: |
/ ((O)=;--.:: |
@ -159,13 +159,13 @@ ART_OLDPHONE3 = """
| |: | |:: |
| |: | |:: |
| |: | |:: |
| /:'__\ |:: |
| /:'__\\ |:: |
| [______]|:: |
| `----` |:: |__
| _.--|:: | ''--._
; .' __{====}__ '.
\ .'_.-'._ `""` _.'-._ '.
'--'/` `''''` `\ '.__
\\ .'_.-'._ `""` _.'-._ '.
'--'/` `''''` `\\ '.__
jgs '._ _.'
`""--......--""`
@ -174,44 +174,561 @@ ART_OLDPHONE3 = """
ART_OLDPHONE4 = """
__
/` _`\
/` _`\\
| (_()| .-.
\_ _/_/ \
\\_ _/_/ \\
||=[_] |
|| | | |
||/ \ |
||/ \\ |
||`---' /
.--'||-.___.'
/` .-||-.
'-/`.____.`\
jgs '.______.'
'-/`.____.`\\
'.______.'
"""
# by jgs
ART_PAYPHONE = """
_________________
/ __ \
/ __ \\
| (__) |
| |
| .-----. .--. |
| | | / \ |
| '-----' \ / |
| | | / \\ |
| '-----' \\ / |
| | | |
| LI LI LI | | |
| LI LI LI | | |Oo
| LI LI LI | | |`Oo
| LI LI LI | | | Oo
| | | | Oo
| .------. / \ | oO
| | | \ / | Oo
| .------. / \\ | oO
| | | \\ / | Oo
| '------' '-oO | oO
| .---Oo | Oo
| || ||`Oo oO
| |'--'| | OoO
| '----' |
jgs \_________________/
jgs \\_________________/
"""
ART_HAMMER = """
,
/( ___________
| >:===========`
)(
""
"""
ART_KEY_PAIR = """
__
/o \\_____
\__/-="="`
__
/ o\\
\_ /
<|
<|
<|
`
"""
ART_KEY_PAIR2 = """
__
/o \\_____
\__/-="="`
__ (public)
/ o\\
\_ /
<|
<|
<| (private)
"""
ART_KEY_PAIR2A = """
__
/o \\_____
\__/-="="`
__ (1) public key
/ o\\
\_ /
<|
<|
<|
"""
ART_KEY_PAIR2B = """
__
/o \\_____
\__/-="="`
__ (1) public key
/ o\\
\_ /
<|
<|
<| (2) private key
"""
ART_KEY_PAIR32 = """
__
/o \\_____
\__/-="="`
_ _ (1) public key
/o \\
\ _ /
< |
< |
< | (2B) privkey_encr
(2A) privkey_decr
"""
ART_KEY_PAIR3A2 = """
__
/o \\_____
\__/-="="`
_ _ (1) public key
/o \\
\ _ /
< |
< |
< |
"""
ART_KEY_PAIR3B2 = """
__
/o \\_____
\__/-="="`
_ _
/o \\
\ _ /
< |
< |
< | (2B) privkey_encr
"""
ART_KEY_PAIR3C2 = """
__
/o \\_____
\__/-="="`
_ _ (1) public key
/o \\
\ _ /
< |
< |
< | (2B) privkey_encr
(2A) privkey_decr
"""
ART_KEY_PAIR3 = """
__
/o \\_____
\__/-="="`
_ _ (1) public key
/o \\
\ _ /
< |
< |
< | (2B) privkey_encr
(2A) privkey_decr
"""
ART_KEY_PAIR4 = """
__
/o \\_____
\__/-="="`
? _
?? \\
? _ /
? |
? |
? | (2B) privkey_encr
(2A) privkey_decr
"""
ART_KEY_PAIR4Z = """
__
/o \\_____
\__/-="="`
? _
?? \\
? _ /
? |
? |
? |
(2A) privkey_decr
"""
ART_KEY_PAIR4D = """
? _
?? \\
? _ /
? |
? |
? | (2B) privkey_encr
(2A) privkey_decr
"""
ART_KEY_PAIR4C = """
? _
?? \\
? _ /
? |
? |
? |
(2A) privkey_decr
"""
ART_KEY_PAIR4B = """ ? _
?? \\
? _ /
? |
? |
? |
"""
ART_KEY_PAIR31A = """
__
/o \\_____
\__/-="="`
(1) public key"""
ART_KEY_PAIR3A = """
__
/o \\_____
\__/-="="`"""
ART_KEY_PAIR3B = """ _ _
/o \\
\ _ /
< |
< |
< |
(2A) (2B) encrypted
encryption form of (2)
key for (2B)
"""
ART_KEY_PAIR5 = """
__
/o \\_____
\__/-="="`
(1) public key
_ _
/o \\
\ _ /
< |
< |
< |
(2A) (2B) encrypted
encryption form of (2)
key for (2B)
"""
ART_KEY_PAIR4Z1 = """
__
/o \\_____
\__/-="="`
(1) public key
? _
?? \\
? _ /
? |
? |
? |
(2B) encrypted
form of (2)
"""
ART_KEY_PAIR4Z2 = """
__
/o \\_____
\__/-="="`
(1) public key
? ?
?? ?
? ? ?
? ?
? ?
? ?
"""
# """
ART_KEY_PAIR4Z3 = """
__
/o \\_____
\__/-="="`
?? (1) public key
? ?
? ?
??
??
??
"""
ART_KEY_PAIR4Z3 = """
__
/o \\_____
\__/-="="`
?? (1) public key
? ??
? ?
??
?
??
"""
ART_KEY_PAIR4Z42 = """
?
? ??????
?? ? ? ??
??
? ??
? ?
??
?
??
"""
ART_KEY_PAIR4Z4B = """
??
?? ??????
??????????
__
/ o\\
\_ /
<|
<|
<|
"""
ART_KEY_PAIR4Z4 = """
??
?? ??????
??????????
__
/ o\\
\_ /
<|
<|
<|
"""
ART_KEY_PAIR3BB = """ ? _
?? \\
? _ /
? |
? |
? |
(2A) (2B) encrypted
encryption form of (2)
key for (2B)
"""
ART_KEY_PAIR3AA = """ _ _
/o \\
\ _ /
< |
< |
< |
"""
ART_KEY_PAIR_SEP = """
__
/o \\_____
\__/-="="`
__
/ o\\
\_ /
<|
<|
<|
`
"""
ART_KEY_CHAIN = """
___________ @ @
/ (@\\ @
\___________/ _@
@ _/@ \\_____
@/ \__/-="="`
\_ /
<|
<|
<|
`
"""
ART_FROG_BLENDER ="""
___
_______|___|______
__|__________________|
\ ]________________[ `---.
`. ___ L
| _ | L |
| .'_`--.___ __ | | |
|( 'o` - .`.'_ ) | F F
| `-._ `_`./_ | / /
J '/\\ ( .'/ )F.' /
L ,__//`---'`-'_/J .'
J /-' '/ F.'
L ' J'
J `.`-. .-'.' F
L `.-'.-' J
|__(__(___)__|
F J
J L
|______________|
"""
@ -264,7 +781,7 @@ def convert_image_to_ascii(image, new_width=100):
image_ascii = [pixels_to_chars[index: index + new_width] for index in
range(0, len_pixels_to_chars, new_width)]
return "\n".join(image_ascii)
return "\\n".join(image_ascii)
def handle_image_conversion(image_filepath):
image = None

@ -2,6 +2,7 @@ import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.p
from komrade import *
from komrade.backend import *
import art
import textwrap as tw
@ -16,8 +17,8 @@ class CLI(Logger):
self.name=''
self.cmd=''
async def run(self,inp,name=''):
if name: self.name=name
def run(self,inp='',name=''):
self.name=name
clear_screen()
self.boot()
self.help()
@ -26,11 +27,11 @@ class CLI(Logger):
while True:
try:
inp=input()
inp=input(f'@{self.name if self.name else "?"}: ')
except KeyboardInterrupt:
exit()
self.route(inp)
await asyncio.sleep(0.5)
#await asyncio.sleep(0.5)
def route(self,inp):
inp=inp.strip()
@ -42,37 +43,42 @@ class CLI(Logger):
f=getattr(self,cmd)
return f(dat)
def boot(self):
print(art.text2art(CLI_TITLE,font=CLI_FONT))
def boot(self,indent=5):
logo=art.text2art(CLI_TITLE,font=CLI_FONT)
# logo=make_key_discreet_str(logo,chance_bowdlerize=0.1) #.decode()
logo=tw.indent(logo, ' '*indent)
scan_print(logo,max_pause=0.005)
def help(self):
print()
for cmd,info in self.ROUTES.items():
print(f' /{cmd}: {info}')
# print('\n')
print('\n')
def intro(self):
self.status(None,)
## routes
def register(self,name=None):
# defaults
if name and not self.name: self.name=name
if not name and self.name: name=self.name
if not name and not self.name: name=''
# self.status(None,ART_PAYPHONE,3,pause=False) #,ticks = None)
def register(self,dat):
self.persona = Persona(self.name)
self.persona.register()
### DIALOGUES
# hello, op?
# hello, op?
def status_keymaker_intro(self,name):
self.status(None,{ART_OLDPHONE4+'\n',True},3) #,scan=False,width=None,pause=None,clear=None)
nm=name if name else '?'
self.status(
f'\n\n@{nm}: Uh yes hello, Operator? I would like to join Komrade, the socialist network. Could you patch me through?',clear=False)
f'\n\n\n@{nm}: Uh yes hello, Operator? I would like to join Komrade, the socialist network. Could you patch me through?',clear=False)
while not name:
name=self.status(('name','@TheTelephone: Of course, Komrade...?\n@')).get('vals').get('name').strip()
print()
self.name = name
self.persona = Persona(name)
self.status(
f'@TheTelephone: Of course, Komrade @{name}. A fine name.',
@ -81,7 +87,7 @@ class CLI(Logger):
'''Komrade @TheOperator lives on the deep web. She's the one you want to speak with.''',
f'''@{name}: Hm, ok. Well, could you patch me through to the remote operator then?''',
None,{ART_OLDPHONE4},f'''@{name}: Hm, ok. Well, could you patch me through to the remote operator then?''',
f'''@{TELEPHONE_NAME}: I could, but it's not safe yet. Your information could be exposed. You need to forge your encryption keys first.''',
@ -91,64 +97,159 @@ class CLI(Logger):
clear=False,pause=True)
### KEYMAKER
self.status(None,ART_KEY,3,pause=False,clear=False)
self.status(None,{tw.indent(ART_KEY,' '*5)+'\n',True},3) #,clear=False,indent=10,pause=False)
# convo
self.status('',
f'@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.',
self.status(
f'\n@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.',
f'@Keymaker: Of course, Komrade @{name}.',
)
'''We will make three keys. First, a matching, "asymmetric" pair.''',
return name
'\t1) A "public key" you can share with anyone.',
'\t2) A "private key" other no one can ever, ever see.',
'With both together, you can communicate privately and securely with anyone who also has their own key pair.',
'We will use the use the iron-clad Elliptic Curve algorthm to generate the keypair, accessed via a high-level cryptography library, Themis (https://github.com/cossacklabs/themis).',
def status_keymaker_body(self,name,passphrase,pubkey,privkey,hasher):
# gen what we need
uri_id = pubkey.data_b64
qr_str = get_qr_str(uri_id)
qr_path = os.path.join(PATH_QRCODES,name+'.png')
)
# # what are pub/priv?
# self.status(
# 'I will forge for you two matching keys, part of an "asymmetric" pair.',
# 'Please, watch me work.',
# None,{tw.indent(ART_KEY,' '*5)+'\n'},
# 'I use a high-level cryptographic function from Themis, a well-respected open-source cryptography library.',
# 'I use the iron-clad Elliptic Curve algorthm to generate the asymmetric keypair.',
# '> GenerateKeyPair(KEY_PAIR_TYPE.EC)',
# 3
# )
# self.status(
# None,
# {ART_KEY_PAIR,True}
# ) #,clear=False,indent=10,pause=False)
# self.status(
# None,{ART_KEY_PAIR},
# 'A matching set of keys have been generated.',
# None,{ART_KEY_PAIR2A+'\n\nA matching set of keys have been generated.'},
# '1) First, I have made a "public key" which you can share with anyone:',
# f'{repr(pubkey)}',
# 'This key is a randomly-generated binary string, which acts as your "address" on Komrade.',
# 'By sharing this key with someone, you enable them to write you an encrypted message which only you can read.'
# )
# self.status(
# None,{ART_KEY_PAIR2A},
# f'You can share your public key by copy/pasting it to them over a secure channel (e.g. Signal).',
# 'Or, you can share it as a QR code, especially phone to phone:',
# {qr_str+'\n\n',True,5},
# f'\n\n(If registration is successful, this QR code be saved as an image to your device at: {qr_path}.)'
# )
# make and save keys locally
self.log(f'{KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER}!!!!!')
uri_id,keys_returned = self.persona.forge_new_keys(
name=name,
passphrase=None,
keys_to_save = [],
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER
# private keys
# self.status(None,
# {ART_KEY_PAIR2B},
# 'Second, I have forged a matching "private key":',
# f'{repr(privkey)}',
# 'With it, you can decrypt any message sent to you via your public key.',
# 'You you should never, ever give this key to anyone.',
# 'In fact, this key is so dangerous that I will immediately destroy it by splitting it into two half-keys:'
# )
# self.status(None,
# {ART_KEY_PAIR31A},
# {ART_KEY_PAIR3B+'\n',True},
# 3,'Allow me to explain.',
# '(2A) is a separate encryption key generated by your password.',
# '(2B) is a version of (2) which has been encrypted by (2A).',
# "Because (2) will be destroyed, to rebuild it requires decrypting (2B) with (2A).",
# )
# self.status(
# None,{ART_KEY_PAIR5+'\n'},
# "However, in a final move, I will now destroy (2A), too.",
# None,{ART_KEY_PAIR4Z1+'\n'},
# 'Why? Because now only you can regenerate it, by remembering the password which created it.',
# # None,{ART_KEY_PAIR4Z1+'\n'},
# 'However, this also means that if you lose or forget your password, you\'re screwed.',
# None,{ART_KEY_PAIR4Z2+'\n'},
# "Because without key (2A),you couldn never unlock (2B).",
# None,{ART_KEY_PAIR4Z3+'\n'},
# "And without (2B) and (2A) together, you could never re-assemble the private key of (2).",
# None,{ART_KEY_PAIR4Z42+'\n'},
# "And without (2), you couldn't read messages sent to your public key.",
)
self.status('got back',dict_format(keys_returned))
#self.log(f'my new uri is {uri_id} and I got new keys!: {dict_format(keys_returned)}')
self.status(
'Generating public key now: ',5,'\n\t',repr(KomradeAsymmetricPublicKey(keychain['pubkey'])),'\n\n',
'Generating private key now: ',5,'\n\t',repr(KomradeAsymmetricPrivateKey(keychain['privkey'])),
clear=False,pause=False,end=' ',speed=2
None,{ART_KEY_PAIR4Z1},
'So choosing a password is an important thing!'
)
if not passphrase:
self.status(
'And it looks like you haven\'t yet chosen a password.',
3,"Don't tell it to me! Never tell it to anyone.",
"Ideally, don't even save it on your computer; just remember it, or write it down on paper.",
"Instead, whisper it to Komrade @Hasher, who scrambles information '1-way', like a blender.",
)
res = self.status(None,
{ART_FROG_BLENDER,True},
"@Keymaker: Go ahead, try it. Type anything to @Hasher.",
('str_to_hash',f'@{name}: ',input)
)
str_to_hash = res.get('vals').get('str_to_hash')
hashed_str = hasher(str_to_hash.encode())
res = self.status(
'@Hasher: '+hashed_str
)
res = self.status(
'@Keymaker: See? Ok, now type in a password.'
('str_to_hash',f'@{name}: ',getpass)
)
str_to_hash = res.get('vals').get('str_to_hash')
hashed_pass1 = hasher(str_to_hash.encode())
res = self.status(
'@Hasher: '+hashed_pass1
)
res = self.status(
'@Keymaker: Whatever you entered, it\'s already forgotten. That hashed mess is all that remains.',
'Now type in the same password one more time to verify it:',
('str_to_hash',f'@{name}: ',getpass)
)
str_to_hash = res.get('vals').get('str_to_hash')
hashed_pass2 = hasher(str_to_hash.encode())
res = self.status(
'@Hasher: '+hashed_pass2
)
if hashed_pass1==hashed_pass2:
self.status('The passwords matched.')
else:
self.status('The passwords did not match.')
# save the ones we should on server
data = {
**{'name':name, 'passphrase':self.crypt_keys.hash(passphrase.encode()), ROUTE_KEYNAME:'register_new_user'},
**keys_returned
}
self.log('sending to server:',dict_format(data,tab=2))
# msg_to_op = self.compose_msg_to(data, self.op)
# ring operator
# call from phone since I don't have pubkey on record on Op yet
resp_msg_obj = self.phone.ring_ring(data)
self.log('register got back from op:',dict_format(resp_msg_obj,tab=2))
def run_cli():
cli = CLI()
asyncio.run(cli.run('/register',name='elon'))
cli.run('/register','elon') #'/register',name='elon')
if __name__=='__main__':
run_cli()

@ -105,8 +105,8 @@ KEYMAKER_DEFAULT_KEY_TYPES = {
'adminkey':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'pubkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'privkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'adminkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'privkey_decr':KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE,
'adminkey_decr':KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE,
'pubkey_decr_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'privkey_decr_decr':KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE,
@ -151,7 +151,6 @@ PATH_OPERATOR_WEB_CONTACTS_DIR = '/home/ryan/www/website-komrade/.contacts'
PATH_OPERATOR_WEB_CONTACT_OP_URL = f'http://{KOMRADE_URL}/.contacts/TheOperator.png'
PATH_OPERATOR_WEB_CONTACT_PH_URL = f'http://{KOMRADE_URL}/.contacts/TheTelephone.png'
PAUSE_LOGGER = True
# dangerous! leave on only if absolutely necessary for initial dev
ALLOW_CLEARNET = True
@ -182,9 +181,11 @@ DEFAULT_USER_SETTINGS = {
'visibility':VISIBILITY_TYPE_SEMIPUBLIC
}
SHOW_LOG = True
SHOW_STATUS = True
SHOW_LOG = 1
SHOW_STATUS = 1
PAUSE_LOGGER = 1
CLI_TITLE = 'KOMRADE'
CLI_FONT = 'colossal'
CLI_FONT = 'clr5x6'#'colossal'
STATUS_LINE_WIDTH = 50

@ -26,10 +26,14 @@ def log(*x):
def clear_screen():
import os
# pass
os.system('cls' if os.name == 'nt' else 'clear')
def do_pause():
input('')
try:
input('')
except KeyboardInterrupt:
exit('\n\nGoodbye.')
def dict_format(d, tab=0):
@ -47,11 +51,11 @@ def dict_format(d, tab=0):
# s.append('%s%r: %s (%s),\n' % (' '*tab, k, v, type(v).__name__))
s.append('%s%r: %s,\n\n' % (' '*tab, k, reppr(v)))
s.append('%s}' % (' '*tab))
s.append('%s}' % (' '*(tab-2)))
return ''.join(s)
import inspect,time
from komrade.constants import PAUSE_LOGGER,SHOW_LOG,SHOW_STATUS
from komrade.constants import *
class Logger(object):
def log(self,*x,pause=PAUSE_LOGGER,clear=PAUSE_LOGGER):
if not SHOW_LOG: return
@ -65,9 +69,22 @@ class Logger(object):
if pause: do_pause()
if pause: clear_screen()
# except KeyboardInterrupt:
exit()
# exit()
def status(self,*msg,pause=True,clear=False,ticks=[],tab=2,speed=2,end=None):
def print(*x,width=STATUS_LINE_WIDTH,end='\n',indent=1,scan=False,**y):
if not scan and not width:
print(*x,end=end,**y)
else:
import textwrap as tw
xs=end.join(str(xx) for xx in x if type(xx)==str)
if width:
xw = [_.strip() for _ in tw.wrap(xs,width=width)]
# xw = [_ for _ in tw.wrap(xs,width=width)]
xs=end.join(xw)
xs = tw.indent(xs,' '*indent)
print(xs) if scan==False else scan_print(xs)
def status(self,*msg,pause=True,clear=False,ticks=[],tab=2,speed=10,end=None,indent=0,width=80,scan=False):
import random
if not SHOW_STATUS: return
# if len(msg)==1 and type(msg[0])==str:
@ -76,17 +93,33 @@ class Logger(object):
paras=[]
res={}
for para in msg:
indentstr=' '*indent
plen = para if type(para)==int or type(para)==float else None
if type(para) in {int,float}:
plen=int(para)
for i in range(plen * speed):
# print()
print(' '*indent,end='',flush=True)
for i in range(plen):
tick = ticks[i] if i<len(ticks) else '.'
print(tick,end=end if end else ' ',flush=True)
time.sleep(random.random() / speed)
print(tick,end=end if end else ' ',flush=True) #,scan=scan)
# time.sleep(random.random() / speed)
time.sleep(random.uniform(0.05,0.2))
# print()
elif para is None:
clear_screen()
elif para is False:
pass
elif para is True:
pass
elif type(para) is set: # logo/image
pl = [x for x in para if type(x)==str]
txt=pl[0]
speed =[x for x in para if type(x)==int]
speed = speed[0] if speed else 1
if True in para:
scan_print(txt,speed=speed)
else:
print(txt,end=end)
elif type(para) is tuple:
k=para[0]
q=para[1]
@ -100,11 +133,11 @@ class Logger(object):
elif para is 0:
do_pause()
elif pause:
print(para,flush=True,end=end if end else '\n')
self.print(para,flush=True,end=end if end else '\n',scan=scan,indent=indent)
paras+=[para]
do_pause()
else:
print(para,flush=True,end=end if end else '\n')
self.print(para,flush=True,end=end if end else '\n',scan=scan,indent=indent)
paras+=[para]
return {'paras':paras, 'vals':res}
@ -222,4 +255,25 @@ def capture_stdout(func):
with redirect_stdout(f):
func()
out = f.getvalue()
return out
return out
def scan_print(xstr,min_pause=0,max_pause=0.015,speed=100000):
import random,time
for c in xstr:
print(c,end='',flush=True)
# naptime=random.uniform(min_pause, max_pause / speed)
# time.sleep(naptime)
time.sleep(.001)
def get_qr_str(data):
import qrcode
qr=qrcode.QRCode()
qr.add_data(data)
ascii = capture_stdout(qr.print_ascii)
ascii = ascii[:-1] # removing last line break
return '\n ' + ascii.strip()
Loading…
Cancel
Save