From c7056a7ba2457c492c961f79d248fb81ab85aaac Mon Sep 17 00:00:00 2001 From: philemon Date: Sat, 10 Jan 2015 18:52:30 +0300 Subject: [PATCH] Improved options handling, some files moved and renamed. Users who are upgrading must delete the 'opt' directory in their previous installation before installing. On a Linux system, this is typically located at: /usr/local/lib/python2.7/dist-packages/mmgen/opt --- mmgen/addr.py | 19 +++-- mmgen/config.py | 72 ++++++++-------- mmgen/crypto.py | 91 ++++++++++---------- mmgen/license.py | 3 +- mmgen/main_addrgen.py | 56 ++++++------ mmgen/main_addrimport.py | 27 +++--- mmgen/main_passchg.py | 35 ++++---- mmgen/main_tool.py | 11 +-- mmgen/main_txcreate.py | 36 ++++---- mmgen/main_txsend.py | 15 ++-- mmgen/main_txsign.py | 78 +++++++++-------- mmgen/main_walletchk.py | 61 +++++++------ mmgen/main_walletgen.py | 40 ++++----- mmgen/mnemonic.py | 1 + mmgen/opt.py | 22 +++++ mmgen/{Opts.py => opts.py} | 142 ++++++++++++++++++------------- mmgen/{opt => share}/Opts.py | 32 +++---- mmgen/share/Opts.pyc | Bin 0 -> 3143 bytes mmgen/{opt => share}/__init__.py | 0 mmgen/share/__init__.pyc | Bin 0 -> 360 bytes mmgen/term.py | 1 + mmgen/test.py | 6 +- mmgen/tool.py | 12 +-- mmgen/tx.py | 5 +- mmgen/util.py | 114 ++++++++++++++----------- setup.py | 28 +++++- test/test.py | 100 +++++++++++----------- test/tooltest.py | 22 ++--- 28 files changed, 545 insertions(+), 484 deletions(-) create mode 100755 mmgen/opt.py rename mmgen/{Opts.py => opts.py} (70%) rename mmgen/{opt => share}/Opts.py (73%) create mode 100644 mmgen/share/Opts.pyc rename mmgen/{opt => share}/__init__.py (100%) create mode 100644 mmgen/share/__init__.pyc diff --git a/mmgen/addr.py b/mmgen/addr.py index 8e54b24c..a771b981 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -30,6 +30,7 @@ from mmgen.bitcoin import numtowif from mmgen.util import * from mmgen.tx import is_mmgen_idx,is_mmgen_seed_id,is_btc_addr,is_wif,get_wif2addr_f import mmgen.config as g +import mmgen.opt as opt addrmsgs = { 'addrfile_header': """ @@ -60,13 +61,13 @@ def test_for_keyconv(): return True -def generate_addrs(seed, addrnums, opts): +def generate_addrs(seed, addrnums): from util import make_chksum_8 seed_id = make_chksum_8(seed) # Must do this before seed gets clobbered - if 'a' in opts['gen_what']: - if g.no_keyconv or test_for_keyconv() == False: + if 'a' in opt.gen_what: + if opt.no_keyconv or test_for_keyconv() == False: msg("Using (slow) internal ECDSA library for address generation") from mmgen.bitcoin import privnum2addr keyconv = False @@ -81,7 +82,7 @@ def generate_addrs(seed, addrnums, opts): 'ka': ('key/address pair','s'), 'k': ('key','s'), 'a': ('address','es') - }[opts['gen_what']] + }[opt.gen_what] from mmgen.addr import AddrInfoEntry,AddrInfo @@ -89,7 +90,7 @@ def generate_addrs(seed, addrnums, opts): seed = sha512(seed).digest() num += 1 # round - if g.debug: print "Seed round %s: %s" % (num, hexlify(seed)) + if opt.debug: print "Seed round %s: %s" % (num, hexlify(seed)) if num != addrnums[pos]: continue pos += 1 @@ -103,20 +104,20 @@ def generate_addrs(seed, addrnums, opts): sec = sha256(sha256(seed).digest()).hexdigest() wif = numtowif(int(sec,16)) - if 'a' in opts['gen_what']: + if 'a' in opt.gen_what: if keyconv: e.addr = check_output([keyconv, wif]).split()[1] else: e.addr = privnum2addr(int(sec,16)) - if 'k' in opts['gen_what']: e.wif = wif - if 'b16' in opts: e.sec = sec + if 'k' in opt.gen_what: e.wif = wif + if opt.b16: e.sec = sec out.append(e) m = w[0] if t_addrs == 1 else w[0]+w[1] qmsg("\r%s: %s %s generated%s" % (seed_id,t_addrs,m," "*15)) - a = AddrInfo(has_keys='k' in opts['gen_what']) + a = AddrInfo(has_keys='k' in opt.gen_what) a.initialize(seed_id,out) return a diff --git a/mmgen/config.py b/mmgen/config.py index ff3fa201..52669d06 100755 --- a/mmgen/config.py +++ b/mmgen/config.py @@ -21,23 +21,38 @@ config.py: Constants and configuration options for the MMGen suite """ import sys, os -prog_name = os.path.basename(sys.argv[0]) -author = "Philemon" -email = "" -Cdates = '2013-2015' -version = '0.7.9' +# Variables - these might be altered at runtime: -quiet,verbose,no_keyconv = False,False,False +user_entropy = "" +hash_preset = '3' +usr_randchars = 30 +use_urandchars = False -min_screen_width = 80 -max_tx_comment_len = 72 +# 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") from decimal import Decimal tx_fee = Decimal("0.00005") max_tx_fee = Decimal("0.01") -proj_name = "MMGen" +seed_len = 256 +http_timeout = 30 + +# Constants - these don't change at runtime + +proj_name = "MMGen" +prog_name = os.path.basename(sys.argv[0]) +author = "Philemon" +email = "" +Cdates = '2013-2015' +version = '0.7.9' + +min_screen_width = 80 +max_tx_comment_len = 72 wallet_ext = "mmdat" seed_ext = "mmseed" @@ -48,49 +63,37 @@ incog_hex_ext = "mmincox" seedfile_exts = wallet_ext, seed_ext, mn_ext, brain_ext, incog_ext -rawtx_ext = "raw" -sigtx_ext = "sig" -addrfile_ext = "addrs" +rawtx_ext = "raw" +sigtx_ext = "sig" +addrfile_ext = "addrs" addrfile_chksum_ext = "chk" -keyfile_ext = "keys" -keyaddrfile_ext = "akeys" -mmenc_ext = "mmenc" +keyfile_ext = "keys" +keyaddrfile_ext = "akeys" +mmenc_ext = "mmenc" default_wl = "electrum" #default_wl = "tirosh" -# Global value sets user opt -dfl_vars = "seed_len","hash_preset" +# If user opt is set, different global opt is set to 'True' +usr_set_vars = { "usr_randchars": "use_urandchars" } -# User opt sets global value -usr_set_vars = "no_keyconv","verbose","quiet","usr_randchars" +# Global value sets user opt +dfl_vars = "seed_len","hash_preset","usr_randchars","debug" seed_lens = 128,192,256 -seed_len = 256 mn_lens = [i / 32 * 3 for i in seed_lens] -http_timeout = 30 - keyconv_exec = "keyconv" -# 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") - -mins_per_block = 8.5 +mins_per_block = 8.5 passwd_max_tries = 5 -usr_randchars = 30 max_urandchars,min_urandchars = 80,10 -use_urandchars = False -salt_len = 16 -aesctr_iv_len = 16 +salt_len = 16 +aesctr_iv_len = 16 -hash_preset = '3' hash_presets = { # Scrypt params: # ID N p r @@ -114,7 +117,6 @@ max_addr_label_len = 32 wallet_label_symbols = addr_label_symbols max_wallet_label_len = 32 -user_entropy = "" #addr_label_punc = ".","_",",","-"," ","(",")" #addr_label_symbols = tuple(ascii_letters + digits) + addr_label_punc #wallet_label_punc = addr_label_punc diff --git a/mmgen/crypto.py b/mmgen/crypto.py index 7dea0739..eee858c7 100755 --- a/mmgen/crypto.py +++ b/mmgen/crypto.py @@ -25,6 +25,7 @@ from binascii import hexlify from hashlib import sha256 import mmgen.config as g +import mmgen.opt as opt from mmgen.util import * from mmgen.term import get_char @@ -77,7 +78,7 @@ def decrypt_seed(enc_seed, key, seed_id, key_id): if compare_checksums(chk2,"of decrypted seed",seed_id,"in header"): qmsg("Passphrase is OK") else: - if not g.debug: + if not opt.debug: msg_r("Checking key ID...") if compare_checksums(chk1, "of key", key_id, "in header"): msg("Key ID is correct but decryption of seed failed") @@ -89,7 +90,7 @@ def decrypt_seed(enc_seed, key, seed_id, key_id): # else: # qmsg("Generated IDs (Seed/Key): %s/%s" % (chk2,chk1)) - if g.debug: print "Decrypted seed: %s" % hexlify(dec_seed) + if opt.debug: print "Decrypted seed: %s" % hexlify(dec_seed) vmsg("OK") return dec_seed @@ -153,18 +154,18 @@ def make_key(passwd,salt,hash_preset, what="encryption key",from_what="passphrase",verbose=False): if from_what: what += " from " - if g.verbose or verbose: + if opt.verbose or verbose: msg_r("Generating %s%s.\nPlease wait..." % (what,from_what)) key = scrypt_hash_passphrase(passwd, salt, hash_preset) - if g.verbose or verbose: + if opt.verbose or verbose: msg("done") - if g.debug: print "Key: %s" % hexlify(key) + if opt.debug: print "Key: %s" % hexlify(key) return key def get_random_data_from_user(uchars): - if g.quiet: msg("Enter %s random symbols" % uchars) + if opt.quiet: msg("Enter %s random symbols" % uchars) else: msg(crmsg['usr_rand_notice'] % uchars) prompt = "You may begin typing. %s symbols left: " @@ -184,12 +185,12 @@ def get_random_data_from_user(uchars): time_data.append(now - saved_time) saved_time = now - if g.quiet: msg_r("\r") + if opt.quiet: msg_r("\r") else: msg_r("\rThank you. That's enough.%s\n\n" % (" "*18)) fmt_time_data = ["{:.22f}".format(i) for i in time_data] - if g.debug: + if opt.debug: msg("\nUser input:\n%s\nKeystroke time intervals:\n%s\n" % (key_data,"\n".join(fmt_time_data))) @@ -206,7 +207,7 @@ def get_random(length): from_what = "OS random data" if not g.user_entropy: g.user_entropy = \ - sha256(get_random_data_from_user(g.usr_randchars)).digest() + sha256(get_random_data_from_user(opt.usr_randchars)).digest() from_what += " plus user-supplied entropy" else: from_what += " plus saved user-supplied entropy" @@ -218,7 +219,6 @@ def get_random(length): def get_seed_from_wallet( infile, - opts, prompt_info="{} wallet".format(g.proj_name), silent=False ): @@ -226,22 +226,22 @@ def get_seed_from_wallet( wdata = get_data_from_wallet(infile,silent=silent) label,metadata,hash_preset,salt,enc_seed = wdata - if g.debug: display_control_data(*wdata) + if opt.debug: display_control_data(*wdata) - padd = " "+infile if g.quiet else "" - passwd = get_mmgen_passphrase(prompt_info+padd,opts) + padd = " "+infile if opt.quiet else "" + passwd = get_mmgen_passphrase(prompt_info+padd) key = make_key(passwd, salt, hash_preset) return decrypt_seed(enc_seed, key, metadata[0], metadata[1]) -def get_hidden_incog_data(opts): +def get_hidden_incog_data(): # Already sanity-checked: - fname,offset,seed_len = opts['from_incog_hidden'].split(",") + fname,offset,seed_len = opt.from_incog_hidden.split(",") qmsg("Getting hidden incog data from file '%s'" % fname) - z = 0 if 'old_incog_fmt' in opts else 8 + z = 0 if opt.old_incog_fmt else 8 dlen = g.aesctr_iv_len + g.salt_len + (int(seed_len)/8) + z fsize = check_data_fits_file_at_offset(fname,int(offset),dlen,"read") @@ -265,13 +265,12 @@ def confirm_old_format(): elif reply in 'nN': msg("\nExiting at user request"); sys.exit(1) elif reply in 'mM': msg(""); return True else: - if g.verbose: msg("\nInvalid reply") + if opt.verbose: msg("\nInvalid reply") else: msg_r("\r") def get_seed_from_incog_wallet( infile, - opts, prompt_info="{} incognito wallet".format(g.proj_name), silent=False, hex_input=False @@ -279,8 +278,8 @@ def get_seed_from_incog_wallet( what = "incognito wallet data" - if "from_incog_hidden" in opts: - d = get_hidden_incog_data(opts) + if opt.from_incog_hidden: + d = get_hidden_incog_data() else: d = get_data_from_file(infile,what) if hex_input: @@ -290,7 +289,7 @@ def get_seed_from_incog_wallet( msg("Data in file '%s' is not in hexadecimal format" % infile) sys.exit(2) # File could be of invalid length, so check: - z = 0 if 'old_incog_fmt' in opts else 8 + z = 0 if opt.old_incog_fmt else 8 valid_dlens = [i/8 + g.aesctr_iv_len + g.salt_len + z for i in g.seed_lens] # New fmt: [56, 64, 72]. Old fmt: [48, 56, 64]. if len(d) not in valid_dlens: @@ -308,11 +307,11 @@ def get_seed_from_incog_wallet( incog_id = make_iv_chksum(iv) msg("Incog ID: %s (IV ID: %s)" % (incog_id,make_chksum_8(iv))) qmsg("Check the applicable value against your records.") - vmsg(crmsg['incog_iv_id_hidden' if "from_incog_hidden" in opts + vmsg(crmsg['incog_iv_id_hidden' if opt.from_incog_hidden else 'incog_iv_id']) while True: - passwd = get_mmgen_passphrase(prompt_info+" "+incog_id,opts) + passwd = get_mmgen_passphrase(prompt_info+" "+incog_id) qmsg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets))) hp = get_hash_preset_from_user(what="incog wallet") @@ -333,7 +332,7 @@ def get_seed_from_incog_wallet( m = "Seed ID: %s. Is the Seed ID correct?" % sid return keypress_confirm(m, True) - if 'old_incog_fmt' in opts: + if opt.old_incog_fmt: if confirm_correct_seed_id(old_fmt_sid): break else: @@ -349,7 +348,7 @@ def get_seed_from_incog_wallet( return seed -def _get_seed(infile,opts,silent=False,seed_id=""): +def _get_seed(infile,silent=False,seed_id=""): ext = get_extension(infile) @@ -359,10 +358,10 @@ def _get_seed(infile,opts,silent=False,seed_id=""): elif ext == g.wallet_ext: source = "wallet" elif ext == g.incog_ext: source = "incognito wallet" elif ext == g.incog_hex_ext: source = "incognito wallet" - elif 'from_mnemonic' in opts: source = "mnemonic" - elif 'from_brain' in opts: source = "brainwallet" - elif 'from_seed' in opts: source = "seed" - elif 'from_incog' in opts: source = "incognito wallet" + elif opt.from_mnemonic : source = "mnemonic" + elif opt.from_brain : source = "brainwallet" + elif opt.from_seed : source = "seed" + elif opt.from_incog : source = "incognito wallet" else: if infile: msg( "Invalid file extension for file: %s\nValid extensions: '.%s'" % @@ -373,26 +372,26 @@ def _get_seed(infile,opts,silent=False,seed_id=""): seed_id_str = " for seed ID "+seed_id if seed_id else "" if source == "mnemonic": prompt = "Enter mnemonic%s: " % seed_id_str - words = get_words(infile,"mnemonic data",prompt,opts) + words = get_words(infile,"mnemonic data",prompt) wl = get_default_wordlist() from mmgen.mnemonic import get_seed_from_mnemonic seed = get_seed_from_mnemonic(words,wl) elif source == "brainwallet": - if 'from_brain' not in opts: + if not opt.from_brain: msg("'--from-brain' parameters must be specified for brainwallet file") sys.exit(2) prompt = "Enter brainwallet passphrase%s: " % seed_id_str - words = get_words(infile,"brainwallet data",prompt,opts) - seed = _get_seed_from_brain_passphrase(words,opts) + words = get_words(infile,"brainwallet data",prompt) + seed = _get_seed_from_brain_passphrase(words) elif source == "seed": prompt = "Enter seed%s in %s format: " % (seed_id_str,g.seed_ext) - words = get_words(infile,"seed data",prompt,opts) + words = get_words(infile,"seed data",prompt) seed = get_seed_from_seed_data(words) elif source == "wallet": - seed = get_seed_from_wallet(infile, opts, silent=silent) + seed = get_seed_from_wallet(infile, silent=silent) elif source == "incognito wallet": - h = ext == g.incog_hex_ext or 'from_incog_hex' in opts - seed = get_seed_from_incog_wallet(infile, opts, silent=silent, hex_input=h) + h = (ext == g.incog_hex_ext) or opt.from_incog_hex + seed = get_seed_from_incog_wallet(infile, silent=silent, hex_input=h) if infile and not seed and ( @@ -400,25 +399,25 @@ def _get_seed(infile,opts,silent=False,seed_id=""): msg("Invalid %s file '%s'" % (source,infile)) sys.exit(2) - if g.debug: print "Seed: %s" % hexlify(seed) + if opt.debug: print "Seed: %s" % hexlify(seed) return seed # Repeat if entered data is invalid -def get_seed_retry(infile,opts,seed_id=""): +def get_seed_retry(infile,seed_id=""): silent = False while True: - seed = _get_seed(infile,opts,silent=silent,seed_id=seed_id) + seed = _get_seed(infile,silent=silent,seed_id=seed_id) silent = True if seed: return seed -def _get_seed_from_brain_passphrase(words,opts): +def _get_seed_from_brain_passphrase(words): bp = " ".join(words) - if g.debug: print "Sanitized brain passphrase: %s" % bp - seed_len,hash_preset = get_from_brain_opt_params(opts) - if g.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset) + if opt.debug: print "Sanitized brain passphrase: %s" % bp + seed_len,hash_preset = get_from_brain_opt_params() + if opt.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset) vmsg_r("Hashing brainwallet data. Please wait...") # Use buflen arg of scrypt.hash() to get seed of desired length seed = scrypt_hash_passphrase(bp, "", hash_preset, buflen=seed_len/8) @@ -429,7 +428,7 @@ def _get_seed_from_brain_passphrase(words,opts): # Vars for mmgen_*crypt functions only salt_len,sha256_len,nonce_len = 32,32,32 -def mmgen_encrypt(data,what="data",hash_preset='',opts={}): +def mmgen_encrypt(data,what="data",hash_preset=''): salt,iv,nonce = get_random(salt_len),\ get_random(g.aesctr_iv_len), \ get_random(nonce_len) @@ -451,7 +450,7 @@ def mmgen_decrypt(data,what="data",hash_preset=""): hp = hash_preset or get_hash_preset_from_user('3',what) m = "default" if hp == '3' else "user-requested" qmsg("Using %s hash preset of '%s'" % (m,hp)) - passwd = get_mmgen_passphrase(what,{}) + passwd = get_mmgen_passphrase(what) key = make_key(passwd, salt, hp) dec_d = decrypt_data(enc_d, key, int(hexlify(iv),16), what) if dec_d[:sha256_len] == sha256(dec_d[sha256_len:]).digest(): diff --git a/mmgen/license.py b/mmgen/license.py index fb6c7a60..0748421d 100755 --- a/mmgen/license.py +++ b/mmgen/license.py @@ -24,6 +24,7 @@ import sys from mmgen.util import msg, msg_r from mmgen.term import get_char import mmgen.config as g +import mmgen.opt as opt gpl = { 'warning': """ @@ -589,7 +590,7 @@ copy of the Program in return for a fee. def do_license_msg(immed=False): - if g.quiet or g.no_license: return + if opt.quiet or g.no_license: return msg(gpl['warning']) prompt = "%s " % gpl['prompt'].strip() diff --git a/mmgen/main_addrgen.py b/mmgen/main_addrgen.py index 58903269..30dfcc03 100755 --- a/mmgen/main_addrgen.py +++ b/mmgen/main_addrgen.py @@ -24,7 +24,7 @@ mmgen-addrgen: Generate a series or range of addresses from an MMGen import sys import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.license import * from mmgen.util import * from mmgen.crypto import * @@ -32,8 +32,7 @@ from mmgen.addr import * what = "keys" if sys.argv[0].split("-")[-1] == "keygen" else "addresses" -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': """Generate a range or list of {} from an {g.proj_name} wallet, mnemonic, seed or password""".format(what,g=g), 'usage':"[opts] [infile]
", @@ -114,25 +113,24 @@ UNENCRYPTED form. Generate only the key(s) you need and guard them carefully. """.format(g.proj_name), } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data,add_opts=["b16"]) -if 'show_hash_presets' in opts: show_hash_presets() -if 'from_incog_hex' in opts or 'from_incog_hidden' in opts: - opts['from_incog'] = True +if opt.show_hash_presets: show_hash_presets() +if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True -if g.debug: show_opts_and_cmd_args(opts,cmd_args) +if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args) if len(cmd_args) == 1 and ( - 'from_mnemonic' in opts - or 'from_brain' in opts - or 'from_seed' in opts - or 'from_incog_hidden' in opts + opt.from_mnemonic + or opt.from_brain + or opt.from_seed + or opt.from_incog_hidden ): infile,addr_idx_arg = "",cmd_args[0] elif len(cmd_args) == 2: infile,addr_idx_arg = cmd_args check_infile(infile) -else: usage(help_data) +else: opt.opts.usage(opts_data) addr_idxs = parse_addr_idxs(addr_idx_arg) @@ -141,46 +139,46 @@ if not addr_idxs: sys.exit(2) do_license_msg() # Interact with user: -if what == "keys" and not g.quiet: +if what == "keys" and not opt.quiet: confirm_or_exit(wmsg['unencrypted_secret_keys'], 'continue') # Generate data: -seed = get_seed_retry(infile,opts) +seed = get_seed_retry(infile) -opts['gen_what'] = "a" if what == "addresses" else ( - "k" if 'no_addresses' in opts else "ka") +opt.gen_what = "a" if what == "addresses" else ( + "k" if opt.no_addresses else "ka") -ainfo = generate_addrs(seed, addr_idxs, opts) +ainfo = generate_addrs(seed, addr_idxs) addrdata_str = ainfo.fmt_data() outfile_base = "{}[{}]".format(make_chksum_8(seed), ainfo.idxs_fmt) -if 'a' in opts['gen_what']: - w = "key-address" if 'k' in opts['gen_what'] else "address" +if 'a' in opt.gen_what: + w = "key-address" if 'k' in opt.gen_what else "address" qmsg("Checksum for %s data %s: %s" % (w,outfile_base,ainfo.checksum)) - if 'save_checksum' in opts: + if opt.save_checksum: write_to_file(outfile_base+"."+g.addrfile_chksum_ext, - ainfo.checksum+"\n",opts,"%s data checksum" % w,True,True,False) + ainfo.checksum+"\n","%s data checksum" % w,True,True,False) else: qmsg("This checksum will be used to verify the %s file in the future."%w) qmsg("Record it to a safe location.") -if 'k' in opts['gen_what'] and keypress_confirm("Encrypt key list?"): - addrdata_str = mmgen_encrypt(addrdata_str,"new key list","",opts) +if 'k' in opt.gen_what and keypress_confirm("Encrypt key list?"): + addrdata_str = mmgen_encrypt(addrdata_str,"new key list","") enc_ext = "." + g.mmenc_ext else: enc_ext = "" # Output data: -if 'stdout' in opts or not sys.stdout.isatty(): +if opt.stdout or not sys.stdout.isatty(): if enc_ext and sys.stdout.isatty(): msg("Cannot write encrypted data to screen. Exiting") sys.exit(2) write_to_stdout(addrdata_str,what, - (what=="keys"and not g.quiet and sys.stdout.isatty())) + (what=="keys"and not opt.quiet and sys.stdout.isatty())) else: outfile = "%s.%s%s" % (outfile_base, ( - g.keyaddrfile_ext if "ka" in opts['gen_what'] else ( - g.keyfile_ext if "k" in opts['gen_what'] else + g.keyaddrfile_ext if "ka" in opt.gen_what else ( + g.keyfile_ext if "k" in opt.gen_what else g.addrfile_ext)), enc_ext) - write_to_file(outfile,addrdata_str,opts,what,not g.quiet,True) + write_to_file(outfile,addrdata_str,what,not opt.quiet,True) diff --git a/mmgen/main_addrimport.py b/mmgen/main_addrimport.py index 42ee0cf6..8fd3963e 100755 --- a/mmgen/main_addrimport.py +++ b/mmgen/main_addrimport.py @@ -21,14 +21,14 @@ mmgen-addrimport: Import addresses into a MMGen bitcoind tracking wallet """ import sys, time -from mmgen.Opts import * +import mmgen.config as g +import mmgen.opt as opt from mmgen.license import * from mmgen.util import * from mmgen.tx import connect_to_bitcoind from mmgen.addr import AddrInfo,AddrInfoEntry -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': """Import addresses (both {pnm} and non-{pnm}) into a bitcoind tracking wallet""".format(pnm=g.proj_name), 'usage':"[opts] [mmgen address file]", @@ -47,12 +47,12 @@ in the tracking wallet. """ } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) if len(cmd_args) == 1: infile = cmd_args[0] check_infile(infile) - if 'addrlist' in opts: + if opt.addrlist: lines = get_lines_from_file( infile,"non-{} addresses".format(g.proj_name),trim_comments=True) ai,adata = AddrInfo(),[] @@ -62,7 +62,7 @@ if len(cmd_args) == 1: adata.append(a) ai.initialize(None,adata) else: - ai = AddrInfo(infile,has_keys='keyaddr_file' in opts) + ai = AddrInfo(infile,has_keys=opt.keyaddr_file) else: msg(""" "You must specify an mmgen address file (or a list of non-%s addresses @@ -80,10 +80,9 @@ for e in ai.addrdata: m = (" from seed ID %s" % ai.seed_id) if ai.seed_id else "" qmsg("OK. %s addresses%s" % (ai.num_addrs,m)) -import mmgen.config as g g.http_timeout = 3600 -if not 'test' in opts: +if not opt.test: c = connect_to_bitcoind() m = """ @@ -92,30 +91,30 @@ necessary only if an address you're importing is already on the blockchain, has a balance and is not already in your tracking wallet. Note that the rescanning process is very slow (>30 min. for each imported address on a low-powered computer). - """.strip() if "rescan" in opts else """ + """.strip() if opt.rescan else """ WARNING: If any of the addresses you're importing is already on the blockchain, has a balance and is not already in your tracking wallet, you must exit the program now and rerun it using the '--rescan' option. Otherwise you may ignore this message and continue. """.strip() -if g.quiet: m = "" +if opt.quiet: m = "" confirm_or_exit(m, "continue", expect="YES") err_flag = False def import_address(addr,label,rescan): try: - if not 'test' in opts: + if not opt.test: c.importaddress(addr,label,rescan) except: global err_flag err_flag = True w_n_of_m = len(str(ai.num_addrs)) * 2 + 2 -w_mmid = "" if 'addrlist' in opts else len(str(max(ai.idxs()))) + 12 +w_mmid = "" if opt.addrlist else len(str(max(ai.idxs()))) + 12 -if "rescan" in opts: +if opt.rescan: import threading msg_fmt = "\r%s %-{}s %-34s %s".format(w_n_of_m) else: @@ -128,7 +127,7 @@ for n,e in enumerate(ai.addrdata): if e.comment: label += " " + e.comment else: label = "non-%s" % g.proj_name - if "rescan" in opts: + if opt.rescan: t = threading.Thread(target=import_address, args=(e.addr,label,True)) t.daemon = True t.start() diff --git a/mmgen/main_passchg.py b/mmgen/main_passchg.py index f4870452..f3a1eb51 100755 --- a/mmgen/main_passchg.py +++ b/mmgen/main_passchg.py @@ -22,13 +22,12 @@ mmgen-passchg: Change an MMGen deterministic wallet's passphrase, label or """ import sys -from mmgen.Opts import * from mmgen.util import * from mmgen.crypto import * import mmgen.config as g +import mmgen.opt as opt -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': """Change the passphrase, hash preset or label of an {} deterministic wallet""".format(g.proj_name), 'usage': "[opts] [filename]", @@ -55,9 +54,9 @@ NOTE: The key ID will change if either the passphrase or hash preset are """ } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) -if 'show_hash_presets' in opts: show_hash_presets() +if opt.show_hash_presets: show_hash_presets() if len(cmd_args) != 1: msg("One input file must be specified") @@ -71,36 +70,36 @@ seed_id,key_id = metadata[:2] # Repeat on incorrect pw entry while True: p = "{} wallet".format(g.proj_name) - passwd = get_mmgen_passphrase(p,{},not 'keep_old_passphrase' in opts) + passwd = get_mmgen_passphrase(p,not opt.keep_old_passphrase) key = make_key(passwd, salt, hash_preset) seed = decrypt_seed(enc_seed, key, seed_id, key_id) if seed: break changed = {} -if 'label' in opts: - if opts['label'] != label: - msg("Label changed: '%s' -> '%s'" % (label, opts['label'])) +if opt.label: + if opt.label != label: + msg("Label changed: '%s' -> '%s'" % (label, opt.label)) changed['label'] = True else: msg("Label is unchanged: '%s'" % (label)) -else: opts['label'] = label # Copy the old label +else: opt.label = label # Copy the old label -if 'hash_preset' in opts: - if hash_preset != opts['hash_preset']: +if opt.hash_preset: + if hash_preset != opt.hash_preset: qmsg("Hash preset has changed (%s -> %s)" % - (hash_preset, opts['hash_preset'])) + (hash_preset, opt.hash_preset)) changed['preset'] = True else: msg("Hash preset is unchanged") else: - opts['hash_preset'] = hash_preset + opt.hash_preset = hash_preset -if 'keep_old_passphrase' in opts: +if opt.keep_old_passphrase: msg("Keeping old passphrase by user request") else: new_passwd = get_new_passphrase( - "{} wallet".format(g.proj_name), opts, True) + "{} wallet".format(g.proj_name), True) if new_passwd == passwd: qmsg("Passphrase is unchanged") @@ -115,7 +114,7 @@ if 'preset' in changed or 'passwd' in changed: # Update key ID, salt from hashlib import sha256 salt = sha256(salt + get_random(128)).digest()[:g.salt_len] - key = make_key(passwd, salt, opts['hash_preset']) + key = make_key(passwd, salt, opt.hash_preset) new_key_id = make_chksum_8(key) qmsg("Key ID changed: %s -> %s" % (key_id,new_key_id)) key_id = new_key_id @@ -124,4 +123,4 @@ elif not 'label' in changed: msg("Data unchanged. No file will be written") sys.exit(2) -write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts) +write_wallet_to_file(seed, passwd, key_id, salt, enc_seed) diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 1837ff00..8becf2eb 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -23,11 +23,10 @@ mmgen-tool: Perform various MMGen- and Bitcoin-related operations. import sys import mmgen.config as g +import mmgen.opt as opt import mmgen.tool as tool -from mmgen.Opts import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Perform various MMGen- and Bitcoin-related operations", 'usage': "[opts] ", 'options': """ @@ -46,10 +45,10 @@ command """.format(tool.cmd_help,g.prog_name) } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) if len(cmd_args) < 1: - usage(help_data) + opt.opts.usage(opts_data) sys.exit(1) command = cmd_args.pop(0) @@ -64,6 +63,4 @@ if cmd_args and cmd_args[0] == '--help': args,kwargs = tool.process_args(g.prog_name, command, cmd_args) -tool.opts = opts - tool.__dict__[command](*args,**kwargs) diff --git a/mmgen/main_txcreate.py b/mmgen/main_txcreate.py index b9a9e7dc..6ebca02c 100755 --- a/mmgen/main_txcreate.py +++ b/mmgen/main_txcreate.py @@ -25,12 +25,11 @@ import sys from decimal import Decimal import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.license import * from mmgen.tx import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Create a BTC transaction with outputs to specified addresses", 'usage': "[opts] ... [change addr] [addr file] ...", 'options': """ @@ -124,7 +123,7 @@ def format_unspent_outputs_for_printing(out,sort_info,total): ) -def sort_and_view(unspent,opts): +def sort_and_view(unspent): def s_amt(i): return i.amount def s_txid(i): return "%s %03s" % (i.txid,i.vout) @@ -239,7 +238,7 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen elif reply == 'p': d = format_unspent_outputs_for_printing(unsp,sort_info,total) of = "listunspent[%s].out" % ",".join(sort_info) - write_to_file(of, d, opts,"",False,False) + write_to_file(of, d, "",False,False) write_to_file_msg = "Data written to '%s'\n\n" % of elif reply == 'v': do_pager("\n".join(out)) @@ -333,16 +332,16 @@ def mmaddr2btcaddr(c,mmaddr,acct_data,ail): return btcaddr -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) -if g.debug: show_opts_and_cmd_args(opts,cmd_args) +if opt.debug: show_opts_and_cmd_args(cmd_args) -if 'comment_file' in opts: - comment = get_tx_comment_from_file(opts['comment_file']) +if opt.comment_file: + comment = get_tx_comment_from_file(opt.comment_file) c = connect_to_bitcoind() -if not 'info' in opts: +if not opt.info: do_license_msg(immed=True) tx_out,acct_data,change_addr = {},{},"" @@ -389,30 +388,31 @@ if not 'info' in opts: msg("At least one output must be specified on the command line") sys.exit(2) - tx_fee = opts['tx_fee'] if 'tx_fee' in opts else g.tx_fee + tx_fee = opt.tx_fee if opt.tx_fee else g.tx_fee tx_fee = normalize_btc_amt(tx_fee) if tx_fee > g.max_tx_fee: msg("Transaction fee too large: %s > %s" % (tx_fee,g.max_tx_fee)) sys.exit(2) -if g.debug: show_opts_and_cmd_args(opts,cmd_args) +if opt.debug: show_opts_and_cmd_args(cmd_args) if g.bogus_wallet_data: # for debugging purposes only + import mmgen.rpc.data us = eval(get_data_from_file(g.bogus_wallet_data)) else: us = c.listunspent() -# write_to_file("bogus_unspent.json", repr(us), opts); sys.exit() +# write_to_file("bogus_unspent.json", repr(us)); sys.exit() if not us: msg(wmsg['no_spendable_outputs']); sys.exit(2) for o in us: o.mmid,o.comment = parse_mmgen_label(o.account) del o.account -unspent = sort_and_view(us,opts) +unspent = sort_and_view(us) total = trim_exponent(sum([i.amount for i in unspent])) msg("Total unspent: %s BTC (%s outputs)" % (total, len(unspent))) -if 'info' in opts: sys.exit(0) +if opt.info: sys.exit(0) send_amt = sum([tx_out[i] for i in tx_out.keys()]) msg("Total amount to spend: %s%s" % ( @@ -458,11 +458,11 @@ if change > 0: tx_out[change_addr] = float(change) tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent] -if g.debug: +if opt.debug: print "tx_in:", repr(tx_in) print "tx_out:", repr(tx_out) -if 'comment_file' in opts: +if opt.comment_file: if keypress_confirm("Edit comment?",False): comment = get_tx_comment_from_user(comment) else: @@ -493,6 +493,6 @@ if keypress_confirm("Save transaction?",default_yes=False): outfile = "tx_%s[%s].%s" % (tx_id,amt,g.rawtx_ext) data = make_tx_data("{} {} {}".format(*metadata), tx_hex,sel_unspent,b2m_map,comment) - write_to_file(outfile,data,opts,"transaction",False,True) + write_to_file(outfile,data,"transaction",False,True) else: msg("Transaction not saved") diff --git a/mmgen/main_txsend.py b/mmgen/main_txsend.py index 937775ac..9c41f8c3 100755 --- a/mmgen/main_txsend.py +++ b/mmgen/main_txsend.py @@ -23,13 +23,12 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network import sys import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.license import * from mmgen.tx import * from mmgen.util import msg,check_infile,get_lines_from_file,confirm_or_exit -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Send a Bitcoin transaction signed by {}-txsign".format(g.proj_name.lower()), 'usage': "[opts] ", 'options': """ @@ -39,11 +38,11 @@ help_data = { """ } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) if len(cmd_args) == 1: infile = cmd_args[0]; check_infile(infile) -else: usage(help_data) +else: opt.opts.usage(opts_data) # Begin execution @@ -66,13 +65,13 @@ if keypress_confirm("Edit transaction comment?"): inputs_data, b2m_map, comment) w = "signed transaction with edited comment" outfile = infile - write_to_file(outfile,data,opts,w,False,True,True) + write_to_file(outfile,data,w,False,True,True) warn = "Once this transaction is sent, there's no taking it back!" what = "broadcast this transaction to the network" expect = "YES, I REALLY WANT TO DO THIS" -if g.quiet: warn,expect = "","YES" +if opt.quiet: warn,expect = "","YES" confirm_or_exit(warn, what, expect) @@ -87,4 +86,4 @@ except: msg("Transaction sent: %s" % tx_id) of = "tx_{}[{}].txid".format(*metadata[:2]) -write_to_file(of, tx_id+"\n",opts,"transaction ID",True,True) +write_to_file(of, tx_id+"\n","transaction ID",True,True) diff --git a/mmgen/main_txsign.py b/mmgen/main_txsign.py index 818345d6..64749a65 100755 --- a/mmgen/main_txsign.py +++ b/mmgen/main_txsign.py @@ -23,12 +23,11 @@ mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate' import sys import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.license import * from mmgen.tx import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Sign Bitcoin transactions generated by {}-txcreate".format(g.proj_name.lower()), 'usage': "[opts] .. [mmgen wallet/seed/words/brainwallet file] ..", 'options': """ @@ -103,7 +102,7 @@ Removed %s duplicate wif key%s from keylist (also in {MMG} key-address file """.strip().format(MMG=g.proj_name), } -def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts): +def get_seed_for_seed_id(seed_id,infiles,saved_seeds): if seed_id in saved_seeds.keys(): return saved_seeds[seed_id] @@ -112,11 +111,10 @@ def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts): while True: if infiles: - seed = get_seed_retry(infiles.pop(0),opts) - elif "from_brain" in opts or "from_mnemonic" in opts \ - or "from_seed" in opts or "from_incog" in opts: + seed = get_seed_retry(infiles.pop(0)) + elif opt.from_brain or opt.from_mnemonic or opt.from_seed or opt.from_incog: qmsg("Need seed data for seed ID %s" % seed_id) - seed = get_seed_retry("",opts,seed_id) + seed = get_seed_retry("",seed_id) msg("User input produced seed ID %s" % make_chksum_8(seed)) else: msg("ERROR: No seed source found for seed ID: %s" % seed_id) @@ -128,7 +126,7 @@ def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts): if sid == seed_id: return seed -def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts): +def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds): seed_ids = set([i[:8] for i in mmgen_addrs]) vmsg("Need seed%s: %s" % (suf(seed_ids,"k")," ".join(seed_ids))) @@ -137,9 +135,10 @@ def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts): from mmgen.addr import generate_addrs for seed_id in seed_ids: # Returns only if seed is found - seed = get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts) + seed = get_seed_for_seed_id(seed_id,infiles,saved_seeds) addr_nums = [int(i[9:]) for i in mmgen_addrs if i[:8] == seed_id] - ai = generate_addrs(seed,addr_nums,{'gen_what':"ka"}) + opt.gen_what = "ka" + ai = generate_addrs(seed,addr_nums) d += [("{}:{}".format(seed_id,e.idx),e.addr,e.wif) for e in ai.addrdata] return d @@ -148,7 +147,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None): if keys: qmsg("Passing %s key%s to bitcoind" % (len(keys),suf(keys,"k"))) - if g.debug: print "Keys:\n %s" % "\n ".join(keys) + if opt.debug: print "Keys:\n %s" % "\n ".join(keys) msg_r("Signing transaction{}...".format(tx_num_str)) from mmgen.rpc import exceptions @@ -161,7 +160,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None): return sig_tx -def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts): +def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys): try: sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys) @@ -170,7 +169,7 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts): msg("Using keys in wallet.dat as per user request") prompt = "Enter passphrase for bitcoind wallet: " while True: - passwd = get_bitcoind_passphrase(prompt,opts) + passwd = get_bitcoind_passphrase(prompt) try: c.walletpassphrase(passwd, 9999) @@ -190,11 +189,11 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts): return sig_tx -def check_maps_from_seeds(maplist,label,infiles,saved_seeds,opts,return_keys=False): +def check_maps_from_seeds(maplist,label,infiles,saved_seeds,return_keys=False): if not maplist: return [] qmsg("Checking MMGen -> BTC address mappings for %ss (from seeds)" % label) - d = get_keys_for_mmgen_addrs(maplist.keys(),infiles,saved_seeds,opts) + d = get_keys_for_mmgen_addrs(maplist.keys(),infiles,saved_seeds) # 0=mmaddr 1=addr 2=wif m = dict([(e[0],e[1]) for e in d]) for a,b in zip(sorted(m),sorted(maplist)): @@ -214,9 +213,9 @@ for the following non-{} address{}:\n {}""".format( g.proj_name,suf(addrs,"a"),"\n ".join(addrs)).strip() -def parse_mmgen_keyaddr_file(opts): +def parse_mmgen_keyaddr_file(): from mmgen.addr import AddrInfo - ai = AddrInfo(opts['mmgen_keys_from_file'],has_keys=True) + ai = AddrInfo(opt.mmgen_keys_from_file,has_keys=True) vmsg("Found %s wif key%s for seed ID %s" % (ai.num_addrs, suf(ai.num_addrs,"k"), ai.seed_id)) # idx: (0=addr, 1=comment 2=wif) -> mmaddr: (0=addr, 1=wif) @@ -224,8 +223,8 @@ def parse_mmgen_keyaddr_file(opts): [("%s:%s"%(ai.seed_id,e.idx), (e.addr,e.wif)) for e in ai.addrdata]) -def parse_keylist(opts,from_file): - fn = opts['keys_from_file'] +def parse_keylist(from_file): + fn = opt.keys_from_file d = get_data_from_file(fn,"non-%s keylist" % g.proj_name) enc_ext = get_extension(fn) == g.mmenc_ext if enc_ext or not is_utf8(d): @@ -279,17 +278,16 @@ def get_keys_from_keylist(kldata,other_addrs): return ret -opts,infiles = parse_opts(sys.argv,help_data) +infiles = opt.opts.init(opts_data,add_opts=["b16"]) for l in ( ('tx_id', 'info'), ('tx_id', 'terse_info'), -): warn_incompatible_opts(opts,l) +): opt.opts.warn_incompatible_opts(l) -if 'from_incog_hex' in opts or 'from_incog_hidden' in opts: - opts['from_incog'] = True +if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True -if not infiles: usage(help_data) +if not infiles: opt.opts.usage(opts_data) for i in infiles: check_infile(i) c = connect_to_bitcoind() @@ -298,14 +296,14 @@ saved_seeds = {} tx_files = [i for i in infiles if get_extension(i) == g.rawtx_ext] seed_files = [i for i in infiles if get_extension(i) != g.rawtx_ext] -if not "info" in opts and not "terse_info" in opts: +if not opt.info and not opt.terse_info: do_license_msg(immed=True) from_file = { 'mmdata':{}, 'kldata':{} } -if 'mmgen_keys_from_file' in opts: - from_file['mmdata'] = parse_mmgen_keyaddr_file(opts) or {} -if 'keys_from_file' in opts: - from_file['kldata'] = parse_keylist(opts,from_file) or {} +if opt.mmgen_keys_from_file: + from_file['mmdata'] = parse_mmgen_keyaddr_file() or {} +if opt.keys_from_file: + from_file['kldata'] = parse_keylist(from_file) or {} tx_num_str = "" for tx_num,tx_file in enumerate(tx_files,1): @@ -313,19 +311,19 @@ for tx_num,tx_file in enumerate(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" + m = "" if opt.tx_id else "transaction data" tx_data = get_lines_from_file(tx_file,m) metadata,tx_hex,inputs_data,b2m_map,comment = parse_tx_file(tx_data,tx_file) vmsg("Successfully opened transaction file '%s'" % tx_file) - if 'tx_id' in opts: + if opt.tx_id: msg(metadata[0]) sys.exit(0) - if 'info' in opts or 'terse_info' in opts: + if opt.info or opt.terse_info: view_tx_data(c,inputs_data,tx_hex,b2m_map,comment,metadata,pause=False, - terse='terse_info' in opts) + terse=opt.terse_info) sys.exit(0) prompt_and_view_tx_data(c,"View data for transaction{}?".format(tx_num_str), @@ -336,7 +334,7 @@ for tx_num,tx_file in enumerate(tx_files,1): keys = get_keys_from_keylist(from_file['kldata'],other_addrs) - if other_addrs and not 'use_wallet_dat' in opts: + if other_addrs and not opt.use_wallet_dat: missing_keys_errormsg(other_addrs) sys.exit(2) @@ -347,8 +345,8 @@ for tx_num,tx_file in enumerate(tx_files,1): keys += check_maps_from_kafile(imap,"input",from_file['mmdata'],True) check_maps_from_kafile(omap,"output",from_file['mmdata']) - keys += check_maps_from_seeds(imap,"input",seed_files,saved_seeds,opts,True) - check_maps_from_seeds(omap,"output",seed_files,saved_seeds,opts) + keys += check_maps_from_seeds(imap,"input",seed_files,saved_seeds,True) + check_maps_from_seeds(omap,"output",seed_files,saved_seeds) extra_sids = set(saved_seeds.keys()) - sids if extra_sids: @@ -360,9 +358,9 @@ for tx_num,tx_file in enumerate(tx_files,1): {"txid":i['txid'],"vout":i['vout'],"scriptPubKey":i['scriptPubKey']} for i in inputs_data] - if 'use_wallet_dat' in opts: + if opt.use_wallet_dat: sig_tx = sign_tx_with_bitcoind_wallet( - c,tx_hex,tx_num_str,sig_data,keys,opts) + c,tx_hex,tx_num_str,sig_data,keys) else: sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys) @@ -374,7 +372,7 @@ for tx_num,tx_file in enumerate(tx_files,1): data = make_tx_data("{} {} {t}".format(*metadata[:2], t=make_timestamp()), sig_tx['hex'], inputs_data, b2m_map, comment) w = "signed transaction{}".format(tx_num_str) - write_to_file(outfile,data,opts,w,(not g.quiet),True,False) + write_to_file(outfile,data,w,(not opt.quiet),True,False) else: msg_r("failed\nSome keys were missing. ") msg("Transaction %scould not be signed." % tx_num_str) diff --git a/mmgen/main_walletchk.py b/mmgen/main_walletchk.py index 418df74a..5bc05173 100755 --- a/mmgen/main_walletchk.py +++ b/mmgen/main_walletchk.py @@ -23,12 +23,11 @@ mmgen-walletchk: Check integrity of an MMGen deterministic wallet, display import sys import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.util import * from mmgen.crypto import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': """Check integrity of an {} deterministic wallet, display its information, and export seed and mnemonic data. """.format(g.proj_name), @@ -61,14 +60,14 @@ to disable this option, then specify '-r0' on the command line. """ } -def wallet_to_incog_data(infile,opts): +def wallet_to_incog_data(infile): d = get_data_from_wallet(infile,silent=True) seed_id,key_id,preset,salt,enc_seed = \ d[1][0], d[1][1], d[2].split(":")[0], d[3], d[4] while True: - passwd = get_mmgen_passphrase("{} wallet".format(g.proj_name),opts) + passwd = get_mmgen_passphrase("{} wallet".format(g.proj_name)) key = make_key(passwd, salt, preset, "main key") seed = decrypt_seed(enc_seed, key, seed_id, key_id) if seed: break @@ -77,7 +76,7 @@ def wallet_to_incog_data(infile,opts): iv_id = make_iv_chksum(iv) msg("Incog ID: %s" % iv_id) - if not 'old_incog_fmt' in opts: + if not opt.old_incog_fmt: salt = get_random(g.salt_len) key = make_key(passwd, salt, preset, "incog wallet key") key_id = make_chksum_8(key) @@ -92,13 +91,13 @@ def wallet_to_incog_data(infile,opts): return iv+wrap_enc,seed_id,key_id,iv_id,preset -def export_to_hidden_incog(incog_enc,opts): - outfile,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked - if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile) +def export_to_hidden_incog(incog_enc): + outfile,offset = opt.export_incog_hidden.split(",") #Already sanity-checked + if opt.outdir: outfile = make_full_path(opt.outdir,outfile) check_data_fits_file_at_offset(outfile,int(offset),len(incog_enc),"write") - if not g.quiet: confirm_or_exit("","alter file '%s'" % outfile) + if not opt.quiet: confirm_or_exit("","alter file '%s'" % outfile) import os f = os.open(outfile,os.O_RDWR) os.lseek(f, int(offset), os.SEEK_SET) @@ -108,60 +107,60 @@ def export_to_hidden_incog(incog_enc,opts): (os.path.relpath(outfile),offset)) -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) -if 'export_incog_hidden' in opts or 'export_incog_hex' in opts: - opts['export_incog'] = True +if opt.export_incog_hidden or opt.export_incog_hex: + opt.export_incog = True -if len(cmd_args) != 1: usage(help_data) +if len(cmd_args) != 1: opt.opts.usage(opts_data) check_infile(cmd_args[0]) -if set(['outdir','export_incog_hidden']) <= set(opts.keys()): +if opt.outdir and opt.export_incog_hidden: msg("Warning: '--outdir' option is ignored when exporting hidden incog data") g.use_urandchars = True -if 'export_mnemonic' in opts: +if opt.export_mnemonic: qmsg("Exporting mnemonic data to file by user request") -elif 'export_seed' in opts: +elif opt.export_seed: qmsg("Exporting seed data to file by user request") -elif 'export_incog' in opts: +elif opt.export_incog: qmsg("Exporting wallet to incognito format by user request") incog_enc,seed_id,key_id,iv_id,preset = \ - wallet_to_incog_data(cmd_args[0],opts) + wallet_to_incog_data(cmd_args[0]) - if "export_incog_hidden" in opts: - export_to_hidden_incog(incog_enc,opts) + if opt.export_incog_hidden: + export_to_hidden_incog(incog_enc) else: - z = 0 if 'old_incog_fmt' in opts else 8 + z = 0 if opt.old_incog_fmt else 8 seed_len = (len(incog_enc)-g.salt_len-g.aesctr_iv_len-z)*8 fn = "%s-%s-%s[%s,%s].%s" % ( seed_id, key_id, iv_id, seed_len, preset, - g.incog_hex_ext if "export_incog_hex" in opts else g.incog_ext + g.incog_hex_ext if opt.export_incog_hex else g.incog_ext ) data = pretty_hexdump(incog_enc,2,8,line_nums=False) \ - if "export_incog_hex" in opts else incog_enc - write_to_file_or_stdout(fn, data, opts, "incognito wallet data") + if opt.export_incog_hex else incog_enc + write_to_file_or_stdout(fn, data, "incognito wallet data") sys.exit() -seed = get_seed_retry(cmd_args[0], opts) +seed = get_seed_retry(cmd_args[0]) if seed: msg("Wallet is OK") else: msg("Error opening wallet") sys.exit(2) -if 'export_mnemonic' in opts: +if opt.export_mnemonic: wl = get_default_wordlist() from mmgen.mnemonic import get_mnemonic_from_seed - mn = get_mnemonic_from_seed(seed, wl, g.default_wl, g.debug) + mn = get_mnemonic_from_seed(seed, wl, g.default_wl, opt.debug) fn = "%s.%s" % (make_chksum_8(seed).upper(), g.mn_ext) - write_to_file_or_stdout(fn, " ".join(mn)+"\n", opts, "mnemonic data") + write_to_file_or_stdout(fn, " ".join(mn)+"\n", "mnemonic data") -elif 'export_seed' in opts: +elif opt.export_seed: 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) - write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), opts, "seed data") + write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), "seed data") diff --git a/mmgen/main_walletgen.py b/mmgen/main_walletgen.py index 004b77e8..27416f30 100755 --- a/mmgen/main_walletgen.py +++ b/mmgen/main_walletgen.py @@ -24,13 +24,12 @@ import sys, os from hashlib import sha256 import mmgen.config as g -from mmgen.Opts import * +import mmgen.opt as opt from mmgen.license import * from mmgen.util import * from mmgen.crypto import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Generate an {} deterministic wallet".format(g.proj_name), 'usage': "[opts] [infile]", 'options': """ @@ -121,11 +120,12 @@ future, you must continue using these same parameters """, } -opts,cmd_args = parse_opts(sys.argv,help_data) +import mmgen.opt as opt +cmd_args = opt.opts.init(opts_data) -if 'show_hash_presets' in opts: show_hash_presets() +if opt.show_hash_presets: show_hash_presets() -if g.debug: show_opts_and_cmd_args(opts,cmd_args) +if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args) if len(cmd_args) == 1: infile = cmd_args[0] @@ -140,7 +140,7 @@ if len(cmd_args) == 1: sys.exit(1) elif len(cmd_args) == 0: infile = "" -else: usage(help_data) +else: opt.opts.usage(opts_data) g.use_urandchars = True @@ -148,31 +148,27 @@ g.use_urandchars = True do_license_msg() -if 'from_brain' in opts and not g.quiet: +if opt.from_brain and not opt.quiet: confirm_or_exit(wmsg['brain_warning'].format( - g.proj_name, *get_from_brain_opt_params(opts)), + g.proj_name, *get_from_brain_opt_params()), "continue") -for i in 'from_mnemonic','from_brain','from_seed','from_incog': - if infile or (i in opts): - seed = get_seed_retry(infile,opts) -# if "from_incog" in opts or get_extension(infile) == g.incog_ext: -# qmsg(cmessages['incog'] % make_chksum_8(seed)) -# else: qmsg("") - qmsg("") - break +if infile or (opt.from_mnemonic or opt.from_brain + or opt.from_seed or opt.from_incog): + seed = get_seed_retry(infile) + qmsg("") else: # Truncate random data for smaller seed lengths - seed = sha256(get_random(128)).digest()[:opts['seed_len']/8] + seed = sha256(get_random(128)).digest()[:opt.seed_len/8] salt = sha256(get_random(128)).digest()[:g.salt_len] -qmsg(wmsg['choose_wallet_passphrase'] % opts['hash_preset']) +qmsg(wmsg['choose_wallet_passphrase'] % opt.hash_preset) -passwd = get_new_passphrase("new {} wallet".format(g.proj_name), opts) +passwd = get_new_passphrase("new {} wallet".format(g.proj_name)) -key = make_key(passwd, salt, opts['hash_preset']) +key = make_key(passwd, salt, opt.hash_preset) enc_seed = encrypt_seed(seed, key) -write_wallet_to_file(seed,passwd,make_chksum_8(key),salt,enc_seed,opts) +write_wallet_to_file(seed,passwd,make_chksum_8(key),salt,enc_seed) diff --git a/mmgen/mnemonic.py b/mmgen/mnemonic.py index 659a51a4..074e02b7 100755 --- a/mmgen/mnemonic.py +++ b/mmgen/mnemonic.py @@ -25,6 +25,7 @@ from binascii import hexlify from mmgen.util import msg,msg_r,make_chksum_8,Vmsg from mmgen.crypto import get_random import mmgen.config as g +import mmgen.opt as opt wl_checksums = { "electrum": '5ca31424', diff --git a/mmgen/opt.py b/mmgen/opt.py new file mode 100755 index 00000000..6437a7d8 --- /dev/null +++ b/mmgen/opt.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# +# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution +# Copyright (C)2013-2015 Philemon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +opt.py: an empty namespace for the global opt variables +""" +import opts diff --git a/mmgen/Opts.py b/mmgen/opts.py similarity index 70% rename from mmgen/Opts.py rename to mmgen/opts.py index d7e67c32..4d47e8a5 100755 --- a/mmgen/Opts.py +++ b/mmgen/opts.py @@ -17,15 +17,18 @@ # along with this program. If not, see . """ -Opts.py: Option handling routines for the MMGen suite +opts.py: Further options processing after mmgen.share.Opts """ - import sys -import mmgen.config as g -import mmgen.opt.Opts -from mmgen.util import msg,check_infile,check_outfile,check_outdir,msgrepr_exit,msgrepr -def usage(hd): mmgen.opt.Opts.usage(hd) +import mmgen.config as g +import mmgen.share.Opts +import opt +from mmgen.util import msg,msgrepr_exit,msgrepr + +def usage(opts_data): + print "USAGE: %s %s" % (opts_data['prog_name'], opts_data['usage']) + sys.exit(2) def print_version_info(): print """ @@ -33,19 +36,38 @@ def print_version_info(): Copyright (C) {g.Cdates} by {g.author} {g.email}. """.format(g=g).strip() -def warn_incompatible_opts(opts,incompat_list): - bad = [k for k in opts.keys() if k in incompat_list] +def warn_incompatible_opts(incompat_list): + bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in incompat_list] if len(bad) > 1: msg("Mutually exclusive options: %s" % " ".join( ["--"+b.replace("_","-") for b in bad])) sys.exit(1) -def parse_opts(argv,help_data): +def typeconvert_from_dfl(opts,opt): - if len(argv) == 2 and argv[1] == '--version': + vtype = type(g.__dict__[opt]) + if g.debug: print "Override opt: %-15s [%s]" % (opt,vtype) + + try: + opts[opt] = vtype(opts[opt]) + except: + d = { + 'int': 'an integer', + 'str': 'a string', + 'float': 'a float', + 'bool': 'a boolean value', + } + m = [d[k] for k in d if __builtins__[k] == vtype][0] + msg("'%s': invalid parameter for '--%s' option (not %s)" % + (opts[opt],opt.replace("_","-"),m)) + sys.exit(1) + +def init(opts_data,add_opts=[]): + + if len(sys.argv) == 2 and sys.argv[1] == '--version': print_version_info(); sys.exit() - opts,args,short_opts,long_opts = mmgen.opt.Opts.parse_opts(argv,help_data) + opts,args,short_opts,long_opts = mmgen.share.Opts.parse_opts(sys.argv,opts_data) if g.debug: print "short opts: %s" % repr(short_opts) @@ -53,46 +75,58 @@ def parse_opts(argv,help_data): print "user-selected opts: %s" % repr(opts) print "cmd args: %s" % repr(args) + # check opts without modifying them + if not check_opts(opts,long_opts): sys.exit(1) + + # If user opt is set, an opt in mmgen.config is set to 'True' + for v in g.usr_set_vars: + if v in opts: + g.__dict__[g.usr_set_vars[v]] = True + + # If user opt is unset, set it to default value in mmgen.config (g): + # If set, convert its type based on value in mmgen.config + for v in g.dfl_vars: + if v in opts: typeconvert_from_dfl(opts,v) + else: opts[v] = g.__dict__[v] + + if g.debug: print "opts after typeconvert: %s" % opts + + # A hack, but harmless + extra_opts = [ + "quiet","verbose","debug", + "outdir","echo_passphrase","passwd_file" + ] + add_opts + + # Transfer opts into our custom namespace + for o in [s.rstrip("=") for s in long_opts] + extra_opts: + opt.__dict__[o] = opts[o] if o in opts else None + for l in ( ('from_incog_hidden','from_incog','from_seed','from_mnemonic','from_brain'), ('export_incog','export_incog_hex','export_incog_hidden','export_mnemonic', 'export_seed'), ('quiet','verbose') - ): warn_incompatible_opts(opts,l) + ): warn_incompatible_opts(l) - if 'usr_randchars' in opts: g.use_urandchars = True + del mmgen.share.Opts + return args - # check opts[] dictionary without modifying it - if not check_opts(opts,long_opts): sys.exit(1) +def show_opts_and_cmd_args(cmd_args): + print "Processed options:" + d = opt.__dict__ + for k in d: + if k[:2] != "__" and k != "opts" and d[k] != None: + msg("%-20s: %s" % (k, d[k])) + print "Cmd args: %s" % repr(cmd_args) - # If user opt is unset, set it to default value in mmgen.config (g): - for v in g.dfl_vars: - if v in opts: typeconvert_override_var(opts,v) - else: opts[v] = g.__dict__[v] +def show_all_opts(): + msg("Processed options:") + d = opt.__dict__ + for k in d: + if k[:2] != "__" and k != "opts": + msg("%-20s: %s" % (k, d[k])) - # Opposite of above: set the value in mmgen.config (g) from user opt: - for k in g.usr_set_vars: - if k in opts: - v = opts[k] - try: v = type(g.__dict__[k])(v) - except: - msg( - "Argument '%s' for option '--%s' cannot be converted to target type %s" % - (v,k.replace("_","-"),type(g.__dict__[k])) - ) - sys.exit(1) - g.__dict__[k] = v - - if g.debug: print "opts after typeconvert: %s" % opts - - return opts,args - - -def show_opts_and_cmd_args(opts,cmd_args): - print "Processed options: %s" % repr(opts) - print "Cmd args: %s" % repr(cmd_args) - -def check_opts(opts,long_opts): +def check_opts(opts,long_opts): # Returns false if any check fails def opt_splits(val,sep,n,what): sepword = "comma" if sep == "," else ( @@ -136,10 +170,12 @@ def check_opts(opts,long_opts): # Check for file existence and readability if opt in ('keys_from_file','mmgen_keys_from_file', 'passwd_file','keysforaddrs','comment_file'): + from mmgen.util import check_infile check_infile(val) # exits on error continue if opt == 'outdir': + from mmgen.util import check_outdir check_outdir(val) # exits on error elif opt == 'label': if not opt_compares(len(val),"<=",g.max_wallet_label_len,"label length"): @@ -155,11 +191,13 @@ def check_opts(opts,long_opts): if opt == 'from_incog_hidden': if not opt_splits(val,",",3,what): return False infile,offset,seed_len = val.split(",") + from mmgen.util import check_infile check_infile(infile) w = "seed length " + what if not opt_is_int(seed_len,w): return False if not opt_is_in_list(int(seed_len),g.seed_lens,w): return False else: + from mmgen.util import check_outfile if not opt_splits(val,",",2,what): return False outfile,offset = val.split(",") check_outfile(outfile) @@ -184,24 +222,6 @@ def check_opts(opts,long_opts): if not opt_compares(val,">=",g.min_urandchars,what): return False if not opt_compares(val,"<=",g.max_urandchars,what): return False else: - if g.debug: print "check_opts(): No test for opt '%s'" % opt + if 'debug' in opts: print "check_opts(): No test for opt '%s'" % opt return True - - -def typeconvert_override_var(opts,opt): - - vtype = type(eval("g."+opt)) - if g.debug: print "Override opt: %-15s [%s]" % (opt,vtype) - - if vtype == int: f,t = int,"an integer" - elif vtype == str: f,t = str,"a string" - elif vtype == float: f,t = float,"a float" - elif vtype == bool: f,t = bool,"a boolean value" - - try: - opts[opt] = f(opts[opt]) - except: - msg("'%s': invalid parameter for '--%s' option (not %s)" % - (opts[opt],opt.replace("_","-"),t)) - sys.exit(1) diff --git a/mmgen/opt/Opts.py b/mmgen/share/Opts.py similarity index 73% rename from mmgen/opt/Opts.py rename to mmgen/share/Opts.py index 58bf948b..232b53f8 100755 --- a/mmgen/opt/Opts.py +++ b/mmgen/share/Opts.py @@ -18,23 +18,25 @@ import sys, getopt -def usage(hd): - print "USAGE: %s %s" % (hd['prog_name'], hd['usage']) +def usage(opts_data): + print "USAGE: %s %s" % (opts_data['prog_name'], opts_data['usage']) sys.exit(2) -def print_help(help_data): - pn = help_data['prog_name'] +def print_help(opts_data): + pn = opts_data['prog_name'] pn_len = str(len(pn)+2) - print (" %-"+pn_len+"s %s") % (pn.upper()+":", help_data['desc'].strip()) - print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, help_data['usage'].strip()) + print (" %-"+pn_len+"s %s") % (pn.upper()+":", opts_data['desc'].strip()) + print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, opts_data['usage'].strip()) sep = "\n " - print " OPTIONS:"+sep+"%s" % sep.join(help_data['options'].strip().split("\n")) - if "notes" in help_data: - print " %s" % "\n ".join(help_data['notes'][1:-1].split("\n")) + print " OPTIONS:"+sep+"%s" % sep.join(opts_data['options'].strip().split("\n")) + if "notes" in opts_data: + print " %s" % "\n ".join(opts_data['notes'][1:-1].split("\n")) -def process_opts(argv,help_data,short_opts,long_opts): +def process_opts(argv,opts_data,short_opts,long_opts): + import os + opts_data['prog_name'] = os.path.split(sys.argv[0])[1] long_opts = [i.replace("_","-") for i in long_opts] try: cl_opts, args = getopt.getopt(argv[1:], short_opts, long_opts) @@ -48,7 +50,7 @@ def process_opts(argv,help_data,short_opts,long_opts): else: short_opts_l += i for opt, arg in cl_opts: - if opt in ("-h","--help"): print_help(help_data); sys.exit() + if opt in ("-h","--help"): print_help(opts_data); sys.exit() elif opt[:2] == "--" and opt[2:] in long_opts: opts[opt[2:].replace("-","_")] = True elif opt[:2] == "--" and opt[2:]+"=" in long_opts: @@ -63,9 +65,9 @@ def process_opts(argv,help_data,short_opts,long_opts): return opts,args -def parse_opts(argv,help_data): +def parse_opts(argv,opts_data): - lines = help_data['options'].strip().split("\n") + lines = opts_data['options'].strip().split("\n") import re pat = r"^-([a-zA-Z0-9]), --([a-zA-Z0-9-]{1,64})(=| )(.+)" rep = r"-{0}, --{1}{w}{3}" @@ -75,10 +77,10 @@ def parse_opts(argv,help_data): if d[2] == " ": d[2] = "" short_opts = "".join([d[0]+d[2].replace("=",":") for d in opt_data]) long_opts = [d[1].replace("-","_")+d[2] for d in opt_data] - help_data['options'] = "\n".join( + opts_data['options'] = "\n".join( [rep.format(w=" ", *m.groups()) if m else k for m,k in [(re.match(pat,l),l) for l in lines]] ) - opts,args = process_opts(argv,help_data,short_opts,long_opts) + opts,args = process_opts(argv,opts_data,short_opts,long_opts) return opts,args,short_opts,long_opts diff --git a/mmgen/share/Opts.pyc b/mmgen/share/Opts.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aed26eb0ee0c01e0da985075092518bfda84da7a GIT binary patch literal 3143 zcmbtW&r?%Z6h8MQBqR_NX~DFk#sND)4QO?Air6V5igtmWhaEb$7-QZuB!uMg?nANU zZKTWo6J2!QZo23{(nS~D*JWLHrv1M22wLfMQQ^J&?!7tZ-t+7G?oIts$e;T2hkJF| z|8wyD1g~Y|;W5${xqr|%a^HyO$TygD#7k)>C0<%PY4HZMGeE_aat4bu|H9vL-Jr`i zjrRs#TSfz+9$H6={G_D#*pcz2+mT2MyQF2$h=CC+k+&Gj7hADU&f3Gi>U#qJVb@?+v`R29r=&$OC{HBgJWg2lWHXka2>Gbp~*uP*7d- z4b);v7T1nTJRrRRVNUU6WY3WYj%;0K;XIoZIN8c*#iZmE>J3VJDf!BgI3saZRy#A2 zrc72g@)CY8CLRReNY6ASJgib&4U$Fe(Vi{2}G<`pSUS#Qp-9gBkz106fB?-2H_v zz>MT|_ZR)$f$O}q5`PeM1g`jRro38d!J!`zMffK6SHoOl${VXugexMtr8ifN3SwVM zG$LMs>3VJiUa!)hEIDVTd<3PotUy8*0V(220S_hn_z@<#)oN7B-$JD};W~uGM`-XTy)M zFtRGLq}`ig*bQBt7%m~}9z&y8zZY&NXGgQ+`8$gGTeY_J5e<Wt&xZf2t;tZS9=8Th)Nps8$$*5Cs3T9Zw%!o6FZ(a(fWKMvDPT+gi zOgSH#aR(3;VO@}rm5P2uEs$hbw!-6zr#KF>{`uyCqX1dGE`X_kFE9`&fs8~h03(5L zKpUuB5ZM7EUBhoD$vLRTaFtm@2PKRhur@hsRX{#F=g2*aYm)+sLGAL`1jdQD=fZfZn(@b*B0{I7atXL2NigK^P!`32yR}dXhh^GYo$rT+rhbM44=@I=_>l z5QAi^zN2vFkfU%HNaH?JW^wJ35^Yw=4NhA_q8=0+(eUWN`)@(4h}E#F-7*M968?GI zaB!4kKknV`x1HjeuPbQUO&cXx54+oebrqaEId$@JH-xBr z7Goum*I-MAYBxK+b!R9|c!5^*3kp#S+S+d7IMd69UKDl8b4!?VPovTChWi1>#M0a1 zlRgKv(E5tbMU3o8G~yI-@MrMCe*@cUO>qDK literal 0 HcmV?d00001 diff --git a/mmgen/opt/__init__.py b/mmgen/share/__init__.py similarity index 100% rename from mmgen/opt/__init__.py rename to mmgen/share/__init__.py diff --git a/mmgen/share/__init__.pyc b/mmgen/share/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3eb366d14518e37825365b7ae832583714d095e GIT binary patch literal 360 zcmYLDyH3L}6un7kfB+ji9y8FG0jUchgoG*~r5(zY#Y*E#YRQi%b}I2#d<{Rs4{%e0 zYRSjvac!UE=PG00U+)b}E1~n5w!a~e02N^bZ3I;WGKMM!nL?F-oWUkP9S7eCva(#F zWsj^JbWrosNo32{74~&-{Vi*pF}0O*tt_$^6&j~3nOZVWdEFxOP7gsjoB8q0br*cm zefk;kyJAr+6cJEkw93bZM}08!6Y|0s3n5)2#Kdc@iC-N2J@%eHAbm;tUn%?Ha?)@F ze@~L{oI&1gxx_tczWwXWjcL(N=y!FGTnJ@V5Q6H4GrIU-oE$VhT@&{yK^mVYY4Qs^ CkyK3p literal 0 HcmV?d00001 diff --git a/mmgen/term.py b/mmgen/term.py index d5ef9a73..785bf08b 100755 --- a/mmgen/term.py +++ b/mmgen/term.py @@ -22,6 +22,7 @@ term.py: Terminal-handling routines for the MMGen suite import sys, os, struct import mmgen.config as g +import opt from mmgen.util import msg, msg_r def _kb_hold_protect_unix(): diff --git a/mmgen/test.py b/mmgen/test.py index fb720b16..25a1e8a3 100755 --- a/mmgen/test.py +++ b/mmgen/test.py @@ -23,7 +23,7 @@ addr.py: Shared routines for the test suites import sys,os from binascii import hexlify from mmgen.util import msg,write_to_file -import mmgen.config as g +import mmgen.opt as opt _red,_grn,_yel,_cya,_reset = ( ["\033[%sm" % c for c in "31;1","32;1","33;1","36;1","0"] @@ -58,7 +58,7 @@ def get_tmpfile_fn(cfg,fn): return os.path.join(cfg['tmpdir'],fn) def write_to_tmpfile(cfg,fn,data): - write_to_file(os.path.join(cfg['tmpdir'],fn),data,{},silent=True) + write_to_file(os.path.join(cfg['tmpdir'],fn),data,silent=True) def read_from_tmpfile(cfg,fn): from mmgen.util import get_data_from_file @@ -69,7 +69,7 @@ def read_from_file(fn): return get_data_from_file(fn,silent=True) def ok(): - if g.verbose or g.exact_output: + if opt.verbose or opt.exact_output: sys.stderr.write(green("OK\n")) else: msg(" OK") diff --git a/mmgen/tool.py b/mmgen/tool.py index c72de070..1c6f5f87 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -25,11 +25,11 @@ import mmgen.bitcoin as bitcoin import binascii as ba import mmgen.config as g +import mmgen.opt as opt from mmgen.crypto import * from mmgen.util import * from mmgen.tx import * -opts = {} from collections import OrderedDict cmd_data = OrderedDict([ ("help", []), @@ -230,7 +230,7 @@ def print_convert_results(indata,enc,dec,dtype): error = False if are_equal(indata,dec,dtype) else True - if error or g.verbose: + if error or opt.verbose: Msg("Input: %s" % repr(indata)) Msg("Encoded data: %s" % repr(enc)) Msg("Recoded data: %s" % repr(dec)) @@ -470,13 +470,13 @@ def hex2wif(hexpriv,compressed=False): def encrypt(infile,outfile="",hash_preset=""): data = get_data_from_file(infile,"data for encryption") - enc_d = mmgen_encrypt(data,"user data",hash_preset,opts) + enc_d = mmgen_encrypt(data,"user data",hash_preset) if outfile == '-': write_to_stdout(enc_d,"encrypted data",confirm=True) else: if not outfile: outfile = os.path.basename(infile) + "." + g.mmenc_ext - write_to_file(outfile, enc_d, opts,"encrypted data",True,True) + write_to_file(outfile,enc_d,"encrypted data",True,True) def decrypt(infile,outfile="",hash_preset=""): @@ -494,7 +494,7 @@ def decrypt(infile,outfile="",hash_preset=""): outfile = outfile[:-len(g.mmenc_ext)-1] else: outfile = outfile + ".dec" - write_to_file(outfile, dec_d, opts,"decrypted data",True,True) + write_to_file(outfile, dec_d, "decrypted data",True,True) def find_incog_data(filename,iv_id,keep_searching=False): @@ -553,7 +553,7 @@ def rand2file(outfile, nbytes, threads=4, silent=False): from threading import Thread bsize = 2**20 roll = bsize * 4 - if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile) + if opt.outdir: outfile = make_full_path(opt.outdir,outfile) f = open(outfile,"w") from Crypto.Cipher import AES diff --git a/mmgen/tx.py b/mmgen/tx.py index eed43ee5..aab9b9d7 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -26,6 +26,7 @@ from decimal import Decimal from collections import OrderedDict import mmgen.config as g +import mmgen.opt as opt from mmgen.util import * from mmgen.term import do_pager @@ -45,7 +46,7 @@ def normalize_btc_amt(amt): msg("%s: Invalid amount" % amt) return False - if g.debug: + if opt.debug: print "Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple())) if ret.as_tuple()[-1] < -8: @@ -260,7 +261,7 @@ def wiftoaddr_keyconv(wif): return wiftoaddr(wif) def get_wif2addr_f(): - if g.no_keyconv: return wiftoaddr + if opt.no_keyconv: return wiftoaddr from mmgen.addr import test_for_keyconv return wiftoaddr_keyconv if test_for_keyconv() else wiftoaddr diff --git a/mmgen/util.py b/mmgen/util.py index 1c0fac8b..a13a0fa1 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -26,27 +26,37 @@ from binascii import hexlify,unhexlify import mmgen.config as g -def msg(s): sys.stderr.write(s + "\n") +_red,_grn,_yel,_cya,_reset = ( + ["\033[%sm" % c for c in "31;1","32;1","33;1","36;1","0"] +) +def red(s): return _red+s+_reset +def green(s): return _grn+s+_reset +def yellow(s): return _yel+s+_reset +def cyan(s): return _cya+s+_reset + +def msgred(s): sys.stderr.write(red(s+"\n")) + +def msg(s): sys.stderr.write(s+"\n") def msg_r(s): sys.stderr.write(s) def qmsg(s,alt=False): - if g.quiet: + if opt.quiet: if alt != False: sys.stderr.write(alt + "\n") else: sys.stderr.write(s + "\n") def qmsg_r(s,alt=False): - if g.quiet: + if opt.quiet: if alt != False: sys.stderr.write(alt) else: sys.stderr.write(s) def vmsg(s): - if g.verbose: sys.stderr.write(s + "\n") + if opt.verbose: sys.stderr.write(s + "\n") def vmsg_r(s): - if g.verbose: sys.stderr.write(s) + if opt.verbose: sys.stderr.write(s) def Msg(s): sys.stdout.write(s + "\n") def Msg_r(s): sys.stdout.write(s) def Vmsg(s): - if g.verbose: sys.stdout.write(s + "\n") + if opt.verbose: sys.stdout.write(s + "\n") def Vmsg_r(s): - if g.verbose: sys.stdout.write(s) + if opt.verbose: sys.stdout.write(s) def msgrepr(*args): @@ -122,8 +132,10 @@ def is_utf8(s): def match_ext(addr,ext): return addr.split(".")[-1] == ext -def get_from_brain_opt_params(opts): - l,p = opts['from_brain'].split(",") +import opt as opt + +def get_from_brain_opt_params(): + l,p = opt.from_brain.split(",") return(int(l),p) def pretty_hexdump(data,gw=2,cols=8,line_nums=False): @@ -165,7 +177,7 @@ def compare_checksums(chksum1, desc1, chksum2, desc2): vmsg("OK (%s)" % chksum1.upper()) return True else: - if g.debug: + if opt.debug: print \ "ERROR!\nComputed checksum %s (%s) doesn't match checksum %s (%s)" \ % (desc1,chksum1,desc2,chksum2) @@ -266,18 +278,18 @@ def parse_addr_idxs(arg,sep=","): return sorted(set(ret)) -def get_new_passphrase(what, opts, passchg=False): +def get_new_passphrase(what, passchg=False): w = "{}passphrase for {}".format("new " if passchg else "", what) - if 'passwd_file' in opts: - pw = " ".join(_get_words_from_file(opts['passwd_file'],w)) - elif 'echo_passphrase' in opts: - pw = " ".join(_get_words_from_user("Enter {}: ".format(w), opts)) + if opt.passwd_file: + pw = " ".join(_get_words_from_file(opt.passwd_file,w)) + elif opt.echo_passphrase: + pw = " ".join(_get_words_from_user("Enter {}: ".format(w))) else: for i in range(g.passwd_max_tries): - pw = " ".join(_get_words_from_user("Enter {}: ".format(w),opts)) - pw2 = " ".join(_get_words_from_user("Repeat passphrase: ",opts)) - if g.debug: print "Passphrases: [%s] [%s]" % (pw,pw2) + pw = " ".join(_get_words_from_user("Enter {}: ".format(w))) + pw2 = " ".join(_get_words_from_user("Repeat passphrase: ")) + if opt.debug: print "Passphrases: [%s] [%s]" % (pw,pw2) if pw == pw2: vmsg("Passphrases match"); break else: msg("Passphrases do not match. Try again.") @@ -324,9 +336,9 @@ 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,exit_on_error=True,silent=False): +def write_to_file(outfile,data,what="data",confirm_overwrite=False,verbose=False,exit_on_error=True,silent=False): - if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile) + if opt.outdir: outfile = make_full_path(opt.outdir,outfile) from os import stat try: stat(outfile) @@ -355,18 +367,18 @@ def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose= return True -def write_to_file_or_stdout(outfile, data, opts, what="data"): +def write_to_file_or_stdout(outfile, data, what="data"): - if 'stdout' in opts or not sys.stdout.isatty(): + if opt.stdout or not sys.stdout.isatty(): write_to_stdout(data, what, confirm=True) else: - write_to_file(outfile,data,opts,what,not g.quiet,True) + write_to_file(outfile,data,what,not opt.quiet,True) from mmgen.bitcoin import b58decode_pad,b58encode_pad def display_control_data(label,metadata,hash_preset,salt,enc_seed): - msg("WALLET DATA") + print "WALLET DATA" fs = " {:18} {}" pw_empty = "yes" if metadata[3] == "E" else "no" for i in ( @@ -379,7 +391,7 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed): " ".join([str(i) for i in get_hash_params(hash_preset)]))), ("Passphrase empty?", pw_empty.capitalize()), ("Timestamp:", "%s UTC" % metadata[4]), - ): msg(fs.format(*i)) + ): print fs.format(*i) fs = " {:6} {}" for i in ( @@ -389,16 +401,16 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed): ("Encrypted seed:", ""), (" b58:", b58encode_pad(enc_seed)), (" hex:", hexlify(enc_seed)) - ): msg(fs.format(*i)) + ): print fs.format(*i) -def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts): +def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed): seed_id = make_chksum_8(seed) seed_len = str(len(seed)*8) pw_status = "NE" if len(passwd) else "E" - hash_preset = opts['hash_preset'] - label = opts['label'] if 'label' in opts else "No Label" + hash_preset = opt.hash_preset + label = opt.label if opt.label else "No Label" metadata = seed_id.lower(),key_id.lower(),seed_len,\ pw_status,make_timestamp() sf = b58encode_pad(salt) @@ -417,9 +429,9 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts): seed_id,key_id,seed_len,hash_preset,g.wallet_ext) d = "\n".join((chk,)+lines)+"\n" - write_to_file(outfile,d,opts,"wallet",not g.quiet,True) + write_to_file(outfile,d,"wallet",not opt.quiet,True) - if g.debug: + if opt.debug: display_control_data(label,metadata,hash_preset,salt,enc_seed) @@ -467,7 +479,7 @@ def _check_chksum_6(chk,val,desc,infile): msg("%s checksum incorrect in file '%s'!" % (desc,infile)) msg("Checksum: %s. Computed value: %s" % (chk,comp_chk)) sys.exit(2) - elif g.debug: + elif opt.debug: print "%s checksum passed: %s" % (desc.capitalize(),chk) @@ -475,7 +487,7 @@ def get_data_from_wallet(infile,silent=False): # Don't make this a qmsg: User will be prompted for passphrase and must see # the filename. - if not silent and not g.quiet: + if not silent and not opt.quiet: msg("Getting {} wallet data from file '{}'".format(g.proj_name,infile)) f = open_file_or_exit(infile, 'r') @@ -515,10 +527,10 @@ def get_data_from_wallet(infile,silent=False): return label,metadata,hash_preset,res['salt'],res['enc_seed'] -def _get_words_from_user(prompt, opts): +def _get_words_from_user(prompt): # split() also strips - words = my_raw_input(prompt, echo='echo_passphrase' in opts).split() - if g.debug: print "Sanitized input: [%s]" % " ".join(words) + words = my_raw_input(prompt, echo=opt.echo_passphrase).split() + if opt.debug: print "Sanitized input: [%s]" % " ".join(words) return words @@ -528,15 +540,15 @@ def _get_words_from_file(infile,what): # split() also strips words = f.read().split() f.close() - if g.debug: print "Sanitized input: [%s]" % " ".join(words) + if opt.debug: print "Sanitized input: [%s]" % " ".join(words) return words -def get_words(infile,what,prompt,opts): +def get_words(infile,what,prompt): if infile: return _get_words_from_file(infile,what) else: - return _get_words_from_user(prompt,opts) + return _get_words_from_user(prompt) def remove_comments(lines): import re @@ -594,31 +606,31 @@ def get_seed_from_seed_data(words): passwd_file_used = False -def mark_passwd_file_as_used(opts): +def mark_passwd_file_as_used(): global passwd_file_used if passwd_file_used: - msg_r("WARNING: Reusing passphrase from file '%s'." % opts['passwd_file']) + msg_r("WARNING: Reusing passphrase from file '%s'." % opt.passwd_file) msg(" This may not be what you want!") passwd_file_used = True -def get_mmgen_passphrase(prompt_info,opts,passchg=False): +def get_mmgen_passphrase(prompt_info,passchg=False): prompt = "Enter {}passphrase for {}: ".format( "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")) + if opt.passwd_file: + mark_passwd_file_as_used() + return " ".join(_get_words_from_file(opt.passwd_file,"passphrase")) else: - return " ".join(_get_words_from_user(prompt,opts)) + return " ".join(_get_words_from_user(prompt)) -def get_bitcoind_passphrase(prompt,opts): - if 'passwd_file' in opts: - mark_passwd_file_as_used(opts) - return get_data_from_file(opts['passwd_file'], +def get_bitcoind_passphrase(prompt): + if opt.passwd_file: + mark_passwd_file_as_used() + return get_data_from_file(opt.passwd_file, "passphrase").strip("\r\n") else: - return my_raw_input(prompt, echo='echo_passphrase' in opts) + return my_raw_input(prompt, echo=opt.echo_passphrase) def check_data_fits_file_at_offset(fname,offset,dlen,action): diff --git a/setup.py b/setup.py index a1081522..e45b2c56 100755 --- a/setup.py +++ b/setup.py @@ -1,12 +1,33 @@ #!/usr/bin/env python +# +# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution +# Copyright (C)2013-2015 Philemon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + from distutils.core import setup setup( name = 'mmgen', + decription = 'A complete Bitcoin cold-storage solution for the command line', version = '0.7.9', author = 'Philemon', author_email = 'mmgen-py@yandex.com', url = 'https://github.com/mmgen/mmgen', + license = 'GNU GPL v3', + platforms = 'Linux, MS Windows', + keywords = 'Bitcoin, wallet, cold storage, offline storage, open-source, command-line, Python, Bitcoin Core, bitcoind', py_modules = [ 'mmgen.__init__', 'mmgen.addr', @@ -17,7 +38,8 @@ setup( 'mmgen.mn_electrum', 'mmgen.mnemonic', 'mmgen.mn_tirosh', - 'mmgen.Opts', + 'mmgen.opts', + 'mmgen.opt', 'mmgen.term', 'mmgen.test', 'mmgen.tool', @@ -36,8 +58,8 @@ setup( 'mmgen.main_walletchk', 'mmgen.main_walletgen', - 'mmgen.opt.__init__', - 'mmgen.opt.Opts', + 'mmgen.share.__init__', + 'mmgen.share.Opts', 'mmgen.rpc.__init__', 'mmgen.rpc.config', diff --git a/test/test.py b/test/test.py index 62b42c5c..f86f3edd 100755 --- a/test/test.py +++ b/test/test.py @@ -9,6 +9,7 @@ os.chdir(os.path.join(pn,os.pardir)) sys.path.__setitem__(0,os.path.abspath(os.curdir)) import mmgen.config as g +import mmgen.opt as opt from mmgen.util import msgrepr,msgrepr_exit,Msg from mmgen.test import * @@ -202,15 +203,14 @@ meta_cmds = OrderedDict([ ['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref"))], ]) -from mmgen.Opts import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Test suite for the MMGen suite", 'usage':"[options] [command or metacommand]", 'options': """ -h, --help Print this help message -b, --buf-keypress Use buffered keypresses as with real human input -d, --debug Produce debugging output +-D, --direct-exec Bypass pexpect and execute a command directly (for debugging only) -e, --exact-output Show the exact output of the MMGen script(s) being run -l, --list-cmds List and describe the tests and commands in the test suite -p, --pause Pause between tests, resuming on keypress @@ -224,47 +224,43 @@ If no command is given, the whole suite of tests is run. """ } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data) -if 'system' in opts: sys.path.pop(0) +if opt.system: sys.path.pop(0) -env = os.environ -if 'buf_keypress' in opts: +if opt.buf_keypress: send_delay = 0.3 else: send_delay = 0 - env["MMGEN_DISABLE_HOLD_PROTECT"] = "1" + os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1" -for k in 'debug','verbose','exact_output','pause','quiet': - g.__dict__[k] = True if k in opts else False +if opt.debug: opt.verbose = True -if g.debug: g.verbose = True - -if g.exact_output: +if opt.exact_output: def msg(s): pass vmsg = vmsg_r = msg_r = msg else: def msg(s): sys.stderr.write(s+"\n") def vmsg(s): - if g.verbose: sys.stderr.write(s+"\n") + if opt.verbose: sys.stderr.write(s+"\n") def msg_r(s): sys.stderr.write(s) def vmsg_r(s): - if g.verbose: sys.stderr.write(s) + if opt.verbose: sys.stderr.write(s) stderr_save = sys.stderr def silence(): - if not (g.verbose or g.exact_output): + if not (opt.verbose or opt.exact_output): sys.stderr = open("/dev/null","a") def end_silence(): - if not (g.verbose or g.exact_output): + if not (opt.verbose or opt.exact_output): sys.stderr = stderr_save def errmsg(s): stderr_save.write(s+"\n") def errmsg_r(s): stderr_save.write(s) -if "list_cmds" in opts: +if opt.list_cmds: fs = " {:<{w}} - {}" Msg("Available commands:") w = max([len(i) for i in cmd_data]) @@ -281,15 +277,14 @@ if "list_cmds" in opts: sys.exit() import pexpect,time,re -import mmgen.config as g from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file def my_send(p,t,delay=send_delay,s=False): if delay: time.sleep(delay) ret = p.send(t) # returns num bytes written if delay: time.sleep(delay) - if g.verbose: - ls = "" if g.debug or not s else " " + if opt.verbose: + ls = "" if opt.debug or not s else " " es = "" if s else " " msg("%sSEND %s%s" % (ls,es,yellow("'%s'"%t.replace('\n',r'\n')))) return ret @@ -297,7 +292,7 @@ def my_send(p,t,delay=send_delay,s=False): def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False): quo = "'" if type(s) == str else "" - if g.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo)) + if opt.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo)) else: msg_r("+") try: @@ -309,7 +304,7 @@ def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False): errmsg(red("\nERROR. Expect %s%s%s timed out. Exiting" % (quo,s,quo))) sys.exit(1) - if g.debug or (g.verbose and type(s) != str): msg_r(" ==> %s " % ret) + if opt.debug or (opt.verbose and type(s) != str): msg_r(" ==> %s " % ret) if ret == -1: errmsg("Error. Expect returned %s" % ret) @@ -329,7 +324,7 @@ def get_file_with_ext(ext,mydir,delete=True): if len(flist) > 1: if delete: - if not g.quiet: + if not opt.quiet: msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir)) for f in flist: os.unlink(f) return False @@ -341,7 +336,7 @@ def get_addrfile_checksum(display=False): silence() from mmgen.addr import AddrInfo chk = AddrInfo(addrfile).checksum - if g.verbose and display: msg("Checksum: %s" % cyan(chk)) + if opt.verbose and display: msg("Checksum: %s" % cyan(chk)) end_silence() return chk @@ -354,21 +349,24 @@ def verify_checksum_or_exit(checksum,chk): class MMGenExpect(object): - def __init__(self,name,mmgen_cmd,cmd_args=[],env=env): - if not 'system' in opts: + def __init__(self,name,mmgen_cmd,cmd_args=[]): + if not opt.system: mmgen_cmd = os.path.join(os.curdir,mmgen_cmd) desc = cmd_data[name][1] - if g.verbose or g.exact_output: + if opt.verbose or opt.exact_output: sys.stderr.write( green("Testing %s\nExecuting " % desc) + cyan("'%s %s'\n" % (mmgen_cmd," ".join(cmd_args))) ) else: msg_r("Testing %s " % (desc+":")) -# msgrepr(mmgen_cmd,cmd_args); msg("") - if env: self.p = pexpect.spawn(mmgen_cmd,cmd_args,env=env) - else: self.p = pexpect.spawn(mmgen_cmd,cmd_args) - if g.exact_output: self.p.logfile = sys.stdout + + if opt.direct_exec: + os.system(" ".join([mmgen_cmd] + cmd_args)) + sys.exit() + else: + self.p = pexpect.spawn(mmgen_cmd,cmd_args) + if opt.exact_output: self.p.logfile = sys.stdout def license(self): p = "'w' for conditions and warranty info, or 'c' to continue: " @@ -381,7 +379,7 @@ class MMGenExpect(object): vmsg_r("SEND ") while self.p.expect('left: ',0.1) == 0: ch = rand_chars.pop(0) - msg_r(yellow(ch)+" " if g.verbose else "+") + msg_r(yellow(ch)+" " if opt.verbose else "+") self.p.send(ch) except: vmsg("EOT") @@ -476,12 +474,12 @@ def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input='') btcaddr = privnum2addr(privnum,compressed=True) of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn) write_to_file(of, hextowif("{:064x}".format(privnum), - compressed=True)+"\n",{},"compressed bitcoin key") + compressed=True)+"\n","compressed bitcoin key") add_fake_unspent_entry(out,btcaddr,"Non-MMGen address") # msg("\n".join([repr(o) for o in out])); sys.exit() - write_to_file(unspent_data_file,repr(out),{},"Unspent outputs",verbose=True) + write_to_file(unspent_data_file,repr(out),"Unspent outputs",verbose=True) def add_comments_to_addr_file(addrfile,tfile): @@ -503,18 +501,18 @@ def make_brainwallet_file(fn): return "".join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)]) rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)] d = "".join(rand_pairs).rstrip() + "\n" - if g.verbose: msg_r("Brainwallet password:\n%s" % cyan(d)) - write_to_file(fn,d,{},"brainwallet password") + if opt.verbose: msg_r("Brainwallet password:\n%s" % cyan(d)) + write_to_file(fn,d,"brainwallet password") def do_between(): - if g.pause: + if opt.pause: from mmgen.util import keypress_confirm if keypress_confirm(green("Continue?"),default_yes=True): - if g.verbose or g.exact_output: sys.stderr.write("\n") + if opt.verbose or opt.exact_output: sys.stderr.write("\n") else: errmsg("Exiting at user request") sys.exit() - elif g.verbose or g.exact_output: + elif opt.verbose or opt.exact_output: sys.stderr.write("\n") @@ -569,7 +567,7 @@ def refcheck(what,chk,refchk): if chk == refchk: ok() else: - if not g.verbose: errmsg("") + if not opt.verbose: errmsg("") errmsg(red(""" Fatal error - %s '%s' does not match reference value '%s'. Aborting test """.strip() % (what,chk,refchk))) @@ -586,7 +584,7 @@ def check_deps(ts,name,cmds): msg("'%s': unrecognized command" % cmd) sys.exit(1) - if not g.quiet: + if not opt.quiet: msg("Checking dependencies for '%s'" % (cmd)) check_needs_rerun(ts,cmd,build=False) @@ -603,8 +601,8 @@ def clean(dirs=[]): ts = MMGenTestSuite() dirlist = ts.list_tmp_dirs() if not dirs: dirs = dirlist.keys() - for d in dirs: - if d in sorted(dirlist): + for d in sorted(dirs): + if d in dirlist: cleandir(dirlist[d]) else: msg("%s: invalid directory number" % d) @@ -741,7 +739,7 @@ class MMGenTestSuite(object): self.txcreate_common(name,sources=['1']) def txcreate_common(self,name,sources=['1'],non_mmgen_input=''): - if g.verbose or g.exact_output: + if opt.verbose or opt.exact_output: sys.stderr.write(green("Generating fake transaction info\n")) silence() from mmgen.addr import AddrInfo,AddrInfoList @@ -784,11 +782,11 @@ class MMGenTestSuite(object): for num in tx_data: cmd_args += [tx_data[num]['addrfile']] - env["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file + os.environ["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file end_silence() - if g.verbose or g.exact_output: sys.stderr.write("\n") + if opt.verbose or opt.exact_output: sys.stderr.write("\n") - t = MMGenExpect(name,"mmgen-txcreate",cmd_args,env) + t = MMGenExpect(name,"mmgen-txcreate",cmd_args) t.license() for num in tx_data.keys(): t.expect_getend("Getting address data from file ") @@ -871,7 +869,7 @@ class MMGenTestSuite(object): def export_incog_hidden(self,name,walletfile): rf,rd = os.path.join(cfg['tmpdir'],hincog_fn),os.urandom(hincog_bytes) vmsg(green("Writing %s bytes of data to file '%s'" % (hincog_bytes,rf))) - write_to_file(rf,rd,{},verbose=g.verbose) + write_to_file(rf,rd,verbose=opt.verbose) t = self.export_incog(name,walletfile,args=["-G","%s,%s"%(rf,hincog_offset)]) t.written_to_file("Data",query="") ok() @@ -1033,7 +1031,7 @@ class MMGenTestSuite(object): def tool_encrypt_ref(self,name): infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn']) - write_to_file(infn,cfg['tool_enc_reftext'],{},silent=True) + write_to_file(infn,cfg['tool_enc_reftext'],silent=True) self.tool_encrypt(name,infn) # Two deps produced by one prog is broken - TODO @@ -1051,7 +1049,7 @@ class MMGenTestSuite(object): self.tool_decrypt(name,f1,f2) # main() -if g.pause: +if opt.pause: import termios,atexit fd = sys.stdin.fileno() old = termios.tcgetattr(fd) diff --git a/test/tooltest.py b/test/tooltest.py index 4be4a4cd..1ed5eb7a 100755 --- a/test/tooltest.py +++ b/test/tooltest.py @@ -8,7 +8,7 @@ pn = os.path.dirname(sys.argv[0]) os.chdir(os.path.join(pn,os.pardir)) sys.path.__setitem__(0,os.path.abspath(os.curdir)) -import mmgen.config as g +import mmgen.opt as opt from mmgen.util import msg,msg_r,vmsg,vmsg_r,Msg,msgrepr, msgrepr_exit from collections import OrderedDict @@ -74,9 +74,7 @@ cfg = { 'tmpdir_num': 10, } -from mmgen.Opts import * -help_data = { - 'prog_name': g.prog_name, +opts_data = { 'desc': "Test suite for the 'mmgen-tool' utility", 'usage':"[options] [command]", 'options': """ @@ -92,18 +90,15 @@ If no command is given, the whole suite of tests is run. """ } -opts,cmd_args = parse_opts(sys.argv,help_data) +cmd_args = opt.opts.init(opts_data,add_opts=["exact_output"]) -if 'system' in opts: sys.path.pop(0) +if opt.system: sys.path.pop(0) env = os.environ -for k in 'debug','verbose','quiet','exact_output': - g.__dict__[k] = True if k in opts else False +if opt.debug: opt.verbose = True -if g.debug: g.verbose = True - -if "list_cmds" in opts: +if opt.list_cmds: fs = " {:<{w}} - {}" Msg("Available commands:") w = max([len(i) for i in cmd_data]) @@ -114,7 +109,6 @@ if "list_cmds" in opts: sys.exit() import binascii -import mmgen.config as g from mmgen.test import * from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file from mmgen.tx import is_wif,is_btc_addr,is_b58_str @@ -162,14 +156,14 @@ class MMGenToolTestSuite(object): def run_cmd(self,name,tool_args,kwargs="",extra_msg="",silent=False): mmgen_tool = "mmgen-tool" - if not 'system' in opts: + if not opt.system: mmgen_tool = os.path.join(os.curdir,mmgen_tool) sys_cmd = [mmgen_tool, "-d",cfg['tmpdir'], name] + tool_args + kwargs.split() if extra_msg: extra_msg = "(%s)" % extra_msg full_name = " ".join([name]+kwargs.split()+extra_msg.split()) if not silent: - if g.verbose: + if opt.verbose: sys.stderr.write(green("Testing %s\nExecuting " % full_name)) sys.stderr.write("%s\n" % cyan(repr(sys_cmd))) else: