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

@ -3,6 +3,15 @@ from komrade import *
from komrade.backend.crypt import * from komrade.backend.crypt import *
from abc import ABC, abstractmethod 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): class KomradeKey(ABC,Logger):
@abstractmethod @abstractmethod
def encrypt(self,msg,**kwargs): pass def encrypt(self,msg,**kwargs): pass
@ -14,7 +23,8 @@ class KomradeKey(ABC,Logger):
def data_b64(self):return b64encode(self.data) def data_b64(self):return b64encode(self.data)
@property @property
def discreet(self): return make_key_discreet(self.data) def discreet(self): return make_key_discreet(self.data)
def __str__(self):
return repr(self)
class KomradeSymmetricKey(KomradeKey): class KomradeSymmetricKey(KomradeKey):
@ -32,6 +42,7 @@ class KomradeSymmetricKey(KomradeKey):
def decrypt(self,msg,**kwargs): def decrypt(self,msg,**kwargs):
return self.cell.decrypt(msg,**kwargs) return self.cell.decrypt(msg,**kwargs)
def getpass_status(passphrase=None): def getpass_status(passphrase=None):
while not passphrase: while not passphrase:
passphrase1 = getpass(f'@Keymaker: What is a *memorable* pass word or phrase? Do not write it down.\n@{name}: ') 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: else:
return passphrase1 return passphrase1
get_pass_func = getpass_status if SHOW_STATUS else getpass
class KomradeSymmetricKeyWithPassphrase(KomradeSymmetricKey): class KomradeSymmetricKeyWithPassphrase(KomradeSymmetricKey):
def __init__(self,passphrase=DEBUG_DEFAULT_PASSPHRASE, why=WHY_MSG): def __init__(self,passphrase=DEBUG_DEFAULT_PASSPHRASE, why=WHY_MSG):
self.passphrase=passphrase self.passphrase=passphrase
if not self.passphrase: if not self.passphrase:
self.passphrase=getpass_status if SHOW_LOG else getpass.getpass(why) self.passphrase=getpass(why)
#return self.passphrase #return self.passphrase
@property @property
def data(self): return KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE.encode('utf-8') def data(self): return KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE.encode('utf-8')
@ -63,9 +75,16 @@ class KomradeSymmetricKeyWithoutPassphrase(KomradeSymmetricKey):
class KomradeAsymmetricKey(KomradeKey): 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.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): def encrypt(self,msg,pubkey=None,privkey=None):
if issubclass(type(msg), KomradeKey): msg=msg.data if issubclass(type(msg), KomradeKey): msg=msg.data
pubkey=pubkey if pubkey else self.pubkey 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) 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): def make_key_discreet1(data,len_start=10,len_end=10,ellipsis='.',show_len=True):
if not data: return '?' if not data: return '?'
@ -124,6 +148,8 @@ class KomradeEncryptedKey(Logger):
def __repr__(self): return f'[Encrypted Key] ({self.discreet})' def __repr__(self): return f'[Encrypted Key] ({self.discreet})'
@property @property
def discreet(self): return make_key_discreet(self.data) def discreet(self): return make_key_discreet(self.data)
def __str__(self):
return repr(self)
class KomradeEncryptedAsymmetricPrivateKey(KomradeEncryptedKey): class KomradeEncryptedAsymmetricPrivateKey(KomradeEncryptedKey):
def __repr__(self): return f'[Encrypted Asymmetric Private Key] ({self.discreet})' def __repr__(self): return f'[Encrypted Asymmetric Private Key] ({self.discreet})'
@ -211,7 +237,7 @@ class Keymaker(Logger):
for keyname in look_for: for keyname in look_for:
if keyname in keys and keys[keyname]: continue if keyname in keys and keys[keyname]: continue
key = self.crypt_keys.get(uri,prefix=f'/{keyname}/') 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 # try to assemble
keys = self.assemble(self.assemble(keys)) keys = self.assemble(self.assemble(keys))
@ -222,6 +248,12 @@ class Keymaker(Logger):
#return #return
return keys 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 @property
def pubkey(self): return self.keychain().get('pubkey') def pubkey(self): return self.keychain().get('pubkey')
@property @property
@ -301,26 +333,37 @@ class Keymaker(Logger):
""" """
Get new asymmetric/symmetric keys, given a dictionary of constants describing their type Get new asymmetric/symmetric keys, given a dictionary of constants describing their type
""" """
# print('bbbbb')
asymmetric_pubkey=None asymmetric_pubkey=None
asymmetric_privkey=None asymmetric_privkey=None
keychain = {} keychain = {}
# print('hello?')
for key_name,key_type_desc in key_types.items(): 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 key_type_desc in {KEY_TYPE_ASYMMETRIC_PUBKEY,KEY_TYPE_ASYMMETRIC_PRIVKEY}:
if not asymmetric_privkey or not asymmetric_pubkey: if not asymmetric_privkey or not asymmetric_pubkey:
keypair = GenerateKeyPair(KEY_PAIR_TYPE.EC) keypair = GenerateKeyPair(KEY_PAIR_TYPE.EC)
asymmetric_privkey = keypair.export_private_key() asymmetric_privkey = keypair.export_private_key()
asymmetric_pubkey = keypair.export_public_key() asymmetric_pubkey = keypair.export_public_key()
if key_type_desc==KEY_TYPE_ASYMMETRIC_PRIVKEY: if key_type_desc==KEY_TYPE_ASYMMETRIC_PRIVKEY:
keychain[key_name] = KomradeAsymmetricPrivateKey(asymmetric_pubkey,asymmetric_privkey) keychain[key_name] = KomradeAsymmetricPrivateKey(asymmetric_pubkey,asymmetric_privkey)
elif key_type_desc==KEY_TYPE_ASYMMETRIC_PUBKEY: elif key_type_desc==KEY_TYPE_ASYMMETRIC_PUBKEY:
keychain[key_name] = KomradeAsymmetricPublicKey(asymmetric_pubkey,asymmetric_privkey) keychain[key_name] = KomradeAsymmetricPublicKey(asymmetric_pubkey,asymmetric_privkey)
elif key_type_desc==KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE: elif key_type_desc==KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE:
keychain[key_name]=KomradeSymmetricKeyWithoutPassphrase() keychain[key_name]=KomradeSymmetricKeyWithoutPassphrase()
elif key_type_desc==KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE: 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 passphrase=passphrase if passphrase else self.passphrase
keychain[key_name]=KomradeSymmetricKeyWithPassphrase(passphrase=passphrase) keychain[key_name]=KomradeSymmetricKeyWithPassphrase(passphrase=passphrase)
return keychain return keychain
@ -346,6 +389,7 @@ class Keymaker(Logger):
_key_encr_obj = get_encrypted_key_obj(_key_encr, name_of_what_to_encrypt) _key_encr_obj = get_encrypted_key_obj(_key_encr, name_of_what_to_encrypt)
# self.log(f'{_key}\n-- encrypting ----->\n{_key_encr}') # self.log(f'{_key}\n-- encrypting ----->\n{_key_encr}')
# keychain[key_name]=_key_encr
keychain[key_name]=_key_encr_obj keychain[key_name]=_key_encr_obj
return keychain return keychain
@ -356,52 +400,68 @@ class Keymaker(Logger):
keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER, keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER,
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT, keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT,
keys_to_gen = KEYMAKER_DEFAULT_KEYS_TO_GEN, 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 # setup
keys_to_gen = set(keys_to_gen) | set(keys_to_save) | set(keys_to_return) 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('_')) 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]) key_types = dict([(k,key_types[k]) for k in keys_to_gen])
if not name: name=self.name if not name: name=self.name
print('forging!')
# show user what's happening # show user what's happening
self.log(f''' self.log(f'''
Keymaker ({self}) is forging new keys for {name} Keymaker ({self}) is forging new keys for {name}
I will save these keys in this crypt: ''' + ('''
{keys_to_save} * I will save these keys in this crypt: {', '.join(keys_to_save)}
I will also save this user's pubkey (as b64 URI) to: ''' if save_keychain else '') #+ #'''
{self.get_path_qrcode(name=name)} # * I will also save this user's pubkey (as b64 URI) to:
I will return these keys to you: # {self.get_path_qrcode(name=name)}
{keys_to_return} # ''' + (f'''
which means I will end up generating these keys: + (f'''
{keys_to_gen} * I will return these keys to you: {', '.join(keys_to_return)}
I will also be using these key types to do so: ''' 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)} {dict_format(key_types,tab=4)}
''') ''')
# gen decryptor keys! # gen decryptor keys!
keychain = self.gen_keys_from_types(key_types,passphrase=passphrase) keychain = self.gen_keys_from_types(key_types,passphrase=passphrase)
# gen encrypted keys! # 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) 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) # self.status('@Keymaker: I ended up building these keys:',keychain)
# save keys! # save keys!
if save_keychain:
# get URI id to save under (except for pubkeys, accessible by name) # 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) 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) # self.log('I saved this keychain:',dict_format(keys_saved_d,tab=2),'using the generated-from-pubkey URI ID',uri_id)
# return keys! # return keys!
if return_all_keys:
return keychain
if return_keychain:
keys_returned = self.return_keychain(keychain,keys_to_return) keys_returned = self.return_keychain(keychain,keys_to_return)
self.log('I am returning this keychain:',dict_format(keys_returned,tab=2)) # 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): 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(self): return self.qr_str(data=self.uri_id)
def qr_str(self,data=None): def qr_str(self,data=None):
import qrcode data = self.uri_id if not data else data
qr=qrcode.QRCode() return get_qr_str(data)
qr.add_data(self.uri_id if not data else data)
ascii = capture_stdout(qr.print_ascii)
return ascii
def save_uri_as_qrcode(self,uri_id=None,name=None): def save_uri_as_qrcode(self,uri_id=None,name=None):
if not uri_id: uri_id = self.uri_id if not uri_id: uri_id = self.uri_id
@ -458,7 +516,7 @@ Keymaker ({self}) is forging new keys for {name}
keys_saved_d={} keys_saved_d={}
for keyname in keys_to_save: for keyname in keys_to_save:
if not '_' in keyname and keyname!='pubkey': 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: if keyname in keychain:
# uri = uri_id # uri = uri_id
uri = uri_id if keyname!='pubkey' else name 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) # self.log('assembled_key built:',key)
return key return key
except ThemisError as e: except ThemisError as e:
# self.log('!! decryption failed:',e) self.log('!! decryption failed:',e)
return return
def get_cell(self, str_or_key_or_cell): 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__),'..')),'..'))) 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 import *
from komrade.backend import * from komrade.backend import *
from komrade.backend.keymaker import *
class Persona(Caller): class Persona(Caller):
def __init__(self, name=None, passphrase=DEBUG_DEFAULT_PASSPHRASE): def __init__(self, name=None, passphrase=DEBUG_DEFAULT_PASSPHRASE):
super().__init__(name=name,passphrase=passphrase) super().__init__(name=name,passphrase=passphrase)
if SHOW_STATUS:
from komrade.cli import CLI
self.cli = CLI()
# self.boot(create=False) # self.boot(create=False)
# def boot(self,create=False): # def boot(self,create=False):
@ -42,22 +45,38 @@ class Persona(Caller):
# def login(self): # def login(self):
# if keys.get('pubkey') and keys.get('privkey') # 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 # defaults
if name and not self.name: self.name=name if name and not self.name: self.name=name
if not name and self.name: name=self.name if not name and self.name: name=self.name
if not name and not self.name: 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)
if not passphrase: passphrase=getpass('Enter a memorable password: ')
# make and save keys locally # forge public/private keys
uri_id,keys_returned = self.forge_new_keys( keypair = KomradeAsymmetricKey()
name=name, pubkey,privkey = keypair.pubkey_obj,keypair.privkey_obj
passphrase=passphrase,
keys_to_save = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT, # make sure we have passphrase
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER if SHOW_STATUS:
passphrase = self.cli.status_keymaker_body(
name,
passphrase,
pubkey,
privkey,
self.crypt_keys.hash
) )
self.log(f'my new uri is {uri_id} and I got new keys!: {dict_format(keys_returned)}') else:
if not passphrase: passphrase=getpass('Enter a memorable password to encrypt your private key with: ')
# encrypt private key
exit()
# save the ones we should on server # save the ones we should on server
data = { data = {
@ -96,15 +115,16 @@ def test_register():
marxbot.register() marxbot.register()
if __name__=='__main__': if __name__=='__main__':
marx = Persona('marx') test_register()
elon = Persona('elon') # marx = Persona('marx')
# elon = Persona('elon')
marx.register() # marx.register()
# elon.register() # # elon.register()
# person.register() # # person.register()
# print(person.pubkey) # # print(person.pubkey)
# elon.send_msg_to('youre dumb',marx) # # elon.send_msg_to('youre dumb',marx)
#Caller('elon').ring_ring({'_route':'say_hello','_msg':'my dumb message to operator'}) # #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-. .-" ..--""""--.j-.
.-" .-" .--.""--.. .-" .-" .--.""--..
.-" .-" ..--"-. \/ ; .-" .-" ..--"-. \\/ ;
.-" .-"_.--..--"" ..--' "-. : .-" .-"_.--..--"" ..--' "-. :
.' .' / `. \..--"" __ _ \ ; .' .' / `. \\..--"" __ _ \\ ;
:.__.-" \ / .' ( )"-. Y :.__.-" \\ / .' ( )"-. Y
; ;: ( ) ( ). \ ; ;: ( ) ( ). \\
.': /:: : \ \ .': /:: : \\ \\
.'.-"\._ _.-" ; ; ( ) .-. ( ) \ .'.-"\\._ _.-" ; ; ( ) .-. ( ) \\
" `.""" .j" : : \ ; ; \ " `.""" .j" : : \\ ; ; \\
bug /"""""/ ; ( ) "" :.( ) \ bug /"""""/ ; ( ) "" :.( ) \\
/\ / : \ \`.: _ \ /\\ / : \\ \\`.: _ \\
: `. / ; `( ) (\/ :" \ \ : `. / ; `( ) (\\/ :" \\ \\
\ `. : "-.(_)_.' t-' ; \\ `. : "-.(_)_.' t-' ;
\ `. ; ..--": \\ `. ; ..--":
`. `. : ..--"" : `. `. : ..--"" :
`. "-. ; ..--"" ; `. "-. ; ..--"" ;
`. "-.:_..--"" ..--" `. "-.:_..--"" ..--"
@ -25,30 +25,30 @@ ART_TELEPHONE = '''
''' '''
ART_PHONE_SM1 = """ ART_PHONE_SM1 = """
.----------------. .----------------.
/ _H______H_ \@, / _H______H_ \\@,
\____/ \____/ @, \\____/ \\____/ @,
/ \ `@ / \\ `@
| LI LI LI | ,@ | LI LI LI | ,@
| LI LI LI | ,@' | LI LI LI | ,@'
| LI LI LI | ,@' | LI LI LI | ,@'
| LI LI LI |@@' | LI LI LI |@@'
jgs \ /' jgs \\ /'
`----------' `----------'
""" """
ART_ROTARY2=""" ART_ROTARY2="""
_______________ _______________
/ \ / \\
| .---------. |@ | .---------. |@
'---' .-----. '---'@ '---' .-----. '---'@
.' /6 5_4 3\ '. @ .' /6 5_4 3\\ '. @
| |7 /...\ 2| | @ | |7 /...\\ 2| | @
| |8 \___/ 1| | @ | |8 \\___/ 1| | @
| \_9_0_)\/ | @@ | \\_9_0_)\\/ | @@
/==|_____________|@@@@ /==|_____________|@@@@
H-------------------@@ H-------------------@@
H ) || || ( @@ H ) || || ( @@
H / || || \ @ H / || || \\ @
H |----''---''----| H |----''---''----|
=/ |_______________| =/ |_______________|
""" """
@ -64,16 +64,16 @@ ART_KEY = """
ART_OLDPHONE = """ ART_OLDPHONE = """
__ __
/` _`\ /` _`\\
| (_()| .-. | (_()| .-.
\_ _/_/ \ \\_ _/_/ \\
||=[_] | ||=[_] |
|| | | | || | | |
||/ \ | ||/ \\ |
||`---' / ||`---' /
.--'||-.___.' .--'||-.___.'
/` .-||-. /` .-||-.
'-/`.____.`\ '-/`.____.`\\
jgs '.______.' jgs '.______.'
""" """
@ -81,13 +81,13 @@ ART_OLDPHONE2="""
_|~|/| _|~|/|
( | | | ( | | |
/_|_|\| /_|_|\\|
| | | |
| |~| | |~|
| | | | | |
| | | | | |
| |-| | |-|
| | \ | | \\
| |__| | |__|
|_|_ |_|_
/ ~-_ / ~-_
@ -101,16 +101,16 @@ ART_ROTARY = """
,-' ,-. `-. ,-' ,-. `-.
,' ,-. ( 4 ) ,-. `. ,' ,-. ( 4 ) ,-. `.
,' ( 5 ) `-' ( 3 ) `. ,' ( 5 ) `-' ( 3 ) `.
/ ,-. `-',-'' ``-.`-' ,-. \ / ,-. `-',-'' ``-.`-' ,-. \\
/ ( 6 ) ,' `. ( 2 ) \ / ( 6 ) ,' `. ( 2 ) \\
: `-' / FEUER \ `-' : : `-' / FEUER \\ `-' :
| ,-. : ________ : ,-. | | ,-. : ________ : ,-. |
|( 7 ) | |________| | ( 1 )| |( 7 ) | |________| | ( 1 )|
| `-' : ; `-' | | `-' : ; `-' |
: ,-. \ NOTRUF / ; : ,-. \\ NOTRUF / ;
\ ( 8 ) `. ,'(`. / \\ ( 8 ) `. ,'(`. /
\ `-' ,-.`-..__..-' \ `-./ \\ `-' ,-.`-..__..-' \\ `-./
`. ( 9 ) ,-. \ ,' `. ( 9 ) ,-. \\ ,'
`. `-' ( 0 ) ,'` `. `-' ( 0 ) ,'`
`-._ `-' _.-' `-._ `-' _.-'
```----''' SSt ```----''' 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)=;--.:: | / ((O)=;--.:: |
@ -159,13 +159,13 @@ ART_OLDPHONE3 = """
| |: | |:: | | |: | |:: |
| |: | |:: | | |: | |:: |
| |: | |:: | | |: | |:: |
| /:'__\ |:: | | /:'__\\ |:: |
| [______]|:: | | [______]|:: |
| `----` |:: |__ | `----` |:: |__
| _.--|:: | ''--._ | _.--|:: | ''--._
; .' __{====}__ '. ; .' __{====}__ '.
\ .'_.-'._ `""` _.'-._ '. \\ .'_.-'._ `""` _.'-._ '.
'--'/` `''''` `\ '.__ '--'/` `''''` `\\ '.__
jgs '._ _.' jgs '._ _.'
`""--......--""` `""--......--""`
@ -174,44 +174,561 @@ ART_OLDPHONE3 = """
ART_OLDPHONE4 = """ ART_OLDPHONE4 = """
__ __
/` _`\ /` _`\\
| (_()| .-. | (_()| .-.
\_ _/_/ \ \\_ _/_/ \\
||=[_] | ||=[_] |
|| | | | || | | |
||/ \ | ||/ \\ |
||`---' / ||`---' /
.--'||-.___.' .--'||-.___.'
/` .-||-. /` .-||-.
'-/`.____.`\ '-/`.____.`\\
jgs '.______.' '.______.'
""" """
# by jgs
ART_PAYPHONE = """ ART_PAYPHONE = """
_________________ _________________
/ __ \ / __ \\
| (__) | | (__) |
| | | |
| .-----. .--. | | .-----. .--. |
| | | / \ | | | | / \\ |
| '-----' \ / | | '-----' \\ / |
| | | | | | | |
| LI LI LI | | | | LI LI LI | | |
| LI LI LI | | |Oo | LI LI LI | | |Oo
| LI LI LI | | |`Oo | LI LI LI | | |`Oo
| LI LI LI | | | Oo | LI LI LI | | | Oo
| | | | Oo | | | | Oo
| .------. / \ | oO | .------. / \\ | oO
| | | \ / | Oo | | | \\ / | Oo
| '------' '-oO | oO | '------' '-oO | oO
| .---Oo | Oo | .---Oo | Oo
| || ||`Oo oO | || ||`Oo oO
| |'--'| | OoO | |'--'| | 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 image_ascii = [pixels_to_chars[index: index + new_width] for index in
range(0, len_pixels_to_chars, new_width)] range(0, len_pixels_to_chars, new_width)]
return "\n".join(image_ascii) return "\\n".join(image_ascii)
def handle_image_conversion(image_filepath): def handle_image_conversion(image_filepath):
image = None 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 import *
from komrade.backend import * from komrade.backend import *
import art import art
import textwrap as tw
@ -16,8 +17,8 @@ class CLI(Logger):
self.name='' self.name=''
self.cmd='' self.cmd=''
async def run(self,inp,name=''): def run(self,inp='',name=''):
if name: self.name=name self.name=name
clear_screen() clear_screen()
self.boot() self.boot()
self.help() self.help()
@ -26,11 +27,11 @@ class CLI(Logger):
while True: while True:
try: try:
inp=input() inp=input(f'@{self.name if self.name else "?"}: ')
except KeyboardInterrupt: except KeyboardInterrupt:
exit() exit()
self.route(inp) self.route(inp)
await asyncio.sleep(0.5) #await asyncio.sleep(0.5)
def route(self,inp): def route(self,inp):
inp=inp.strip() inp=inp.strip()
@ -42,37 +43,42 @@ class CLI(Logger):
f=getattr(self,cmd) f=getattr(self,cmd)
return f(dat) return f(dat)
def boot(self): def boot(self,indent=5):
print(art.text2art(CLI_TITLE,font=CLI_FONT)) 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): def help(self):
print() print()
for cmd,info in self.ROUTES.items(): for cmd,info in self.ROUTES.items():
print(f' /{cmd}: {info}') print(f' /{cmd}: {info}')
# print('\n')
print('\n') print('\n')
def intro(self): def intro(self):
self.status(None,) self.status(None,)
## routes def register(self,dat):
def register(self,name=None): self.persona = Persona(self.name)
# defaults self.persona.register()
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)
### 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 '?' nm=name if name else '?'
self.status( 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: while not name:
name=self.status(('name','@TheTelephone: Of course, Komrade...?\n@')).get('vals').get('name').strip() name=self.status(('name','@TheTelephone: Of course, Komrade...?\n@')).get('vals').get('name').strip()
print() print()
self.name = name
self.persona = Persona(name)
self.status( self.status(
f'@TheTelephone: Of course, Komrade @{name}. A fine name.', 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.''', '''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.''', 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) clear=False,pause=True)
### KEYMAKER ### 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 # convo
self.status('', self.status(
f'@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.', f'\n@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.',
f'@Keymaker: Of course, Komrade @{name}.', 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.', def status_keymaker_body(self,name,passphrase,pubkey,privkey,hasher):
# gen what we need
'With both together, you can communicate privately and securely with anyone who also has their own key pair.', 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}.)'
# )
# 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.",
'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).', )
self.status(
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
) )
# make and save keys locally res = self.status(
self.log(f'{KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER}!!!!!') '@Keymaker: See? Ok, now type in a password.'
uri_id,keys_returned = self.persona.forge_new_keys( ('str_to_hash',f'@{name}: ',getpass)
name=name, )
passphrase=None, str_to_hash = res.get('vals').get('str_to_hash')
keys_to_save = [], hashed_pass1 = hasher(str_to_hash.encode())
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER res = self.status(
'@Hasher: '+hashed_pass1
) )
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( res = self.status(
'Generating public key now: ',5,'\n\t',repr(KomradeAsymmetricPublicKey(keychain['pubkey'])),'\n\n', '@Keymaker: Whatever you entered, it\'s already forgotten. That hashed mess is all that remains.',
'Generating private key now: ',5,'\n\t',repr(KomradeAsymmetricPrivateKey(keychain['privkey'])), 'Now type in the same password one more time to verify it:',
clear=False,pause=False,end=' ',speed=2 ('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(): def run_cli():
cli = CLI() cli = CLI()
asyncio.run(cli.run('/register',name='elon')) cli.run('/register','elon') #'/register',name='elon')
if __name__=='__main__': if __name__=='__main__':
run_cli() run_cli()

@ -105,8 +105,8 @@ KEYMAKER_DEFAULT_KEY_TYPES = {
'adminkey':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE, 'adminkey':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'pubkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE, 'pubkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'privkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE, 'privkey_decr':KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE,
'adminkey_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE, 'adminkey_decr':KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE,
'pubkey_decr_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE, 'pubkey_decr_decr':KEY_TYPE_SYMMETRIC_WITHOUT_PASSPHRASE,
'privkey_decr_decr':KEY_TYPE_SYMMETRIC_WITH_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_OP_URL = f'http://{KOMRADE_URL}/.contacts/TheOperator.png'
PATH_OPERATOR_WEB_CONTACT_PH_URL = f'http://{KOMRADE_URL}/.contacts/TheTelephone.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 # dangerous! leave on only if absolutely necessary for initial dev
ALLOW_CLEARNET = True ALLOW_CLEARNET = True
@ -182,9 +181,11 @@ DEFAULT_USER_SETTINGS = {
'visibility':VISIBILITY_TYPE_SEMIPUBLIC 'visibility':VISIBILITY_TYPE_SEMIPUBLIC
} }
SHOW_LOG = True SHOW_LOG = 1
SHOW_STATUS = True SHOW_STATUS = 1
PAUSE_LOGGER = 1
CLI_TITLE = 'KOMRADE' CLI_TITLE = 'KOMRADE'
CLI_FONT = 'colossal' CLI_FONT = 'clr5x6'#'colossal'
STATUS_LINE_WIDTH = 50

@ -26,10 +26,14 @@ def log(*x):
def clear_screen(): def clear_screen():
import os import os
# pass
os.system('cls' if os.name == 'nt' else 'clear') os.system('cls' if os.name == 'nt' else 'clear')
def do_pause(): def do_pause():
try:
input('') input('')
except KeyboardInterrupt:
exit('\n\nGoodbye.')
def dict_format(d, tab=0): 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 (%s),\n' % (' '*tab, k, v, type(v).__name__))
s.append('%s%r: %s,\n\n' % (' '*tab, k, reppr(v))) s.append('%s%r: %s,\n\n' % (' '*tab, k, reppr(v)))
s.append('%s}' % (' '*tab)) s.append('%s}' % (' '*(tab-2)))
return ''.join(s) return ''.join(s)
import inspect,time import inspect,time
from komrade.constants import PAUSE_LOGGER,SHOW_LOG,SHOW_STATUS from komrade.constants import *
class Logger(object): class Logger(object):
def log(self,*x,pause=PAUSE_LOGGER,clear=PAUSE_LOGGER): def log(self,*x,pause=PAUSE_LOGGER,clear=PAUSE_LOGGER):
if not SHOW_LOG: return if not SHOW_LOG: return
@ -65,9 +69,22 @@ class Logger(object):
if pause: do_pause() if pause: do_pause()
if pause: clear_screen() if pause: clear_screen()
# except KeyboardInterrupt: # 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 import random
if not SHOW_STATUS: return if not SHOW_STATUS: return
# if len(msg)==1 and type(msg[0])==str: # if len(msg)==1 and type(msg[0])==str:
@ -76,17 +93,33 @@ class Logger(object):
paras=[] paras=[]
res={} res={}
for para in msg: for para in msg:
indentstr=' '*indent
plen = para if type(para)==int or type(para)==float else None plen = para if type(para)==int or type(para)==float else None
if type(para) in {int,float}: if type(para) in {int,float}:
plen=int(para) 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 '.' tick = ticks[i] if i<len(ticks) else '.'
print(tick,end=end if end else ' ',flush=True) print(tick,end=end if end else ' ',flush=True) #,scan=scan)
time.sleep(random.random() / speed) # time.sleep(random.random() / speed)
time.sleep(random.uniform(0.05,0.2))
# print()
elif para is None: elif para is None:
clear_screen() clear_screen()
elif para is False: elif para is False:
pass 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: elif type(para) is tuple:
k=para[0] k=para[0]
q=para[1] q=para[1]
@ -100,11 +133,11 @@ class Logger(object):
elif para is 0: elif para is 0:
do_pause() do_pause()
elif 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] paras+=[para]
do_pause() do_pause()
else: 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] paras+=[para]
return {'paras':paras, 'vals':res} return {'paras':paras, 'vals':res}
@ -223,3 +256,24 @@ def capture_stdout(func):
func() func()
out = f.getvalue() 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