diff --git a/impra/cli.py b/impra/cli.py index e1a0e7c..3ea0232 100644 --- a/impra/cli.py +++ b/impra/cli.py @@ -30,9 +30,11 @@ # ~~ package cli ~~ from optparse import OptionParser, OptionGroup -desc="""version : 0.41 copyright : pluie.org -author : a-Sansara license : GNU GPLv3 +import sys +import impra.util as util +import impra.core as core +desc=""" ImpraStorage provided a private imap access to store large files. Each file stored on the server is split in severals random parts. Each part also contains random noise data (lenght depends on a crypt key) @@ -52,7 +54,7 @@ ImpraStorage randomly upload each parts then update the index. """ -class _SimplerOptionParser(OptionParser): +class _OptionParser(OptionParser): """A simplified OptionParser""" def format_description(self, formatter): @@ -61,7 +63,28 @@ class _SimplerOptionParser(OptionParser): def format_epilog(self, formatter): return self.epilog -parser = _SimplerOptionParser(prog='imprastorage', usage='\n\n %prog COMMAND [OPTION]...',epilog=""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~ class Cli ~~ + +class Cli: + + def __init__(self,path): + + self.ini = util.IniFile(path+'impra.ini') + parser = _OptionParser(prog='imprastorage', usage='\n\n\ +------------------------------------------------------------------------------\n\ +-- ImpraStorage --\n\ +------------------------------------------------------------------------------\n\ +-- version : 0.41 copyright : pluie.org --\n\ +-- author : a-Sansara license : GNU GPLv3 --\n\ +------------------------------------------------------------------------------\n\ +\n\ +%prog conf [-D|-L| -K,-H {host},-U {user},-X {password},-P {port},\n\ + -B {boxname}] [-A profileName]\n\ +%prog data [-l |-a {file, label} |-g {label} |-G {id} |-s {pattern} |\n\ + -r {label} |-R {id}] [-c {catg}, -u {owner}, -b {boxname},\n\ + -o {outputdir}]',epilog=""" conf command Examples: @@ -69,8 +92,7 @@ conf command Examples: imprastorage conf -K -H imap.gmail.com -P 993 -U login -X password Set config on a new profile with same keys from previous active profile: - imprastorage conf -A profile1 -H myimapserver.net -P 993 -U login \\ - -X password -B boxname + imprastorage conf -H myimapserver.net -P 993 -U login -X password -B boxname -A profile1 Load config from a profile (wich become active) : imprastorage conf -DA profile2 @@ -108,49 +130,161 @@ data command Examples: """,description=desc) -gpData = OptionGroup(parser, '\ndata related Options (command data)\n-----------------------------------') -gpConf = OptionGroup(parser, '\nconf related Options (command conf)\n-----------------------------------') + gpData = OptionGroup(parser, '\n------------------------------------\ndata related Options (command data)') + gpConf = OptionGroup(parser, '\n------------------------------------\nconf related Options (command conf)') -# metavar=' ', nargs=2 -parser.add_option('-v', '--version' , help='show program\'s version number and exit' , dest='version' , action='store_true' , default=False) -parser.add_option('-q', '--quiet' , help='don\'t print status messages to stdout' , dest='verbose' , action='store_false', default=True) -parser.add_option('-f', '--force' , help='dont confirm and force action' , dest='force' , action='store_true' , default=False) -parser.add_option('-d', '--debug' , help='set debug mode' , dest='debug' , action='store_true' , default=False) + # metavar=' ', nargs=2 + parser.add_option('-v', '--version' , help='show program\'s version number and exit' , action='store_true' , default=False) + parser.add_option('-q', '--quiet' , help='don\'t print status messages to stdout' , action='store_false', default=True) + parser.add_option('-f', '--force' , help='dont confirm and force action' , action='store_true' , default=False) + parser.add_option('-d', '--debug' , help='set debug mode' , action='store_true' , default=False) -gpData.add_option('-l', '--list' , help='list index on imap server' , dest='list_index' , action='store_true' , default=False) -gpData.add_option('-b', '--boxname' , help='switch boxname on imap server' , dest='switch_boxname' , action='store', metavar='BOXN') -gpData.add_option('-a', '--add' , help='add file FILE with specified LABEL on server' , dest='add' , action='store', metavar='FILE LABEL', nargs=2) -gpData.add_option('-g', '--get' , help='get file with specified LABEL from server' , dest='get' , action='store', metavar='LABEL') -gpData.add_option('-G', '--get-by-id' , help='get file with specified ID from server' , dest='get_by_id' , action='store', metavar='ID') -gpData.add_option('-s', '--search' , help='search file with specified PATTERN' , dest='search' , action='store', metavar='PATTERN') -gpData.add_option('-c', '--category' , help='set specified CATEGORY (crit. for opt. -l,-a or -s)' , dest='category' , action='store', metavar='CATG' , default='none') -gpData.add_option('-u', '--user' , help='set specified USER (crit. for opt. -l,-a or -s)' , dest='owner' , action='store', metavar='OWNER' , default='all') -gpData.add_option('-o', '--output-dir' , help='set specified OUTPUT DIR (for opt. -l,-a,-d or -g)' , dest='output' , action='store', metavar='DIR') -gpData.add_option('-r', '--remove' , help='remove FILE with specified LABEL from server' , dest='remove' , action='store', metavar='LABEL') -gpData.add_option('-R', '--remove-by-id' , help='remove FILE with specified ID from server' , dest='remove_by_id' , action='store', metavar='ID') -parser.add_option_group(gpData) + gpData.add_option('-l', '--list' , help='list index on imap server' , action='store_true' ) + gpData.add_option('-a', '--add' , help='add file FILE with specified LABEL on server' , action='store', metavar='FILE LABEL ', nargs=2) + gpData.add_option('-g', '--get' , help='get file with specified LABEL from server' , action='store', metavar='LABEL ') + gpData.add_option('-G', '--get-by-id' , help='get file with specified ID from server' , action='store', metavar='ID ') + gpData.add_option('-s', '--search' , help='search file with specified PATTERN' , action='store', metavar='PATTERN ') + gpData.add_option('-r', '--remove' , help='remove FILE with specified LABEL from server' , action='store', metavar='LABEL ') + gpData.add_option('-R', '--remove-by-id' , help='remove FILE with specified ID from server' , action='store', metavar='ID ') + gpData.add_option('-b', '--boxname' , help='switch boxname on imap server' , action='store', metavar='BOXN ') + gpData.add_option('-c', '--category' , help='set specified CATEGORY (crit. for opt. -l,-a or -s)' , action='store', metavar='CATG ' , default='none') + gpData.add_option('-u', '--user' , help='set specified USER (crit. for opt. -l,-a or -s)' , action='store', metavar='OWNER ' , default='all') + gpData.add_option('-o', '--output-dir' , help='set specified OUTPUT DIR (for opt. -l,-a,-d or -g)' , action='store', metavar='DIR ') + parser.add_option_group(gpData) -gpConf.add_option('-L', '--list-conf' , help='list configuration' , dest='list_conf' , action='store') -gpConf.add_option('-A', '--active-profile', help='set active profile' , dest='profile' , action='store', metavar='PROFILE', default='default') -gpConf.add_option('-H', '--set-host' , help='set imap host server' , dest='host' , action='store', metavar='HOST') -gpConf.add_option('-U', '--set-user' , help='set imap user login' , dest='user' , action='store', metavar='USER') -gpConf.add_option('-X', '--set-pass' , help='set imap user password' , dest='password' , action='store', metavar='PASS') -gpConf.add_option('-P', '--set-port' , help='set imap port (default:[%default])' , dest='port' , action='store', metavar='PORT' , default=993) -gpConf.add_option('-B', '--set-boxname' , help='set boxName on imap server (default:[%default])' , dest='boxname' , action='store', metavar='BOXN' , default='__IMPRA') -gpConf.add_option('-K', '--gen-keys' , help='generate new pub/private keys' , dest='generate_keys' , action='store_true', default=False) -gpConf.add_option('-D', '--load-conf' , help='load configuration' , dest='load_conf' , action='store_true', default=False) -parser.add_option_group(gpConf) + gpConf.add_option('-L', '--list-conf' , help='list configuration' , action='store_true', default=False) + gpConf.add_option('-D', '--load-conf' , help='load configuration' , action='store_true', default=False) + gpConf.add_option('-H', '--set-host' , help='set imap host server' , action='store', metavar='HOST ') + gpConf.add_option('-U', '--set-user' , help='set imap user login' , action='store', metavar='USER ') + gpConf.add_option('-X', '--set-pass' , help='set imap user password' , action='store', metavar='PASS ') + gpConf.add_option('-P', '--set-port' , help='set imap port' , action='store', metavar='PORT ') + gpConf.add_option('-N', '--set-name' , help='set user name' , action='store', metavar='NAME ') + gpConf.add_option('-B', '--set-boxn' , help='set boxName on imap server (default:[%default])' , action='store', metavar='BOXNAME ') + gpConf.add_option('-K', '--gen-keys' , help='generate new pub/private keys' , action='store_true', default=False) + gpConf.add_option('-A', '--active-profile', help='set active profile' , action='store', metavar='PROFILE ') -def show_index(): - print('show_index') + parser.add_option_group(gpConf) -(opts, args) = parser.parse_args() -#~ if not 'toto' in opts.__dict__ : - #~ print("mandatory option is missing\n") - #~ parser.print_help() - #~ exit(-1)*/ -#~ print('--------') -#~ print(opts) -#~ print('--------') -#~ print(args) - + (o, a) = parser.parse_args() + + + + if not a: + parser.print_help() + print() + parser.error(' no commando specified') + sys.exit(1) + + else: + + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # ~~ conf CMD ~~ + if a[0] == 'conf' : + + if o.active_profile==None: + if self.ini.has('profile') : o.active_profile = self.ini.get('profile') + else : o.active_profile = 'default' + + if o.load_conf : self.load_profile(o) + + elif o.list_conf : print(self.ini.toString(o.active_profile)) + + else : + if not o.set_host and not o.set_user and not o.set_pass and not o.set_port and not o.set_boxn and not o.set_name and not o.gen_keys: + parser.error(' no options specified') + else : + if o.set_port and not util.represents_int(o.set_port): + parser.error(' port must be a number') + sys.exit(1) + if o.set_boxn: ini.set('box' , o.set_boxn,o.active_profile+'.imap') + if o.set_host: ini.set('host', o.set_host,o.active_profile+'.imap') + if o.set_user: ini.set('user', o.set_user,o.active_profile+'.imap') + if o.set_pass: ini.set('pass', o.set_pass,o.active_profile+'.imap') + if o.set_port: ini.set('port', o.set_port,o.active_profile+'.imap') + if o.set_name: ini.set('name', o.set_name,o.active_profile+'.infos') + if o.gen_keys: + rsa = util.Rsa(None,None,path,True) + self.ini.set('prvKey',rsa.prvKey,o.active_profile+'.keys') + self.ini.set('pubKey',rsa.pubKey,o.active_profile+'.keys') + self.ini.set('salt' ,'-¤-ImpraStorage-¤-',o.active_profile+'.keys') + if self.check_profile(o.active_profile): + self.ini.set('profile', o.active_profile) + self.ini.write() + print(self.ini.toString(o.active_profile)) + + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # ~~ data CMD ~~ + elif a[0] == 'data' : + + o.active_profile = self.ini.get('profile') + + if not o.list and not o.add and not o.get and not o.get_by_id and not o.search and not o.remove and not o.remove_by_id : + parser.error(' no options specified') + else : + + if self.check_profile(o.active_profile): + conf = core.ImpraConf(self.ini,o.active_profile) + rsa = util.Rsa(conf.get('prvKey','keys'),conf.get('pubKey','keys')) + impst = None + try: + impst = core.ImpraStorage(rsa, conf) + except util.BadKeysException as e : + print('Error : ') + print(e) + print(""" +it seems that your current profile %s has bad keys to decrypt index on server. +you can remove index but all presents files on the box %s will be unrecoverable +""" % (o.active_profile, conf.get('box','imap'))) + remIndex = input('remove index ? (yes/no)') + if remIndex.lower()=='yes': + impst = core.ImpraStorage(rsa, conf, True) + else : + print('bye') + sys.exit(1) + + if o.list : + impst.index.print(True,'-'*120+'\n -- INDEX '+impst.rootBox+'\n'+'-'*120) + elif o.add : + impst.addFile(o.add[0],o.add[1],o.user,o.category) + elif o.get : + print(o.get) + elif o.get_by_id : + print(o.get_by_id) + elif o.search : + print(o.search) + elif o.remove : + print(o.remove) + elif o.remove_by_id : + print(o.remove_by_id) + + #~ filePath = '/media/Data/dev/big_toph3.jpg' + #~ lab = 'Meuf\'bonne aussi4' + #~ print('\n -- ADD FILE -- ') + #~ impst.addFile(filePath,lab,conf.get('name','infos'),'images') + + #~ else : + #~ self.load_profile(o) + #~ print('data cmd') + #~ print(o) + + else : parser.print_help() + + + + def check_profile(self,profile): + """""" + return self.ini.hasSection(profile+'.keys') and self.ini.has('host',profile+'.imap') and self.ini.has('user',profile+'.imap') and self.ini.has('pass',profile+'.imap') and self.ini.has('port',profile+'.imap') + + + + def load_profile(self,o): + """""" + if self.check_profile(o.active_profile): + print('profile '+o.active_profile+' loaded') + self.ini.set('profile', o.active_profile) + self.ini.write() + else : + if not self.ini.hasSection(o.active_profile+'.imap'): + print('profile '+o.active_profile+' don\'t exist !') + else : + print('profile '+o.active_profile+' can\'t be load - incomplete\n (did you remember to generate keys ?)') diff --git a/impra/core.py b/impra/core.py index 79ee39d..2378702 100644 --- a/impra/core.py +++ b/impra/core.py @@ -29,7 +29,6 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ package core ~~ -import inspect from base64 import urlsafe_b64encode from email.encoders import encode_base64 from email.header import Header @@ -43,8 +42,9 @@ from os import remove, urandom, sep from os.path import abspath, dirname, join, realpath, basename, getsize, splitext from re import split as regsplit from impra.imap import ImapHelper, ImapConfig -from impra.util import __CALLER__, Rsa, RuTime, Noiser, Randomiz, RuTime, hash_sha256, formatBytes, randomFrom, bstr, quote_escape, stack +from impra.util import __CALLER__, Rsa, RuTime, Noiser, Randomiz, RuTime, hash_sha256, formatBytes, randomFrom, bstr, quote_escape, stack, run +DEBUG = True # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ class ConfigKey ~~ @@ -63,7 +63,6 @@ class ConfigKey: def getHashList(self,name,count,noSorted=False): """""" - rt = RuTime('getHashList') rt = RuTime(eval(__CALLER__('"%s",%s,%i' % (name,count,noSorted)))) self.rdmz.new(count) dic, lst, hroot = {}, [], hash_sha256(self.salt+name) @@ -185,21 +184,23 @@ class ImpraConf: if self.ini.isEmpty(): save = True rsa = Rsa() - self.set('host','imap.gmail.com','imap') + self.set('host','host','imap') self.set('port','993','imap') self.set('user','login','imap') - self.set('pass','**********','imap') - self.set('box' ,'__SMILF','imap') + self.set('pass','password','imap') + self.set('box' ,'__IMPRA','imap') self.set('pubKey',rsa.pubKey,'keys') self.set('prvKey',rsa.prvKey,'keys') self.set('salt' ,'-¤-ImpraStorage-¤-','keys') if not self.ini.hasSection(self.profile+self.SEP_SECTION+'catg'): save = True - self.set('users', self.get('name','infos'),'catg') - self.set('types', 'music,films,doc,images,archives,games','catg') + try: + self.set('users', self.get('name','infos'),'catg') + except Exception : pass + self.set('types', 'music,films,doc,images,archives,games','catg') if save : self.ini.write() - print(self.ini.toString()) + #print(self.ini.toString()) def get(self, key, section='main', profile=None): """""" @@ -227,7 +228,7 @@ class ImpraIndex: SEP_CATEGORY = '¤' """Separator used for category section""" - QUOTE_REPL = '-§' + QUOTE_REPL = '§' """Char replacement of simple quote String""" SEP_KEY_INTERN = '@' @@ -246,15 +247,19 @@ class ImpraIndex: """ self.rsa = rsa self.dic = {} + self.id = 0 if encdata =='' : data = encdata else : data = self.rsa.decrypt(encdata) data = data.replace(self.QUOTE_REPL, '\'') ld = regsplit('\n? ?'+self.SEP_CATEGORY+' ?\n?',data) - l = regsplit(self.SEP_ITEM,ld[0]) + l = regsplit(self.SEP_ITEM,ld[0]) for row in l: d = regsplit(self.SEP_TOKEN,row) # key : count, hash, ext, usr, cat - if len(d)>4 and d!='': self.dic[d[1]] = d + if len(d)>4 and d!='': + d.append(self.id) + self.dic[d[1]] = d + self.id += 1 if len(ld)>1: l = regsplit(self.SEP_ITEM,ld[1].lstrip('\n')) for row in l: @@ -270,7 +275,8 @@ class ImpraIndex: to decode data, and parts count """ if self.search(label) == None : - self.dic[label] = (key,label,count,ext,usr,cat) + self.dic[label] = (key,label,count,ext,usr,cat, self.id) + self.id +=1 else : print(label+' already exist') @@ -282,7 +288,7 @@ class ImpraIndex: """Search the corresponding label in the index""" return self.dic.get(label) - def toString(self): + def toString(self, withoutCatg=False): """Make a string representation of the index as it was store on the server""" data = cdata = '' for k in sorted(self.dic): @@ -292,26 +298,33 @@ class ImpraIndex: else : for i in v: data += str(i)+self.SEP_TOKEN data = data.rstrip(self.SEP_TOKEN)+self.SEP_ITEM - return data+self.SEP_CATEGORY+'\n'+cdata; + if not withoutCatg : + data += self.SEP_CATEGORY+'\n'+cdata + return data; def encrypt(self): """""" return self.rsa.encrypt(self.toString().replace('\'', self.QUOTE_REPL)) - def print(self): + def print(self,withoutCatg=False, header=''): """Print index content as formated bloc""" - data = self.toString().split(';') + data = self.toString(withoutCatg).split(';') + i = 0 + print(header) for row in data: - if row.rstrip('\n') != '': print(row) + if row.rstrip('\n') != '': + print(str(i).rjust(1+ceil(len(data)/10),' ')+' - '+row) + i += 1 + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ class ImpraStorage ~~ class ImpraStorage: """""" - def __init__(self, rsa, conf, wkdir=None): + def __init__(self, rsa, conf, remIndex=False, wkdir=None): """""" if wkdir == None : wkdir = abspath(join(dirname( __file__ ), '..', 'wk')) self.wkdir = wkdir @@ -323,6 +336,7 @@ class ImpraStorage: self.rsa = rsa self.fsplit = FSplitter(ConfigKey(),self.wkdir) self.delids = [] + if remIndex : self.removeIndex() self.index = self.getIndex() def _getIdIndex(self): @@ -345,6 +359,7 @@ class ImpraStorage: def getIndex(self): """""" + index = None self._getIdIndex() if self.idx : msgIndex = self.ih.email(self.idx) @@ -355,22 +370,31 @@ class ImpraStorage: else : encData = '' self.ih.deleteBin() - return ImpraIndex(self.rsa,encData, {'catg':self.conf.get('types','catg')}) + index = ImpraIndex(self.rsa, encData, {'catg':self.conf.get('types','catg')}) + return index + + def removeIndex(self): + """""" + self._getIdIndex() + if self.idx : + self.ih.delete(self.idx) def saveIndex(self): """""" + global DEBUG rt = RuTime(eval(__CALLER__())) if self.idx != None : self.ih.delete(self.idx) encData = self.index.encrypt() msgIndex = self.mb.buildIndex(encData) - print(msgIndex.as_string()) + if DEBUG: print(msgIndex.as_string()) self.ih.send(msgIndex.as_string(), self.rootBox) #self.index = self.getIndex() rt.stop() def addFile(self, path, label, usr='all', catg=''): """""" + global DEBUG rt = RuTime(eval(__CALLER__('"%s","%s","%s"' % (path[:13]+'...',label,usr)))) #~ hlst = self.fsplit.addFile(path,label) @@ -379,9 +403,10 @@ class ImpraStorage: try: if self.index.search(label)==None : hlst = self.fsplit.addFile(path,label) - print(hlst['head']) - for v in hlst['data']: - print(v) + if DEBUG : + print(hlst['head']) + for v in hlst['data']: + print(v) nameFrom = self.conf.ini.get('name',self.conf.profile+'.infos') for row in hlst['data'] : msg = self.mb.build(nameFrom,usr,hlst['head'][2],self.fsplit.DIR_OUTBOX+row[1]+'.ipr') @@ -397,6 +422,7 @@ class ImpraStorage: def getFile(self,label): """""" + global DEBUG rt = RuTime(eval(__CALLER__('"%s"' % label))) key = self.index.search(label) if key!=None : @@ -410,9 +436,10 @@ class ImpraStorage: if to == self.mb.getHashName('all')+'@'+self.mb.DOMAIN_NAME or to == self.mb.getHashName(self.conf.ini.get('name',self.conf.profile+'.infos'))+'@'+self.mb.DOMAIN_NAME : for mid in ids : self.ih.downloadAttachment(mid,self.fsplit.DIR_INBOX) - print(hlst['head']) - for v in hlst['data']: - print(v) + if DEBUG : + print(hlst['head']) + for v in hlst['data']: + print(v) self.fsplit.deployFile(hlst, key[3]) else : raise Exception(label+' is private') diff --git a/impra/imap.py b/impra/imap.py index 7cee6a1..afc063a 100755 --- a/impra/imap.py +++ b/impra/imap.py @@ -29,7 +29,6 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ package imap ~~ -import inspect from email import message_from_bytes from email.header import decode_header from email.message import Message diff --git a/impra/util.py b/impra/util.py index 6a7285e..e5156b4 100755 --- a/impra/util.py +++ b/impra/util.py @@ -29,19 +29,30 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ package util ~~ -from hashlib import sha256 -from math import log, floor, ceil -from random import choice -from os import urandom, popen -from os.path import dirname, realpath -from time import time -from re import split as regsplit -from base64 import urlsafe_b64encode -from inspect import stack +from hashlib import sha256 +from math import log, floor, ceil +from random import choice +from os import urandom, popen, sep +from os.path import dirname, realpath, abspath +from time import time +from re import split as regsplit +from base64 import urlsafe_b64encode +from inspect import stack +from subprocess import PIPE, Popen +from sys import stderr + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ methods ~~ +def represents_int(s): + """""" + try: + int(s) + return True + except ValueError: + return False + def quote_escape(data): """Escape simple quote :Returns: `str` @@ -70,6 +81,10 @@ def randomFrom(val, sval=0): lst = list(range(sval,val)) return choice(lst) +def get_file_path(val): + """""" + return abspath(dirname(val))+sep + def formatBytes(b, p=2): """Give a human representation of bytes size `b` :Returns: `str` @@ -89,6 +104,19 @@ def bstr(b,enc='utf-8'): """""" return str(b, encoding=enc) +def run(cmdline): + """""" + try: + p = Popen(cmdline, shell=True,stdout=PIPE, stderr=PIPE) + cmdout, cmderr = p.communicate() + rcode = p.wait() + if rcode < 0: + print((stderr,"Child was terminated by signal",rcode)) + else: + return (rcode,cmdout,cmderr) + except OSError as e : + return (e,cmdout,cmderr) + def __CALLER__(args=''): """Give basic information of caller method usage :: @@ -174,13 +202,15 @@ class RuTime: self._start() def _start(self): - print(' ==> '+self.label) + from impra.core import DEBUG + if DEBUG :print(' ==> '+self.label) self.sc = time() def stop(self): """Stop duration and print basics stats duration on console""" + from impra.core import DEBUG self.ec = time() - self._stats() + if DEBUG:self._stats() def _stats(self): print(' <== '+self.label+(' [%.9f s]' % (self.ec - self.sc))+' <¤¤ ') @@ -204,7 +234,7 @@ class IniFile: def has(self, key, section='main'): """""" - d = (key in self.dic[section]) + d = self.hasSection(section) and (key in self.dic[section]) return d def hasSection(self, section): @@ -243,19 +273,21 @@ class IniFile: with open(path, mode='w', encoding='utf-8') as o: o.write(content) - def toString(self,path=None): + def toString(self,section='*'): """""" - if path == None : path = self.path content = '' main = '' for s in self.dic: - if s!='main': - content += '\n['+s+']\n' - for k in sorted(self.dic[s]): - k = k.rstrip(' ') + if section=='*' or section+'.'==s[:len(section)+1]: if s!='main': - content += k+' = '+self.dic[s][k]+'\n' - else : main += k+' = '+self.dic[s][k]+'\n' + #~ if section=='*': content += '\n['+s+']\n' + #~ else : content += '\n['+s[len(section)+1:]+']\n' + content += '\n['+s+']\n' + for k in sorted(self.dic[s]): + k = k.rstrip(' ') + if s!='main' : + content += k+' = '+self.dic[s][k]+'\n' + else : main += k+' = '+self.dic[s][k]+'\n' return main + content def read(self): @@ -275,33 +307,43 @@ class IniFile: except IOError : pass + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~ class ImpraStorage ~~ + +class BadKeysException(BaseException): + pass + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ~~ class Rsa ~~ class Rsa: """""" - def __init__(self, prvKey=None, pubKey=None, dpath='./'): + def __init__(self, prvKey=None, pubKey=None, dpath='./', forceKeyGen=False): """""" self.cpath = dirname(realpath(__file__))+'/../desurveil/scripts/' self.prvKey = prvKey self.pubKey = pubKey self.dpath = dpath - if prvKey == None or pubKey==None : self.key() + if prvKey == None or pubKey==None : self.key(forceKeyGen) - def key(self): + def key(self,force=False): """""" cmd = self.cpath+"desurveil key -a "+self.dpath+".impra_id_rsa -l "+self.dpath+".impra_id_rsa.pub" #print(cmd) + try : with open(self.dpath+'.impra_id_rsa','rt') as f: pass - except IOError as e: + if force:d = popen(cmd).read() + except IOError as e: d = popen(cmd).read() #print(d) self.prvKey = get_file_content(self.dpath+'.impra_id_rsa') self.pubKey = get_file_content(self.dpath+'.impra_id_rsa.pub') - #print('pubKey : \n'+self.pubKey) - #print('prvKey : \n'+self.prvKey) + #~ print('pubKey : \n'+self.pubKey) + #~ print('prvKey : \n'+self.prvKey) def encrypt(self,data): """""" @@ -318,5 +360,10 @@ class Rsa: if self.prvKey != None : key = " -CI '"+self.prvKey+"'" #if self.prvKey != None : key = " -C '"+self.dpath+".impra_id_rsa'" cmd = self.cpath+"desurveil decrypt -i '"+data+"'"+key - #print(cmd) - return popen(cmd).read() + + rs = run(cmd) + if rs[0]==1: + raise BadKeysException('bad key to decrypt') + else : + encData = str(rs[1],'utf-8') + return encData