From ee9ef363b97774ca4c71a70b25f71412e27d1c78 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 17:20:25 +0300 Subject: [PATCH] auditable watch-only wallet now can be restored from awo-blob (by a third party): --restore-awo-wallet simplewallet new command: awo_blob --- src/currency_core/account.cpp | 9 ++- src/currency_core/account.h | 1 + src/currency_core/currency_format_utils.cpp | 40 +++++++++++++ src/currency_core/currency_format_utils.h | 1 + src/simplewallet/simplewallet.cpp | 66 ++++++++++++++++++--- src/simplewallet/simplewallet.h | 4 +- src/wallet/wallet2.cpp | 13 ++++ src/wallet/wallet2.h | 1 + 8 files changed, 125 insertions(+), 10 deletions(-) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 1e492975..601b8d5f 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -162,6 +162,13 @@ namespace currency return true; } //----------------------------------------------------------------- + bool account_base::restore_from_awo_blob(const std::string& awo_blob) + { + set_null(); + bool r = parse_awo_blob(awo_blob, m_keys.account_address, m_keys.view_secret_key, m_creation_timestamp); + return r; + } + //----------------------------------------------------------------- std::string account_base::get_public_address_str() const { //TODO: change this code into base 58 @@ -172,7 +179,7 @@ namespace currency { // keep only: // timestamp - // view pub & spend pub (public address) + // view pub & spend pub + flags (public address) // view sec // store to local tmp diff --git a/src/currency_core/account.h b/src/currency_core/account.h index bcb35961..156d058e 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -55,6 +55,7 @@ namespace currency std::string get_restore_braindata() const; bool restore_from_braindata(const std::string& seed_phrase); + bool restore_from_awo_blob(const std::string& awo_blob); uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index d4855cd0..d51b7821 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -313,6 +313,46 @@ namespace currency return string_tools::get_xtype_from_string(amount, str_amount); } //-------------------------------------------------------------------------------- + bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp) + { + std::vector parts; + boost::split(parts, awo_blob, [](char x){ return x == ':'; } ); + if (parts.size() != 2 && parts.size() != 3) + return false; + + if (!get_account_address_from_str(address, parts[0])) + return false; + + if (!address.is_auditable()) + return false; + + if (!epee::string_tools::parse_tpod_from_hex_string(parts[1], view_sec_key)) + return false; + + crypto::public_key view_pub_key = AUTO_VAL_INIT(view_pub_key); + if (!crypto::secret_key_to_public_key(view_sec_key, view_pub_key)) + return false; + + if (view_pub_key != address.view_public_key) + return false; + + creation_timestamp = 0; + if (parts.size() == 3) + { + // parse timestamp + int64_t ts = 0; + if (!epee::string_tools::string_to_num_fast(parts[2], ts)) + return false; + + if (ts < WALLET_BRAIN_DATE_OFFSET) + return false; + + creation_timestamp = ts; + } + + return true; + } + //-------------------------------------------------------------------------------- std::string print_stake_kernel_info(const stake_kernel& sk) { std::stringstream ss; diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index c4edefeb..598b2cb3 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -239,6 +239,7 @@ namespace currency bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); bool parse_amount(uint64_t& amount, const std::string& str_amount); + bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 117b1771..475dae49 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -52,6 +52,7 @@ namespace const command_line::arg_descriptor arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false }; const command_line::arg_descriptor arg_pos_mining_reward_address = { "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" }; const command_line::arg_descriptor arg_restore_wallet = { "restore-wallet", "Restore wallet from the seed phrase and save it to ", "" }; + const command_line::arg_descriptor arg_restore_awo_wallet = { "restore-awo-wallet", "Restore auditable watch-only wallet from address and view key. Use \"address:viewkey\" as argument", "" }; const command_line::arg_descriptor arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true }; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; @@ -220,6 +221,8 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), "Get transaction one-time secret key (r) for a given "); + m_cmd_binder.set_handler("awo_blob", boost::bind(&simple_wallet::awo_blob, this, _1), "For auditable wallets: prints auditable watch-only blob for wallet's audit by a third party"); + m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only - save as watch-only wallet file."); @@ -271,9 +274,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_generate_new_aw.empty()) + if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_restore_awo_wallet.empty() && m_generate_new_aw.empty()) { - fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet or --restore-wallet"; + fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet, --restore-wallet or --restore-awo-wallet"; return false; } @@ -335,7 +338,25 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password()); + bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), false); + CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed"); + } + else if (!m_restore_awo_wallet.empty()) + { + if (boost::filesystem::exists(m_restore_awo_wallet)) + { + fail_msg_writer() << "file " << m_restore_awo_wallet << " already exists"; + return false; + } + + tools::password_container restore_addr_and_viewkey_container; + if (!restore_addr_and_viewkey_container.read_password("please, enter wallet auditable address, viewkey and timestamp, separated by a colon (\"address:viewkey:timestamp\"):\n")) + { + fail_msg_writer() << "failed to read seed phrase"; + return false; + } + + bool r = restore_wallet(m_restore_awo_wallet, restore_addr_and_viewkey_container.password(), pwd_container.password(), true); CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed"); } else @@ -366,6 +387,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ m_do_not_set_date = command_line::get_arg(vm, arg_dont_set_date); m_do_pos_mining = command_line::get_arg(vm, arg_do_pos_mining); m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet); + m_restore_awo_wallet = command_line::get_arg(vm, arg_restore_awo_wallet); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::try_connect_to_daemon() @@ -417,7 +439,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password) +bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only) { m_wallet_file = wallet_file; @@ -426,15 +448,24 @@ bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::st m_wallet->set_do_rise_transfer(false); try { - m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, restore_seed); - message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str(); - std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; + if (auditable_watch_only) + { + m_wallet->restore_awo(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + message_writer(epee::log_space::console_color_white, true) << "Auditable watch-only wallet restored: " << m_wallet->get_account().get_public_address_str(); + } + else + { + // normal wallet + m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str(); + std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; + } if (m_do_not_set_date) m_wallet->reset_creation_time(0); } catch (const std::exception& e) { - fail_msg_writer() << "failed to restore wallet, check your seed phrase!" << ENDL << e.what(); + fail_msg_writer() << "failed to restore wallet, check your " << (auditable_watch_only ? "awo blob!" : "seed phrase!") << ENDL << e.what(); return false; } @@ -1471,6 +1502,24 @@ bool simple_wallet::get_tx_key(const std::vector &args_) } } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::awo_blob(const std::vector &args_) +{ + if (!m_wallet->is_auditable()) + { + fail_msg_writer() << "this command is allowed for auditable wallets only"; + return true; + } + + const account_base& acc = m_wallet->get_account(); + + success_msg_writer() << "Auditable watch-only blob for this wallet is: "; + std::cout << acc.get_public_address_str() << ":" << epee::string_tools::pod_to_hex(acc.get_keys().view_secret_key); + if (acc.get_createtime()) + std::cout << ":" << acc.get_createtime(); + std::cout << ENDL; + return true; +} +//---------------------------------------------------------------------------------------------------- void simple_wallet::set_offline_mode(bool offline_mode) { if (offline_mode && !m_offline_mode) @@ -1734,6 +1783,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_do_pos_mining); command_line::add_arg(desc_params, arg_pos_mining_reward_address); command_line::add_arg(desc_params, arg_restore_wallet); + command_line::add_arg(desc_params, arg_restore_awo_wallet); command_line::add_arg(desc_params, arg_offline_mode); command_line::add_arg(desc_params, command_line::arg_log_file); command_line::add_arg(desc_params, command_line::arg_log_level); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index a99f62a5..7808333b 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -46,7 +46,7 @@ namespace currency bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet); bool open_wallet(const std::string &wallet_file, const std::string& password); - bool restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password); + bool restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only); bool close_wallet(); bool help(const std::vector &args = std::vector()); @@ -81,6 +81,7 @@ namespace currency bool enable_console_logger(const std::vector &args); bool integrated_address(const std::vector &args); bool get_tx_key(const std::vector &args_); + bool awo_blob(const std::vector &args_); bool save_watch_only(const std::vector &args); bool sign_transfer(const std::vector &args); bool submit_transfer(const std::vector &args); @@ -166,6 +167,7 @@ namespace currency bool m_do_pos_mining; bool m_offline_mode; std::string m_restore_wallet; + std::string m_restore_awo_wallet; epee::console_handlers_binder m_cmd_binder; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3404cc7a..36fa53e5 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2203,6 +2203,19 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s store(); } //---------------------------------------------------------------------------------------------------- +void wallet2::restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob) +{ + clear(); + prepare_file_names(path); + m_password = pass; + bool r = m_account.restore_from_awo_blob(awo_blob); + init_log_prefix(); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob"); + boost::system::error_code ignored_ec; + THROW_IF_FALSE_WALLET_EX(!boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); + store(); +} +//---------------------------------------------------------------------------------------------------- bool wallet2::check_connection() { return m_core_proxy->check_connection(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 00f27450..5a9f1dd1 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -489,6 +489,7 @@ namespace tools void assign_account(const currency::account_base& acc); void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase); + void restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob); void load(const std::wstring& path, const std::string& password); void store(); void store(const std::wstring& path);