string formatting, whitespace, minor fixes and cleanups throughout

This commit is contained in:
The MMGen Project 2020-05-28 10:13:37 +00:00
commit 973c7be78d
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
10 changed files with 144 additions and 102 deletions

View file

@ -203,19 +203,18 @@ def add_user_random(rand_bytes,desc):
else:
return rand_bytes
def get_hash_preset_from_user(hp=g.hash_preset,desc='data'):
prompt = """Enter hash preset for {},
or hit ENTER to accept the default value ('{}'): """.format(desc,hp)
def get_hash_preset_from_user(hp=g.dfl_hash_preset,desc='data'):
prompt = f'Enter hash preset for {desc},\n or hit ENTER to accept the default value ({hp!r}): '
while True:
ret = my_raw_input(prompt)
if ret:
if ret in g.hash_presets.keys():
if ret in g.hash_presets:
return ret
else:
m = 'Invalid input. Valid choices are {}'
msg(m.format(', '.join(sorted(g.hash_presets.keys()))))
msg('Invalid input. Valid choices are {}'.format(', '.join(g.hash_presets)))
continue
else: return hp
else:
return hp
_salt_len,_sha256_len,_nonce_len = 32,32,32
@ -226,15 +225,15 @@ def mmgen_encrypt(data,desc='data',hash_preset=''):
hp = hash_preset or (
opt.hash_preset if 'hash_preset' in opt.set_by_user else get_hash_preset_from_user('3',desc))
m = ('user-requested','default')[hp=='3']
vmsg('Encrypting {}'.format(desc))
qmsg("Using {} hash preset of '{}'".format(m,hp))
vmsg(f'Encrypting {desc}')
qmsg(f'Using {m} hash preset of {hp!r}')
passwd = get_new_passphrase(desc,{})
key = make_key(passwd,salt,hp)
enc_d = encrypt_data(sha256(nonce+data).digest() + nonce + data, key, iv, desc=desc)
return salt+iv+enc_d
def mmgen_decrypt(data,desc='data',hash_preset=''):
vmsg('Preparing to decrypt {}'.format(desc))
vmsg(f'Preparing to decrypt {desc}')
dstart = _salt_len + g.aesctr_iv_len
salt = data[:_salt_len]
iv = data[_salt_len:dstart]
@ -242,8 +241,8 @@ def mmgen_decrypt(data,desc='data',hash_preset=''):
hp = hash_preset or (
opt.hash_preset if 'hash_preset' in opt.set_by_user else get_hash_preset_from_user('3',desc))
m = ('user-requested','default')[hp=='3']
qmsg("Using {} hash preset of '{}'".format(m,hp))
passwd = get_mmgen_passphrase(desc)
qmsg(f'Using {m} hash preset of {hp!r}')
passwd = get_passphrase(desc)
key = make_key(passwd,salt,hp)
dec_d = decrypt_data(enc_d,key,iv,desc)
if dec_d[:_sha256_len] == sha256(dec_d[_sha256_len:]).digest():

View file

@ -62,9 +62,9 @@ class GlobalContext:
# Variables - these might be altered at runtime:
user_entropy = ''
hash_preset = '3'
usr_randchars = 30
user_entropy = b''
hash_preset = '3'
usr_randchars = 30
tx_fee_adj = Decimal('1.0')
tx_confs = 3

View file

@ -198,21 +198,27 @@ if invoked_as != 'gen':
gmsg_r('Processing output wallet' + ('\n',' ')[invoked_as == 'seedsplit'])
if invoked_as == 'subgen':
ss_out = Wallet(seed_bin=ss_in.seed.subseed(ss_idx,print_msg=True).data)
ss_out = Wallet( seed_bin = ss_in.seed.subseed(ss_idx,print_msg=True).data )
elif invoked_as == 'seedsplit':
shares = ss_in.seed.split(sss.count,sss.id,master_share)
seed_out = shares.get_share_by_idx(sss.idx,base_seed=True)
msg(seed_out.get_desc(ui=True))
ss_out = Wallet(seed=seed_out)
else:
ss_out = Wallet(ss=ss_in,passchg=invoked_as=='passchg')
ss_out = Wallet(
ss = ss_in,
passchg = invoked_as == 'passchg' )
if invoked_as == 'gen':
qmsg("This wallet's Seed ID: {}".format(ss_out.seed.sid.hl()))
qmsg(f"This wallet's Seed ID: {ss_out.seed.sid.hl()}")
if invoked_as == 'passchg':
if not (opt.force_update or [k for k in ('passwd','hash_preset','label')
if getattr(ss_out.ssdata,k) != getattr(ss_in.ssdata,k)]):
def data_changed(attrs):
for attr in attrs:
if getattr(ss_out.ssdata,attr) != getattr(ss_in.ssdata,attr):
return True
return False
if not ( opt.force_update or data_changed(('passwd','hash_preset','label')) ):
die(1,'Password, hash preset and label are unchanged. Taking no action')
if invoked_as == 'passchg' and ss_in.infile.dirname == g.data_dir:
@ -226,18 +232,20 @@ if invoked_as == 'passchg' and ss_in.infile.dirname == g.data_dir:
try:
run(wipe_cmd + [ss_in.infile.name],check=True)
except:
ymsg("WARNING: '{}' command failed, using regular file delete instead".format(wipe_cmd[0]))
ymsg(f'WARNING: {wipe_cmd[0]!r} command failed, using regular file delete instead')
os.unlink(ss_in.infile.name)
else:
try:
assert invoked_as == 'gen','dw'
assert not opt.outdir,'dw'
assert not opt.stdout,'dw'
assert not find_file_in_dir(MMGenWallet,g.data_dir),'dw'
m = 'Make this wallet your default and move it to the data directory?'
assert keypress_confirm(m,default_yes=True),'dw'
assert invoked_as == 'gen', 'dw'
assert not opt.outdir, 'dw'
assert not opt.stdout, 'dw'
assert not find_file_in_dir( MMGenWallet, g.data_dir ), 'dw'
assert keypress_confirm(
'Make this wallet your default and move it to the data directory?',
default_yes = True ), 'dw'
except Exception as e:
if e.args[0] != 'dw': raise
if str(e) != 'dw':
raise
ss_out.write_to_file()
else:
ss_out.write_to_file(outdir=g.data_dir)
@ -248,4 +256,4 @@ if invoked_as == 'passchg':
else:
msg('Wallet passphrase has changed')
if ss_out.ssdata.hash_preset != ss_in.ssdata.hash_preset:
msg("Hash preset has been changed to '{}'".format(ss_out.ssdata.hash_preset))
msg(f'Hash preset has been changed to {ss_out.ssdata.hash_preset!r}')

View file

@ -31,7 +31,7 @@ import mmgen.share.Opts
from .util import *
def usage():
Die(1,'USAGE: {} {}'.format(g.prog_name,usage_txt))
Die(1,f'USAGE: {g.prog_name} {usage_txt}')
def version():
Die(0,fmt("""

View file

@ -636,11 +636,13 @@ class MMGenToolCmdFile(MMGenToolCmds):
"utilities for viewing/checking MMGen address and transaction files"
def _file_chksum(self,mmgen_addrfile,objname):
verbose = opt.verbose
opt.verbose = False
opt.yes = True
opt.quiet = True
from .addr import AddrList,KeyAddrList,PasswordList
ret = locals()[objname](self.proto,mmgen_addrfile)
if opt.verbose:
if verbose:
if ret.al_id.mmtype.name == 'password':
fs = 'Passwd fmt: {}\nPasswd len: {}\nID string: {}'
msg(fs.format(capfirst(ret.pw_info[ret.pw_fmt].desc),ret.pw_len,ret.pw_id_str))
@ -1117,15 +1119,17 @@ class MMGenToolCmdMonero(MMGenToolCmds):
gmsg('\n{}ing {} wallet{}'.format(op.desc,dl,suf(dl)))
from .daemon import MoneroWalletDaemon
wd = MoneroWalletDaemon(opt.outdir or '.',test_suite=g.test_suite)
wd = MoneroWalletDaemon(
wallet_dir = opt.outdir or '.',
test_suite = g.test_suite )
wd.restart()
from .rpc import MoneroWalletRPCClient
c = MoneroWalletRPCClient(
host = g.monero_wallet_rpc_host,
host = wd.host,
port = wd.rpc_port,
user = g.monero_wallet_rpc_user,
passwd = g.monero_wallet_rpc_password)
user = wd.user,
passwd = wd.passwd )
wallets_processed = 0
for n,d in enumerate(data): # [d.sec,d.wallet_passwd,d.viewkey,d.addr]

View file

@ -30,8 +30,7 @@ from .seed import Seed
def check_usr_seed_len(seed_len):
if opt.seed_len != seed_len and 'seed_len' in opt.set_by_user:
m = "ERROR: requested seed length ({}) doesn't match seed length of source ({})"
die(1,m.format((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 = opt.quiet
@ -66,8 +65,15 @@ class Wallet(MMGenObject,metaclass=WalletMeta):
class WalletData(MMGenObject): pass
def __new__(cls,fn=None,ss=None,seed_bin=None,seed=None,
passchg=False,in_data=None,ignore_in_fmt=False,in_fmt=None):
def __new__(cls,
fn = None,
ss = None,
seed_bin = None,
seed = None,
passchg = False,
in_data = None,
ignore_in_fmt = False,
in_fmt = None ):
in_fmt = in_fmt or opt.in_fmt
@ -115,9 +121,17 @@ class Wallet(MMGenObject,metaclass=WalletMeta):
return me
def __init__(self,fn=None,ss=None,seed_bin=None,seed=None,
passchg=False,in_data=None,ignore_in_fmt=False,in_fmt=None):
def __init__(self,
fn = None,
ss = None,
seed_bin = None,
seed = None,
passchg = False,
in_data = None,
ignore_in_fmt = False,
in_fmt = None ):
self.passwd_file = opt.passwd_file
self.ssdata = self.WalletData()
self.msg = {}
self.in_data = in_data
@ -168,7 +182,7 @@ class Wallet(MMGenObject,metaclass=WalletMeta):
while True:
if self._decrypt():
break
if opt.passwd_file:
if self.passwd_file:
die(2,'Passphrase from password file, so exiting')
msg('Trying again...')
@ -295,20 +309,20 @@ an empty passphrase, just hit ENTER twice.
if hasattr(self,'ss_in') and hasattr(self.ss_in.ssdata,'hash_preset'):
old_hp = self.ss_in.ssdata.hash_preset
if opt.keep_hash_preset:
qmsg("Reusing hash preset '{}' at user request".format(old_hp))
qmsg(f'Reusing hash preset {old_hp!r} at user request')
self.ssdata.hash_preset = old_hp
elif 'hash_preset' in opt.set_by_user:
hp = self.ssdata.hash_preset = opt.hash_preset
qmsg("Using hash preset '{}' requested on command line".format(opt.hash_preset))
qmsg(f'Using hash preset {opt.hash_preset!r} requested on command line')
else: # Prompt, using old value as default
hp = self._get_hash_preset_from_user(old_hp,desc_suf)
if (not opt.keep_hash_preset) and self.op == 'pwchg_new':
m = ("changed to '{}'".format(hp),'unchanged')[hp==old_hp]
qmsg('Hash preset {}'.format(m))
m = (f'changed to {hp!r}','unchanged')[hp==old_hp]
qmsg(f'Hash preset {m}')
elif 'hash_preset' in opt.set_by_user:
self.ssdata.hash_preset = opt.hash_preset
qmsg("Using hash preset '{}' requested on command line".format(opt.hash_preset))
qmsg(f'Using hash preset {opt.hash_preset!r} requested on command line')
else:
self._get_hash_preset_from_user(opt.hash_preset,desc_suf)
@ -318,21 +332,23 @@ an empty passphrase, just hit ENTER twice.
('','new ')[self.op in ('new','conv')],
self.desc
)
if opt.passwd_file:
w = pwfile_reuse_warning()
pw = ' '.join(get_words_from_file(opt.passwd_file,desc,quiet=w))
if self.passwd_file:
pw = ' '.join(get_words_from_file(
self.passwd_file,
desc,
quiet = pwfile_reuse_warning(self.passwd_file) ))
elif opt.echo_passphrase:
pw = ' '.join(get_words_from_user('Enter {}: '.format(desc)))
pw = ' '.join(get_words_from_user(f'Enter {desc}: '))
else:
for i in range(g.passwd_max_tries):
pw = ' '.join(get_words_from_user('Enter {}: '.format(desc)))
pw2 = ' '.join(get_words_from_user('Repeat passphrase: '))
dmsg('Passphrases: [{}] [{}]'.format(pw,pw2))
if pw == pw2:
pw = ' '.join(get_words_from_user(f'Enter {desc}: '))
pw_chk = ' '.join(get_words_from_user('Repeat passphrase: '))
dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
if pw == pw_chk:
vmsg('Passphrases match'); break
else: msg('Passphrases do not match. Try again.')
else:
die(2,'User failed to duplicate passphrase in {} attempts'.format(g.passwd_max_tries))
die(2,f'User failed to duplicate passphrase in {g.passwd_max_tries} attempts')
if pw == '':
qmsg('WARNING: Empty passphrase')
@ -345,9 +361,11 @@ an empty passphrase, just hit ENTER twice.
self.desc,
('',' '+desc_suf)[bool(desc_suf)]
)
if opt.passwd_file:
w = pwfile_reuse_warning()
ret = ' '.join(get_words_from_file(opt.passwd_file,desc,quiet=w))
if self.passwd_file:
ret = ' '.join(get_words_from_file(
self.passwd_file,
desc,
quiet = pwfile_reuse_warning(self.passwd_file) ))
else:
ret = ' '.join(get_words_from_user('Enter {}: '.format(desc)))
self.ssdata.passwd = ret
@ -691,11 +709,20 @@ class MMGenWallet(WalletEnc):
desc = g.proj_name + ' wallet'
ext = 'mmdat'
def __init__(self,*args,**kwargs):
if opt.label:
self.label = MMGenWalletLabel(
opt.label,
msg = "Error in option '--label'" )
else:
self.label = None
super().__init__(*args,**kwargs)
def _get_label_from_user(self,old_lbl=''):
d = "to reuse the label '{}'".format(old_lbl.hl()) if old_lbl else 'for no label'
p = 'Enter a wallet label, or hit ENTER {}: '.format(d)
prompt = 'Enter a wallet label, or hit ENTER {}: '.format(
f'to reuse the label {old_lbl.hl()!r}' if old_lbl else 'for no label' )
while True:
msg_r(p)
msg_r(prompt)
ret = my_raw_input('')
if ret:
self.ssdata.label = MMGenWalletLabel(ret,on_fail='return')
@ -713,20 +740,20 @@ class MMGenWallet(WalletEnc):
if hasattr(self,'ss_in') and hasattr(self.ss_in.ssdata,'label'):
old_lbl = self.ss_in.ssdata.label
if opt.keep_label:
qmsg("Reusing label '{}' at user request".format(old_lbl.hl()))
qmsg(f'Reusing label {old_lbl.hl()!r} at user request')
self.ssdata.label = old_lbl
elif opt.label:
qmsg("Using label '{}' requested on command line".format(opt.label.hl()))
lbl = self.ssdata.label = opt.label
elif self.label:
qmsg(f'Using label {self.label.hl()!r} requested on command line')
lbl = self.ssdata.label = self.label
else: # Prompt, using old value as default
lbl = self._get_label_from_user(old_lbl)
if (not opt.keep_label) and self.op == 'pwchg_new':
m = ("changed to '{}'".format(lbl),'unchanged')[lbl==old_lbl]
qmsg('Label {}'.format(m))
elif opt.label:
qmsg("Using label '{}' requested on command line".format(opt.label.hl()))
self.ssdata.label = opt.label
m = (f'changed to {lbl!r}','unchanged')[lbl==old_lbl]
qmsg(f'Label {m}')
elif self.label:
qmsg(f'Using label {self.label.hl()!r} requested on command line')
self.ssdata.label = self.label
else:
self._get_label_from_user()
@ -797,7 +824,7 @@ class MMGenWallet(WalletEnc):
hash_params = list(map(int,hpdata[1:]))
if hash_params != get_hash_params(d.hash_preset):
msg("Hash parameters '{}' don't match hash preset '{}'".format(' '.join(hash_params),d.hash_preset))
msg(f"Hash parameters {' '.join(hash_params)!r} don't match hash preset {d.hash_preset!r}")
return False
lmin,foo,lmax = sorted(baseconv.seedlen_map_rev['b58']) # 22,33,44
@ -866,19 +893,24 @@ class Brainwallet(WalletEnc):
def _decrypt(self):
d = self.ssdata
# Don't set opt.seed_len! In txsign, BW seed len might differ from other seed srcs
if opt.brain_params:
seed_len,d.hash_preset = self.get_bw_params()
"""
Don't set opt.seed_len! When using multiple wallets, BW seed len might differ from others
"""
bw_seed_len,d.hash_preset = self.get_bw_params()
else:
if 'seed_len' not in opt.set_by_user:
m1 = 'Using default seed length of {} bits\n'
m2 = 'If this is not what you want, use the --seed-len option'
qmsg((m1+m2).format(yellow(str(opt.seed_len))))
qmsg(f'Using default seed length of {yellow(str(opt.seed_len))} bits\n'
+ 'If this is not what you want, use the --seed-len option' )
self._get_hash_preset()
seed_len = opt.seed_len
bw_seed_len = opt.seed_len
qmsg_r('Hashing brainwallet data. Please wait...')
# Use buflen arg of scrypt.hash() to get seed of desired length
seed = scrypt_hash_passphrase(self.brainpasswd.encode(),b'',d.hash_preset,buflen=seed_len//8)
seed = scrypt_hash_passphrase(
self.brainpasswd.encode(),
b'',
d.hash_preset,
buflen = bw_seed_len // 8 )
qmsg('Done')
self.seed = Seed(seed)
msg('Seed ID: {}'.format(self.seed.sid))
@ -922,19 +954,19 @@ to exit and re-run the program with the '--old-incog-fmt' option.
def _incog_data_size_chk(self):
# valid sizes: 56, 64, 72
dlen = len(self.fmt_data)
valid_dlen = self._get_incog_data_len(opt.seed_len)
seed_len = opt.seed_len
valid_dlen = self._get_incog_data_len(seed_len)
if dlen == valid_dlen:
return True
else:
if opt.old_incog_fmt:
msg('WARNING: old-style incognito format requested. Are you sure this is correct?')
m = 'Invalid incognito data size ({} bytes) for this seed length ({} bits)'
msg(m.format(dlen,opt.seed_len))
msg('Valid data size for this seed length: {} bytes'.format(valid_dlen))
msg(f'Invalid incognito data size ({dlen} bytes) for this seed length ({seed_len} bits)')
msg(f'Valid data size for this seed length: {valid_dlen} bytes')
for sl in g.seed_lens:
if dlen == self._get_incog_data_len(sl):
die(1,'Valid seed length for this data size: {} bits'.format(sl))
msg('This data size ({} bytes) is invalid for all available seed lengths'.format(dlen))
die(1,f'Valid seed length for this data size: {sl} bits')
msg(f'This data size ({dlen} bytes) is invalid for all available seed lengths')
return False
def _encrypt (self):

View file

@ -360,11 +360,8 @@ class MMGenToolTestCmds(object):
def pubhex2redeem_script(self,name,f1,f2,f3): # from above
addr = read_from_file(f3).strip()
tu.run_cmd_out(name,addr,add_opts=type_segwit_arg,fn_idx=3)
type_save = opt.type
opt.type = 'segwit'
rs = read_from_tmpfile(cfg,'privhex2pubhex3.out').strip()
tu.run_cmd_out('pubhex2addr',rs,add_opts=type_segwit_arg,fn_idx=3,hush=True)
opt.type = type_save
addr1 = read_from_tmpfile(cfg,'pubhex2addr3.out').strip()
addr2 = read_from_tmpfile(cfg,'randpair3.out').split()[1]
cmp_or_die(addr1,addr2)

View file

@ -953,11 +953,11 @@ async def do_group(gid):
continue
await run_test(gid,cname)
def do_cmd_in_group(cmd):
async def do_cmd_in_group(cmd):
for gid in tests:
for cname in tests[gid]:
if cname == cmd:
run_test(gid,cname)
await run_test(gid,cname)
return True
return False
@ -1026,7 +1026,7 @@ async def main():
if cmd in tests:
await do_group(cmd)
else:
if not do_cmd_in_group(cmd):
if not await do_cmd_in_group(cmd):
die(1,f'{cmd!r}: not a recognized test or test group')
else:
for garg in tests:

View file

@ -92,22 +92,24 @@ class unit_tests:
if not opt.no_daemon_autostart:
md.start()
g.monero_wallet_rpc_password = 'passwOrd'
mwd = MoneroWalletDaemon(wallet_dir='test/trash',test_suite=True)
mwd.start()
wd = MoneroWalletDaemon(
wallet_dir = 'test/trash',
passwd = 'ut_rpc_passw0rd',
test_suite = True )
wd.start()
c = MoneroWalletRPCClient(
host = g.monero_wallet_rpc_host,
port = mwd.rpc_port,
user = g.monero_wallet_rpc_user,
passwd = g.monero_wallet_rpc_password)
host = wd.host,
port = wd.rpc_port,
user = wd.user,
passwd = wd.passwd )
await c.call('get_version')
gmsg('OK')
mwd.wait = False
mwd.stop()
wd.wait = False
wd.stop()
if not opt.no_daemon_stop:
md.wait = False

View file

@ -11,7 +11,7 @@ class unit_test(object):
from mmgen.seed import Seed,SeedShareList
from mmgen.obj import SeedShareIdx
g.debug_subseed = opt.verbose
g.debug_subseed = bool(opt.verbose)
def basic_ops(master_idx):
test_data = {