From 91a8f7f1505c1d2b55b1ba8aa8c8d6a1625ab948 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sat, 28 Aug 2021 11:17:31 +0200 Subject: [PATCH 1/4] genwallet.py: Minor improvments Changes from top to bottom: - Add header comment - Import wallet_utils (needed for DEFAULT_MIXDEPTH) - Make password optional in usage string - Set variable wallet_name at the top where options are parsed - Use DEFAULT_MIXDEPTH instead of hardcoded value --- scripts/genwallet.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/genwallet.py b/scripts/genwallet.py index 369b88f..e902164 100755 --- a/scripts/genwallet.py +++ b/scripts/genwallet.py @@ -1,33 +1,41 @@ #!/usr/bin/env python3 +# A script for noninteractively creating wallets. +# The implementation is similar to wallet_generate_recover_bip39 in jmclient/wallet_utils.py + import sys import os from optparse import OptionParser -from jmclient import load_program_config, add_base_options, SegwitWallet, SegwitLegacyWallet, create_wallet, jm_single +from jmclient import ( + load_program_config, add_base_options, SegwitWallet, SegwitLegacyWallet, + create_wallet, jm_single, wallet_utils +) from jmbase.support import get_log, jmprint log = get_log() def main(): parser = OptionParser( - usage='usage: %prog [options] wallet_file_name password', - description='Create a wallet with the given wallet name and password.') + usage='usage: %prog [options] wallet_file_name [password]', + description='Create a wallet with the given wallet name and password.' + ) add_base_options(parser) (options, args) = parser.parse_args() + wallet_name = args[0] if options.wallet_password_stdin: - stdin = sys.stdin.read() - password = stdin.encode("utf-8") + password = sys.stdin.read().encode("utf-8") else: assert len(args) > 1, "must provide password via stdin (see --help), or as second argument." password = args[1].encode("utf-8") + load_program_config(config_path=options.datadir) wallet_root_path = os.path.join(jm_single().datadir, "wallets") - wallet_name = os.path.join(wallet_root_path, args[0]) + wallet_path = os.path.join(wallet_root_path, wallet_name) if jm_single().config.get("POLICY", "native") == "true": walletclass = SegwitWallet else: walletclass = SegwitLegacyWallet - wallet = create_wallet(wallet_name, password, 4, walletclass) + wallet = create_wallet(wallet_path, password, wallet_utils.DEFAULT_MIXDEPTH, walletclass) jmprint("recovery_seed:{}" .format(wallet.get_mnemonic_words()[0]), "important") wallet.close() From c5621ad774a33ba23cfbf4d0ac3425adfeca6268 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sat, 28 Aug 2021 11:17:32 +0200 Subject: [PATCH 2/4] genwallet.py: Enable Fidelity Bonds by default This change simply unlocks Fidelity Bonds and has no downsides for users. --- scripts/genwallet.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/genwallet.py b/scripts/genwallet.py index e902164..ebdf584 100755 --- a/scripts/genwallet.py +++ b/scripts/genwallet.py @@ -7,7 +7,7 @@ import sys import os from optparse import OptionParser from jmclient import ( - load_program_config, add_base_options, SegwitWallet, SegwitLegacyWallet, + load_program_config, add_base_options, SegwitWalletFidelityBonds, SegwitLegacyWallet, create_wallet, jm_single, wallet_utils ) from jmbase.support import get_log, jmprint @@ -32,8 +32,9 @@ def main(): wallet_root_path = os.path.join(jm_single().datadir, "wallets") wallet_path = os.path.join(wallet_root_path, wallet_name) if jm_single().config.get("POLICY", "native") == "true": - walletclass = SegwitWallet + walletclass = SegwitWalletFidelityBonds else: + # Fidelity Bonds are not available for segwit legacy wallets walletclass = SegwitLegacyWallet wallet = create_wallet(wallet_path, password, wallet_utils.DEFAULT_MIXDEPTH, walletclass) jmprint("recovery_seed:{}" From e4be0343eb8d58f2111015f681e288d47cdcf324 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sat, 28 Aug 2021 11:17:33 +0200 Subject: [PATCH 3/4] Extract function `read_password_stdin` This ensures that `wallet_utils.py` and `genwallet.py` use the same logic for reading the password. The current algorithm for reading the password entails some non-obvious details like utf-8 encoding and not stripping trailing newlines. --- jmclient/jmclient/wallet_utils.py | 7 +++++-- scripts/genwallet.py | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jmclient/jmclient/wallet_utils.py b/jmclient/jmclient/wallet_utils.py index d175c76..649541f 100644 --- a/jmclient/jmclient/wallet_utils.py +++ b/jmclient/jmclient/wallet_utils.py @@ -1368,8 +1368,7 @@ def open_test_wallet_maybe(path, seed, max_mixdepth, return test_wallet_cls(storage, **kwargs) if wallet_password_stdin is True: - stdin = sys.stdin.read() - password = stdin.encode('utf-8') + password = read_password_stdin() return open_wallet(path, ask_for_password=False, password=password, mixdepth=max_mixdepth, **kwargs) return open_wallet(path, mixdepth=max_mixdepth, **kwargs) @@ -1444,6 +1443,10 @@ def get_wallet_path(file_name, wallet_dir=None): return os.path.join(wallet_dir, file_name) +def read_password_stdin(): + return sys.stdin.read().encode('utf-8') + + def wallet_tool_main(wallet_root_path): """Main wallet tool script function; returned is a string (output or error) """ diff --git a/scripts/genwallet.py b/scripts/genwallet.py index ebdf584..c1d760c 100755 --- a/scripts/genwallet.py +++ b/scripts/genwallet.py @@ -3,7 +3,6 @@ # A script for noninteractively creating wallets. # The implementation is similar to wallet_generate_recover_bip39 in jmclient/wallet_utils.py -import sys import os from optparse import OptionParser from jmclient import ( @@ -23,7 +22,7 @@ def main(): (options, args) = parser.parse_args() wallet_name = args[0] if options.wallet_password_stdin: - password = sys.stdin.read().encode("utf-8") + password = wallet_utils.read_password_stdin() else: assert len(args) > 1, "must provide password via stdin (see --help), or as second argument." password = args[1].encode("utf-8") From 53e7bf1018c4f0be361ed01b28f8983dba5b6d58 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Sat, 28 Aug 2021 11:17:34 +0200 Subject: [PATCH 4/4] genwallet.py: Add option --recovery-seed-file --- scripts/genwallet.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/genwallet.py b/scripts/genwallet.py index c1d760c..ddffaf0 100755 --- a/scripts/genwallet.py +++ b/scripts/genwallet.py @@ -5,6 +5,7 @@ import os from optparse import OptionParser +from pathlib import Path from jmclient import ( load_program_config, add_base_options, SegwitWalletFidelityBonds, SegwitLegacyWallet, create_wallet, jm_single, wallet_utils @@ -19,6 +20,13 @@ def main(): description='Create a wallet with the given wallet name and password.' ) add_base_options(parser) + parser.add_option( + '--recovery-seed-file', + dest='seed_file', + default=None, + help=('File containing a mnemonic recovery phrase. If provided, the wallet ' + 'is recovered from this seed instead of being newly generated.') + ) (options, args) = parser.parse_args() wallet_name = args[0] if options.wallet_password_stdin: @@ -26,6 +34,7 @@ def main(): else: assert len(args) > 1, "must provide password via stdin (see --help), or as second argument." password = args[1].encode("utf-8") + seed = options.seed_file and Path(options.seed_file).read_text().rstrip() load_program_config(config_path=options.datadir) wallet_root_path = os.path.join(jm_single().datadir, "wallets") @@ -35,7 +44,8 @@ def main(): else: # Fidelity Bonds are not available for segwit legacy wallets walletclass = SegwitLegacyWallet - wallet = create_wallet(wallet_path, password, wallet_utils.DEFAULT_MIXDEPTH, walletclass) + entropy = seed and SegwitLegacyWallet.entropy_from_mnemonic(seed) + wallet = create_wallet(wallet_path, password, wallet_utils.DEFAULT_MIXDEPTH, walletclass, entropy=entropy) jmprint("recovery_seed:{}" .format(wallet.get_mnemonic_words()[0]), "important") wallet.close()