From 7affd8ebea2667ed6896aa02cf9707f7cf7b195c Mon Sep 17 00:00:00 2001 From: philemon Date: Wed, 27 Jul 2016 22:55:47 +0300 Subject: [PATCH] Version 0.8.5rc1 --- mmgen/addr.py | 2 +- mmgen/filename.py | 2 +- mmgen/globalvars.py | 32 ++++++++++------------- mmgen/obj.py | 4 +-- mmgen/seed.py | 4 +-- mmgen/term.py | 11 ++------ mmgen/tool.py | 6 ++--- mmgen/tw.py | 4 +-- mmgen/util.py | 18 ++----------- setup.py | 2 +- test/test.py | 62 +++++++++++++++++++++++++-------------------- 11 files changed, 65 insertions(+), 82 deletions(-) diff --git a/mmgen/addr.py b/mmgen/addr.py index 7c1626a1..162cc350 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -89,7 +89,7 @@ class AddrList(MMGenObject): # Address info for a single seed ID # A text label of {n} characters or less may be added to the right of each # address, and it will be appended to the bitcoind wallet label upon import. # The label may contain any printable ASCII symbol. -""".strip().format(n=g.max_addr_label_len,pnm=pnm), +""".strip().format(n=MMGenAddrLabel.max_len,pnm=pnm), 'record_chksum': """ Record this checksum: it will be used to verify the address file in the future """.strip(), diff --git a/mmgen/filename.py b/mmgen/filename.py index e4ba0bdc..0213e559 100755 --- a/mmgen/filename.py +++ b/mmgen/filename.py @@ -51,7 +51,7 @@ class Filename(MMGenObject): import stat if stat.S_ISBLK(os.stat(fn).st_mode): mode = (os.O_RDONLY,os.O_RDWR)[bool(write)] - if sys.platform[:3] == 'win': mode |= os.O_BINARY + if g.platform == 'win': mode |= os.O_BINARY try: fd = os.open(fn, mode) except OSError as e: diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 18949f9c..240b09e0 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -20,7 +20,7 @@ globalvars.py: Constants and configuration options for the MMGen suite """ -import sys, os +import sys,os # Variables - these might be altered at runtime: @@ -29,13 +29,6 @@ hash_preset = '3' usr_randchars = 30 use_urandchars = False -# returns None if env var unset -debug = os.getenv('MMGEN_DEBUG') -no_license = os.getenv('MMGEN_NOLICENSE') -bogus_wallet_data = os.getenv('MMGEN_BOGUS_WALLET_DATA') -disable_hold_protect = os.getenv('MMGEN_DISABLE_HOLD_PROTECT') -color = (False,True)[sys.stdout.isatty() and not os.getenv('MMGEN_DISABLE_COLOR')] - from mmgen.obj import BTCAmt tx_fee = BTCAmt('0.0003') tx_fee_adj = 1.0 @@ -46,12 +39,19 @@ http_timeout = 60 # Constants - these don't change at runtime +# os.getenv() returns None if environmental var is unset +debug = os.getenv('MMGEN_DEBUG') +no_license = os.getenv('MMGEN_NOLICENSE') +bogus_wallet_data = os.getenv('MMGEN_BOGUS_WALLET_DATA') +disable_hold_protect = os.getenv('MMGEN_DISABLE_HOLD_PROTECT') +color = (False,True)[sys.stdout.isatty() and not os.getenv('MMGEN_DISABLE_COLOR')] + proj_name = 'MMGen' prog_name = os.path.basename(sys.argv[0]) author = 'Philemon' email = '' Cdates = '2013-2016' -version = '0.8.4' +version = '0.8.5rc1' required_opts = [ 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file', @@ -100,12 +100,8 @@ hash_presets = { '7': [18, 8, 24], } -mmgen_idx_max_digits = 7 - -printable_nonl = [chr(i+32) for i in range(95)] -printable = printable_nonl + ['\n','\t'] -addr_label_symbols = wallet_label_symbols = printable_nonl - -max_addr_label_len = 32 -max_wallet_label_len = 48 -max_tx_comment_len = 72 # Comment is b58 encoded, so can permit UTF-8 +for k in ('win','linux'): + if sys.platform[:len(k)] == k: platform = k; break +else: + sys.stderr.write("'%s': platform not supported by %s\n" % (sys.platform,proj_name)) + sys.exit(1) diff --git a/mmgen/obj.py b/mmgen/obj.py index 77a604a1..fe7935fa 100755 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -39,8 +39,8 @@ class MMGenObject(object): def conv(v,col_w): vret = '' if type(v) in (str,unicode): - import mmgen.globalvars as g - if not (set(list(v)) <= set(list(g.printable))): + from string import printable + if not (set(list(v)) <= set(list(printable))): vret = repr(v) else: vret = fix_linebreaks(v,fixed_indent=0) diff --git a/mmgen/seed.py b/mmgen/seed.py index 17e29f48..8f541a21 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -955,7 +955,7 @@ harder to find, you're advised to choose a much larger file size than this. d.target_data_len = self._get_incog_data_len(opt.seed_len) self._check_valid_offset(self.infile,'read') - flgs = os.O_RDONLY|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDONLY + flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY fh = os.open(self.infile.name,flgs) os.lseek(fh,int(d.hincog_offset),os.SEEK_SET) self.fmt_data = os.read(fh,d.target_data_len) @@ -1005,7 +1005,7 @@ harder to find, you're advised to choose a much larger file size than this. self._check_valid_offset(f,'write') if not opt.quiet: confirm_or_exit('',"alter file '%s'" % f.name) - flgs = os.O_RDWR|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDWR + flgs = os.O_RDWR|os.O_BINARY if g.platform == 'win' else os.O_RDWR fh = os.open(f.name,flgs) os.lseek(fh, int(d.hincog_offset), os.SEEK_SET) os.write(fh, self.fmt_data) diff --git a/mmgen/term.py b/mmgen/term.py index ad3ca82c..5bf7a9dd 100755 --- a/mmgen/term.py +++ b/mmgen/term.py @@ -21,7 +21,6 @@ term.py: Terminal-handling routines for the MMGen suite """ import os,struct - from mmgen.common import * def _kb_hold_protect_unix(): @@ -201,15 +200,9 @@ except: get_terminal_size = _get_terminal_size_mswin myflush = mswin_dummy_flush except: - if not sys.platform.startswith('linux') \ - and not sys.platform.startswith('win'): - msg('Unsupported platform: %s' % sys.platform) - msg('This program currently runs only on Linux and Windows') - else: - msg('Unable to set terminal mode') + msg('Unable to set terminal mode') sys.exit(2) - def do_pager(text): pagers = ['less','more'] @@ -224,7 +217,7 @@ def do_pager(text): # 'print' instead of the pager. # We risk assuming that 'more' will always be available on a stock # Windows installation. - if sys.platform.startswith('win'): + if g.platform == 'win': if 'HOME' not in environ: # native Windows terminal shell = True pagers = ['more'] diff --git a/mmgen/tool.py b/mmgen/tool.py index 9410157c..c7794839 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -252,7 +252,7 @@ def hexdump(infile, cols=8, line_nums=True): cols=cols,line_nums=line_nums)) def unhexdump(infile): - if sys.platform[:3] == 'win': + if g.platform == 'win': import msvcrt msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY) sys.stdout.write(decode_pretty_hexdump( @@ -425,7 +425,7 @@ def listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=Fa ) def s_mmgen(key): # TODO - return '{}:{:>0{w}}'.format(w=g.mmgen_idx_max_digits, *key.split('_')) + return '{}:{:>0{w}}'.format(w=AddrIdx.max_digits, *key.split('_')) out = [] for k in sorted(addrs,key=s_mmgen): @@ -572,7 +572,7 @@ def decrypt(infile,outfile='',hash_preset=''): def find_incog_data(filename,iv_id,keep_searching=False): ivsize,bsize,mod = g.aesctr_iv_len,4096,4096*8 n,carry = 0,' '*ivsize - flgs = os.O_RDONLY|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDONLY + flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY f = os.open(filename,flgs) for ch in iv_id: if ch not in '0123456789ABCDEF': diff --git a/mmgen/tw.py b/mmgen/tw.py index 2fd8d8b2..9982a082 100755 --- a/mmgen/tw.py +++ b/mmgen/tw.py @@ -84,7 +84,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program. def s_mmid(self,i): if i.mmid: return '{}:{:>0{w}}'.format( - *i.mmid.split(':'), w=g.mmgen_idx_max_digits) + *i.mmid.split(':'), w=AddrIdx.max_digits) else: return 'G' + (i.label or '') def do_sort(self,key,reverse=None): @@ -97,7 +97,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program. def sort_info(self,include_group=True): ret = ([],['Reverse'])[self.reverse] - ret.append(self.sort.capitalize().replace('Mmid','MMGenId')) + ret.append(self.sort.capitalize().replace('Mmid','MMGenID')) if include_group and self.group and (self.sort in ('addr','txid','mmid')): ret.append('Grouped') return ret diff --git a/mmgen/util.py b/mmgen/util.py index 2d3f7eb8..92659993 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -57,7 +57,7 @@ def magenta(s): return _mag+s+_reset def nocolor(s): return s def start_mscolor(): - if sys.platform[:3] == 'win': + if g.platform == 'win': global red,green,yellow,cyan,nocolor import os if 'MMGEN_NOMSCOLOR' in os.environ: @@ -101,20 +101,6 @@ def pp_msg(d): import pprint msg(pprint.PrettyPrinter(indent=4).pformat(d)) -def is_mmgen_wallet_label(s): - if len(s) > g.max_wallet_label_len: - msg('ERROR: wallet label length (%s chars) > maximum allowed (%s chars)' % (len(s),g.max_wallet_label_len)) - return False - - try: s = s.decode('utf8') - except: pass - - for ch in s: - if ch not in g.wallet_label_symbols: - msg('ERROR: wallet label contains illegal symbol (%s)' % ch) - return False - return True - # From 'man dd': # c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024, # GB=1000*1000*1000, G=1024*1024*1024, and so on for T, P, E, Z, Y. @@ -503,7 +489,7 @@ def write_data_to_file( else: msg('Redirecting output to file') - if binary and sys.platform[:3] == 'win': + if binary and g.platform == 'win': import msvcrt msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY) diff --git a/setup.py b/setup.py index 391363d7..79c8e01b 100755 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ from distutils.core import setup setup( name = 'mmgen', description = 'A complete Bitcoin cold-storage solution for the command line', - version = '0.8.4', + version = '0.8.5rc1', author = 'Philemon', author_email = 'mmgen-py@yandex.com', url = 'https://github.com/mmgen/mmgen', diff --git a/test/test.py b/test/test.py index b6edeffa..4f333ca7 100755 --- a/test/test.py +++ b/test/test.py @@ -482,6 +482,7 @@ opts_data = { -s, --system Test scripts and modules installed on system rather than those in the repo root. -S, --skip-deps Skip dependency checking for command +-u, --usr-random Get random data interactively from user -t, --traceback Run the command inside the '{tb_cmd}' script. -v, --verbose Produce more verbose output. """.format(tb_cmd=tb_cmd,lf=log_file), @@ -498,6 +499,9 @@ if opt.log: log_fd = open(log_file,'a') log_fd.write('\nLog started: %s\n' % make_timestr()) +usr_rand_chars = (5,30)[bool(opt.usr_random)] +usr_rand_arg = '-r%s' % usr_rand_chars + if opt.system: sys.path.pop(0) ni = bool(opt.non_interactive) @@ -530,7 +534,7 @@ stderr_save = sys.stderr def silence(): if not (opt.verbose or opt.exact_output): - f = ('/dev/null','stderr.out')[sys.platform[:3]=='win'] + f = ('/dev/null','stderr.out')[g.platform=='win'] sys.stderr = open(f,'a') def end_silence(): @@ -708,17 +712,21 @@ class MMGenExpect(object): my_expect(self.p,'Generating encryption key from OS random data plus ' + m) def usr_rand(self,num_chars): - rand_chars = list(getrandstr(num_chars,no_space=True)) - my_expect(self.p,'symbols left: ','x') - try: - vmsg_r('SEND ') - while self.p.expect('left: ',0.1) == 0: - ch = rand_chars.pop(0) - msg_r(yellow(ch)+' ' if opt.verbose else '+') - self.p.send(ch) - except: - vmsg('EOT') - my_expect(self.p,'ENTER to continue: ','\n') + if opt.usr_random: + self.interactive() + my_send(self.p,'\n') + else: + rand_chars = list(getrandstr(num_chars,no_space=True)) + my_expect(self.p,'symbols left: ','x') + try: + vmsg_r('SEND ') + while self.p.expect('left: ',0.1) == 0: + ch = rand_chars.pop(0) + msg_r(yellow(ch)+' ' if opt.verbose else '+') + self.p.send(ch) + except: + vmsg('EOT') + my_expect(self.p,'ENTER to continue: ','\n') def passphrase_new(self,desc,passphrase): my_expect(self.p,('Enter passphrase for %s: ' % desc), passphrase+'\n') @@ -807,7 +815,7 @@ labels = [ "Healthcare", "Freelancing 1", "Freelancing 2", - "Alice's assets", + "Alice's allowance", "Bob's bequest", "House purchase", "Real estate fund", @@ -1043,14 +1051,14 @@ class MMGenTestSuite(object): def walletgen(self,name,seed_len=None): write_to_tmpfile(cfg,pwfile,cfg['wpasswd']+'\n') - add_args = (['-r5'], + add_args = ([usr_rand_arg], ['-q','-r0','-L','NI Wallet','-P',get_tmpfile_fn(cfg,pwfile)])[bool(ni)] args = ['-d',cfg['tmpdir'],'-p1'] if seed_len: args += ['-l',str(seed_len)] t = MMGenExpect(name,'mmgen-walletgen', args + add_args) if ni: return t.license() - t.usr_rand(10) + t.usr_rand(usr_rand_chars) t.passphrase_new('new MMGen wallet',cfg['wpasswd']) t.label() t.written_to_file('MMGen wallet') @@ -1069,13 +1077,13 @@ class MMGenTestSuite(object): add_args = ['-r0', '-q', '-P%s' % get_tmpfile_fn(cfg,pwfile), get_tmpfile_fn(cfg,bf)] else: - add_args = ['-r5'] + add_args = [usr_rand_arg] t = MMGenExpect(name,'mmgen-walletconv', args + add_args) if ni: return t.license() t.expect('Enter brainwallet: ', ref_wallet_brainpass+'\n') t.passphrase_new('new MMGen wallet',cfg['wpasswd']) - t.usr_rand(10) + t.usr_rand(usr_rand_chars) sid = t.written_to_file('MMGen wallet').split('-')[0].split('/')[-1] refcheck('Seed ID',sid,cfg['seed_id']) @@ -1086,7 +1094,7 @@ class MMGenTestSuite(object): silence() write_to_tmpfile(cfg,pwfile,get_data_from_file(pf)) end_silence() - add_args = (['-r16'],['-q','-r0','-P',pf])[bool(ni)] + add_args = ([usr_rand_arg],['-q','-r0','-P',pf])[bool(ni)] t = MMGenExpect(name,'mmgen-passchg', add_args + ['-d',cfg['tmpdir'],'-p','2','-L','New Label',wf]) if ni: return @@ -1095,7 +1103,7 @@ class MMGenTestSuite(object): t.expect_getend('Hash preset changed to ') t.passphrase('MMGen wallet',cfg['wpasswd'],pwtype='new') t.expect('Repeat passphrase: ',cfg['wpasswd']+'\n') - t.usr_rand(16) + t.usr_rand(usr_rand_chars) t.expect_getend('Label changed to ') # t.expect_getend('Key ID changed: ') t.written_to_file('MMGen wallet') @@ -1295,7 +1303,7 @@ class MMGenTestSuite(object): t.passphrase('MMGen wallet',cfg['wpasswd']) if pw: t.passphrase_new('new '+desc,cfg['wpasswd']) - t.usr_rand(10) + t.usr_rand(usr_rand_chars) if ' '.join(desc.split()[-2:]) == 'incognito data': t.expect('Generating encryption key from OS random data ') t.expect('Generating encryption key from OS random data ') @@ -1323,7 +1331,7 @@ class MMGenTestSuite(object): self.export_seed(name,wf,desc='mnemonic data',out_fmt='words') def export_incog(self,name,wf,desc='incognito data',out_fmt='i',add_args=[]): - uargs = ['-p1','-r5'] + add_args + uargs = ['-p1',usr_rand_arg] + add_args self.walletconv_export(name,wf,desc=desc,out_fmt=out_fmt,uargs=uargs,pw=True) ok() @@ -1453,11 +1461,11 @@ class MMGenTestSuite(object): bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename']) make_brainwallet_file(bwf) seed_len = str(cfg['seed_len']) - args = ['-d',cfg['tmpdir'],'-p1','-r5','-l'+seed_len,'-ib'] + args = ['-d',cfg['tmpdir'],'-p1',usr_rand_arg,'-l'+seed_len,'-ib'] t = MMGenExpect(name,'mmgen-walletconv', args + [bwf]) t.license() t.passphrase_new('new MMGen wallet',cfg['wpasswd']) - t.usr_rand(10) + t.usr_rand(usr_rand_chars) t.label() t.written_to_file('MMGen wallet') ok() @@ -1734,7 +1742,7 @@ class MMGenTestSuite(object): # wallet conversion tests def walletconv_in(self,name,infile,desc,uopts=[],pw=False,oo=False): - opts = ['-d',cfg['tmpdir'],'-o','words','-r5'] + opts = ['-d',cfg['tmpdir'],'-o','words',usr_rand_arg] if_arg = [infile] if infile else [] d = '(convert)' if ni: @@ -1788,7 +1796,7 @@ class MMGenTestSuite(object): rd = os.urandom(ref_wallet_incog_offset+128) write_to_tmpfile(cfg,hincog_fn,rd) else: - aa = ['-r5'] + aa = [usr_rand_arg] infile = os.path.join(ref_dir,cfg['seed_id']+'.mmwords') t = MMGenExpect(name,'mmgen-walletconv',aa+opts+[infile],extra_desc='(convert)') @@ -1807,7 +1815,7 @@ class MMGenTestSuite(object): t.license() if pw: t.passphrase_new('new '+desc,cfg['wpasswd']) - t.usr_rand(10) + t.usr_rand(usr_rand_chars) if ' '.join(desc.split()[-2:]) == 'incognito data': for i in (1,2,3): t.expect('Generating encryption key from OS random data ') @@ -1876,7 +1884,7 @@ ts = MMGenTestSuite() # Laggy flash media cause pexpect to crash, so read and write all temporary # files to volatile memory in '/dev/shm' if not opt.skip_deps: - if sys.platform[:3] == 'win': + if g.platform == 'win': for cfg in sorted(cfgs): mk_tmpdir(cfgs[cfg]) else: d,pfx = '/dev/shm','mmgen-test-'