[tool]: accept stdin input for selected utils
[bitcoin/seed]: input sanitizing and checking for base conversion routines [test]: replace env var with --popen-spawn option
This commit is contained in:
parent
39167e90be
commit
c7fcf448d9
10 changed files with 75 additions and 46 deletions
|
|
@ -54,12 +54,12 @@ b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|||
from mmgen.globalvars import g
|
||||
|
||||
def pubhex2hexaddr(pubhex):
|
||||
step1 = sha256(unhexlify(pubhex)).digest()
|
||||
step1 = sha256(unhexlify(pubhex.strip())).digest()
|
||||
return hashlib_new('ripemd160',step1).hexdigest()
|
||||
|
||||
def hexaddr2addr(hexaddr,p2sh=False):
|
||||
# devdoc/ref_transactions.md:
|
||||
hexaddr2 = ('00','6f','05','c4')[g.testnet+(2*p2sh)] + hexaddr
|
||||
hexaddr2 = ('00','6f','05','c4')[g.testnet+(2*p2sh)] + hexaddr.strip()
|
||||
step1 = sha256(unhexlify(hexaddr2)).digest()
|
||||
step2 = sha256(step1).hexdigest()
|
||||
pubkey = hexaddr2 + step2[:8]
|
||||
|
|
@ -67,6 +67,7 @@ def hexaddr2addr(hexaddr,p2sh=False):
|
|||
return ('1' * lzeroes) + _numtob58(int(pubkey,16))
|
||||
|
||||
def verify_addr(addr,verbose=False,return_hex=False):
|
||||
addr = addr.strip()
|
||||
for vers_num,ldigit in ('00','1'),('05','3'),('6f','mn'),('c4','2'):
|
||||
if addr[0] not in ldigit: continue
|
||||
num = _b58tonum(addr)
|
||||
|
|
@ -95,6 +96,7 @@ def _numtob58(num):
|
|||
return ''.join(ret)[::-1]
|
||||
|
||||
def _b58tonum(b58num):
|
||||
b58num = b58num.strip()
|
||||
for i in b58num:
|
||||
if not i in b58a: return False
|
||||
return sum([b58a.index(n) * (58**i) for i,n in enumerate(list(b58num[::-1]))])
|
||||
|
|
@ -110,6 +112,7 @@ def b58encode(s):
|
|||
return _numtob58(num)
|
||||
|
||||
def b58decode(b58num):
|
||||
b58num = b58num.strip()
|
||||
if b58num == '': return ''
|
||||
# Zap all spaces:
|
||||
# Use translate() only with str, not unicode
|
||||
|
|
@ -146,6 +149,7 @@ def b58decode_pad(s):
|
|||
# Compressed address support:
|
||||
|
||||
def wif2hex(wif):
|
||||
wif = wif.strip()
|
||||
compressed = wif[0] != ('5','9')[g.testnet]
|
||||
idx = (66,68)[bool(compressed)]
|
||||
num = _b58tonum(wif)
|
||||
|
|
@ -157,7 +161,7 @@ def wif2hex(wif):
|
|||
return key[2:66] if (key[:2] == ('80','ef')[g.testnet] and key[idx:] == round2[:8]) else False
|
||||
|
||||
def hex2wif(hexpriv,compressed=False):
|
||||
step1 = ('80','ef')[g.testnet] + hexpriv + ('','01')[bool(compressed)]
|
||||
step1 = ('80','ef')[g.testnet] + hexpriv.strip() + ('','01')[bool(compressed)]
|
||||
step2 = sha256(unhexlify(step1)).digest()
|
||||
step3 = sha256(step2).hexdigest()
|
||||
key = step1 + step3[:8]
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ for c in _colors:
|
|||
else:
|
||||
globals()['_16_'+c] = '\033[{};{}m'.format(*e[1])
|
||||
globals()['_clr_'+c] = ''; _reset = ''
|
||||
exec "def {c}(s): return _clr_{c}+s+_reset".format(c=c)
|
||||
exec 'def {c}(s): return _clr_{c}+s+_reset'.format(c=c)
|
||||
|
||||
def nocolor(s): return s
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def launch(what):
|
|||
__import__('mmgen.main_' + what)
|
||||
else:
|
||||
import sys,os,atexit
|
||||
if not os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
if sys.stdin.isatty():
|
||||
fd = sys.stdin.fileno()
|
||||
old = termios.tcgetattr(fd)
|
||||
def at_exit(): termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ class BitcoinRPCConnection(object):
|
|||
'createrawtransaction',
|
||||
'backupwallet',
|
||||
'decoderawtransaction',
|
||||
'disconnectnode',
|
||||
'estimatefee',
|
||||
'getaddressesbyaccount',
|
||||
'getbalance',
|
||||
|
|
@ -152,6 +153,7 @@ class BitcoinRPCConnection(object):
|
|||
'getblockcount',
|
||||
'getblockhash',
|
||||
'getinfo',
|
||||
'getpeerinfo',
|
||||
'importaddress',
|
||||
'listaccounts',
|
||||
'listunspent',
|
||||
|
|
|
|||
|
|
@ -368,7 +368,12 @@ class Mnemonic (SeedSourceUnenc):
|
|||
def _hex2mn_pad(hexnum): return len(hexnum) * 3 / 8
|
||||
|
||||
@staticmethod
|
||||
def baseNtohex(base,words,wl,pad=0):
|
||||
def baseNtohex(base,words_arg,wl,pad=0): # accepts both string and list input
|
||||
words = words_arg
|
||||
if type(words) not in (list,tuple):
|
||||
words = tuple(words.strip())
|
||||
if not set(words).issubset(set(wl)):
|
||||
die(2,'{} is not in base-{} format'.format(repr(words_arg),base))
|
||||
deconv = [wl.index(words[::-1][i])*(base**i)
|
||||
for i in range(len(words))]
|
||||
ret = ('{:0%sx}' % pad).format(sum(deconv))
|
||||
|
|
@ -376,6 +381,9 @@ class Mnemonic (SeedSourceUnenc):
|
|||
|
||||
@staticmethod
|
||||
def hextobaseN(base,hexnum,wl,pad=0):
|
||||
hexnum = hexnum.strip()
|
||||
if not is_hexstring(hexnum):
|
||||
die(2,"'%s': not a hexadecimal number" % hexnum)
|
||||
num,ret = int(hexnum,16),[]
|
||||
while num:
|
||||
ret.append(num % base)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ except:
|
|||
_platform = 'win'
|
||||
except:
|
||||
die(2,'Unable to set terminal mode')
|
||||
if os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
if not sys.stdin.isatty():
|
||||
msvcrt.setmode(sys.stdin.fileno(),os.O_BINARY)
|
||||
|
||||
def _kb_hold_protect_unix():
|
||||
|
|
@ -140,7 +140,7 @@ def _get_keypress_mswin_raw(prompt='',immed_chars='',prehold_protect=None):
|
|||
if ord(ch) == 3: raise KeyboardInterrupt
|
||||
return ch
|
||||
|
||||
def _get_keypress_mswin_emu(prompt='',immed_chars='',prehold_protect=None):
|
||||
def _get_keypress_mswin_stub(prompt='',immed_chars='',prehold_protect=None):
|
||||
msg_r(prompt)
|
||||
return sys.stdin.read(1)
|
||||
|
||||
|
|
@ -200,12 +200,12 @@ def set_terminal_vars():
|
|||
if _platform == 'linux':
|
||||
get_char = (_get_keypress_unix_raw,_get_keypress_unix)[g.hold_protect]
|
||||
kb_hold_protect = (_kb_hold_protect_unix_raw,_kb_hold_protect_unix)[g.hold_protect]
|
||||
if os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
if not sys.stdin.isatty():
|
||||
get_char,kb_hold_protect = _get_keypress_unix_stub,_kb_hold_protect_unix_raw
|
||||
get_terminal_size = _get_terminal_size_linux
|
||||
else:
|
||||
get_char = (_get_keypress_mswin_raw,_get_keypress_mswin)[g.hold_protect]
|
||||
kb_hold_protect = (_kb_hold_protect_mswin_raw,_kb_hold_protect_mswin)[g.hold_protect]
|
||||
if os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
get_char = _get_keypress_mswin_emu
|
||||
if not sys.stdin.isatty():
|
||||
get_char = _get_keypress_mswin_stub
|
||||
get_terminal_size = _get_terminal_size_mswin
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ def cleandir(d):
|
|||
rmtree(os.path.join(d,f))
|
||||
|
||||
def getrandnum(n): return int(hexlify(os.urandom(n)),16)
|
||||
def getrandhex(n): return hexlify(os.urandom(n))
|
||||
def getrandhex(n): return hexlify(os.urandom(n).lstrip('0'))
|
||||
def getrandstr(num_chars,no_space=False):
|
||||
n,m = 95,32
|
||||
if no_space: n,m = 94,33
|
||||
|
|
|
|||
|
|
@ -33,38 +33,38 @@ from collections import OrderedDict
|
|||
cmd_data = OrderedDict([
|
||||
('help', ['<tool command> [str]']),
|
||||
('usage', ['<tool command> [str]']),
|
||||
('strtob58', ['<string> [str]']),
|
||||
('b58tostr', ['<b58 number> [str]']),
|
||||
('hextob58', ['<hex number> [str]']),
|
||||
('b58tohex', ['<b58 number> [str]']),
|
||||
('strtob58', ['<string> [str-]']),
|
||||
('b58tostr', ['<b58 number> [str-]']),
|
||||
('hextob58', ['<hex number> [str-]']),
|
||||
('b58tohex', ['<b58 number> [str-]']),
|
||||
('b58randenc', []),
|
||||
('b32tohex', ['<b32 num> [str]']),
|
||||
('hextob32', ['<hex num> [str]']),
|
||||
('b32tohex', ['<b32 num> [str-]']),
|
||||
('hextob32', ['<hex num> [str-]']),
|
||||
('randhex', ['nbytes [int=32]']),
|
||||
('id8', ['<infile> [str]']),
|
||||
('id6', ['<infile> [str]']),
|
||||
('sha256x2', ['<str, hexstr or filename> [str]',
|
||||
('sha256x2', ['<str, hexstr or filename> [str]', # TODO handle stdin
|
||||
'hex_input [bool=False]','file_input [bool=False]']),
|
||||
('str2id6', ['<string (spaces are ignored)> [str]']),
|
||||
('str2id6', ['<string (spaces are ignored)> [str-]']),
|
||||
('hexdump', ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]']),
|
||||
('unhexdump', ['<infile> [str]']),
|
||||
('hexreverse', ['<hexadecimal string> [str]']),
|
||||
('hexlify', ['<string> [str]']),
|
||||
('hexreverse', ['<hexadecimal string> [str-]']),
|
||||
('hexlify', ['<string> [str-]']),
|
||||
('rand2file', ['<outfile> [str]','<nbytes> [str]','threads [int=4]','silent [bool=False]']),
|
||||
|
||||
('randwif', ['compressed [bool=False]']),
|
||||
('randpair', ['compressed [bool=False]']),
|
||||
('hex2wif', ['<private key in hex format> [str]', 'compressed [bool=False]']),
|
||||
('wif2hex', ['<wif> [str]', 'compressed [bool=False]']),
|
||||
('wif2addr', ['<wif> [str]', 'compressed [bool=False]']),
|
||||
('hexaddr2addr', ['<btc address in hex format> [str]']),
|
||||
('addr2hexaddr', ['<btc address> [str]']),
|
||||
('pubkey2addr', ['<public key in hex format> [str]']),
|
||||
('pubkey2hexaddr', ['<public key in hex format> [str]']),
|
||||
('privhex2addr', ['<private key in hex format> [str]','compressed [bool=False]']),
|
||||
('hex2wif', ['<private key in hex format> [str-]', 'compressed [bool=False]']),
|
||||
('wif2hex', ['<wif> [str-]', 'compressed [bool=False]']),
|
||||
('wif2addr', ['<wif> [str-]', 'compressed [bool=False]']),
|
||||
('hexaddr2addr', ['<btc address in hex format> [str-]']),
|
||||
('addr2hexaddr', ['<btc address> [str-]']),
|
||||
('pubkey2addr', ['<public key in hex format> [str-]']),
|
||||
('pubkey2hexaddr', ['<public key in hex format> [str-]']),
|
||||
('privhex2addr', ['<private key in hex format> [str-]','compressed [bool=False]']),
|
||||
|
||||
('hex2mn', ['<hexadecimal string> [str]',"wordlist [str='electrum']"]),
|
||||
('mn2hex', ['<mnemonic> [str]', "wordlist [str='electrum']"]),
|
||||
('hex2mn', ['<hexadecimal string> [str-]',"wordlist [str='electrum']"]),
|
||||
('mn2hex', ['<mnemonic> [str-]', "wordlist [str='electrum']"]),
|
||||
('mn_rand128', ["wordlist [str='electrum']"]),
|
||||
('mn_rand192', ["wordlist [str='electrum']"]),
|
||||
('mn_rand256', ["wordlist [str='electrum']"]),
|
||||
|
|
@ -162,7 +162,10 @@ def tool_usage(prog_name, command):
|
|||
if ' ' + command in line:
|
||||
c,h = line.split('-',1)
|
||||
Msg('MMGEN-TOOL {}: {}'.format(c.strip().upper(),h.strip()))
|
||||
msg('USAGE: %s %s %s' % (prog_name, command, ' '.join(cmd_data[command])))
|
||||
cd = cmd_data[command]
|
||||
if cd and cd[0][-2:] == '-]':
|
||||
cd[0] = cd[0][:-2] + ' or STDIN]'
|
||||
msg('USAGE: %s %s %s' % (prog_name, command, ' '.join(cd)))
|
||||
else:
|
||||
msg("'%s': no such tool command" % command)
|
||||
sys.exit(1)
|
||||
|
|
@ -176,10 +179,19 @@ def process_args(prog_name, command, cmd_args):
|
|||
] for i in cmd_data[command] if '=' in i])
|
||||
u_args = [a for a in cmd_args[:len(c_args)]]
|
||||
|
||||
if c_args and c_args[0][1][-1] == '-':
|
||||
c_args[0][1] = c_args[0][1][:-1] # [str-] -> [str]
|
||||
# If we're reading from a pipe, make the input the first argument
|
||||
if len(u_args) < len(c_kwargs) + len(c_args):
|
||||
if not sys.stdin.isatty():
|
||||
u_args = [sys.stdin.read()] + u_args
|
||||
|
||||
if len(u_args) < len(c_args):
|
||||
msg('Command requires exactly %s non-keyword argument%s' % (len(c_args),suf(c_args,'k')))
|
||||
m1 = 'Command requires exactly %s non-keyword argument%s'
|
||||
msg(m1 % (len(c_args),suf(c_args,'k')))
|
||||
tool_usage(prog_name,command)
|
||||
|
||||
# print u_args
|
||||
extra_args = len(cmd_args) - len(c_args)
|
||||
u_kwargs = {}
|
||||
if extra_args > 0:
|
||||
|
|
@ -260,20 +272,23 @@ def strtob58(s):
|
|||
print_convert_results(s,enc,dec,'str')
|
||||
|
||||
def hextob58(s,f_enc=bitcoin.b58encode, f_dec=bitcoin.b58decode):
|
||||
s = s.strip()
|
||||
enc = f_enc(ba.unhexlify(s))
|
||||
dec = ba.hexlify(f_dec(enc))
|
||||
print_convert_results(s,enc,dec,'hex')
|
||||
|
||||
def b58tohex(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
|
||||
s = s.strip()
|
||||
tmp = f_enc(s)
|
||||
if tmp == False: sys.exit(1)
|
||||
if tmp == False: die(1,"Unable to decode string '%s'" % s)
|
||||
enc = ba.hexlify(tmp)
|
||||
dec = f_dec(ba.unhexlify(enc))
|
||||
print_convert_results(s,enc,dec,'b58')
|
||||
|
||||
def b58tostr(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
|
||||
s = s.strip()
|
||||
enc = f_enc(s)
|
||||
if enc == False: sys.exit(1)
|
||||
if enc == False: die(1,"Unable to decode string '%s'" % s)
|
||||
dec = f_dec(enc)
|
||||
print_convert_results(s,enc,dec,'b58')
|
||||
|
||||
|
|
@ -334,7 +349,7 @@ def mn2hex(s,wordlist=dfl_wordlist):
|
|||
|
||||
def b32tohex(s):
|
||||
b32a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
|
||||
Msg(Mnemonic.baseNtohex(32,s,b32a))
|
||||
Msg(Mnemonic.baseNtohex(32,s.upper(),b32a))
|
||||
|
||||
def hextob32(s):
|
||||
b32a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
|
||||
|
|
@ -355,7 +370,8 @@ def id6(infile):
|
|||
Msg(make_chksum_6(
|
||||
get_data_from_file(infile,dash=True,silent=True,binary=True)
|
||||
))
|
||||
def str2id6(s): Msg(make_chksum_6(''.join(s.split())))
|
||||
def str2id6(s): # retain ignoring of space for backwards compat
|
||||
Msg(make_chksum_6(''.join(s.split())))
|
||||
|
||||
# List MMGen addresses and their balances:
|
||||
def listaddresses(addrs='',minconf=1,showempty=False,pager=False,showbtcaddrs=False):
|
||||
|
|
@ -487,8 +503,8 @@ def keyaddrfile_chksum(infile):
|
|||
from mmgen.addr import KeyAddrList
|
||||
KeyAddrList(infile,chksum_only=True)
|
||||
|
||||
def hexreverse(hex_str):
|
||||
Msg(ba.hexlify(decode_pretty_hexdump(hex_str)[::-1]))
|
||||
def hexreverse(s):
|
||||
Msg(ba.hexlify(ba.unhexlify(s.strip())[::-1]))
|
||||
|
||||
def hexlify(s):
|
||||
Msg(ba.hexlify(s))
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ def write_data_to_file(
|
|||
|
||||
if opt.stdout or outfile in ('','-'):
|
||||
do_stdout()
|
||||
elif not sys.stdout.isatty() and not os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
elif sys.stdin.isatty() and not sys.stdout.isatty():
|
||||
do_stdout()
|
||||
else:
|
||||
do_file(outfile,ask_write_prompt)
|
||||
|
|
@ -581,7 +581,7 @@ def my_raw_input(prompt,echo=True,insert_txt='',use_readline=True):
|
|||
|
||||
from mmgen.term import kb_hold_protect
|
||||
kb_hold_protect()
|
||||
if echo or os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
if echo or not sys.stdin.isatty():
|
||||
reply = raw_input(prompt)
|
||||
else:
|
||||
from getpass import getpass
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ opts_data = {
|
|||
-L, --log Log commands to file {lf}
|
||||
-n, --names Display command names instead of descriptions
|
||||
-I, --interactive Interactive mode (without pexpect)
|
||||
-O, --popen-spawn Use pexpect's popen_spawn instead of popen
|
||||
-p, --pause Pause between tests, resuming on keypress
|
||||
-P, --profile Record the execution time of each script
|
||||
-q, --quiet Produce minimal output. Suppress dependency info
|
||||
|
|
@ -668,7 +669,7 @@ if opt.list_cmds:
|
|||
import time,re
|
||||
if g.platform == 'linux':
|
||||
import pexpect
|
||||
if os.getenv('MMGEN_PEXPECT_POPEN_SPAWN'):
|
||||
if opt.popen_spawn:
|
||||
import termios,atexit
|
||||
def at_exit(): os.system('stty sane')
|
||||
atexit.register(at_exit)
|
||||
|
|
@ -690,8 +691,6 @@ else: # Windows
|
|||
if not keypress_confirm(green(m1)+grnbg(m2)+green(m3),default_yes=True):
|
||||
errmsg('Exiting at user request')
|
||||
sys.exit()
|
||||
else:
|
||||
os.environ['MMGEN_PEXPECT_POPEN_SPAWN'] = '1'
|
||||
|
||||
def my_send(p,t,delay=send_delay,s=False):
|
||||
if delay: time.sleep(delay)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue