fixes and cleanups throughout

This commit is contained in:
The MMGen Project 2022-02-07 21:08:08 +00:00
commit fc87dcf0ba
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
19 changed files with 73 additions and 89 deletions

View file

@ -30,6 +30,13 @@ def is_b58_str(s):
def is_b32_str(s):
return set(list(s)) <= set(baseconv('b32').digits)
def is_mmgen_mnemonic(s):
try:
baseconv('mmgen').tobytes(s.split(),pad='seed')
return True
except:
return False
class baseconv(object):
mn_base = 1626
dt = namedtuple('desc_tuple',['short','long'])

View file

@ -25,7 +25,7 @@ from hashlib import sha256
from .baseconv import baseconv
from .util import is_hex_str,die
def is_bip39_str(s):
def is_bip39_mnemonic(s):
return bool( bip39().tohex(s.split()) )
# implements a subset of the baseconv API

View file

@ -231,15 +231,16 @@ if invoked_as == 'passchg' and ss_in.infile.dirname == g.data_dir:
shred_file(
ss_in.infile.name,
verbose = opt.verbose )
elif (
invoked_as == 'gen'
and not opt.outdir
and not opt.stdout
and not find_file_in_dir( MMGenWallet, g.data_dir )
and keypress_confirm(
'Make this wallet your default and move it to the data directory?',
default_yes = True ) ):
ss_out.write_to_file(outdir=g.data_dir)
elif invoked_as == 'gen' and not opt.outdir and not opt.stdout:
from .filename import find_file_in_dir
if (
not find_file_in_dir( MMGenWallet, g.data_dir )
and keypress_confirm(
'Make this wallet your default and move it to the data directory?',
default_yes = True ) ):
ss_out.write_to_file(outdir=g.data_dir)
else:
ss_out.write_to_file()
else:
ss_out.write_to_file()

View file

@ -475,10 +475,12 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
opt_unrecognized(key,val)
if key == 'out_fmt':
p = 'hidden_incog_output_params'
if sstype == IncogWalletHidden and not getattr(opt,p):
die( 'UserOptError',
'Hidden incog format output requested. ' +
f'You must supply a file and offset with the {fmt_opt(p)!r} option' )
if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
opt_display(key,val,beg='Selected',end=' ')
opt_display('old_incog_fmt',beg='conflicts with',end=':\n')

View file

@ -55,7 +55,7 @@ class PasswordList(AddrList):
pw_info = {
'b32': pwinfo(10, 42 ,24, None, 'base32 password', 'baseconv.is_b32_str'), # 32**24 < 2**128
'b58': pwinfo(8, 36 ,20, None, 'base58 password', 'baseconv.is_b58_str'), # 58**20 < 2**128
'bip39': pwinfo(12, 24 ,24, [12,18,24],'BIP39 mnemonic', 'bip39.is_bip39_str'),
'bip39': pwinfo(12, 24 ,24, [12,18,24],'BIP39 mnemonic', 'bip39.is_bip39_mnemonic'),
'xmrseed': pwinfo(25, 25, 25, [25], 'Monero new-style mnemonic','xmrseed.is_xmrseed'),
'hex': pwinfo(32, 64 ,64, [32,48,64],'hexadecimal password', 'util.is_hex_str'),
}

View file

@ -105,12 +105,12 @@ def add_keys(tx,src,infiles=None,saved_seeds=None,keyaddr_list=None):
vmsg(f'Added {len(new_keys)} wif key{suf(new_keys)} from {desc}')
return new_keys
def _pop_and_return(args,cmplist): # strips found args
def _pop_matching_fns(args,cmplist): # strips found args
return list(reversed([args.pop(args.index(a)) for a in reversed(args) if get_extension(a) in cmplist]))
def get_tx_files(opt,args):
from .tx.unsigned import Unsigned
ret = _pop_and_return(args,[Unsigned.ext])
ret = _pop_matching_fns(args,[Unsigned.ext])
if not ret:
die(1,'You must specify a raw transaction file!')
return ret
@ -118,11 +118,12 @@ def get_tx_files(opt,args):
def get_seed_files(opt,args):
# favor unencrypted seed sources first, as they don't require passwords
u,e = WalletUnenc,WalletEnc
ret = _pop_and_return(args,u.get_extensions())
ret = _pop_matching_fns(args,u.get_extensions())
from .filename import find_file_in_dir
wf = find_file_in_dir(MMGenWallet,g.data_dir) # Make this the first encrypted ss in the list
if wf: ret.append(wf)
ret += _pop_and_return(args,e.get_extensions())
if wf:
ret.append(wf)
ret += _pop_matching_fns(args,e.get_extensions())
if not (ret or opt.mmgen_keys_from_file or opt.keys_from_file): # or opt.use_wallet_dat
die(1,'You must specify a seed or key source!')
return ret

View file

@ -332,16 +332,6 @@ def make_iv_chksum(s):
from hashlib import sha256
return sha256(s).hexdigest()[:8].upper()
def splitN(s,n,sep=None): # always return an n-element list
ret = s.split(sep,n-1)
return ret + ['' for i in range(n-len(ret))]
def split2(s,sep=None):
return splitN(s,2,sep) # always return a 2-element list
def split3(s,sep=None):
return splitN(s,3,sep) # always return a 3-element list
def split_into_cols(col_wid,s):
return ' '.join([s[col_wid*i:col_wid*(i+1)] for i in range(len(s)//col_wid+1)]).rstrip()
@ -646,17 +636,6 @@ def do_license_msg(immed=False):
msg_r('\r')
msg('')
def format_par(s,indent=0,width=80,as_list=False):
words,lines = s.split(),[]
assert width >= indent + 4,'width must be >= indent + 4'
while words:
line = ''
while len(line) <= (width-indent) and words:
if line and len(line) + len(words[0]) + 1 > width-indent: break
line += ('',' ')[bool(line)] + words.pop(0)
lines.append(' '*indent + line)
return lines if as_list else '\n'.join(lines) + '\n'
def get_subclasses(cls,names=False):
def gen(cls):
for i in cls.__subclasses__():

View file

@ -32,21 +32,6 @@ def check_usr_seed_len(seed_len):
if opt.seed_len and opt.seed_len != seed_len:
die(1,f'ERROR: requested seed length ({opt.seed_len}) doesn’t match seed length of source ({seed_len})')
def _is_mnemonic(s,fmt):
oq_save = bool(opt.quiet)
opt.quiet = True
try:
Wallet(in_data=s,in_fmt=fmt)
ret = True
except:
ret = False
finally:
opt.quiet = oq_save
return ret
def is_bip39_mnemonic(s): return _is_mnemonic(s,fmt='bip39')
def is_mmgen_mnemonic(s): return _is_mnemonic(s,fmt='words')
class WalletMeta(type):
wallet_classes = set() # one-instance class, so store data in class attr
def __init__(cls,name,bases,namespace):
@ -841,7 +826,7 @@ class MMGenWallet(WalletEnc):
class Brainwallet(WalletEnc):
stdin_ok = True
fmt_codes = ('mmbrain','brainwallet','brain','bw','b')
fmt_codes = ('mmbrain','brainwallet','brain','bw')
desc = 'brainwallet'
ext = 'mmbrain'
# brainwallet warning message? TODO

View file

@ -28,7 +28,7 @@ def exec_wrapper_init(): # don't change: name is used to test if script is runni
if not os.getenv('EXEC_WRAPPER_NO_TRACEBACK'):
try:
os.unlink('my.err')
os.unlink('test.py.err')
except:
pass
@ -55,8 +55,9 @@ def exec_wrapper_write_traceback(e):
c.red(message) )
+ '\n' )
with open('my.err','w') as fp:
fp.write(''.join(lines+[exc]))
if not os.getenv('EXEC_WRAPPER_NO_TRACEBACK'):
with open('test.py.err','w') as fp:
fp.write(''.join(lines+[exc]))
def exec_wrapper_end_msg():
if os.getenv('EXEC_WRAPPER_SPAWN') and not os.getenv('MMGEN_TEST_SUITE_DETERMINISTIC'):
@ -110,7 +111,8 @@ except SystemExit as e:
exec_wrapper_end_msg()
sys.exit(e.code)
except Exception as e:
exec_wrapper_write_traceback(e)
if not os.getenv('EXEC_WRAPPER_NO_TRACEBACK'):
exec_wrapper_write_traceback(e)
retval = e.mmcode if hasattr(e,'mmcode') else e.code if hasattr(e,'code') else 1
sys.exit(retval)

View file

@ -84,8 +84,10 @@ if not (len(sys.argv) == 2 and sys.argv[1] == 'clean'):
from mmgen.common import *
try: os.unlink(os.path.join(repo_root,'my.err'))
except: pass
try:
os.unlink(os.path.join(repo_root,'test.py.err'))
except:
pass
g.quiet = False # if 'quiet' was set in config file, disable here
os.environ['MMGEN_QUIET'] = '0' # for this script and spawned scripts

View file

@ -583,8 +583,8 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t.passphrase(icls.desc,self.wpasswd)
ocls = Wallet.fmt_code_to_type(out_fmt)
out_pw = issubclass(ocls,WalletEnc) and ocls != Brainwallet
if out_pw:
if issubclass(ocls,WalletEnc) and ocls != Brainwallet:
t.passphrase_new('new '+ocls.desc,self.wpasswd)
t.usr_rand(self.usr_rand_chars)
@ -594,6 +594,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t.expect(m)
incog_id = t.expect_getend('New Incog Wallet ID: ')
t.expect(m)
if ocls == IncogWalletHidden:
self.write_to_tmpfile(incog_id_fn,incog_id)
t.hincog_create(hincog_bytes)
@ -637,17 +638,18 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
def addrgen_seed(self,wf,foo,in_fmt='seed'):
wcls = Wallet.fmt_code_to_type(in_fmt)
stdout = wcls == MMGenSeedFile # capture output to screen once
add_args = ([],['-S'])[bool(stdout)] + self.segwit_arg
t = self.spawn('mmgen-addrgen', add_args +
['-i'+in_fmt,'-d',self.tmpdir,wf,self.addr_idx_list])
t = self.spawn(
'mmgen-addrgen',
(['-S'] if stdout else []) +
self.segwit_arg +
[ '-i' + in_fmt, '-d', self.tmpdir, wf, self.addr_idx_list ] )
t.license()
t.expect_getend(f'Valid {wcls.desc} for Seed ID ')
vmsg('Comparing generated checksum with checksum from previous address file')
chk = t.expect_getend(r'Checksum for address data .*?: ',regex=True)
if stdout:
t.read()
verify_checksum_or_exit(self._get_addrfile_checksum(),chk)
if in_fmt != 'seed':
verify_checksum_or_exit(
self._get_addrfile_checksum(),
t.expect_getend(r'Checksum for address data .*?: ',regex=True) )
if not stdout:
t.no_overwrite()
t.req_exit_val = 1
return t

View file

@ -67,7 +67,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
('ref_walletconv_plainhexseed',([],'wallet filename (plain hex seed)')),
('ref_walletconv_dieroll', ([],'wallet filename (dieroll (b6d) seed)')),
('ref_walletconv_incog', ([],'wallet filename (incog)')),
('ref_walletconv_xincog', ([],'wallet filename (hex incog)')),
('ref_walletconv_hexincog', ([],'wallet filename (hex incog)')),
)
def __init__(self,trunner,cfgs,spawn):
@ -135,7 +135,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
hp_arg = f'-p{ref_wallet_hash_preset}'
label = f'test.py ref. wallet (pw {ref_wallet_brainpass!r}, seed len {self.seed_len}) α'
bf = 'ref.mmbrain'
args = ['-d',self.tmpdir,hp_arg,sl_arg,'-ib','-L',label]
args = ['-d',self.tmpdir,hp_arg,sl_arg,'-ibw','-L',label]
self.write_to_tmpfile(bf,ref_wallet_brainpass)
self.write_to_tmpfile(pwfile,self.wpasswd)
t = self.spawn('mmgen-walletconv', args + [self.usr_rand_arg])
@ -190,7 +190,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
pat = r'{}-[0-9A-F]{{8}}-[0-9A-F]{{8}}\[{},1\]' + ('' if g.debug_utf8 else '') + '.' + ext
return self.ref_walletconv(ofmt=ofmt,extra_args=args,re_pat=pat)
def ref_walletconv_xincog(self):
def ref_walletconv_hexincog(self):
return self.ref_walletconv_incog(ofmt='incog_hex',ext='mmincox')
class TestSuiteRef3Addr(TestSuiteRef3Seed):

View file

@ -112,8 +112,7 @@ class TestSuiteSeedSplit(TestSuiteBase):
pat = f'master share #{master}'
t.expect(pat,regex=True)
ocls = Wallet.fmt_code_to_type(ofmt)
pw = issubclass(ocls,WalletEnc)
if pw:
if issubclass(ocls,WalletEnc):
t.hash_preset('new '+ocls.desc,'1')
t.passphrase_new('new '+ocls.desc,sh1_passwd)
if ocls == IncogWalletHidden:

View file

@ -168,8 +168,7 @@ class TestSuiteShared(object):
t.license()
t.view_tx(view)
wcls = MMGenWallet if dfl_wallet else Wallet.ext_to_type(get_extension(wf))
pw = issubclass(wcls,WalletEnc) and wcls != Brainwallet
if pw:
if issubclass(wcls,WalletEnc) and wcls != Brainwallet:
t.passphrase(wcls.desc,self.wpasswd)
if save:
self.txsign_end(t,has_label=has_label)
@ -194,12 +193,12 @@ class TestSuiteShared(object):
extra_desc=extra_desc)
if wcls != IncogWalletHidden:
t.expect(f"Getting {wcls.desc} from file '")
pw = issubclass(wcls,WalletEnc) and wcls != Brainwallet
if pw:
if issubclass(wcls,WalletEnc) and wcls != Brainwallet:
t.passphrase(wcls.desc,self.wpasswd)
t.expect(['Passphrase is OK', 'Passphrase.* are correct'],regex=True)
chk = t.expect_getend(f'Valid {wcls.desc} for Seed ID ')[:8]
if sid: cmp_or_die(chk,sid)
if sid:
cmp_or_die(chk,sid)
return t
def addrgen(self,wf,

View file

@ -106,7 +106,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
def ref_dieroll_conv(self): return self.ref_mn_conv(ext='b6d')
def ref_brain_conv(self):
uopts = ['-i','b','-p','1','-l',str(self.seed_len)]
uopts = ['-i','bw','-p','1','-l',str(self.seed_len)]
return self.walletconv_in(None,uopts,oo=True,icls=Brainwallet)
def ref_incog_conv(self,wfk='ic_wallet',in_fmt='i'):
@ -121,7 +121,11 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
ic_f = joinpath(ref_dir,self.sources[str(self.seed_len)][wfk])
uopts = ['-i','hi','-p','1','-l',str(self.seed_len)] + add_uopts
hi_opt = ['-H',f'{ic_f},{ref_wallet_incog_offset}']
return self.walletconv_in(None,uopts+hi_opt,oo=True,icls=IncogWalletHidden)
return self.walletconv_in(
None,
uopts + hi_opt,
oo = True,
icls = IncogWalletHidden )
def ref_hincog_conv_old(self):
return self.ref_hincog_conv(wfk='hic_wallet_old',add_uopts=['-O'])
@ -178,8 +182,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
icls = icls or Wallet.ext_to_type(get_extension(infile))
if icls == Brainwallet:
t.expect('Enter brainwallet: ',ref_wallet_brainpass+'\n')
pw = issubclass(icls,WalletEnc) and icls != Brainwallet
if pw:
if issubclass(icls,WalletEnc) and icls != Brainwallet:
t.passphrase(icls.desc,self.wpasswd)
if self.test_name[:19] == 'ref_hincog_conv_old':
t.expect('Is the Seed ID correct? (Y/n): ','\n')
@ -202,8 +205,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
add_args = [f'-l{self.seed_len}']
t.license()
pw = issubclass(wcls,WalletEnc) and wcls != Brainwallet
if pw:
if issubclass(wcls,WalletEnc) and wcls != Brainwallet:
t.passphrase_new('new '+wcls.desc,self.wpasswd)
t.usr_rand(self.usr_rand_chars)
if wcls in (IncogWallet,IncogWalletHex,IncogWalletHidden):

View file

@ -33,7 +33,8 @@ sys.path.insert(0,overlay_setup(repo_root))
from mmgen.common import *
from test.include.common import *
from mmgen.wallet import is_bip39_mnemonic,is_mmgen_mnemonic
from mmgen.bip39 import is_bip39_mnemonic
from mmgen.baseconv import is_mmgen_mnemonic
from mmgen.xmrseed import is_xmrseed
from mmgen.baseconv import *

View file

@ -7,6 +7,7 @@ test.unit_tests_d.ut_dep: dependency unit tests for the MMGen suite
"""
from mmgen.common import *
from mmgen.exception import NoLEDSupport
class unit_tests:

View file

@ -4,6 +4,7 @@ test.unit_tests_d.ut_testdep: test dependency unit tests for the MMGen suite
"""
from mmgen.common import *
from subprocess import run,PIPE
sec = 'deadbeef' * 8

View file

@ -41,12 +41,12 @@ async def test_tx(tx_proto,tx_hex,desc,n):
dt = DeserializeTX(tx_proto,tx_hex)
if opt.verbose:
Msg('\n====================================================')
Msg('\n\n================================ Core vector: ==================================')
Msg_r('.' if opt.quiet else f'{n:>3}) {desc}\n')
if opt.verbose:
Pmsg(d)
Msg('----------------------------------------------------')
Pmsg(dt)
Msg('\n------------------------------ MMGen deserialized: -----------------------------')
Pmsg(dt._asdict())
# metadata
assert dt.txid == d['txid'],'TXID does not match'