Browse Source

Version 0.8.5rc1

philemon 8 years ago
parent
commit
7affd8ebea
11 changed files with 65 additions and 82 deletions
  1. 1 1
      mmgen/addr.py
  2. 1 1
      mmgen/filename.py
  3. 14 18
      mmgen/globalvars.py
  4. 2 2
      mmgen/obj.py
  5. 2 2
      mmgen/seed.py
  6. 2 9
      mmgen/term.py
  7. 3 3
      mmgen/tool.py
  8. 2 2
      mmgen/tw.py
  9. 2 16
      mmgen/util.py
  10. 1 1
      setup.py
  11. 35 27
      test/test.py

+ 1 - 1
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(),

+ 1 - 1
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:

+ 14 - 18
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     = '<mmgen-py@yandex.com>'
 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)

+ 2 - 2
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)

+ 2 - 2
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)

+ 2 - 9
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']

+ 3 - 3
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':

+ 2 - 2
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

+ 2 - 16
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)
 

+ 1 - 1
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',

+ 35 - 27
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-'