diff --git a/README.md b/README.md index ce8a883..7bbe0d1 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,23 @@ All simple object-oriented stuff in Python. The database is a simple key-value s ### As developer -The usual installation: +#### 1) Make sure pyenv is installed + +[Pyenv](https://github.com/pyenv) is a virtual environment manager that helps you keep track of Python versions. Komrade requires exactly 3.7, for idiosyncracies owing to Kivy. + +You can install pyenv using the [auto installer](https://github.com/pyenv-installer): +``` +curl https://pyenv.run | bash +``` +Then add pyenv to your $PATH (replace .bashrc with .bash_profile if on Mac): + +``` +echo 'export PATH="~/.pyenv/bin:$PATH"' >> ~/.bashrc +``` + +#### 2) Clone and bootstrap + +Now that pyenv is installed, just clone and bootstrap: ``` git clone https://github.com/quadrismegistus/Komrade.git @@ -109,18 +125,23 @@ cd Komrade . script/bootstrap ``` -~~Then run the client:~~ (this is broken temporarily) -``` -cd client -./run.sh -``` +### Usage + +#### Terminal interface -Run the terminal client: +To run Komrade using the terminal interfae: ``` +cd [path to Komrade repo] python komrade/cli/cli.py ``` -### As user +#### Mobile interface + +~~To run Komrade using the mobile interfae~~ (this is broken at the moment): + +``` +cd [path to Komrade repo] +python komrade/app/main.py +``` -Coming soon. diff --git a/komrade/backend/keymaker.py b/komrade/backend/keymaker.py index 9996936..376a91e 100644 --- a/komrade/backend/keymaker.py +++ b/komrade/backend/keymaker.py @@ -31,15 +31,6 @@ class KomradeKey(ABC,Logger): class KomradeSymmetricKey(KomradeKey): - @property - def cell(self): - if not hasattr(self,'_cell'): - # if hasattr(self,'passphrase') and self.passphrase: - # self._cell = SCellSeal(passphrase=hasher(self.passphrase)) - # elif hasattr(self,'key') and self.key: - # self._cell = SCellSeal(key=self.key) - self._cell = SCellSeal(key=self.key) - return self._cell def encrypt(self,msg,**kwargs): if hasattr(msg,'data'): msg=msg.data # print('??? dec',msg,kwargs) @@ -104,6 +95,11 @@ class KomradeSymmetricKeyWithoutPassphrase(KomradeSymmetricKey): @property def data(self): return self.key def __repr__(self): return f'[Symmetric Key]\n ({self.discreet})' + @property + def cell(self): + if not hasattr(self,'_cell'): + self._cell = SCellSeal(key=self.key) + return self._cell @@ -299,50 +295,10 @@ class Keymaker(Logger): keychain[keyname] = get_key_obj(keyname,keyval) return keychain - def find_pubkey_and_name(self,name=None,pubkey=None): - if not pubkey: pubkey = self._keychain.get('pubkey') - if not name: name = self.name - - if pubkey: - # print('??',pubkey) - if hasattr(pubkey,'data'): - pubkey=pubkey.data_b64 - else: - pubkey=b64enc(pubkey) - - # if name and pubkey: - # make sure they match - #assert self.find_pubkey(name) == self.find_name(pubkey) - # if self.find_pubkey(name) != self.find_name: - # pass - # self.log(f'! {name} and {pubkey} do not match?') - if name and not pubkey: - pubkey = self.find_pubkey(name) - elif pubkey and not name: - self.name = self.find_name(pubkey) - # else: - # self.log('error! Neither name nor pubkey! Who am I?') - # return (None,None) - - if pubkey: - # self.log('!?!?!?!?',type(pubkey),pubkey) - pubkey = b64dec(pubkey) - pubkey=KomradeAsymmetricPublicKey(pubkey) - - self._keychain['pubkey'] = pubkey - self.name = name - - self.log('found for name and pubkey',name,pubkey) - - return (name,pubkey) - def keychain(self,look_for=KEYMAKER_DEFAULT_ALL_KEY_NAMES): # load existing keychain keys = self._keychain - # make sure we have the pubkey - # name,pubkey = self.find_pubkey_and_name() - # get uri pubkey = self.find_pubkey() if pubkey: @@ -410,7 +366,6 @@ class Keymaker(Logger): self._uri_id = pubkey.data_b64 return self._uri_id - ### BASE STORAGE @property def crypt_keys(self): @@ -418,147 +373,14 @@ class Keymaker(Logger): self._crypt_keys = Crypt(fn=self.path_crypt_keys) return self._crypt_keys - @property - def crypt_keys_mem(self): - if not hasattr(self,'_crypt_keys_mem'): - self._crypt_keys_mem = CryptMemory() - return self._crypt_keys_mem - @property def crypt_data(self): if not hasattr(self,'_crypt_data'): self._crypt_data = Crypt(fn=self.path_crypt_data) return self._crypt_data - def can_log_in(self): - if not self.pubkey: return False - if not (self.privkey or self.privkey_encr): return False - return True - - - ### CREATING KEYS - - def get_new_keys(self): - raise KomradeException('Every keymaker must make their own get_new_keys() !') - - - - def gen_keys_from_types(self,key_types=KEYMAKER_DEFAULT_KEY_TYPES,passphrase=DEBUG_DEFAULT_PASSPHRASE): - """ - Get new asymmetric/symmetric keys, given a dictionary of constants describing their type - """ - # print('bbbbb') - - asymmetric_pubkey=None - asymmetric_privkey=None - keychain = {} - - self.log('got key types:',dict_format(key_types)) - - # gen keys requested - for key_name,key_class in key_types.items(): - ## asymmetric? - if issubclass(key_class,KomradeAsymmetricKey): - if not asymmetric_privkey or asymmetric_pubkey: - asymmetric_keys = KomradeAsymmetricKey() - asymmetric_pubkey = asymmetric_keys.pubkey_obj - asymmetric_privkey = asymmetric_keys.privkey_obj - - if key_class == KomradeAsymmetricPublicKey: - keychain[key_name]=asymmetric_pubkey - elif key_class == KomradeAsymmetricPrivateKey: - keychain[key_name]=asymmetric_privkey - - elif key_class == KomradeSymmetricKeyWithPassphrase: - keychain[key_name] = KomradeSymmetricKeyWithPassphrase(passphrase) - else: - # print('??',key_name,key_class) - keychain[key_name] = key_class(None) - - self.log('keytypes -> keychain',dict_format(keychain)) - return keychain - - - - - - - def forge_new_keys(self, - name=None, - passphrase=DEBUG_DEFAULT_PASSPHRASE, - 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, - 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 k]) - if not name: name=self.name - - - - # show user what's happening - self.log(f''' -Keymaker ({self}) is forging new keys for {name} -''' + (f''' -* 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.disassemble(keychain,passphrase=passphrase) - self.log('I built this keychain!',dict_format(keychain,tab=2)) - self.status('@Keymaker: I ended up building these keys:',keychain) - - - # save keys! - 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(f'Trying to save these keys ({keys_to_save}), I saved this keychain:',dict_format(keys_saved_d,tab=2),'using the generated-from-pubkey URI ID',uri_id) - - # return keys! - 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 - - raise KomradeException('What did you want me to do here?') - - - def return_keychain(self,keychain,keys_to_return=None): - keychain_toreturn = {} - if not keys_to_return: keys_to_return = list(keychain.keys()) - for key in keys_to_return: - if key in keychain: - keychain_toreturn[key]=keychain[key] - return keychain_toreturn + def get_path_qrcode(self,name=None,dir=None,ext='.png'): if not name: name=self.name if not dir: dir = PATH_QRCODES @@ -625,7 +447,7 @@ Keymaker ({self}) is forging new keys for {name} return (uri_id,keys_saved_d,keychain) - def assemble(self,keychain,passphrase=None,key_types=KEYMAKER_DEFAULT_KEY_TYPES,decrypt=True): + def assemble(self,keychain,key_types=KEYMAKER_DEFAULT_KEY_TYPES,decrypt=True): encr_keys = [k for k in keychain.keys() if k.endswith('_encr')] for encr_key_name in encr_keys: decr_key_name = encr_key_name[:-5] + '_decr' @@ -634,11 +456,8 @@ Keymaker ({self}) is forging new keys for {name} if decrypt and unencr_key_name in keychain: continue if not decr_key_name in keychain: self.log('! not in keychain: decr key name:',decr_key_name,keychain) - #keychain[decr_key_name] = KomradeSymmetricKeyWithPassphrase(passphrase=passphrase) continue decr_key = keychain.get(decr_key_name) - # self.log('?',decr_key,decr_key_name,encr_key_name,keychain[encr_key_name]) - try: if decrypt: encr_key = keychain.get(encr_key_name) @@ -660,9 +479,5 @@ Keymaker ({self}) is forging new keys for {name} return self.assemble(keychain,decrypt=False,**kwargs) - -if __name__ == '__main__': - keymaker = Keymaker('marx69') - keychain = keymaker.forge_new_keys() - +\ print(keychain) \ No newline at end of file diff --git a/komrade/backend/komrades.py b/komrade/backend/komrades.py index 03d798f..6a486f1 100644 --- a/komrade/backend/komrades.py +++ b/komrade/backend/komrades.py @@ -27,7 +27,7 @@ class KomradeX(Caller): # yes? -- login keys = self.keychain() - self.log(f'booting {self}!',dict_format(keys)) + # self.log(f'booting {self}!',dict_format(keys)) if keys.get('pubkey') and keys.get('privkey'): # self.log('already booted! @'+self.name) diff --git a/komrade/backend/the_operator.py b/komrade/backend/the_operator.py index 9eb28ce..3662129 100644 --- a/komrade/backend/the_operator.py +++ b/komrade/backend/the_operator.py @@ -33,7 +33,6 @@ class TheOperator(Operator): """ super().__init__( name, - passphrase, path_crypt_keys=PATH_CRYPT_OP_KEYS, path_crypt_data=PATH_CRYPT_OP_DATA ) diff --git a/komrade/cli/artcode0.py b/komrade/cli/artcode0.py deleted file mode 100644 index 46c3cd6..0000000 --- a/komrade/cli/artcode0.py +++ /dev/null @@ -1,920 +0,0 @@ -ART_TELEPHONE = ''' - ..--""""----.. - .-" ..--""""--.j-. - .-" .-" .--.""--.. - .-" .-" ..--"-. \\/ ; - .-" .-"_.--..--"" ..--' "-. : - .' .' / `. \\..--"" __ _ \\ ; - :.__.-" \\ / .' ( )"-. Y - ; ;: ( ) ( ). \\ - .': /:: : \\ \\ - .'.-"\\._ _.-" ; ; ( ) .-. ( ) \\ - " `.""" .j" : : \\ ; ; \\ - bug /"""""/ ; ( ) "" :.( ) \\ - /\\ / : \\ \\`.: _ \\ - : `. / ; `( ) (\\/ :" \\ \\ - \\ `. : "-.(_)_.' t-' ; - \\ `. ; ..--": - `. `. : ..--"" : - `. "-. ; ..--"" ; - `. "-.:_..--"" ..--" - `. : ..--"" - "-. : ..--"" - "-.;_..--"" - -''' -ART_PHONE_SM1 = """ - .----------------. - / _H______H_ \\@, - \\____/ \\____/ @, - / \\ `@ - | LI LI LI | ,@ - | LI LI LI | ,@' - | LI LI LI | ,@' - | LI LI LI |@@' -jgs \\ /' - `----------' -""" - -ART_ROTARY2=""" - _______________ - / \\ - | .---------. |@ - '---' .-----. '---'@ - .' /6 5_4 3\\ '. @ - | |7 /...\\ 2| | @ - | |8 \\___/ 1| | @ - | \\_9_0_)\\/ | @@ - /==|_____________|@@@@ - H-------------------@@ - H ) || || ( @@ - H / || || \\ @ - H |----''---''----| -=/ |_______________| -""" - -ART_KEY = """ - - 8 8 8 8 ,ooo. - 8a8 8a8 oP b - d888a888zzzzzzzzzzzzzzzzzzzz8 8b - `""^""' o___oP' - -""" - -ART_OLDPHONE = """ - __ - /` _`\\ - | (_()| .-. - \\_ _/_/ \\ - ||=[_] | - || | | | - ||/ \\ | - ||`---' / - .--'||-.___.' - /` .-||-. - '-/`.____.`\\ -jgs '.______.' -""" - -ART_OLDPHONE2=""" - - _|~|/| - ( | | | - /_|_|\\| - | | - | |~| - | | | - | | | - | |-| - | | \\ - | |__| - |_|_ - / ~-_ -/ ~-_ -|___________| - -""" - -ART_ROTARY = """ - _...----..._ - ,-' ,-. `-. - ,' ,-. ( 4 ) ,-. `. - ,' ( 5 ) `-' ( 3 ) `. - / ,-. `-',-'' ``-.`-' ,-. \\ - / ( 6 ) ,' `. ( 2 ) \\ -: `-' / FEUER \\ `-' : -| ,-. : ________ : ,-. | -|( 7 ) | |________| | ( 1 )| -| `-' : ; `-' | -: ,-. \\ NOTRUF / ; - \\ ( 8 ) `. ,'(`. / - \\ `-' ,-.`-..__..-' \\ `-./ - `. ( 9 ) ,-. \\ ,' - `. `-' ( 0 ) ,'` - `-._ `-' _.-' - ```----''' SSt -""" - - -ART_PHONE_DIAGRAM = """ - ________ - .' / / ) - / /##/ /| - / `--' / | - /__ __ __ / | - //_//_//_// / __ - //_//_//_// / \\`.___ Listening end - //_//_//_// / - //_//_//_// /__ - / / / \\`.___ Buttons - / .-. / / - / /#/ / / - / `-' / /__ - / .====. / / \\`.___ Speaking end - |`--------' / - \\ , .'__ - `-//----' \\`.___ Disconnect button - // -""" - -ART_OLDPHONE3 = """ - - __ _ - .: .' '. - /: / \\_ - ;: ; ,-'/`:\\ - |: | | |():| - ;: ; '-.\\_:/ - \\: \\ /` - ':_'._.' - || - /__\\ - .---. {====} - .' _,"-,__|:: | - / ((O)=;--.:: | - ; `|: | |:: | - | |: | |:: | - | |: | |:: | - | |: | |:: | - | |: | |:: | - | |: | |:: | - | /:'__\\ |:: | - | [______]|:: | - | `----` |:: |__ - | _.--|:: | ''--._ - ; .' __{====}__ '. - \\ .'_.-'._ `""` _.'-._ '. - '--'/` `''''` `\\ '.__ - jgs '._ _.' - `""--......--""` - -""" - -ART_OLDPHONE4 = """ - - __ - /` _`\\ - | (_()| .-. - \\_ _/_/ \\ - ||=[_] | - || | | | - ||/ \\ | - ||`---' / - .--'||-.___.' - /` .-||-. - '-/`.____.`\\ - '.______.' -""" -# 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 - | |'--'| | OoO - | '----' | -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_PAIR_SPLITTING1 = """ - _ - /o - \ - < - < - < - - (2A) - symmetric - encryption - key, from - hashed - passphrase - -""" - - -ART_KEY_PAIR_SPLITTING2 = """ - _ __ - /o / o\\ - \ \_ / - < --(encrypts)--> <| - < <| - < <| - - (2A) (2) - symmetric asymmetric - encryption private - key, from key - hashed - passphrase - -""" - -ART_KEY_PAIR_SPLITTING3 = """ - _ __ _ - /o / o\\ \\ - \ \_ / / - < --(encrypts)--> <| --(into)--> | - < <| | - < <| | - - (2A) (2) (2B) - symmetric asymmetric encrypted form - encryption private of (2) - key, from key - hashed - passphrase - -""" - - -ART_KEY_PAIR_SPLITTING4 = """ - _ _ - /o \\ - \ / - < | - < | - < | - - (2A) (2B) - symmetric encrypted form - encryption of (2) - key, from - hashed - passphrase - -""" - - - - -ART_KEY_PAIR_SPLITTING5 = """ - _ - \\ - / - | - | - | - - (2B) - encrypted form - of (2) - - - - -""" - - - - - - -ART_KEY_PAIR32 = """ - - __ - /o \\_____ - \__/-="="` - _ _ (1) public key - /o \\ - \ _ / - < | - < | - < | (2B) privkey_encr - - (2A) privkey_decr - -""" - - -ART_KEY_PAIR3A2 = """ - - __ - /o \\_____ - \__/-="="` - _ _ (1) public key - /o \\ - \ _ / - < | - < | - < | - - - -""" - -ART_KEY_KEY2A = """ _ - /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_PAIR4ZZ = """ - - __ - /o \\_____ - \__/-="="` - - _ - \\ - _ / - | - | - | - - - -""" - - -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 - |______________| - -""" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#### -# code -### -from PIL import Image -ASCII_CHARS = [ '#', ' ', '%', '.', 'S', '+', '.', '*', ':', ',', '@'] - -def scale_image(image, new_width=100): - """Resizes an image preserving the aspect ratio. - """ - (original_width, original_height) = image.size - aspect_ratio = original_height/float(original_width) - new_height = int(aspect_ratio * new_width) - - new_image = image.resize((new_width, new_height)) - return new_image - -def convert_to_grayscale(image): - return image.convert('L') - -def map_pixels_to_ascii_chars(image, range_width=25): - """Maps each pixel to an ascii char based on the range - in which it lies. - - 0-255 is divided into 11 ranges of 25 pixels each. - """ - - pixels_in_image = list(image.getdata()) - pixels_to_chars = [ASCII_CHARS[pixel_value//range_width] for pixel_value in - pixels_in_image] - - return "".join(pixels_to_chars) - -def convert_image_to_ascii(image, new_width=100): - image = scale_image(image) - image = convert_to_grayscale(image) - - pixels_to_chars = map_pixels_to_ascii_chars(image) - len_pixels_to_chars = len(pixels_to_chars) - - 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) - -def handle_image_conversion(image_filepath): - image = None - try: - image = Image.open(image_filepath) - except Exception as e: - # print "Unable to open image file {image_filepath}.".format(image_filepath=image_filepath) - # print e - return - - image_ascii = convert_image_to_ascii(image) - print(image_ascii) - -if __name__=='__main__': - import sys - - image_file_path = sys.argv[1] - handle_image_conversion(image_file_path) \ No newline at end of file diff --git a/komrade/cli/cli0.py b/komrade/cli/cli0.py deleted file mode 100644 index e181aba..0000000 --- a/komrade/cli/cli0.py +++ /dev/null @@ -1,415 +0,0 @@ -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 * -import art -import textwrap as tw - - - -class CLI(Logger): - ROUTES = { - 'help':'see help messages', - 'register':'register new user', - 'login':'log back in' - } - - def __init__(self,name='',cmd='',persona=None): - self.name=name - self.cmd=cmd - self.persona=persona - - def run(self,inp='',name=''): - self.name=name - clear_screen() - # self.boot() - # self.help() - - if inp: self.route(inp) - - while True: - try: - inp=input(f'@{self.name if self.name else "?"}: ') - except KeyboardInterrupt: - exit() - self.route(inp) - #await asyncio.sleep(0.5) - - def route(self,inp): - inp=inp.strip() - if not inp.startswith('/'): return - cmd=inp.split()[0] - dat=inp[len(cmd):].strip() - cmd=cmd[1:] - if cmd in self.ROUTES and hasattr(self,cmd): - f=getattr(self,cmd) - return f(dat) - - def boot(self,indent=5): - logo=art.text2art(CLI_TITLE,font=CLI_FONT) - # logo=make_key_discreet_str(logo,chance_redacted=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,) - - def register(self,dat): - self.komrade = Komrade(self.name) - self.persona.register() - - - - - ### DIALOGUES - - # hello, op? - def status_keymaker_part1(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\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.status( - f'@TheTelephone: Of course, Komrade @{name}. A fine name.', - - '''@TheTelephone: However, I'm just the local operator who lives on your device; my only job is to communicate with the remote operator securely.''', - - '''Komrade @TheOperator lives on the deep web. She's the one you want to speak with.''', - - 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 cut your encryption keys first.''', - - f'@{name}: Fine, but how do I do that?', - - f'@{TELEPHONE_NAME}: Visit the Keymaker.', - - clear=False,pause=True) - - ### KEYMAKER - self.status(None,{tw.indent(ART_KEY,' '*5)+'\n',True},3) #,clear=False,indent=10,pause=False) - # convo - self.status( - f'\n@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.', - - f'@Keymaker: Of course, Komrade @{name}.', - ) - - self.status( - 'I will cut 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) - - return name - - - - def status_keymaker_part2(self,name,passphrase,pubkey,privkey,hasher,persona): - from getpass import getpass - # 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( - # None,{ART_KEY_PAIR}, - # 'A matching set of keys have been generated.', - # None,{ART_KEY_PAIR2A+'\nA matching set of keys have been generated.'+'\n'}, - # 'First, I have made a "public key" which you can share with anyone:', - # f'(1) {pubkey.data_b64.decode()}', - # 'This key is a randomly-generated binary string, which acts as your "address" on Komrade.', - # 'With it, someone can 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 IRL:', - # {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 cut a matching "private key".', - "It's too dangerous to show in full, so I've redacted most of it:", - f'(2) {make_key_discreet(privkey.data_b64,0.3)}', - 'With it, you can decrypt any message sent to you via your public key.', - 'You can also encrypt messages ', - ) - - # private keys - self.status(None, - {CUBEKEY}, - 'You you should never, ever give your private key to anyone.', - 'In fact, this key is so dangerous that we need to lock it away immediately.', - "We'll even throw away the key we use to lock this private key with!", - "How? By regenerating it each time from your password.", - ) - - if not passphrase: - from getpass import getpass - 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, - {indent_str(ART_FROG_BLENDER,10),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_str1 = hasher(str_to_hash.encode()) - res = self.status( - '@Hasher: '+hashed_str1 - ) - res = self.status( - '@Keymaker: Whatever you typed, there\'s no way to reconstruct it from that garbled mess.', - 'But whatever you typed will always produce the *same* garbled mess.', - ('str_to_hash',f'Try typing the exact same thing over again:\n@{name}: ',input) - ) - str_to_hash = res.get('vals').get('str_to_hash') - hashed_str2 = hasher(str_to_hash.encode()) - res = self.status( - '@Hasher: '+hashed_str2 - ) - if hashed_str1==hashed_str2: - self.status('See how the hashed values are also exactly the same?') - else: - self.status('See how the hashed values have also changed?') - - res = self.status( - ('str_to_hash',f'Now try typing something just a little bit different:\n@{name}: ',input) - ) - str_to_hash = res.get('vals').get('str_to_hash') - hashed_str3 = hasher(str_to_hash.encode()) - res = self.status( - '@Hasher: '+hashed_str3 - ) - if hashed_str2==hashed_str3: - self.status('See how the hashed values are also the same?') - else: - self.status('See how the hashed values have also changed?') - - - self.status( - None,{indent_str(ART_FROG_BLENDER,10)}, - '@Keymaker: Behind the scenes, @Hasher is using the SHA-256 hashing function, which was designed by the NSA.', - 'But @Hasher also adds a secret "salt" to the recipe, as it\'s called.', - 'To whatever you type in, @Hasher adds a secret phrase: another random string of characters which never changes.', - "By doing so, the hash output is \"salted\": made even more idiosyncratic to outside observers.", - ) - - self.status( - None,{indent_str(ART_FROG_BLENDER,10)}, - f"I've taken the liberty of generating a random secret for your device, which I show here mostly redacted:", - make_key_discreet_str(persona.crypt_keys.secret.decode(),0.25), - 'The full version of this secret is silently added to every input you type into @Hasher.', - "I've saved this secret phrase to a hidden location on your device hardware.", - ) - - self.status( - None,{indent_str(ART_FROG_BLENDER,10)}, - 'However, this means that you will be unable to log in to your account from any other device.', - 'This limitation provides yet another level of hardware protection against network attacks.', - 'However, you can always choose (not recommended) to the secret file with another device by a secure channel.', - 3,f'But, please excuse me Komrade @{name} -- I digress.' - ) - - while not passphrase: - res = self.status(None, - {indent_str(ART_FROG_BLENDER,10)}, - "@Keymaker: Please type your chosen password into @Hasher.", - ('str_to_hash',f'\n@{name}: ',getpass), - pause=False - ) - str_to_hash = res.get('vals').get('str_to_hash') - hashed_pass1 = hasher(str_to_hash.encode()) - res = self.status( - '\n@Hasher: '+hashed_pass1, - pause=False - ) - res = self.status( - '\nNow type in the same password one more time to verify it:', - ('str_to_hash',f'\n@{name}: ',getpass), - pause=False - ) - str_to_hash = res.get('vals').get('str_to_hash') - hashed_pass2 = hasher(str_to_hash.encode()) - res = self.status( - '\n@Hasher: '+hashed_pass2, - pause=False - ) - - if hashed_pass1==hashed_pass2: - self.status('','@Keymaker: Excellent. The passwords clearly matched, because the hashed values matched.',pause=False) - passphrase = hashed_pass1 - else: - self.status('@Keymaker: A pity. It looks like the passwords didn\'t match, since the hashed values didn\'t match either. Try again?') - - return passphrase - - def status_keymaker_part3(self,privkey,privkey_decr,privkey_encr,passphrase): - self.status( - None,{tw.indent(ART_KEY,' '*5)+'\n',True}, - # None,{ART_+'\n',True}, - 'Now that we have a hashed passphrase, we can generate the (2A) encryption key.', - {ART_KEY_KEY2A,True,0.1}, - '''The key is formed using Themis's high-level symmetric encryption library: SecureCell, using Seal mode.''', - 'This key (2A) then uses the AES-256 encryption algorithm to encrypt the super-sensitive private key (2):' - ) - - s0=str.center('[Encryption Process]',CLI_WIDTH) - s1=s0 + '\n\n' + self.printt('Now that we have (2A), we can use it to encrypt the super-sensitive private key (2):',ret=True) - s2a = self.printt(f"(2A) {make_key_discreet_str(passphrase)}",ret=True) - s2 = self.printt(f"(2) {make_key_discreet(privkey.data_b64)}",ret=True) - s2b = self.printt(f"(2B) {make_key_discreet(b64encode(privkey_encr))}",ret=True) - self.status( - # screen 1 - None,{f'{s1}'}, - False, - - # 2 - None,{f'{s1}\n\n{ART_KEY_PAIR_SPLITTING1}'}, - {s2a,True}, - False, - - # 3 - None,{f'{s1}\n\n{ART_KEY_PAIR_SPLITTING2}\n{s2a}'}, - {'\n'+s2,True}, - False, - - # 4 - None,{f'{s1}\n\n{ART_KEY_PAIR_SPLITTING3}\n{s2a}\n\n{s2}'}, - {'\n'+s2b,True}, - False, - ) - - - shdr=str.center('[Decryption Process]',CLI_WIDTH) + '\n\n' + self.printt('Once we have (2B), we don\'t need (2A) or (2) anymore. We can regenerate them!',ret=True) - from getpass import getpass - - passhash = None - - while passhash!=passphrase: - res = self.status( - None,{shdr},False if passhash is None else True, - - ("pass",self.printt(f"Let's try. Re-type your password into @Hasher:",ret=True)+f" \n ",getpass) - ) - - passhash = self.persona.crypt_keys.hash(res.get('vals').get('pass').encode()) - if passhash!=passphrase: - self.status({' Looks like they don\'t match. Try again?'},False) - - - self.status( - {' Excellent. We can now regenerate the decryption key:'},False, - {s2a,True},False, - ) - - # self.status('great') - # shdr2= - self.status( - - # 2 - None,{f'{shdr}\n\n{ART_KEY_PAIR_SPLITTING1}'}, - {s2a,True}, - False, - - # 3 - # None,{f'{s1}\n\n{ART_KEY_PAIR_SPLITTING2}\n{s2a}'}, - # {'\n'+s2,True}, - # False, - - # 4 - None,{f'{s1}\n\n{ART_KEY_PAIR_SPLITTING4}\n{s2a}\n\n\n\n'}, - {'\n'+s2b,True}, - False, - ) - - - - - - - - -def run_cli(): - cli = CLI() - cli.run('/register','elon') #'/register',name='elon') - -if __name__=='__main__': - run_cli() - # asyncio.run(test_async()) - - - - - - - - - - - - - - -""" -Outtakes - - 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.", - - ) -""" \ No newline at end of file