terminal-related fixes and cleanups

This commit is contained in:
The MMGen Project 2020-03-15 19:45:32 +00:00
commit 656bb69587
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
6 changed files with 64 additions and 45 deletions

View file

@ -152,8 +152,8 @@ def make_key(passwd,salt,hash_preset,desc='encryption key',from_what='passphrase
dmsg('Key: {}'.format(key.hex()))
return key
def _get_random_data_from_user(uchars,desc):
m = 'Enter {r} random symbols' if opt.quiet else crmsg['usr_rand_notice']
def _get_random_data_from_user(uchars,desc,test_suite=False):
m = 'Enter {r} random symbols' if opt.quiet or test_suite else crmsg['usr_rand_notice']
msg(m.format(r=uchars,d=desc))
prompt = 'You may begin typing. {} symbols left: '
@ -165,15 +165,24 @@ def _get_random_data_from_user(uchars,desc):
key_data += get_char_raw('\r'+prompt.format(uchars-i))
time_data.append(time.time())
if opt.quiet: msg_r('\r')
else: msg_r("\rThank you. That's enough.{}\n\n".format(' '*18))
msg_r('\r' if opt.quiet else "\rThank you. That's enough.{}\n\n".format(' '*18))
fmt_time_data = list(map('{:.22f}'.format,time_data))
dmsg('\nUser input:\n{!r}\nKeystroke time values:\n{}\n'.format(key_data,'\n'.join(fmt_time_data)))
prompt = 'User random data successfully acquired. Press ENTER to continue'
prompt_and_get_char(prompt,'',enter_ok=True)
time_data = ['{:.22f}'.format(t).rstrip('0') for t in time_data]
return key_data.encode() + ''.join(fmt_time_data).encode()
avg_prec = sum(len(t.split('.')[1]) for t in time_data) // len(time_data)
if avg_prec < g.min_time_precision:
m = 'WARNING: Avg. time precision of only {} decimal points. User entropy quality is degraded!'
ymsg(m.format(avg_prec))
ret = key_data + '\n' + '\n'.join(time_data)
if g.debug:
msg('USER ENTROPY (user input + keystroke timings):\n{}'.format(ret))
if not test_suite:
my_raw_input('User random data successfully acquired. Press ENTER to continue: ')
return ret.encode()
def get_random(length):
return add_user_random(os.urandom(length),'OS random data')

View file

@ -58,6 +58,7 @@ class g(object):
http_timeout = 60
err_disp_timeout = 0.7
short_disp_timeout = 0.3
min_time_precision = 18
# Variables - these might be altered at runtime:

View file

@ -344,8 +344,10 @@ watch-only wallet using '{}-addrimport' and then re-run this program.
no_output,oneshot_msg = False,None
while True:
msg_r('' if no_output else '\n\n' if opt.no_blank else CUR_HOME+ERASE_ALL)
reply = get_char('' if no_output else self.format_for_display()+'\n'+(oneshot_msg or '')+prompt,
immed_chars=''.join(self.key_mappings.keys()))
reply = get_char(
'' if no_output else self.format_for_display()+'\n'+(oneshot_msg or '')+prompt,
immed_chars=''.join(self.key_mappings.keys())
)
no_output = False
oneshot_msg = '' if oneshot_msg else None # tristate, saves previous state
if reply not in self.key_mappings:

View file

@ -1030,11 +1030,20 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
ask_tty=ask_tty,
ask_write_default_yes=ask_write_default_yes)
def view_with_prompt(self,prompt=''):
prompt += ' (y)es, (N)o, pager (v)iew, (t)erse view'
reply = prompt_and_get_char(prompt,'YyNnVvTt',enter_ok=True)
if reply and reply in 'YyVvTt':
self.view(pager=reply in 'Vv',terse=reply in 'Tt')
def view_with_prompt(self,prompt='',pause=True):
prompt += ' (y)es, (N)o, pager (v)iew, (t)erse view: '
from mmgen.term import get_char
ok_chars = 'YyNnVvTt'
while True:
reply = get_char(prompt,immed_chars=ok_chars).strip('\n\r')
msg('')
if reply == '' or reply in 'Nn':
break
elif reply in 'YyVvTt':
self.view(pager=reply in 'Vv',terse=reply in 'Tt',pause=pause)
break
else:
msg('Invalid reply')
def view(self,pager=False,pause=True,terse=False):
o = self.format_view(terse=terse)

View file

@ -760,7 +760,7 @@ def keypress_confirm(prompt,default_yes=False,verbose=False,no_nl=False,complete
from mmgen.term import get_char
while True:
reply = get_char(p).strip('\n\r')
reply = get_char(p,immed_chars='yYnN').strip('\n\r')
if not reply:
msg_r(nl)
return True if default_yes else False
@ -770,16 +770,6 @@ def keypress_confirm(prompt,default_yes=False,verbose=False,no_nl=False,complete
else:
msg_r('\nInvalid reply\n' if verbose else '\r')
def prompt_and_get_char(prompt,chars,enter_ok=False,verbose=False):
from mmgen.term import get_char
while True:
reply = get_char('{}: '.format(prompt)).strip('\n\r')
if reply in chars or (enter_ok and not reply):
msg('')
return reply
msg_r('\nInvalid reply\n' if verbose else '\r')
def do_pager(text):
pagers = ['less','more']

View file

@ -67,22 +67,6 @@ def tt_my_raw_input():
reply = my_raw_input('\nEnter text: ')
confirm('Did you enter the text {!r}?'.format(reply))
def tt_prompt_and_get_char():
cmsg('Testing prompt_and_get_char():')
m = 'Type some letters besides "x" or "z", then "x" or "z"'
reply = prompt_and_get_char(m,'xz')
confirm('Did you enter the letter {!r}?'.format(reply))
def tt_prompt_and_get_char_enter_ok():
cmsg('Testing prompt_and_get_char() with blank choices and enter_ok=True:')
for m in (
'Type ENTER',
'Type any letter followed by a pause, followed by ENTER',
):
reply = prompt_and_get_char(m,'',enter_ok=True)
assert reply == ''
msg('OK')
def tt_get_char(raw=False,one_char=False,sleep=0,immed_chars=''):
fname = ('get_char','get_char_raw')[raw]
fs = fmt("""
@ -130,6 +114,30 @@ def tt_get_char(raw=False,one_char=False,sleep=0,immed_chars=''):
except KeyboardInterrupt:
msg('\nDone')
def tt_urand():
cmsg('Testing _get_random_data_from_user():')
from mmgen.crypto import _get_random_data_from_user
ret = _get_random_data_from_user(10,desc='data',test_suite=True).decode()
msg('USER ENTROPY (user input + keystroke timings):\n\n{}'.format(fmt(ret,' ')))
times = ret.splitlines()[1:]
avg_prec = sum(len(t.split('.')[1]) for t in times) // len(times)
if avg_prec < g.min_time_precision:
m = 'WARNING: Avg. time precision of only {} decimal points. User entropy quality is degraded!'
ymsg(m.format(avg_prec))
else:
msg('Average time precision: {} decimal points - OK'.format(avg_prec))
my_raw_input('Press ENTER to continue: ')
def tt_txview():
cmsg('Testing tx.view_with_prompt() (try each viewing option)')
from mmgen.tx import MMGenTX
fn = 'test/ref/0B8D5A[15.31789,14,tl=1320969600].rawtx'
tx = MMGenTX(fn,offline=True)
while True:
tx.view_with_prompt('View data for transaction?',pause=False)
if not keypress_confirm('Continue testing transaction view?',default_yes=True):
break
if g.platform == 'linux':
import termios,atexit
fd = sys.stdin.fileno()
@ -142,8 +150,8 @@ tt_get_terminal_size()
tt_color()
tt_license()
tt_my_raw_input()
tt_prompt_and_get_char()
tt_prompt_and_get_char_enter_ok()
tt_urand()
tt_txview()
tt_get_char(one_char=True)
tt_get_char(one_char=True,sleep=1)