util.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. #!/usr/bin/env python
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2016 Philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. util.py: Low-level routines imported by other modules in the MMGen suite
  20. """
  21. import sys,os,time,stat,re
  22. from hashlib import sha256
  23. from binascii import hexlify,unhexlify
  24. from string import hexdigits
  25. # If 88- or 256-color support is compiled, the following apply.
  26. # P s = 3 8 ; 5 ; P s -> Set foreground color to the second P s .
  27. # P s = 4 8 ; 5 ; P s -> Set background color to the second P s .
  28. if os.environ['TERM'][-8:] == '256color':
  29. _blk,_red,_grn,_yel,_blu,_mag,_cya,_bright,_dim,_ybright,_ydim,_pnk,_orng,_gry = [
  30. '\033[38;5;%s;1m' % c for c in 232,210,121,229,75,90,122,231,245,187,243,218,215,246]
  31. _redbg = '\033[38;5;232;48;5;210;1m'
  32. _grnbg = '\033[38;5;232;48;5;121;1m'
  33. _grybg = '\033[38;5;231;48;5;240;1m'
  34. _reset = '\033[0m'
  35. else:
  36. _blk,_red,_grn,_yel,_blu,_mag,_cya,_reset,_grnbg = \
  37. ['\033[%sm' % c for c in '30;1','31;1','32;1','33;1','34;1','35;1','36;1','0','30;102']
  38. _gry = _orng = _pnk = _redbg = _ybright = _ydim = _bright = _dim = _grybg = _mag # TODO
  39. def red(s): return _red+s+_reset
  40. def green(s): return _grn+s+_reset
  41. def grnbg(s): return _grnbg+s+_reset
  42. def yellow(s): return _yel+s+_reset
  43. def cyan(s): return _cya+s+_reset
  44. def blue(s): return _blu+s+_reset
  45. def pink(s): return _pnk+s+_reset
  46. def orange(s): return _orng+s+_reset
  47. def gray(s): return _gry+s+_reset
  48. def magenta(s): return _mag+s+_reset
  49. def nocolor(s): return s
  50. def msg(s): sys.stderr.write(s+'\n')
  51. def msg_r(s): sys.stderr.write(s)
  52. def Msg(s): sys.stdout.write(s + '\n')
  53. def Msg_r(s): sys.stdout.write(s)
  54. def msgred(s): sys.stderr.write(red(s+'\n'))
  55. def mmsg(*args):
  56. for d in args:
  57. sys.stdout.write(repr(d)+'\n')
  58. def mdie(*args):
  59. for d in args:
  60. sys.stdout.write(repr(d)+'\n')
  61. sys.exit()
  62. def die(ev=0,s=''):
  63. assert type(ev) == int
  64. if s: sys.stderr.write(s+'\n')
  65. sys.exit(ev)
  66. def Die(ev=0,s=''):
  67. assert type(ev) == int
  68. if s: sys.stdout.write(s+'\n')
  69. sys.exit(ev)
  70. def pp_format(d):
  71. import pprint
  72. return pprint.PrettyPrinter(indent=4).pformat(d)
  73. def pp_die(d):
  74. import pprint
  75. die(1,pprint.PrettyPrinter(indent=4).pformat(d))
  76. def pp_msg(d):
  77. import pprint
  78. msg(pprint.PrettyPrinter(indent=4).pformat(d))
  79. def set_for_type(val,refval,desc,invert_bool=False,src=None):
  80. src_str = (''," in '{}'".format(src))[bool(src)]
  81. if type(refval) == bool:
  82. v = str(val).lower()
  83. if v in ('true','yes','1'): ret = True
  84. elif v in ('false','no','none','0'): ret = False
  85. else: die(1,"'{}': invalid value for '{}'{} (must be of type '{}')".format(
  86. val,desc,src_str,'bool'))
  87. if invert_bool: ret = not ret
  88. else:
  89. try:
  90. ret = type(refval)((val,not val)[invert_bool])
  91. except:
  92. die(1,"'{}': invalid value for '{}'{} (must be of type '{}')".format(
  93. val,desc,src_str,type(refval).__name__))
  94. return ret
  95. # From 'man dd':
  96. # c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024,
  97. # GB=1000*1000*1000, G=1024*1024*1024, and so on for T, P, E, Z, Y.
  98. def parse_nbytes(nbytes):
  99. import re
  100. m = re.match(r'([0123456789]+)(.*)',nbytes)
  101. smap = ('c',1),('w',2),('b',512),('kB',1000),('K',1024),('MB',1000*1000),\
  102. ('M',1024*1024),('GB',1000*1000*1000),('G',1024*1024*1024)
  103. if m:
  104. if m.group(2):
  105. for k,v in smap:
  106. if k == m.group(2):
  107. return int(m.group(1)) * v
  108. else:
  109. msg("Valid byte specifiers: '%s'" % "' '".join([i[0] for i in smap]))
  110. else:
  111. return int(nbytes)
  112. die(1,"'%s': invalid byte specifier" % nbytes)
  113. def check_or_create_dir(path):
  114. try:
  115. os.listdir(path)
  116. except:
  117. try:
  118. os.makedirs(path,0700)
  119. except:
  120. die(2,"ERROR: unable to read or create path '{}'".format(path))
  121. from mmgen.opts import opt
  122. def qmsg(s,alt=False):
  123. if opt.quiet:
  124. if alt != False: sys.stderr.write(alt + '\n')
  125. else: sys.stderr.write(s + '\n')
  126. def qmsg_r(s,alt=False):
  127. if opt.quiet:
  128. if alt != False: sys.stderr.write(alt)
  129. else: sys.stderr.write(s)
  130. def vmsg(s):
  131. if opt.verbose: sys.stderr.write(s + '\n')
  132. def vmsg_r(s):
  133. if opt.verbose: sys.stderr.write(s)
  134. def Vmsg(s):
  135. if opt.verbose: sys.stdout.write(s + '\n')
  136. def Vmsg_r(s):
  137. if opt.verbose: sys.stdout.write(s)
  138. def dmsg(s):
  139. if opt.debug: sys.stdout.write(s + '\n')
  140. def suf(arg,suf_type):
  141. t = type(arg)
  142. if t == int:
  143. n = arg
  144. elif t in (list,tuple,set,dict):
  145. n = len(arg)
  146. else:
  147. msg('%s: invalid parameter' % arg)
  148. return ''
  149. if suf_type in ('a','es'): return ('es','')[n == 1]
  150. if suf_type in ('k','s'): return ('s','')[n == 1]
  151. def get_extension(f):
  152. a,b = os.path.splitext(f)
  153. return ('',b[1:])[len(b) > 1]
  154. def remove_extension(f,e):
  155. a,b = os.path.splitext(f)
  156. return (f,a)[len(b)>1 and b[1:]==e]
  157. def make_chksum_N(s,nchars,sep=False):
  158. if nchars%4 or not (4 <= nchars <= 64): return False
  159. s = sha256(sha256(s).digest()).hexdigest().upper()
  160. sep = ('',' ')[bool(sep)]
  161. return sep.join([s[i*4:i*4+4] for i in range(nchars/4)])
  162. def make_chksum_8(s,sep=False):
  163. s = sha256(sha256(s).digest()).hexdigest()[:8].upper()
  164. return '{} {}'.format(s[:4],s[4:]) if sep else s
  165. def make_chksum_6(s): return sha256(s).hexdigest()[:6]
  166. def is_chksum_6(s): return len(s) == 6 and is_hexstring_lc(s)
  167. def make_iv_chksum(s): return sha256(s).hexdigest()[:8].upper()
  168. def splitN(s,n,sep=None): # always return an n-element list
  169. ret = s.split(sep,n-1)
  170. return ret + ['' for i in range(n-len(ret))]
  171. def split2(s,sep=None): return splitN(s,2,sep) # always return a 2-element list
  172. def split3(s,sep=None): return splitN(s,3,sep) # always return a 3-element list
  173. def split_into_cols(col_wid,s):
  174. return ' '.join([s[col_wid*i:col_wid*(i+1)]
  175. for i in range(len(s)/col_wid+1)]).rstrip()
  176. def capfirst(s): # different from str.capitalize() - doesn't downcase any uc in string
  177. return s if len(s) == 0 else s[0].upper() + s[1:]
  178. def decode_timestamp(s):
  179. # with open('/etc/timezone') as f:
  180. # tz_save = f.read().rstrip()
  181. os.environ['TZ'] = 'UTC'
  182. ts = time.strptime(s,'%Y%m%d_%H%M%S')
  183. t = time.mktime(ts)
  184. # os.environ['TZ'] = tz_save
  185. return int(t)
  186. def make_timestamp(secs=None):
  187. t = int(secs) if secs else time.time()
  188. tv = time.gmtime(t)[:6]
  189. return '{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}'.format(*tv)
  190. def make_timestr(secs=None):
  191. t = int(secs) if secs else time.time()
  192. tv = time.gmtime(t)[:6]
  193. return '{:04d}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}'.format(*tv)
  194. def secs_to_hms(secs):
  195. return '{:02d}:{:02d}:{:02d}'.format(secs/3600, (secs/60) % 60, secs % 60)
  196. def secs_to_ms(secs):
  197. return '{:02d}:{:02d}'.format(secs/60, secs % 60)
  198. def _is_whatstring(s,chars):
  199. return set(list(s)) <= set(chars)
  200. def is_int(s):
  201. try:
  202. int(s)
  203. return True
  204. except:
  205. return False
  206. def is_hexstring(s):
  207. return _is_whatstring(s.lower(),hexdigits.lower())
  208. def is_hexstring_lc(s):
  209. return _is_whatstring(s,hexdigits.lower())
  210. def is_hexstring_uc(s):
  211. return _is_whatstring(s,hexdigits.upper())
  212. def is_b58string(s):
  213. from mmgen.bitcoin import b58a
  214. return _is_whatstring(s,b58a)
  215. def is_utf8(s):
  216. try: s.decode('utf8')
  217. except: return False
  218. else: return True
  219. def is_ascii(s):
  220. try: s.decode('ascii')
  221. except: return False
  222. else: return True
  223. def match_ext(addr,ext):
  224. return addr.split('.')[-1] == ext
  225. def file_exists(f):
  226. try:
  227. os.stat(f)
  228. return True
  229. except:
  230. return False
  231. def file_is_readable(f):
  232. from stat import S_IREAD
  233. try:
  234. assert os.stat(f).st_mode & S_IREAD
  235. except:
  236. return False
  237. else:
  238. return True
  239. def get_from_brain_opt_params():
  240. l,p = opt.from_brain.split(',')
  241. return(int(l),p)
  242. def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
  243. r = (0,1)[bool(len(data) % gw)]
  244. return ''.join(
  245. [
  246. ('' if (line_nums == False or i % cols) else '{:06x}: '.format(i*gw)) +
  247. hexlify(data[i*gw:i*gw+gw]) + ('\n',' ')[bool((i+1) % cols)]
  248. for i in range(len(data)/gw + r)
  249. ]
  250. ).rstrip() + '\n'
  251. def decode_pretty_hexdump(data):
  252. from string import hexdigits
  253. pat = r'^[%s]+:\s+' % hexdigits
  254. lines = [re.sub(pat,'',l) for l in data.splitlines()]
  255. try:
  256. return unhexlify(''.join((''.join(lines).split())))
  257. except:
  258. msg('Data not in hexdump format')
  259. return False
  260. def strip_comments(line):
  261. return re.sub(ur'\s+$',u'',re.sub(ur'#.*',u'',line,1))
  262. def remove_comments(lines):
  263. return [m for m in [strip_comments(l) for l in lines] if m != '']
  264. from mmgen.globalvars import g
  265. def start_mscolor():
  266. if g.platform == 'win':
  267. global red,green,yellow,cyan,nocolor
  268. import os
  269. if 'MMGEN_NOMSCOLOR' in os.environ:
  270. red = green = yellow = cyan = grnbg = nocolor
  271. else:
  272. try:
  273. import colorama
  274. colorama.init(strip=True,convert=True)
  275. except:
  276. red = green = yellow = cyan = grnbg = nocolor
  277. def get_hash_params(hash_preset):
  278. if hash_preset in g.hash_presets:
  279. return g.hash_presets[hash_preset] # N,p,r,buflen
  280. else: # Shouldn't be here
  281. die(3,"%s: invalid 'hash_preset' value" % hash_preset)
  282. def compare_chksums(chk1, desc1, chk2, desc2, hdr='', die_on_fail=False):
  283. if not chk1 == chk2:
  284. m = "%s ERROR: %s checksum (%s) doesn't match %s checksum (%s)"\
  285. % ((hdr+':\n ' if hdr else 'CHECKSUM'),desc2,chk2,desc1,chk1)
  286. if die_on_fail:
  287. die(3,m)
  288. else:
  289. vmsg(m)
  290. return False
  291. vmsg('%s checksum OK (%s)' % (capfirst(desc1),chk1))
  292. return True
  293. def compare_or_die(val1, desc1, val2, desc2, e='Error'):
  294. if cmp(val1,val2):
  295. die(3,"%s: %s (%s) doesn't match %s (%s)"
  296. % (e,desc2,val2,desc1,val1))
  297. dmsg('%s OK (%s)' % (capfirst(desc2),val2))
  298. return True
  299. def open_file_or_exit(filename,mode):
  300. try:
  301. f = open(filename, mode)
  302. except:
  303. op = ('writing','reading')['r' in mode]
  304. die(2,"Unable to open file '%s' for %s" % (filename,op))
  305. return f
  306. def check_file_type_and_access(fname,ftype,blkdev_ok=False):
  307. a = ((os.R_OK,'read'),(os.W_OK,'writ'))
  308. access,m = a[ftype in ('output file','output directory')]
  309. ok_types = [
  310. (stat.S_ISREG,'regular file'),
  311. (stat.S_ISLNK,'symbolic link')
  312. ]
  313. if blkdev_ok: ok_types.append((stat.S_ISBLK,'block device'))
  314. if ftype == 'output directory': ok_types = [(stat.S_ISDIR, 'output directory')]
  315. try: mode = os.stat(fname).st_mode
  316. except:
  317. die(1,"Unable to stat requested %s '%s'" % (ftype,fname))
  318. for t in ok_types:
  319. if t[0](mode): break
  320. else:
  321. die(1,"Requested %s '%s' is not a %s" % (ftype,fname,
  322. ' or '.join([t[1] for t in ok_types])))
  323. if not os.access(fname, access):
  324. die(1,"Requested %s '%s' is not %sable by you" % (ftype,fname,m))
  325. return True
  326. def check_infile(f,blkdev_ok=False):
  327. return check_file_type_and_access(f,'input file',blkdev_ok=blkdev_ok)
  328. def check_outfile(f,blkdev_ok=False):
  329. return check_file_type_and_access(f,'output file',blkdev_ok=blkdev_ok)
  330. def check_outdir(f):
  331. return check_file_type_and_access(f,'output directory')
  332. def make_full_path(outdir,outfile):
  333. return os.path.normpath(os.path.join(outdir, os.path.basename(outfile)))
  334. def get_seed_file(cmd_args,nargs,invoked_as=None):
  335. from mmgen.filename import find_file_in_dir
  336. from mmgen.seed import Wallet
  337. wf = find_file_in_dir(Wallet,g.data_dir)
  338. wd_from_opt = bool(opt.hidden_incog_input_params or opt.in_fmt) # have wallet data from opt?
  339. import mmgen.opts as opts
  340. if len(cmd_args) + (wd_from_opt or bool(wf)) < nargs:
  341. opts.usage()
  342. elif len(cmd_args) > nargs:
  343. opts.usage()
  344. elif len(cmd_args) == nargs and wf and invoked_as != 'gen':
  345. msg('Warning: overriding wallet in data directory with user-supplied wallet')
  346. if cmd_args or wf:
  347. check_infile(cmd_args[0] if cmd_args else wf)
  348. return cmd_args[0] if cmd_args else (wf,None)[wd_from_opt]
  349. def get_new_passphrase(desc,passchg=False):
  350. w = '{}passphrase for {}'.format(('','new ')[bool(passchg)], desc)
  351. if opt.passwd_file:
  352. pw = ' '.join(get_words_from_file(opt.passwd_file,w))
  353. elif opt.echo_passphrase:
  354. pw = ' '.join(get_words_from_user('Enter {}: '.format(w)))
  355. else:
  356. for i in range(g.passwd_max_tries):
  357. pw = ' '.join(get_words_from_user('Enter {}: '.format(w)))
  358. pw2 = ' '.join(get_words_from_user('Repeat passphrase: '))
  359. dmsg('Passphrases: [%s] [%s]' % (pw,pw2))
  360. if pw == pw2:
  361. vmsg('Passphrases match'); break
  362. else: msg('Passphrases do not match. Try again.')
  363. else:
  364. die(2,'User failed to duplicate passphrase in %s attempts' %
  365. g.passwd_max_tries)
  366. if pw == '': qmsg('WARNING: Empty passphrase')
  367. return pw
  368. def confirm_or_exit(message,question,expect='YES',exit_msg='Exiting at user request'):
  369. m = message.strip()
  370. if m: msg(m)
  371. a = question+' ' if question[0].isupper() else \
  372. 'Are you sure you want to %s?\n' % question
  373. b = "Type uppercase '%s' to confirm: " % expect
  374. if my_raw_input(a+b).strip() != expect:
  375. die(2,exit_msg)
  376. # New function
  377. def write_data_to_file(
  378. outfile,
  379. data,
  380. desc='data',
  381. ask_write=False,
  382. ask_write_prompt='',
  383. ask_write_default_yes=True,
  384. ask_overwrite=True,
  385. ask_tty=True,
  386. no_tty=False,
  387. silent=False,
  388. binary=False
  389. ):
  390. if silent: ask_tty = ask_overwrite = False
  391. if opt.quiet: ask_overwrite = False
  392. if ask_write_default_yes == False or ask_write_prompt:
  393. ask_write = True
  394. if opt.stdout or not sys.stdout.isatty() or outfile in ('','-'):
  395. qmsg('Output to STDOUT requested')
  396. if sys.stdout.isatty():
  397. if no_tty:
  398. die(2,'Printing %s to screen is not allowed' % desc)
  399. if ask_tty and not opt.quiet:
  400. confirm_or_exit('','output %s to screen' % desc)
  401. else:
  402. try: of = os.readlink('/proc/%d/fd/1' % os.getpid()) # Linux
  403. except: of = None # Windows
  404. if of:
  405. if of[:5] == 'pipe:':
  406. if no_tty:
  407. die(2,'Writing %s to pipe is not allowed' % desc)
  408. if ask_tty and not opt.quiet:
  409. confirm_or_exit('','output %s to pipe' % desc)
  410. msg('')
  411. of2,pd = os.path.relpath(of),os.path.pardir
  412. msg("Redirecting output to file '%s'" % (of2,of)[of2[:len(pd)] == pd])
  413. else:
  414. msg('Redirecting output to file')
  415. if binary and g.platform == 'win':
  416. import msvcrt
  417. msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)
  418. sys.stdout.write(data)
  419. else:
  420. if opt.outdir and not os.path.isabs(outfile):
  421. outfile = make_full_path(opt.outdir,outfile)
  422. if ask_write:
  423. if not ask_write_prompt: ask_write_prompt = 'Save %s?' % desc
  424. if not keypress_confirm(ask_write_prompt,
  425. default_yes=ask_write_default_yes):
  426. die(1,'%s not saved' % capfirst(desc))
  427. hush = False
  428. if file_exists(outfile) and ask_overwrite:
  429. q = "File '%s' already exists\nOverwrite?" % outfile
  430. confirm_or_exit('',q)
  431. msg("Overwriting file '%s'" % outfile)
  432. hush = True
  433. f = open_file_or_exit(outfile,('w','wb')[bool(binary)])
  434. try:
  435. f.write(data)
  436. except:
  437. die(2,"Failed to write %s to file '%s'" % (desc,outfile))
  438. f.close
  439. if not (hush or silent):
  440. msg("%s written to file '%s'" % (capfirst(desc),outfile))
  441. return True
  442. def get_words_from_user(prompt):
  443. # split() also strips
  444. words = my_raw_input(prompt, echo=opt.echo_passphrase).split()
  445. dmsg('Sanitized input: [%s]' % ' '.join(words))
  446. return words
  447. def get_words_from_file(infile,desc,silent=False):
  448. if not silent:
  449. qmsg("Getting %s from file '%s'" % (desc,infile))
  450. f = open_file_or_exit(infile, 'r')
  451. # split() also strips
  452. words = f.read().split()
  453. f.close()
  454. dmsg('Sanitized input: [%s]' % ' '.join(words))
  455. return words
  456. def get_words(infile,desc,prompt):
  457. if infile:
  458. return get_words_from_file(infile,desc)
  459. else:
  460. return get_words_from_user(prompt)
  461. def mmgen_decrypt_file_maybe(fn,desc=''):
  462. d = get_data_from_file(fn,desc,binary=True)
  463. have_enc_ext = get_extension(fn) == g.mmenc_ext
  464. if have_enc_ext or not is_ascii(d):
  465. m = ('Attempting to decrypt','Decrypting')[have_enc_ext]
  466. msg("%s %s '%s'" % (m,desc,fn))
  467. from mmgen.crypto import mmgen_decrypt_retry
  468. d = mmgen_decrypt_retry(d,desc)
  469. return d
  470. def get_lines_from_file(fn,desc='',trim_comments=False):
  471. dec = mmgen_decrypt_file_maybe(fn,desc)
  472. ret = dec.decode('utf8').splitlines() # DOS-safe
  473. return remove_comments(ret) if trim_comments else ret
  474. def get_data_from_user(desc='data',silent=False):
  475. data = my_raw_input('Enter %s: ' % desc, echo=opt.echo_passphrase)
  476. dmsg('User input: [%s]' % data)
  477. return data
  478. def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False):
  479. if dash and infile == '-': return sys.stdin.read()
  480. if not silent and desc:
  481. qmsg("Getting %s from file '%s'" % (desc,infile))
  482. f = open_file_or_exit(infile,('r','rb')[bool(binary)])
  483. data = f.read()
  484. f.close()
  485. return data
  486. def pwfile_reuse_warning():
  487. if 'passwd_file_used' in globals():
  488. qmsg("Reusing passphrase from file '%s' at user request" % opt.passwd_file)
  489. return True
  490. globals()['passwd_file_used'] = True
  491. return False
  492. def get_mmgen_passphrase(desc,passchg=False):
  493. prompt ='Enter {}passphrase for {}: '.format(('','old ')[bool(passchg)],desc)
  494. if opt.passwd_file:
  495. pwfile_reuse_warning()
  496. return ' '.join(get_words_from_file(opt.passwd_file,'passphrase'))
  497. else:
  498. return ' '.join(get_words_from_user(prompt))
  499. def my_raw_input(prompt,echo=True,insert_txt='',use_readline=True):
  500. try: import readline
  501. except: use_readline = False # Windows
  502. if use_readline and sys.stdout.isatty():
  503. def st_hook(): readline.insert_text(insert_txt)
  504. readline.set_startup_hook(st_hook)
  505. else:
  506. msg_r(prompt)
  507. prompt = ''
  508. from mmgen.term import kb_hold_protect
  509. kb_hold_protect()
  510. if echo:
  511. reply = raw_input(prompt)
  512. else:
  513. from getpass import getpass
  514. reply = getpass(prompt)
  515. kb_hold_protect()
  516. return reply.strip()
  517. def keypress_confirm(prompt,default_yes=False,verbose=False):
  518. from mmgen.term import get_char
  519. q = ('(y/N)','(Y/n)')[bool(default_yes)]
  520. while True:
  521. reply = get_char('%s %s: ' % (prompt, q)).strip('\n\r')
  522. if not reply:
  523. if default_yes: msg(''); return True
  524. else: msg(''); return False
  525. elif reply in 'yY': msg(''); return True
  526. elif reply in 'nN': msg(''); return False
  527. else:
  528. if verbose: msg('\nInvalid reply')
  529. else: msg_r('\r')
  530. def prompt_and_get_char(prompt,chars,enter_ok=False,verbose=False):
  531. from mmgen.term import get_char
  532. while True:
  533. reply = get_char('%s: ' % prompt).strip('\n\r')
  534. if reply in chars or (enter_ok and not reply):
  535. msg('')
  536. return reply
  537. if verbose: msg('\nInvalid reply')
  538. else: msg_r('\r')
  539. def do_pager(text):
  540. pagers,shell = ['less','more'],False
  541. # --- Non-MSYS Windows code deleted ---
  542. # raw, chop, scroll right 1 char, disable buggy line chopping for Windows
  543. os.environ['LESS'] = (('-RS -#1'),('-cR -#1'))[g.platform=='win']
  544. if 'PAGER' in os.environ and os.environ['PAGER'] != pagers[0]:
  545. pagers = [os.environ['PAGER']] + pagers
  546. for pager in pagers:
  547. end = ('\n(end of text)\n','')[pager=='less']
  548. try:
  549. from subprocess import Popen,PIPE,STDOUT
  550. p = Popen([pager], stdin=PIPE, shell=shell)
  551. except: pass
  552. else:
  553. p.communicate(text+end+'\n')
  554. msg_r('\r')
  555. break
  556. else: Msg(text+end)
  557. def do_license_msg(immed=False):
  558. if opt.quiet or g.no_license: return
  559. import mmgen.license as gpl
  560. p = "Press 'w' for conditions and warranty info, or 'c' to continue:"
  561. msg(gpl.warning)
  562. prompt = '%s ' % p.strip()
  563. from mmgen.term import get_char
  564. while True:
  565. reply = get_char(prompt, immed_chars=('','wc')[bool(immed)])
  566. if reply == 'w':
  567. do_pager(gpl.conditions)
  568. elif reply == 'c':
  569. msg(''); break
  570. else:
  571. msg_r('\r')
  572. msg('')
  573. def get_bitcoind_cfg_options(cfg_keys):
  574. cfg_file = os.path.join(g.bitcoin_data_dir,'bitcoin.conf')
  575. cfg = dict([(k,v) for k,v in [split2(str(line).translate(None,'\t '),'=')
  576. for line in get_lines_from_file(cfg_file,'')] if k in cfg_keys]) \
  577. if file_is_readable(cfg_file) else {}
  578. for k in set(cfg_keys) - set(cfg.keys()): cfg[k] = ''
  579. return cfg
  580. def get_bitcoind_auth_cookie():
  581. f = os.path.join(g.bitcoin_data_dir,('',g.testnet_name)[g.testnet],'.cookie')
  582. if file_is_readable(f):
  583. return get_lines_from_file(f,'')[0]
  584. else:
  585. return ''
  586. def bitcoin_connection():
  587. cfg = get_bitcoind_cfg_options(('rpcuser','rpcpassword'))
  588. import mmgen.rpc
  589. c = mmgen.rpc.BitcoinRPCConnection(
  590. g.rpc_host or 'localhost',
  591. g.rpc_port or (8332,18332)[g.testnet],
  592. g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override bitcoind's
  593. g.rpc_password or cfg['rpcpassword'],
  594. auth_cookie=get_bitcoind_auth_cookie())
  595. # do an RPC call to make the function fail if we can't connect
  596. c.client_version = int(c.getinfo()['version'])
  597. return c