|
@@ -9,7 +9,7 @@
|
|
|
# https://gitlab.com/mmgen/mmgen-wallet
|
|
# https://gitlab.com/mmgen/mmgen-wallet
|
|
|
|
|
|
|
|
"""
|
|
"""
|
|
|
-autosign: Auto-sign MMGen transactions, message files and XMR wallet output files
|
|
|
|
|
|
|
+autosign: Autosign MMGen transactions, message files and XMR wallet output files
|
|
|
"""
|
|
"""
|
|
|
|
|
|
|
|
import sys, os, asyncio
|
|
import sys, os, asyncio
|
|
@@ -142,6 +142,7 @@ class Signable:
|
|
|
clean_all = False
|
|
clean_all = False
|
|
|
multiple_ok = True
|
|
multiple_ok = True
|
|
|
action_desc = 'signed'
|
|
action_desc = 'signed'
|
|
|
|
|
+ fail_msg = 'failed to sign'
|
|
|
|
|
|
|
|
def __init__(self, parent):
|
|
def __init__(self, parent):
|
|
|
self.parent = parent
|
|
self.parent = parent
|
|
@@ -149,30 +150,10 @@ class Signable:
|
|
|
self.dir = getattr(parent, self.dir_name)
|
|
self.dir = getattr(parent, self.dir_name)
|
|
|
self.name = type(self).__name__
|
|
self.name = type(self).__name__
|
|
|
|
|
|
|
|
- @property
|
|
|
|
|
- def submitted(self):
|
|
|
|
|
- return self._processed('_submitted', self.subext)
|
|
|
|
|
-
|
|
|
|
|
- def _processed(self, attrname, ext):
|
|
|
|
|
- if not hasattr(self, attrname):
|
|
|
|
|
- setattr(self, attrname, tuple(f for f in sorted(self.dir.iterdir()) if f.name.endswith('.'+ext)))
|
|
|
|
|
- return getattr(self, attrname)
|
|
|
|
|
-
|
|
|
|
|
@property
|
|
@property
|
|
|
def unsigned(self):
|
|
def unsigned(self):
|
|
|
return self._unprocessed('_unsigned', self.rawext, self.sigext)
|
|
return self._unprocessed('_unsigned', self.rawext, self.sigext)
|
|
|
|
|
|
|
|
- @property
|
|
|
|
|
- def unsubmitted(self):
|
|
|
|
|
- return self._unprocessed('_unsubmitted', self.sigext, self.subext)
|
|
|
|
|
-
|
|
|
|
|
- @property
|
|
|
|
|
- def unsubmitted_raw(self):
|
|
|
|
|
- return self._unprocessed('_unsubmitted_raw', self.rawext, self.subext)
|
|
|
|
|
-
|
|
|
|
|
- unsent = unsubmitted
|
|
|
|
|
- unsent_raw = unsubmitted_raw
|
|
|
|
|
-
|
|
|
|
|
def _unprocessed(self, attrname, rawext, sigext):
|
|
def _unprocessed(self, attrname, rawext, sigext):
|
|
|
if not hasattr(self, attrname):
|
|
if not hasattr(self, attrname):
|
|
|
dirlist = sorted(self.dir.iterdir())
|
|
dirlist = sorted(self.dir.iterdir())
|
|
@@ -191,81 +172,23 @@ class Signable:
|
|
|
b = ' {}\n'.format('\n '.join(
|
|
b = ' {}\n'.format('\n '.join(
|
|
|
self.gen_bad_list(sorted(bad_files, key=lambda f: f.name))))))
|
|
self.gen_bad_list(sorted(bad_files, key=lambda f: f.name))))))
|
|
|
|
|
|
|
|
- def die_wrong_num_txs(self, tx_type, *, msg=None, desc=None, show_dir=False):
|
|
|
|
|
- num_txs = len(getattr(self, tx_type))
|
|
|
|
|
- die('AutosignTXError', "{m}{a} {b} transaction{c} {d} {e}!".format(
|
|
|
|
|
- m = msg + '\n' if msg else '',
|
|
|
|
|
- a = 'One' if num_txs == 1 else 'More than one' if num_txs else 'No',
|
|
|
|
|
- b = desc or tx_type,
|
|
|
|
|
- c = suf(num_txs),
|
|
|
|
|
- d = 'already present' if num_txs else 'present',
|
|
|
|
|
- e = f'in ‘{getattr(self.parent, self.dir_name)}’' if show_dir else 'on removable device'))
|
|
|
|
|
-
|
|
|
|
|
- def check_create_ok(self):
|
|
|
|
|
- if len(self.unsigned):
|
|
|
|
|
- self.die_wrong_num_txs('unsigned', msg='Cannot create transaction')
|
|
|
|
|
- if len(self.unsent):
|
|
|
|
|
- die('AutosignTXError', 'Cannot create transaction: you have an unsent transaction')
|
|
|
|
|
-
|
|
|
|
|
- def get_unsubmitted(self, tx_type='unsubmitted'):
|
|
|
|
|
- if len(self.unsubmitted) == 1:
|
|
|
|
|
- return self.unsubmitted[0]
|
|
|
|
|
- else:
|
|
|
|
|
- self.die_wrong_num_txs(tx_type)
|
|
|
|
|
-
|
|
|
|
|
- def get_unsent(self):
|
|
|
|
|
- return self.get_unsubmitted('unsent')
|
|
|
|
|
-
|
|
|
|
|
- def get_submitted(self):
|
|
|
|
|
- if len(self.submitted) == 0:
|
|
|
|
|
- self.die_wrong_num_txs('submitted')
|
|
|
|
|
- else:
|
|
|
|
|
- return self.submitted
|
|
|
|
|
-
|
|
|
|
|
- def get_abortable(self):
|
|
|
|
|
- if len(self.unsent_raw) != 1:
|
|
|
|
|
- self.die_wrong_num_txs('unsent_raw', desc='unsent')
|
|
|
|
|
- if len(self.unsent) > 1:
|
|
|
|
|
- self.die_wrong_num_txs('unsent')
|
|
|
|
|
- if self.unsent:
|
|
|
|
|
- if self.unsent[0].stem != self.unsent_raw[0].stem:
|
|
|
|
|
- die(1, f'{self.unsent[0]}, {self.unsent_raw[0]}: file mismatch')
|
|
|
|
|
- return self.unsent_raw + self.unsent
|
|
|
|
|
-
|
|
|
|
|
- def shred_abortable(self):
|
|
|
|
|
- files = self.get_abortable() # raises AutosignTXError if no unsent TXs available
|
|
|
|
|
- keypress_confirm(
|
|
|
|
|
- self.cfg,
|
|
|
|
|
- 'The following file{} will be securely deleted:\n{}\nOK?'.format(
|
|
|
|
|
- suf(files),
|
|
|
|
|
- fmt_list(map(str, files), fmt='col', indent=' ')),
|
|
|
|
|
- do_exit = True)
|
|
|
|
|
- for fn in files:
|
|
|
|
|
- msg(f'Shredding file ‘{fn}’')
|
|
|
|
|
- shred_file(self.cfg, fn, iterations=15)
|
|
|
|
|
- sys.exit(0)
|
|
|
|
|
-
|
|
|
|
|
- async def get_last_created(self):
|
|
|
|
|
- from .tx import CompletedTX
|
|
|
|
|
- ext = '.' + Signable.automount_transaction.subext
|
|
|
|
|
- files = [f for f in self.dir.iterdir() if f.name.endswith(ext)]
|
|
|
|
|
- return sorted(
|
|
|
|
|
- [await CompletedTX(cfg=self.cfg, filename=str(txfile), quiet_open=True) for txfile in files],
|
|
|
|
|
- key = lambda x: x.timestamp)[-1]
|
|
|
|
|
|
|
+ def gen_bad_list(self, bad_files):
|
|
|
|
|
+ for f in bad_files:
|
|
|
|
|
+ yield red(f.name)
|
|
|
|
|
|
|
|
class transaction(base):
|
|
class transaction(base):
|
|
|
desc = 'non-automount transaction'
|
|
desc = 'non-automount transaction'
|
|
|
rawext = 'rawtx'
|
|
rawext = 'rawtx'
|
|
|
sigext = 'sigtx'
|
|
sigext = 'sigtx'
|
|
|
dir_name = 'tx_dir'
|
|
dir_name = 'tx_dir'
|
|
|
- fail_msg = 'failed to sign'
|
|
|
|
|
|
|
+ automount = False
|
|
|
|
|
|
|
|
async def sign(self, f):
|
|
async def sign(self, f):
|
|
|
from .tx import UnsignedTX
|
|
from .tx import UnsignedTX
|
|
|
tx1 = UnsignedTX(
|
|
tx1 = UnsignedTX(
|
|
|
cfg = self.cfg,
|
|
cfg = self.cfg,
|
|
|
filename = f,
|
|
filename = f,
|
|
|
- automount = self.name=='automount_transaction')
|
|
|
|
|
|
|
+ automount = self.automount)
|
|
|
if tx1.proto.sign_mode == 'daemon':
|
|
if tx1.proto.sign_mode == 'daemon':
|
|
|
from .rpc import rpc_init
|
|
from .rpc import rpc_init
|
|
|
tx1.rpc = await rpc_init(self.cfg, tx1.proto, ignore_wallet=True)
|
|
tx1.rpc = await rpc_init(self.cfg, tx1.proto, ignore_wallet=True)
|
|
@@ -318,19 +241,101 @@ class Signable:
|
|
|
else:
|
|
else:
|
|
|
msg('\nNo non-MMGen outputs')
|
|
msg('\nNo non-MMGen outputs')
|
|
|
|
|
|
|
|
- def gen_bad_list(self, bad_files):
|
|
|
|
|
- for f in bad_files:
|
|
|
|
|
- yield red(f.name)
|
|
|
|
|
-
|
|
|
|
|
class automount_transaction(transaction):
|
|
class automount_transaction(transaction):
|
|
|
- desc = 'automount transaction'
|
|
|
|
|
|
|
+ desc = 'automount transaction'
|
|
|
dir_name = 'txauto_dir'
|
|
dir_name = 'txauto_dir'
|
|
|
rawext = 'arawtx'
|
|
rawext = 'arawtx'
|
|
|
sigext = 'asigtx'
|
|
sigext = 'asigtx'
|
|
|
subext = 'asubtx'
|
|
subext = 'asubtx'
|
|
|
multiple_ok = False
|
|
multiple_ok = False
|
|
|
|
|
+ automount = True
|
|
|
|
|
|
|
|
- class xmr_signable(transaction): # mixin class
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def unsubmitted(self):
|
|
|
|
|
+ return self._unprocessed('_unsubmitted', self.sigext, self.subext)
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def unsubmitted_raw(self):
|
|
|
|
|
+ return self._unprocessed('_unsubmitted_raw', self.rawext, self.subext)
|
|
|
|
|
+
|
|
|
|
|
+ unsent = unsubmitted
|
|
|
|
|
+ unsent_raw = unsubmitted_raw
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def submitted(self):
|
|
|
|
|
+ return self._processed('_submitted', self.subext)
|
|
|
|
|
+
|
|
|
|
|
+ def _processed(self, attrname, ext):
|
|
|
|
|
+ if not hasattr(self, attrname):
|
|
|
|
|
+ setattr(self, attrname, tuple(f for f in sorted(self.dir.iterdir())
|
|
|
|
|
+ if f.name.endswith('.' + ext)))
|
|
|
|
|
+ return getattr(self, attrname)
|
|
|
|
|
+
|
|
|
|
|
+ def die_wrong_num_txs(self, tx_type, *, msg=None, desc=None, show_dir=False):
|
|
|
|
|
+ num_txs = len(getattr(self, tx_type))
|
|
|
|
|
+ die('AutosignTXError', '{m}{a} {b} transaction{c} {d} {e}!'.format(
|
|
|
|
|
+ m = msg + '\n' if msg else '',
|
|
|
|
|
+ a = 'One' if num_txs == 1 else 'More than one' if num_txs else 'No',
|
|
|
|
|
+ b = desc or tx_type,
|
|
|
|
|
+ c = suf(num_txs),
|
|
|
|
|
+ d = 'already present' if num_txs else 'present',
|
|
|
|
|
+ e = f'in ‘{getattr(self.parent, self.dir_name)}’'
|
|
|
|
|
+ if show_dir else 'on removable device'))
|
|
|
|
|
+
|
|
|
|
|
+ def check_create_ok(self):
|
|
|
|
|
+ if len(self.unsigned):
|
|
|
|
|
+ self.die_wrong_num_txs('unsigned', msg='Cannot create transaction')
|
|
|
|
|
+ if len(self.unsent):
|
|
|
|
|
+ die('AutosignTXError', 'Cannot create transaction: you have an unsent transaction')
|
|
|
|
|
+
|
|
|
|
|
+ def get_unsubmitted(self, tx_type='unsubmitted'):
|
|
|
|
|
+ if len(self.unsubmitted) == 1:
|
|
|
|
|
+ return self.unsubmitted[0]
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.die_wrong_num_txs(tx_type)
|
|
|
|
|
+
|
|
|
|
|
+ def get_unsent(self):
|
|
|
|
|
+ return self.get_unsubmitted('unsent')
|
|
|
|
|
+
|
|
|
|
|
+ def get_submitted(self):
|
|
|
|
|
+ if len(self.submitted) == 0:
|
|
|
|
|
+ self.die_wrong_num_txs('submitted')
|
|
|
|
|
+ else:
|
|
|
|
|
+ return self.submitted
|
|
|
|
|
+
|
|
|
|
|
+ def get_abortable(self):
|
|
|
|
|
+ if len(self.unsent_raw) != 1:
|
|
|
|
|
+ self.die_wrong_num_txs('unsent_raw', desc='unsent')
|
|
|
|
|
+ if len(self.unsent) > 1:
|
|
|
|
|
+ self.die_wrong_num_txs('unsent')
|
|
|
|
|
+ if self.unsent:
|
|
|
|
|
+ if self.unsent[0].stem != self.unsent_raw[0].stem:
|
|
|
|
|
+ die(1, f'{self.unsent[0]}, {self.unsent_raw[0]}: file mismatch')
|
|
|
|
|
+ return self.unsent_raw + self.unsent
|
|
|
|
|
+
|
|
|
|
|
+ def shred_abortable(self):
|
|
|
|
|
+ files = self.get_abortable() # raises AutosignTXError if no unsent TXs available
|
|
|
|
|
+ keypress_confirm(
|
|
|
|
|
+ self.cfg,
|
|
|
|
|
+ 'The following file{} will be securely deleted:\n{}\nOK?'.format(
|
|
|
|
|
+ suf(files),
|
|
|
|
|
+ fmt_list(map(str, files), fmt='col', indent=' ')),
|
|
|
|
|
+ do_exit = True)
|
|
|
|
|
+ for fn in files:
|
|
|
|
|
+ msg(f'Shredding file ‘{fn}’')
|
|
|
|
|
+ shred_file(self.cfg, fn, iterations=15)
|
|
|
|
|
+ sys.exit(0)
|
|
|
|
|
+
|
|
|
|
|
+ async def get_last_created(self):
|
|
|
|
|
+ from .tx import CompletedTX
|
|
|
|
|
+ files = [f for f in self.dir.iterdir() if f.name.endswith(self.subext)]
|
|
|
|
|
+ return sorted(
|
|
|
|
|
+ [await CompletedTX(cfg=self.cfg, filename=str(txfile), quiet_open=True)
|
|
|
|
|
+ for txfile in files],
|
|
|
|
|
+ key = lambda x: x.timestamp)[-1]
|
|
|
|
|
+
|
|
|
|
|
+ class xmr_signable: # mixin class
|
|
|
|
|
+ automount = True
|
|
|
|
|
|
|
|
def need_daemon_restart(self, m, new_idx):
|
|
def need_daemon_restart(self, m, new_idx):
|
|
|
old_idx = self.parent.xmr_cur_wallet_idx
|
|
old_idx = self.parent.xmr_cur_wallet_idx
|
|
@@ -341,11 +346,12 @@ class Signable:
|
|
|
bmsg('\nAutosign summary:')
|
|
bmsg('\nAutosign summary:')
|
|
|
msg('\n'.join(s.get_info(indent=' ') for s in signables) + self.summary_footer)
|
|
msg('\n'.join(s.get_info(indent=' ') for s in signables) + self.summary_footer)
|
|
|
|
|
|
|
|
- class xmr_transaction(xmr_signable):
|
|
|
|
|
|
|
+ class xmr_transaction(xmr_signable, automount_transaction):
|
|
|
dir_name = 'xmr_tx_dir'
|
|
dir_name = 'xmr_tx_dir'
|
|
|
desc = 'Monero transaction'
|
|
desc = 'Monero transaction'
|
|
|
|
|
+ rawext = 'rawtx'
|
|
|
|
|
+ sigext = 'sigtx'
|
|
|
subext = 'subtx'
|
|
subext = 'subtx'
|
|
|
- multiple_ok = False
|
|
|
|
|
summary_footer = ''
|
|
summary_footer = ''
|
|
|
|
|
|
|
|
async def sign(self, f):
|
|
async def sign(self, f):
|
|
@@ -361,7 +367,7 @@ class Signable:
|
|
|
tx2.write(ask_write=False)
|
|
tx2.write(ask_write=False)
|
|
|
return tx2
|
|
return tx2
|
|
|
|
|
|
|
|
- class xmr_wallet_outputs_file(xmr_signable):
|
|
|
|
|
|
|
+ class xmr_wallet_outputs_file(xmr_signable, base):
|
|
|
desc = 'Monero wallet outputs file'
|
|
desc = 'Monero wallet outputs file'
|
|
|
rawext = 'raw'
|
|
rawext = 'raw'
|
|
|
sigext = 'sig'
|
|
sigext = 'sig'
|
|
@@ -405,7 +411,9 @@ class Signable:
|
|
|
outdir = self.dir.resolve(),
|
|
outdir = self.dir.resolve(),
|
|
|
ask_overwrite = False)
|
|
ask_overwrite = False)
|
|
|
if m.data.get('failed_sids'):
|
|
if m.data.get('failed_sids'):
|
|
|
- die('MsgFileFailedSID', f'Failed Seed IDs: {fmt_list(m.data["failed_sids"], fmt="bare")}')
|
|
|
|
|
|
|
+ die(
|
|
|
|
|
+ 'MsgFileFailedSID',
|
|
|
|
|
+ f'Failed Seed IDs: {fmt_list(m.data["failed_sids"], fmt="bare")}')
|
|
|
return m
|
|
return m
|
|
|
|
|
|
|
|
def print_summary(self, signables):
|
|
def print_summary(self, signables):
|
|
@@ -575,7 +583,9 @@ class Autosign:
|
|
|
try:
|
|
try:
|
|
|
dirlist = self.wallet_dir.iterdir()
|
|
dirlist = self.wallet_dir.iterdir()
|
|
|
except:
|
|
except:
|
|
|
- die(1, f"Cannot open wallet directory '{self.wallet_dir}'. Did you run ‘mmgen-autosign setup’?")
|
|
|
|
|
|
|
+ die(1,
|
|
|
|
|
+ f'Cannot open wallet directory ‘{self.wallet_dir}’. '
|
|
|
|
|
+ 'Did you run ‘mmgen-autosign setup’?')
|
|
|
|
|
|
|
|
self._wallet_files = [f for f in dirlist if f.suffix == '.mmdat']
|
|
self._wallet_files = [f for f in dirlist if f.suffix == '.mmdat']
|
|
|
|
|
|
|
@@ -611,9 +621,9 @@ class Autosign:
|
|
|
redir = None if verbose else DEVNULL
|
|
redir = None if verbose else DEVNULL
|
|
|
if run(self.mount_cmd.split(), stderr=redir, stdout=redir).returncode == 0:
|
|
if run(self.mount_cmd.split(), stderr=redir, stdout=redir).returncode == 0:
|
|
|
if not silent:
|
|
if not silent:
|
|
|
- msg(f"Mounting '{self.mountpoint}'")
|
|
|
|
|
|
|
+ msg(f'Mounting ‘{self.mountpoint}’')
|
|
|
else:
|
|
else:
|
|
|
- die(1, f'Unable to mount device {self.dev_label} at {self.mountpoint}')
|
|
|
|
|
|
|
+ die(1, f'Unable to mount device ‘{self.dev_label}’ at ‘{self.mountpoint}’')
|
|
|
|
|
|
|
|
for dirname in self.dirs:
|
|
for dirname in self.dirs:
|
|
|
check_or_create(dirname)
|
|
check_or_create(dirname)
|
|
@@ -622,14 +632,14 @@ class Autosign:
|
|
|
if self.mountpoint.is_mount():
|
|
if self.mountpoint.is_mount():
|
|
|
run(['sync'], check=True)
|
|
run(['sync'], check=True)
|
|
|
if not silent:
|
|
if not silent:
|
|
|
- msg(f"Unmounting '{self.mountpoint}'")
|
|
|
|
|
|
|
+ msg(f'Unmounting ‘{self.mountpoint}’')
|
|
|
redir = None if verbose else DEVNULL
|
|
redir = None if verbose else DEVNULL
|
|
|
run(self.umount_cmd.split(), stdout=redir, check=True)
|
|
run(self.umount_cmd.split(), stdout=redir, check=True)
|
|
|
if not silent:
|
|
if not silent:
|
|
|
bmsg('It is now safe to extract the removable device')
|
|
bmsg('It is now safe to extract the removable device')
|
|
|
|
|
|
|
|
def decrypt_wallets(self):
|
|
def decrypt_wallets(self):
|
|
|
- msg(f"Unlocking wallet{suf(self.wallet_files)} with key from ‘{self.keyfile}’")
|
|
|
|
|
|
|
+ msg(f'Unlocking wallet{suf(self.wallet_files)} with key from ‘{self.keyfile}’')
|
|
|
fails = 0
|
|
fails = 0
|
|
|
for wf in self.wallet_files:
|
|
for wf in self.wallet_files:
|
|
|
try:
|
|
try:
|
|
@@ -654,9 +664,10 @@ class Autosign:
|
|
|
try:
|
|
try:
|
|
|
ret = await target.sign(f)
|
|
ret = await target.sign(f)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- ymsg(f"An error occurred with {target.desc} '{f.name}':\n {type(e).__name__}: {e!s}")
|
|
|
|
|
|
|
+ ymsg('An error occurred with {} ‘{}’:\n {}: ‘{}’'.format(
|
|
|
|
|
+ target.desc, f.name, type(e).__name__, e))
|
|
|
except:
|
|
except:
|
|
|
- ymsg(f"An error occurred with {target.desc} '{f.name}'")
|
|
|
|
|
|
|
+ ymsg('An error occurred with {} ‘{}’'.format(target.desc, f.name))
|
|
|
good.append(ret) if ret else bad.append(f)
|
|
good.append(ret) if ret else bad.append(f)
|
|
|
self.cfg._util.qmsg('')
|
|
self.cfg._util.qmsg('')
|
|
|
await asyncio.sleep(0.3)
|
|
await asyncio.sleep(0.3)
|
|
@@ -704,7 +715,7 @@ class Autosign:
|
|
|
gmsg('No wallet encryption key on removable device')
|
|
gmsg('No wallet encryption key on removable device')
|
|
|
|
|
|
|
|
def create_key(self):
|
|
def create_key(self):
|
|
|
- desc = f"key file '{self.keyfile}'"
|
|
|
|
|
|
|
+ desc = f'key file ‘{self.keyfile}’'
|
|
|
msg('Creating ' + desc)
|
|
msg('Creating ' + desc)
|
|
|
try:
|
|
try:
|
|
|
self.keyfile.write_text(os.urandom(32).hex())
|
|
self.keyfile.write_text(os.urandom(32).hex())
|
|
@@ -747,7 +758,7 @@ class Autosign:
|
|
|
def setup(self):
|
|
def setup(self):
|
|
|
|
|
|
|
|
def remove_wallet_dir():
|
|
def remove_wallet_dir():
|
|
|
- msg(f"Deleting '{self.wallet_dir}'")
|
|
|
|
|
|
|
+ msg(f'Deleting ‘{self.wallet_dir}’')
|
|
|
import shutil
|
|
import shutil
|
|
|
try:
|
|
try:
|
|
|
shutil.rmtree(self.wallet_dir)
|
|
shutil.rmtree(self.wallet_dir)
|
|
@@ -762,7 +773,7 @@ class Autosign:
|
|
|
try:
|
|
try:
|
|
|
self.wallet_dir.stat()
|
|
self.wallet_dir.stat()
|
|
|
except:
|
|
except:
|
|
|
- die(2, f"Unable to create wallet directory '{self.wallet_dir}'")
|
|
|
|
|
|
|
+ die(2, f'Unable to create wallet directory ‘{self.wallet_dir}’')
|
|
|
|
|
|
|
|
self.gen_key(no_unmount=True)
|
|
self.gen_key(no_unmount=True)
|
|
|
|
|
|
|
@@ -777,7 +788,7 @@ class Autosign:
|
|
|
wf = find_file_in_dir(get_wallet_cls('mmgen'), self.cfg.data_dir)
|
|
wf = find_file_in_dir(get_wallet_cls('mmgen'), self.cfg.data_dir)
|
|
|
if wf and keypress_confirm(
|
|
if wf and keypress_confirm(
|
|
|
cfg = self.cfg,
|
|
cfg = self.cfg,
|
|
|
- prompt = f"Default wallet '{wf}' found.\nUse default wallet for autosigning?",
|
|
|
|
|
|
|
+ prompt = f'Default wallet ‘{wf}’ found.\nUse default wallet for autosigning?',
|
|
|
default_yes = True):
|
|
default_yes = True):
|
|
|
ss_in = Wallet(Config(), fn=wf)
|
|
ss_in = Wallet(Config(), fn=wf)
|
|
|
else:
|
|
else:
|
|
@@ -810,7 +821,9 @@ class Autosign:
|
|
|
def create_signing_wallets():
|
|
def create_signing_wallets():
|
|
|
from . import xmrwallet
|
|
from . import xmrwallet
|
|
|
if len(self.wallet_files) > 1:
|
|
if len(self.wallet_files) > 1:
|
|
|
- ymsg(f'Warning: more than one wallet file, using the first ({self.wallet_files[0]}) for xmrwallet generation')
|
|
|
|
|
|
|
+ ymsg(
|
|
|
|
|
+ 'Warning: more than one wallet file, using the first '
|
|
|
|
|
+ f'({self.wallet_files[0]}) for xmrwallet generation')
|
|
|
m = xmrwallet.op(
|
|
m = xmrwallet.op(
|
|
|
'create_offline',
|
|
'create_offline',
|
|
|
self.xmrwallet_cfg,
|
|
self.xmrwallet_cfg,
|
|
@@ -844,7 +857,7 @@ class Autosign:
|
|
|
|
|
|
|
|
s = getattr(Signable, s_name)(self)
|
|
s = getattr(Signable, s_name)(self)
|
|
|
|
|
|
|
|
- msg_r(f"Cleaning directory '{s.dir}'..")
|
|
|
|
|
|
|
+ msg_r(f'Cleaning directory ‘{s.dir}’..')
|
|
|
|
|
|
|
|
if s.dir.is_dir():
|
|
if s.dir.is_dir():
|
|
|
clean_files(s.rawext, s.sigext)
|
|
clean_files(s.rawext, s.sigext)
|
|
@@ -875,7 +888,9 @@ class Autosign:
|
|
|
if self.cfg.test_suite_root_pfx:
|
|
if self.cfg.test_suite_root_pfx:
|
|
|
return self.mountpoint.exists()
|
|
return self.mountpoint.exists()
|
|
|
else:
|
|
else:
|
|
|
- return run(['diskutil', 'info', self.dev_label], stdout=DEVNULL, stderr=DEVNULL).returncode == 0
|
|
|
|
|
|
|
+ return run(
|
|
|
|
|
+ ['diskutil', 'info', self.dev_label],
|
|
|
|
|
+ stdout=DEVNULL, stderr=DEVNULL).returncode == 0
|
|
|
|
|
|
|
|
async def main_loop(self):
|
|
async def main_loop(self):
|
|
|
if not self.cfg.stealth_led:
|
|
if not self.cfg.stealth_led:
|
|
@@ -890,7 +905,7 @@ class Autosign:
|
|
|
await self.do_sign()
|
|
await self.do_sign()
|
|
|
prev_status = status
|
|
prev_status = status
|
|
|
if not n % 10:
|
|
if not n % 10:
|
|
|
- msg_r(f"\r{' '*17}\rWaiting")
|
|
|
|
|
|
|
+ msg_r(f'\r{" "*17}\rWaiting')
|
|
|
await asyncio.sleep(0.2 if threaded else 1)
|
|
await asyncio.sleep(0.2 if threaded else 1)
|
|
|
if not threaded:
|
|
if not threaded:
|
|
|
msg_r('.')
|
|
msg_r('.')
|