autosign: print summary of non-MMGen output addresses and amounts

To allow the user to verify that transaction outputs have not been altered
by a compromised online MMGen installation, print a list of non-MMGen output
addresses and amounts for all signed transactions after every autosign run.

With --full-summary, print a full view of each signed transaction instead.
This commit is contained in:
The MMGen Project 2019-04-24 14:39:21 +00:00
commit d558822941
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
3 changed files with 61 additions and 4 deletions

View file

@ -44,6 +44,9 @@ opts_data = {
-m, --mountpoint=m Specify an alternate mountpoint (default: '{mp}')
-s, --stealth-led Stealth LED mode - signal busy and error only, and only
after successful authorization.
-S, --full-summary Print a full summary of each signed transaction after
each autosign run. The default list of non-MMGen outputs
will not be printed.
-q, --quiet Produce quieter output
-v, --verbose Produce more verbose output
""".format(mp=mountpoint),
@ -191,6 +194,7 @@ def sign_tx_file(txfile):
if txsign(tx,wfs,None,None):
tx.write_to_file(ask_write=False)
txlist.append(tx)
return True
else:
return False
@ -241,13 +245,48 @@ def decrypt_wallets():
return False if fails else True
def print_summary():
if opt.full_summary:
bmsg('\nAutosign summary:')
for tx in txlist:
init_coin(tx.coin,tx.chain == 'testnet')
msg_r(tx.format_view(terse=True))
return
body = []
for tx in txlist:
non_mmgen = [o for o in tx.outputs if not o.mmid]
if non_mmgen:
body.append((tx,non_mmgen))
if body:
bmsg('\nAutosign summary:')
fs = '{} {} {}'
t_wid,a_wid = 6,44
msg(fs.format('TX ID ','Non-MMGen outputs'+' '*(a_wid-17),'Amount'))
msg(fs.format('-'*t_wid, '-'*a_wid, '-'*7))
for tx,non_mmgen in body:
for nm in non_mmgen:
msg(fs.format(
tx.txid.fmt(width=t_wid,color=True) if nm is non_mmgen[0] else ' '*t_wid,
nm.addr.fmt(width=a_wid,color=True),
nm._amt.hl() + ' ' + yellow(tx.coin)))
else:
msg('No non-MMGen outputs')
def do_sign():
if not opt.stealth_led: set_led('busy')
do_mount()
key_ok = decrypt_wallets()
if key_ok:
if opt.stealth_led: set_led('busy')
global txlist
txlist = []
ret = sign()
print_summary()
txlist = []
do_umount()
set_led(('standby','off','error')[(not ret)*2 or bool(opt.stealth_led)])
return ret

View file

@ -0,0 +1,5 @@
3df942
TESTNET 25EFA3 2.34 20190424_101833 433
0200000001db9d489e2b43e30b96931364d1a4ba97bd2f5515790c82703e7b7f11e549f51a0100000000ffffffff03c0b99d06000000001976a91496235113a5c6608bdb9bc5f5e08c69458a6b17dd88acc0d45407000000001976a9148970c0a71207de041f707febfcbdac46cbd7aaf588ac702e19460200000017a914daaf772bc9d05b41f6811fa200a34fcd4d58ed2c8700000000
[{'txid': '1af549e5117f7b3e70820c7915552fbd97baa4d1641393960be3432b9e489ddb', 'vout': 1, 'label': '', 'scriptPubKey': 'a914f199a1b4f46bd0f659287517435f4d84fda854c887', 'amt': '100', 'addr': '2NFGgt2iky94KDocUV6nE2GsGg6uvetUWzH', 'confs': 1, 'mmid': '98831F3A:S:31'}]
[{'addr': 'muCoxgBTXA1CFb9phJqMZgqP2rm1mPrbKE', 'amt': '1.11', 'is_chg': False}, {'addr': 'mt3fwX52huqVB1aU6Y2cLts3WVG4bBeqS1', 'amt': '1.23', 'is_chg': False}, {'addr': '2NDBXVfG7uUDwrZPyEZPc8vRMyZN4dfPoY7', 'amt': '97.6599', 'is_chg': True, 'mmid': '98831F3A:S:1'}]

View file

@ -44,14 +44,14 @@ class TestSuiteAutosign(TestSuiteBase):
return self.autosign(
coins=['btc','eth'],
txfiles=['btc','eth','mm1','etc'],
txcount=7,
txcount=8,
live=live)
# tests everything except device detection, mount/unmount
def autosign( self,
coins=['btc','bch','ltc','eth'],
txfiles=['btc','bch','ltc','eth','mm1','etc'],
txcount=11,
txcount=12,
live=False):
if self.skip_for_win(): return
@ -103,8 +103,9 @@ class TestSuiteAutosign(TestSuiteBase):
fdata = [e for e in fdata_in if e[0] in txfiles]
from test.test_py_d.ts_ref import TestSuiteRef
tfns = [TestSuiteRef.sources['ref_tx_file'][c][1] for c,d in fdata] + \
[TestSuiteRef.sources['ref_tx_file'][c][0] for c,d in fdata]
tfs = [joinpath(ref_dir,d[1],fn) for d,fn in zip(fdata+fdata,tfns)]
[TestSuiteRef.sources['ref_tx_file'][c][0] for c,d in fdata] + \
['25EFA3[2.34].testnet.rawtx'] # TX with 2 non-MMGen outputs
tfs = [joinpath(ref_dir,d[1],fn) for d,fn in zip(fdata+fdata+[('btc','')],tfns)]
for f,fn in zip(tfs,tfns):
if fn: # use empty fn to skip file
@ -172,13 +173,25 @@ class TestSuiteAutosign(TestSuiteBase):
def do_autosign(opts,mountpoint):
make_wallet(opts)
copy_files(mountpoint,include_bad_tx=True)
t = self.spawn('mmgen-autosign',opts+['--full-summary','wait'],extra_desc='(sign - full summary)')
t.expect('{} transactions signed'.format(txcount))
t.expect('1 transaction failed to sign')
t.expect('Waiting')
t.kill(2)
t.req_exit_val = 1
imsg('')
t.ok()
copy_files(mountpoint,remove_signed_only=True)
t = self.spawn('mmgen-autosign',opts+['wait'],extra_desc='(sign)')
t.expect('{} transactions signed'.format(txcount))
t.expect('1 transaction failed to sign')
t.expect('Waiting')
t.kill(2)
t.req_exit_val = 1
imsg('')
return t
if live: