From 44259e560e484350204a4c11f978cd9a6f090494 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 2 Sep 2018 09:59:01 +0000 Subject: [PATCH] wallet: ask-password can now ask without encrypting the secret spend key --- src/common/json_util.h | 4 +- src/simplewallet/simplewallet.cpp | 48 ++++++++++++++++-------- src/wallet/wallet2.cpp | 61 ++++++++++++++++--------------- src/wallet/wallet2.h | 26 ++++++++----- 4 files changed, 83 insertions(+), 56 deletions(-) diff --git a/src/common/json_util.h b/src/common/json_util.h index 661022a6f..c320c3956 100644 --- a/src/common/json_util.h +++ b/src/common/json_util.h @@ -29,14 +29,14 @@ #pragma once #define GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, name, type, jtype, mandatory, def) \ - type field_##name = def; \ + type field_##name = static_cast(def); \ bool field_##name##_found = false; \ (void)field_##name##_found; \ do if (json.HasMember(#name)) \ { \ if (json[#name].Is##jtype()) \ { \ - field_##name = json[#name].Get##jtype(); \ + field_##name = static_cast(json[#name].Get##jtype()); \ field_##name##_found = true; \ } \ else \ diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 602cdfe44..e9aac52ee 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1992,18 +1992,29 @@ bool simple_wallet::set_ask_password(const std::vector &args/* = st const auto pwd_container = get_and_verify_password(); if (pwd_container) { - parse_bool_and_use(args[1], [&](bool r) { - const bool cur_r = m_wallet->ask_password(); - if (!m_wallet->watch_only()) - { - if (cur_r && !r) - m_wallet->decrypt_keys(pwd_container->password()); - else if (!cur_r && r) - m_wallet->encrypt_keys(pwd_container->password()); - } - m_wallet->ask_password(r); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); - }); + tools::wallet2::AskPasswordType ask = tools::wallet2::AskPasswordToDecrypt; + if (args[1] == "never" || args[1] == "0") + ask = tools::wallet2::AskPasswordNever; + else if (args[1] == "action" || args[1] == "1") + ask = tools::wallet2::AskPasswordOnAction; + else if (args[1] == "encrypt" || args[1] == "decrypt" || args[1] == "2") + ask = tools::wallet2::AskPasswordToDecrypt; + else + { + fail_msg_writer() << tr("invalid argument: must be either 0/never, 1/action, or 2/encrypt/decrypt"); + return true; + } + + const tools::wallet2::AskPasswordType cur_ask = m_wallet->ask_password(); + if (!m_wallet->watch_only()) + { + if (cur_ask == tools::wallet2::AskPasswordToDecrypt && ask != tools::wallet2::AskPasswordToDecrypt) + m_wallet->decrypt_keys(pwd_container->password()); + else if (cur_ask != tools::wallet2::AskPasswordToDecrypt && ask == tools::wallet2::AskPasswordToDecrypt) + m_wallet->encrypt_keys(pwd_container->password()); + } + m_wallet->ask_password(ask); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); } return true; } @@ -2394,7 +2405,7 @@ simple_wallet::simple_wallet() "priority [0|1|2|3|4]\n " " Set the fee to default/unimportant/normal/elevated/priority.\n " "confirm-missing-payment-id <1|0>\n " - "ask-password <1|0>\n " + "ask-password <0|1|2 (or never|action|decrypt)>\n " "unit \n " " Set the default monero (sub-)unit.\n " "min-outputs-count [n]\n " @@ -2607,6 +2618,13 @@ bool simple_wallet::set_variable(const std::vector &args) uint32_t priority = m_wallet->get_default_priority(); if (priority < allowed_priority_strings.size()) priority_string = allowed_priority_strings[priority]; + std::string ask_password_string = "invalid"; + switch (m_wallet->ask_password()) + { + case tools::wallet2::AskPasswordNever: ask_password_string = "never"; break; + case tools::wallet2::AskPasswordOnAction: ask_password_string = "action"; break; + case tools::wallet2::AskPasswordToDecrypt: ask_password_string = "decrypt"; break; + } success_msg_writer() << "seed = " << seed_language; success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers(); success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members(); @@ -2616,7 +2634,7 @@ bool simple_wallet::set_variable(const std::vector &args) success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type()); success_msg_writer() << "priority = " << priority<< " (" << priority_string << ")"; success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id(); - success_msg_writer() << "ask-password = " << m_wallet->ask_password(); + success_msg_writer() << "ask-password = " << m_wallet->ask_password() << " (" << ask_password_string << ")"; success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point()); success_msg_writer() << "min-outputs-count = " << m_wallet->get_min_output_count(); success_msg_writer() << "min-outputs-value = " << cryptonote::print_money(m_wallet->get_min_output_value()); @@ -2672,7 +2690,7 @@ bool simple_wallet::set_variable(const std::vector &args) CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)")); CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", ")); CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1")); - CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1")); + CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0|1|2 (or never|action|decrypt)")); CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("monero, millinero, micronero, nanonero, piconero")); CHECK_SIMPLE_VARIABLE("min-outputs-count", set_min_output_count, tr("unsigned integer")); CHECK_SIMPLE_VARIABLE("min-outputs-value", set_min_output_value, tr("amount")); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f670febbf..2a655208e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -200,7 +200,7 @@ std::string get_weight_string(const cryptonote::transaction &tx, size_t blob_siz return get_weight_string(get_transaction_weight(tx, blob_size)); } -std::unique_ptr make_basic(const boost::program_options::variables_map& vm, bool rpc, const options& opts, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr make_basic(const boost::program_options::variables_map& vm, bool unattended, const options& opts, const std::function(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool stagenet = command_line::get_arg(vm, opts.stagenet); @@ -262,7 +262,7 @@ std::unique_ptr make_basic(const boost::program_options::variabl } std::unique_ptr wallet(new tools::wallet2(nettype, kdf_rounds)); - wallet->init(rpc, std::move(daemon_address), std::move(login), 0, false, *trusted_daemon); + wallet->init(unattended, std::move(daemon_address), std::move(login), 0, false, *trusted_daemon); boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir); wallet->set_ring_database(ringdb_path.string()); return wallet; @@ -297,7 +297,7 @@ boost::optional get_password(const boost::program_opt return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify); } -std::unique_ptr generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, bool rpc, const options& opts, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, bool unattended, const options& opts, const std::function(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool stagenet = command_line::get_arg(vm, opts.stagenet); @@ -435,7 +435,7 @@ std::unique_ptr generate_from_json(const std::string& json_file, THROW_WALLET_EXCEPTION_IF(deprecated_wallet, tools::error::wallet_internal_error, tools::wallet2::tr("Cannot generate deprecated wallets from JSON")); - wallet.reset(make_basic(vm, rpc, opts, password_prompter).release()); + wallet.reset(make_basic(vm, unattended, opts, password_prompter).release()); wallet->set_refresh_from_block_height(field_scan_from_height); wallet->explicit_refresh_from_block_height(field_scan_from_height_found); @@ -721,8 +721,11 @@ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, const boost::optionalpassword(); w.generate_chacha_key_from_password(pass, key); w.decrypt_keys(key); @@ -764,7 +767,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds): m_explicit_refresh_from_block_height(true), m_confirm_missing_payment_id(true), m_confirm_non_default_ring_size(true), - m_ask_password(true), + m_ask_password(AskPasswordToDecrypt), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), @@ -793,7 +796,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds): m_ringdb(), m_last_block_reward(0), m_encrypt_keys_after_refresh(boost::none), - m_rpc(false) + m_unattended(false) { } @@ -828,14 +831,14 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.kdf_rounds); } -std::unique_ptr wallet2::make_from_json(const boost::program_options::variables_map& vm, bool rpc, const std::string& json_file, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function(const char *, bool)> &password_prompter) { const options opts{}; - return generate_from_json(json_file, vm, rpc, opts, password_prompter); + return generate_from_json(json_file, vm, unattended, opts, password_prompter); } std::pair, password_container> wallet2::make_from_file( - const boost::program_options::variables_map& vm, bool rpc, const std::string& wallet_file, const std::function(const char *, bool)> &password_prompter) + const boost::program_options::variables_map& vm, bool unattended, const std::string& wallet_file, const std::function(const char *, bool)> &password_prompter) { const options opts{}; auto pwd = get_password(vm, opts, password_prompter, false); @@ -843,7 +846,7 @@ std::pair, password_container> wallet2::make_from_file( { return {nullptr, password_container{}}; } - auto wallet = make_basic(vm, rpc, opts, password_prompter); + auto wallet = make_basic(vm, unattended, opts, password_prompter); if (wallet) { wallet->load(wallet_file, pwd->password()); @@ -851,7 +854,7 @@ std::pair, password_container> wallet2::make_from_file( return {std::move(wallet), std::move(*pwd)}; } -std::pair, password_container> wallet2::make_new(const boost::program_options::variables_map& vm, bool rpc, const std::function(const char *, bool)> &password_prompter) +std::pair, password_container> wallet2::make_new(const boost::program_options::variables_map& vm, bool unattended, const std::function(const char *, bool)> &password_prompter) { const options opts{}; auto pwd = get_password(vm, opts, password_prompter, true); @@ -859,19 +862,19 @@ std::pair, password_container> wallet2::make_new(const { return {nullptr, password_container{}}; } - return {make_basic(vm, rpc, opts, password_prompter), std::move(*pwd)}; + return {make_basic(vm, unattended, opts, password_prompter), std::move(*pwd)}; } -std::unique_ptr wallet2::make_dummy(const boost::program_options::variables_map& vm, bool rpc, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr wallet2::make_dummy(const boost::program_options::variables_map& vm, bool unattended, const std::function(const char *, bool)> &password_prompter) { const options opts{}; - return make_basic(vm, rpc, opts, password_prompter); + return make_basic(vm, unattended, opts, password_prompter); } //---------------------------------------------------------------------------------------------------- -bool wallet2::init(bool rpc, std::string daemon_address, boost::optional daemon_login, uint64_t upper_transaction_weight_limit, bool ssl, bool trusted_daemon) +bool wallet2::init(bool unattended, std::string daemon_address, boost::optional daemon_login, uint64_t upper_transaction_weight_limit, bool ssl, bool trusted_daemon) { - m_rpc = rpc; + m_unattended = unattended; m_checkpoints.init_default_checkpoints(m_nettype); if(m_http_client.is_connected()) m_http_client.disconnect(); @@ -1210,7 +1213,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index"); // if keys are encrypted, ask for password - if (m_ask_password && !m_rpc && !m_watch_only && !m_multisig_rescan_k) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only && !m_multisig_rescan_k) { static critical_section password_lock; CRITICAL_REGION_LOCAL(password_lock); @@ -2847,7 +2850,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable crypto::chacha_key key; crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds); - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) { account.encrypt_viewkey(key); account.decrypt_keys(key); @@ -2926,7 +2929,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetInt(m_confirm_non_default_ring_size ? 1 :0); json.AddMember("confirm_non_default_ring_size", value2, json.GetAllocator()); - value2.SetInt(m_ask_password ? 1 :0); + value2.SetInt(m_ask_password); json.AddMember("ask_password", value2, json.GetAllocator()); value2.SetUint(m_min_output_count); @@ -3007,7 +3010,7 @@ void wallet2::setup_keys(const epee::wipeable_string &password) crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds); // re-encrypt, but keep viewkey unencrypted - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) { m_account.encrypt_keys(key); m_account.decrypt_viewkey(key); @@ -3023,7 +3026,7 @@ void wallet2::setup_keys(const epee::wipeable_string &password) //---------------------------------------------------------------------------------------------------- void wallet2::change_password(const std::string &filename, const epee::wipeable_string &original_password, const epee::wipeable_string &new_password) { - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) decrypt_keys(original_password); setup_keys(new_password); rewrite(filename, new_password); @@ -3071,7 +3074,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_refresh_type = RefreshType::RefreshDefault; m_confirm_missing_payment_id = true; m_confirm_non_default_ring_size = true; - m_ask_password = true; + m_ask_password = AskPasswordToDecrypt; m_min_output_count = 0; m_min_output_value = 0; m_merge_destinations = false; @@ -3180,7 +3183,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_missing_payment_id = field_confirm_missing_payment_id; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_non_default_ring_size, int, Int, false, true); m_confirm_non_default_ring_size = field_confirm_non_default_ring_size; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, int, Int, false, true); + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, AskPasswordType, Int, false, AskPasswordToDecrypt); m_ask_password = field_ask_password; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_decimal_point, int, Int, false, CRYPTONOTE_DISPLAY_DECIMAL_POINT); cryptonote::set_default_decimal_point(field_default_decimal_point); @@ -3244,7 +3247,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ else { // rewrite with encrypted keys, ignore errors - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) encrypt_keys(key); bool saved_ret = store_keys(keys_file_name, password, m_watch_only); if (!saved_ret) @@ -3252,7 +3255,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ // just moan a bit, but not fatal MERROR("Error saving keys file with encrypted keys, not fatal"); } - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) decrypt_keys(key); m_keys_file_locker.reset(); } @@ -3750,7 +3753,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, // decrypt keys epee::misc_utils::auto_scope_leave_caller keys_reencryptor; - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) { crypto::chacha_key chacha_key; crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds); @@ -3907,7 +3910,7 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unor // keys are decrypted epee::misc_utils::auto_scope_leave_caller keys_reencryptor; - if (m_ask_password && !m_rpc && !m_watch_only) + if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only) { crypto::chacha_key chacha_key; crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds); @@ -4277,7 +4280,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype)); lock_keys_file(); - wallet_keys_unlocker unlocker(*this, m_ask_password && !m_rpc && !m_watch_only, password); + wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, password); //keys loaded ok! //try to load wallet file. but even if we failed, it is not big problem diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0347092c0..42046dee3 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -162,6 +162,12 @@ namespace tools RefreshDefault = RefreshOptimizeCoinbase, }; + enum AskPasswordType { + AskPasswordNever = 0, + AskPasswordOnAction = 1, + AskPasswordToDecrypt = 2, + }; + static const char* tr(const char* str); static bool has_testnet_option(const boost::program_options::variables_map& vm); @@ -169,17 +175,17 @@ namespace tools static void init_options(boost::program_options::options_description& desc_params); //! Uses stdin and stdout. Returns a wallet2 if no errors. - static std::unique_ptr make_from_json(const boost::program_options::variables_map& vm, bool rpc, const std::string& json_file, const std::function(const char *, bool)> &password_prompter); + static std::unique_ptr make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function(const char *, bool)> &password_prompter); //! Uses stdin and stdout. Returns a wallet2 and password for `wallet_file` if no errors. static std::pair, password_container> - make_from_file(const boost::program_options::variables_map& vm, bool rpc, const std::string& wallet_file, const std::function(const char *, bool)> &password_prompter); + make_from_file(const boost::program_options::variables_map& vm, bool unattended, const std::string& wallet_file, const std::function(const char *, bool)> &password_prompter); //! Uses stdin and stdout. Returns a wallet2 and password for wallet with no file if no errors. - static std::pair, password_container> make_new(const boost::program_options::variables_map& vm, bool rpc, const std::function(const char *, bool)> &password_prompter); + static std::pair, password_container> make_new(const boost::program_options::variables_map& vm, bool unattended, const std::function(const char *, bool)> &password_prompter); //! Just parses variables. - static std::unique_ptr make_dummy(const boost::program_options::variables_map& vm, bool rpc, const std::function(const char *, bool)> &password_prompter); + static std::unique_ptr make_dummy(const boost::program_options::variables_map& vm, bool unattended, const std::function(const char *, bool)> &password_prompter); static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds); @@ -631,7 +637,7 @@ namespace tools bool explicit_refresh_from_block_height() const {return m_explicit_refresh_from_block_height;} bool deinit(); - bool init(bool rpc, std::string daemon_address = "http://localhost:8080", + bool init(bool unatteded, std::string daemon_address = "http://localhost:8080", boost::optional daemon_login = boost::none, uint64_t upper_transaction_weight_limit = 0, bool ssl = false, bool trusted_daemon = false); void stop() { m_run.store(false, std::memory_order_relaxed); } @@ -905,8 +911,8 @@ namespace tools void auto_refresh(bool r) { m_auto_refresh = r; } bool confirm_missing_payment_id() const { return m_confirm_missing_payment_id; } void confirm_missing_payment_id(bool always) { m_confirm_missing_payment_id = always; } - bool ask_password() const { return m_ask_password; } - void ask_password(bool always) { m_ask_password = always; } + AskPasswordType ask_password() const { return m_ask_password; } + void ask_password(AskPasswordType ask) { m_ask_password = ask; } void set_min_output_count(uint32_t count) { m_min_output_count = count; } uint32_t get_min_output_count() const { return m_min_output_count; } void set_min_output_value(uint64_t value) { m_min_output_value = value; } @@ -1082,7 +1088,7 @@ namespace tools uint64_t adjust_mixin(uint64_t mixin) const; uint32_t adjust_priority(uint32_t priority); - bool is_rpc() const { return m_rpc; } + bool is_unattended() const { return m_unattended; } // Light wallet specific functions // fetch unspent outs from lw node and store in m_transfers @@ -1293,7 +1299,7 @@ namespace tools bool m_explicit_refresh_from_block_height; bool m_confirm_missing_payment_id; bool m_confirm_non_default_ring_size; - bool m_ask_password; + AskPasswordType m_ask_password; uint32_t m_min_output_count; uint64_t m_min_output_value; bool m_merge_destinations; @@ -1335,7 +1341,7 @@ namespace tools crypto::chacha_key m_cache_key; boost::optional m_encrypt_keys_after_refresh; - bool m_rpc; + bool m_unattended; }; } BOOST_CLASS_VERSION(tools::wallet2, 25)