Code cleanups, small interface improvements

This commit is contained in:
The MMGen Project 2014-08-07 21:39:25 +04:00
commit 9dc54c414d
10 changed files with 103 additions and 83 deletions

View file

@ -49,6 +49,7 @@ seedfile_exts = wallet_ext, seed_ext, mn_ext, brain_ext, incog_ext
rawtx_ext = "raw"
sigtx_ext = "sig"
addrfile_ext = "addrs"
addrfile_chksum_ext = "chk"
keyfile_ext = "keys"
keylist_ext = "keylist"
mmenc_ext = "mmenc"

View file

@ -119,11 +119,13 @@ def scrypt_hash_passphrase(passwd, salt, hash_preset, buflen=32):
return scrypt.hash(passwd, salt, 2**N, r, p, buflen=buflen)
def make_key(passwd, salt, hash_preset, what="key"):
def make_key(passwd, salt, hash_preset, what="key", verbose=False):
vmsg_r("Generating %s. Please wait..." % what)
if g.verbose or verbose:
msg_r("Generating %s. Please wait..." % what)
key = scrypt_hash_passphrase(passwd, salt, hash_preset)
vmsg("done")
if g.verbose or verbose:
msg("done")
if g.debug: print "Key: %s" % hexlify(key)
return key
@ -169,14 +171,14 @@ def get_random(length,opts):
from Crypto import Random
os_rand = Random.new().read(length)
if 'usr_randchars' in opts and opts['usr_randchars'] not in (0,-1):
kwhat = "a key from OS random data + "
kwhat = "a key from OS random data plus "
if not g.user_entropy:
g.user_entropy = sha256(
get_random_data_from_user(opts['usr_randchars'])).digest()
kwhat += "user entropy"
else:
kwhat += "saved user entropy"
key = make_key(g.user_entropy, "", '2', what=kwhat)
key = make_key(g.user_entropy, "", '2', what=kwhat, verbose=True)
return encrypt_data(os_rand,key,what="random data",verify=False)
else:
return os_rand
@ -204,7 +206,7 @@ def get_seed_from_wallet(
def get_seed_from_incog_wallet(
infile,
opts,
prompt="{} wallet".format(g.proj_name),
prompt_what="{} incognito wallet".format(g.proj_name),
silent=False,
hex_input=False
):
@ -236,7 +238,7 @@ def get_seed_from_incog_wallet(
vmsg(cmessages['incog_iv_id_hidden' if "from_incog_hidden" in opts
else 'incog_iv_id'])
passwd = get_mmgen_passphrase(prompt,opts)
passwd = get_mmgen_passphrase(prompt_what,opts)
qmsg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets)))
while True:

View file

@ -35,9 +35,9 @@ what = "keys" if sys.argv[0].split("-")[-1] == "keygen" else "addresses"
help_data = {
'prog_name': g.prog_name,
'desc': """Generate a list or range of {} from an {g.proj_name} wallet,
'desc': """Generate a range or list of {} from an {g.proj_name} wallet,
mnemonic, seed or password""".format(what,g=g),
'usage':"[opts] [infile] <address list>",
'usage':"[opts] [infile] <address range or list>",
'options': """
-h, --help Print this help message{}
-d, --outdir= d Specify an alternate directory 'd' for output
@ -50,7 +50,7 @@ help_data = {
(default: {g.seed_len})
-p, --hash-preset= p Use scrypt.hash() parameters from preset 'p' when
hashing password (default: '{g.hash_preset}')
-P, --passwd-file= f Get passphrase from file 'f'
-P, --passwd-file= f Get MMGen wallet passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without
prompting
-S, --stdout Print {what} to stdout
@ -159,8 +159,16 @@ addr_data_str = format_addr_data(
addr_data, addr_data_chksum, seed_id, addr_idxs, opts)
outfile_base = "{}[{}]".format(seed_id, fmt_addr_idxs(addr_idxs))
if 'addrs' in opts['gen_what']:
qmsg("Checksum for address data %s: %s" % (outfile_base,addr_data_chksum))
if 'save_checksum' in opts:
write_to_file(outfile_base+"."+g.addrfile_chksum_ext,
addr_data_chksum+"\n",opts,"address data checksum",True,True,False)
else:
qmsg("This checksum will be used to verify the address file in the future.")
qmsg("Record it to a safe location.")
if 'flat_list' in opts and user_confirm("Encrypt key list?"):
if 'flat_list' in opts and keypress_confirm("Encrypt key list?"):
addr_data_str = mmgen_encrypt(addr_data_str,"key list","",opts)
enc_ext = "." + g.mmenc_ext
else: enc_ext = ""
@ -176,15 +184,7 @@ else:
confirm_overwrite = False if g.quiet else True
outfile = "%s.%s%s" % (outfile_base, (
g.keylist_ext if 'flat_list' in opts else (
g.keyfile_ext if opts['gen_what'] == ("keys") else (
g.addrfile_ext if opts['gen_what'] == ("addrs") else "akeys"))), enc_ext)
g.keyfile_ext if opts['gen_what'] == ["keys"] else (
g.addrfile_ext if opts['gen_what'] == ["addrs"] else "akeys"))), enc_ext)
write_to_file(outfile,addr_data_str,opts,what,confirm_overwrite,True)
if 'addrs' in opts['gen_what']:
msg("Checksum for address data {}: {}".format(outfile_base,addr_data_chksum))
if 'save_checksum' in opts:
a = "address data checksum"
write_to_file(outfile_base+".chk",addr_data_chksum,opts,a,False,True)
else:
qmsg("This checksum will be used to verify the address file in the future.")
qmsg("Record it to a safe location.")

View file

@ -41,7 +41,7 @@ help_data = {
-L, --label= l Change the wallet's label to 'l'
-p, --hash-preset= p Change scrypt.hash() parameters to preset 'p'
(default: '{g.hash_preset}')
-P, --passwd-file= f Get new passphrase from file 'f'
-P, --passwd-file= f Get new MMGen wallet passphrase from file 'f'
-r, --usr-randchars= n Get 'n' characters of additional randomness from
user (min={g.min_urandchars}, max={g.max_urandchars})
-q, --quiet Suppress warnings; overwrite files without

View file

@ -28,7 +28,7 @@ import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
from mmgen.tx import *
from mmgen.util import msg, msg_r, user_confirm
from mmgen.util import msg, msg_r, keypress_confirm
help_data = {
'prog_name': g.prog_name,
@ -165,7 +165,7 @@ while True:
if mmaddrs and len(mmaddrs) < len(sel_unspent):
msg(txmsg['mixed_inputs'] % ", ".join(sorted(mmaddrs)))
if not user_confirm("Accept?"):
if not keypress_confirm("Accept?"):
continue
total_in = trim_exponent(sum([i.amount for i in sel_unspent]))
@ -173,7 +173,7 @@ while True:
if change >= 0:
prompt = "Transaction produces %s BTC in change. OK?" % change
if user_confirm(prompt,default_yes=True):
if keypress_confirm(prompt,default_yes=True):
break
else:
msg(txmsg['not_enough_btc'] % change)
@ -206,7 +206,7 @@ if reply and reply in "YyVv":
view_tx_data(c,[i.__dict__ for i in sel_unspent],tx_hex,b2m_map,pager=pager)
prompt = "Save transaction?"
if user_confirm(prompt,default_yes=True):
if keypress_confirm(prompt,default_yes=True):
amt = send_amt or change
tx_id = make_chksum_6(unhexlify(tx_hex)).upper()
outfile = "tx_%s[%s].%s" % (tx_id,amt,g.rawtx_ext)

View file

@ -44,7 +44,7 @@ help_data = {
for online signing without an {pnm} seed source.
{pnm}-to-BTC mappings can optionally be verified
using address file(s) listed on the command line
-P, --passwd-file= f Get passphrase from file 'f'
-P, --passwd-file= f Get MMGen wallet or bitcoind passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without
prompting
-v, --verbose Produce more verbose output
@ -127,7 +127,12 @@ if 'keys_from_file' in opts:
keys_from_file = remove_comments(d.split("\n"))
else: keys_from_file = []
for tx_file in tx_files:
tx_num_str = ""
for tx_num,tx_file in enumerate(tx_files,1):
if len(tx_files) > 1:
msg("\nTransaction #%s of %s:" % (tx_num,len(tx_files)))
tx_num_str = " #%s" % tx_num
m = "" if 'tx_id' in opts else "transaction data"
tx_data = get_lines_from_file(tx_file,m)
@ -169,11 +174,8 @@ for tx_file in tx_files:
check_mmgen_to_btc_addr_mappings(
mmgen_inputs,b2m_map,seed_files,saved_seeds,opts)
if len(tx_files) > 1:
msg("\nTransaction %s/%s:" % (tx_files.index(tx_file)+1,len(tx_files)))
prompt = "View transaction data? (y)es, (N)o, (v)iew in pager"
reply = prompt_and_get_char(prompt,"YyNnVv",enter_ok=True)
p = "View data for transaction{}? (y)es, (N)o, (v)iew in pager"
reply = prompt_and_get_char(p.format(tx_num_str),"YyNnVv",enter_ok=True)
if reply and reply in "YyVv":
p = True if reply in "Vv" else False
view_tx_data(c,inputs_data,tx_hex,b2m_map,metadata,pager=p)
@ -187,27 +189,27 @@ for tx_file in tx_files:
keys += get_keys_for_mmgen_addrs(ml,seed_files,saved_seeds,opts)
if 'use_wallet_dat' in opts:
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts)
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts)
else:
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
elif other_inputs:
if keys:
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
else:
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts)
sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts)
if sig_tx['complete']:
prompt = "OK\nSave signed transaction?"
if user_confirm(prompt,default_yes=True):
outfile = "tx_%s[%s].%s" % (metadata[0],metadata[1],g.sigtx_ext)
data = "{}\n{}\n{}\n{}\n".format(
" ".join(metadata[:2] + [make_timestamp()]),
sig_tx['hex'],
repr(inputs_data),
repr(b2m_map)
)
confirm = False if g.quiet else True
write_to_file(outfile,data,opts,"signed transaction",confirm,True)
msg("OK")
outfile = "tx_%s[%s].%s" % (metadata[0],metadata[1],g.sigtx_ext)
data = "{}\n{}\n{}\n{}\n".format(
" ".join(metadata[:2] + [make_timestamp()]),
sig_tx['hex'],
repr(inputs_data),
repr(b2m_map)
)
w = "signed transaction{}".format(tx_num_str)
write_to_file(outfile,data,opts,w,(not g.quiet),True,False)
else:
msg("failed\nSome keys were missing. Transaction could not be signed.")
msg_r("failed\nSome keys were missing. ")
msg("Transaction %scould not be signed." % tx_num_str)
sys.exit(3)

View file

@ -25,7 +25,7 @@ import sys
import mmgen.config as g
from mmgen.Opts import *
from mmgen.util import *
from mmgen.crypto import get_seed_from_wallet,wallet_to_incog_data
from mmgen.crypto import get_seed_retry,wallet_to_incog_data
help_data = {
'prog_name': g.prog_name,
@ -37,7 +37,7 @@ help_data = {
-h, --help Print this help message
-d, --outdir= d Specify an alternate directory 'd' for output
-e, --echo-passphrase Print passphrase to screen when typing it
-P, --passwd-file= f Get passphrase from file 'f'
-P, --passwd-file= f Get MMGen wallet passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without prompting
-r, --usr-randchars= n Get 'n' characters of additional randomness from
user (min={g.min_urandchars}, max={g.max_urandchars})
@ -89,12 +89,12 @@ elif 'export_incog' in opts:
)
data = pretty_hexdump(incog_enc,2,8,line_nums=False) \
if "export_incog_hex" in opts else incog_enc
export_to_file(fn, data, opts, "incognito wallet data")
write_to_file_or_stdout(fn, data, opts, "incognito wallet data")
sys.exit()
seed = get_seed_from_wallet(cmd_args[0], opts)
if seed: qmsg("Wallet is OK")
seed = get_seed_retry(cmd_args[0], opts)
if seed: msg("Wallet is OK")
else:
msg("Error opening wallet")
sys.exit(2)
@ -105,11 +105,11 @@ if 'export_mnemonic' in opts:
p = True if g.debug else False
mn = get_mnemonic_from_seed(seed, wl, g.default_wl, print_info=p)
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.mn_ext)
export_to_file(fn, " ".join(mn)+"\n", opts, "mnemonic data")
write_to_file_or_stdout(fn, " ".join(mn)+"\n", opts, "mnemonic data")
elif 'export_seed' in opts:
from mmgen.bitcoin import b58encode_pad
data = col4(b58encode_pad(seed))
chk = make_chksum_6(b58encode_pad(seed))
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.seed_ext)
export_to_file(fn, "%s %s\n" % (chk,data), opts, "seed data")
write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), opts, "seed data")

View file

@ -44,7 +44,7 @@ help_data = {
Allowed symbols: A-Z, a-z, 0-9, " ", "_", ".")
-p, --hash-preset= p Use scrypt.hash() parameters from preset 'p'
(default: '{g.hash_preset}')
-P, --passwd-file= f Get passphrase from file 'f'
-P, --passwd-file= f Get MMGen wallet passphrase from file 'f'
-q, --quiet Produce quieter output; overwrite files without
prompting
-r, --usr-randchars= n Get 'n' characters of additional randomness from

View file

@ -39,7 +39,7 @@ address was specified.
NOTE: This transaction uses a mixture of both mmgen and non-mmgen inputs,
which makes the signing process more complicated. When signing the
transaction, keys for the non-mmgen inputs must be supplied in a separate
file using the '-k' option to {}-txsign.
file using either the '-k' or '-K' option to '{}-txsign'.
Selected mmgen inputs: %s""".format(g.proj_name.lower()),
'too_many_acct_addresses': """
@ -52,10 +52,9 @@ No data found for MMgen address '%s'. Please import this address into
your tracking wallet, or supply an address file for it on the command line.
""".strip(),
'addrfile_warn_msg': """
Warning: no data for address '{mmaddr}' was found in the tracking wallet, so
this information was taken from the user-supplied address file. You're strongly
advised to import this address into your tracking wallet before proceeding with
this transaction. The address will not be tracked until you do so.
Warning: output address '{mmaddr}' is not in the tracking wallet, which means
its balance will not be tracked. You're strongly advised to import the address
into your tracking wallet before broadcasting this transaction.
""".strip(),
'addrfile_fail_msg': """
No data for MMgen address '{mmaddr}' could be found in either the tracking
@ -496,12 +495,14 @@ def mmaddr2btcaddr_addrfile(mmaddr,addr_data,silent=False):
if j[0] == mmidx:
if not silent:
msg(txmsg['addrfile_warn_msg'].format(mmaddr=mmaddr))
if not user_confirm("Continue anyway?"):
if not keypress_confirm("Continue anyway?"):
sys.exit(1)
return j[1:] if len(j) == 3 else (j[1],"")
if silent: return "",""
else: msg(txmsg['addrfile_fail_msg'].format(mmaddr=mmaddr)); sys.exit(2)
else:
msg(txmsg['addrfile_fail_msg'].format(mmaddr=mmaddr))
sys.exit(2)
def check_mmgen_to_btc_addr_mappings(mmgen_inputs,b2m_map,infiles,saved_seeds,opts):
@ -594,13 +595,13 @@ def parse_addrs_file(f):
sys.exit(3)
def sign_transaction(c,tx_hex,sig_data,keys=None):
def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None):
if keys:
qmsg("%s keys total" % len(keys))
if g.debug: print "Keys:\n %s" % "\n ".join(keys)
msg_r("Signing transaction...")
msg_r("Signing transaction{}...".format(tx_num_str))
from mmgen.rpc import exceptions
try:
sig_tx = c.signrawtransaction(tx_hex,sig_data,keys)
@ -646,18 +647,19 @@ def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts,gen_pairs=Fals
from mmgen.addr import generate_addrs
if gen_pairs:
ret += [("{}:{}".format(seed_id,i.num),i.addr)
for i in generate_addrs(seed, addr_ids, {'gen_what':["addrs"]})]
for i in generate_addrs(seed,addr_ids,
{'gen_what':["addrs"]})]
else:
ret += [i.wif for i in generate_addrs(
seed,addr_ids,{'gen_what':["keys"]})]
ret += [i.wif for i in generate_addrs(seed,addr_ids,
{'gen_what':["keys"]})]
return ret
def sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts):
def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts):
try:
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
except:
from mmgen.rpc import exceptions
msg("Using keys in wallet.dat as per user request")
@ -672,7 +674,7 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts):
else:
msg("Passphrase OK"); break
sig_tx = sign_transaction(c,tx_hex,sig_data,keys)
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
msg("Locking wallet")
try:
@ -761,5 +763,6 @@ def check_mmgen_to_btc_addr_mappings_addrfile(mmgen_inputs,b2m_map,addrfiles):
sys.exit(3)
if missing:
confirm_or_exit(txmsg['missing_mappings'] % " ".join(missing),"continue")
confirm_or_exit(txmsg['missing_mappings'] %
" ".join(missing),"continue")
else: qmsg("Address mappings OK")

View file

@ -311,6 +311,11 @@ def get_new_passphrase(what, opts, passchg=False):
def confirm_or_exit(message, question, expect="YES"):
if not confirm_or_false(message, question, expect):
msg("Exiting at user request")
sys.exit(2)
def confirm_or_false(message, question, expect="YES"):
vmsg("")
@ -322,11 +327,11 @@ def confirm_or_exit(message, question, expect="YES"):
p = question+" "+conf_msg if question[0].isupper() else \
"Are you sure you want to %s?\n%s" % (question,conf_msg)
if my_raw_input(p).strip() != expect:
msg("Exiting at user request")
sys.exit(2)
ret = True if my_raw_input(p).strip() == expect else False
vmsg("")
return ret
def write_to_stdout(data, what, confirm=True):
@ -342,7 +347,7 @@ def write_to_stdout(data, what, confirm=True):
sys.stdout.write(data)
def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=False):
def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=False,exit_on_error=True):
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
@ -351,7 +356,13 @@ def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=
except: pass
else:
if confirm_overwrite:
confirm_or_exit("","File '%s' already exists\nOverwrite?" % outfile)
q = "File '%s' already exists\nOverwrite?" % outfile
if exit_on_error:
confirm_or_exit("",q)
else:
if not confirm_or_false("",q):
msg("Not overwriting file at user request")
return False
else:
msg("Overwriting file '%s'" % outfile)
@ -364,11 +375,12 @@ def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=
f.close
if verbose: msg("%s written to file '%s'" % (what.capitalize(),outfile))
return True
def export_to_file(outfile, data, opts, what="data"):
def write_to_file_or_stdout(outfile, data, opts, what="data"):
if 'stdout' in opts:
if 'stdout' in opts or not sys.stdout.isatty():
write_to_stdout(data, what, confirm=True)
else:
confirm_overwrite = False if g.quiet else True
@ -615,9 +627,9 @@ def mark_passwd_file_as_used(opts):
passwd_file_used = True
def get_mmgen_passphrase(pinfo,opts,passchg=False):
def get_mmgen_passphrase(prompt_info,opts,passchg=False):
prompt = "Enter {}passphrase for {}: ".format(
"old " if passchg else "",pinfo)
"old " if passchg else "",prompt_info)
if 'passwd_file' in opts:
mark_passwd_file_as_used(opts)
return " ".join(_get_words_from_file(opts['passwd_file'],"passphrase"))
@ -712,7 +724,7 @@ def my_raw_input(prompt,echo=True):
return reply
def user_confirm(prompt,default_yes=False,verbose=False):
def keypress_confirm(prompt,default_yes=False,verbose=False):
q = "(Y/n)" if default_yes else "(y/N)"