diff options
Diffstat (limited to 'src/simplewallet')
-rw-r--r-- | src/simplewallet/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 132 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.h | 9 |
3 files changed, 127 insertions, 17 deletions
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 030867dc0..a0820c8eb 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2019, The Monero Project +# Copyright (c) 2014-2020, The Monero Project # # All rights reserved. # @@ -49,6 +49,7 @@ target_link_libraries(simplewallet common mnemonics ${EPEE_READLINE} + qrcodegen version ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b1e69161f..d36e5009b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019, The Monero Project +// Copyright (c) 2014-2020, The Monero Project // // All rights reserved. // @@ -33,6 +33,11 @@ * * \brief Source file that defines simple_wallet class. */ + +// use boost bind placeholders for now +#define BOOST_BIND_GLOBAL_PLACEHOLDERS 1 +#include <boost/bind.hpp> + #include <locale.h> #include <thread> #include <iostream> @@ -69,10 +74,12 @@ #include "version.h" #include <stdexcept> #include "wallet/message_store.h" +#include "QrCode.hpp" #ifdef WIN32 #include <boost/locale.hpp> #include <boost/filesystem.hpp> +#include <fcntl.h> #endif #ifdef HAVE_READLINE @@ -250,6 +257,7 @@ namespace const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]"); const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config"); const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]"); + const char* USAGE_MMS_CONFIG_CHECKSUM("mms config_checksum"); const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config"); const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>"); const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>"); @@ -269,6 +277,7 @@ namespace const char* USAGE_RPC_PAYMENT_INFO("rpc_payment_info"); const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc"); const char* USAGE_STOP_MINING_FOR_RPC("stop_mining_for_rpc"); + const char* USAGE_SHOW_QR_CODE("show_qr_code [<subaddress_index>]"); const char* USAGE_VERSION("version"); const char* USAGE_HELP_ADVANCED("help_advanced [<command>]"); const char* USAGE_HELP("help"); @@ -2388,6 +2397,62 @@ bool simple_wallet::stop_mining_for_rpc(const std::vector<std::string> &args) return true; } +bool simple_wallet::show_qr_code(const std::vector<std::string> &args) +{ + uint32_t subaddress_index = 0; + if (args.size() >= 1) + { + if (!string_tools::get_xtype_from_string(subaddress_index, args[0])) + { + fail_msg_writer() << tr("invalid index: must be an unsigned integer"); + return true; + } + if (subaddress_index >= m_wallet->get_num_subaddresses(m_current_subaddress_account)) + { + fail_msg_writer() << tr("<subaddress_index> is out of bounds"); + return true; + } + } + +#ifdef _WIN32 +#define PRINT_UTF8(pre, x) std::wcout << pre ## x +#define WTEXTON() _setmode(_fileno(stdout), _O_WTEXT) +#define WTEXTOFF() _setmode(_fileno(stdout), _O_TEXT) +#else +#define PRINT_UTF8(pre, x) std::cout << x +#define WTEXTON() +#define WTEXTOFF() +#endif + + WTEXTON(); + try + { + const std::string address = "monero:" + m_wallet->get_subaddress_as_str({m_current_subaddress_account, subaddress_index}); + const qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(address.c_str(), qrcodegen::QrCode::Ecc::LOW); + for (int y = -2; y < qr.getSize() + 2; y+=2) + { + for (int x = -2; x < qr.getSize() + 2; x++) + { + if (qr.getModule(x, y) && qr.getModule(x, y + 1)) + PRINT_UTF8(L, "\u2588"); + else if (qr.getModule(x, y) && !qr.getModule(x, y + 1)) + PRINT_UTF8(L, "\u2580"); + else if (!qr.getModule(x, y) && qr.getModule(x, y + 1)) + PRINT_UTF8(L, "\u2584"); + else + PRINT_UTF8(L, " "); + } + PRINT_UTF8(, std::endl); + } + } + catch (const std::length_error&) + { + fail_msg_writer() << tr("Failed to generate QR code, input too large"); + } + WTEXTOFF(); + return true; +} + bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { const auto pwd_container = get_and_verify_password(); @@ -3144,10 +3209,10 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1), tr("Send all unmixable outputs to yourself with ring_size 1")); - m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1), + m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_all, _1), tr(USAGE_SWEEP_ALL), tr("Send all unlocked balance to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs.")); - m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::sweep_account, this, _1), + m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_account, _1), tr(USAGE_SWEEP_ACCOUNT), tr("Send all unlocked balance from a given account to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs.")); m_cmd_binder.set_handler("sweep_below", @@ -3211,7 +3276,7 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::on_command, this, &simple_wallet::seed, _1), tr("Display the Electrum-style mnemonic seed")); m_cmd_binder.set_handler("restore_height", - boost::bind(&simple_wallet::restore_height, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::restore_height, _1), tr("Display the restore height")); m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_variable, _1), @@ -3460,7 +3525,7 @@ simple_wallet::simple_wallet() tr("Interface with the MMS (Multisig Messaging System)\n" "<subcommand> is one of:\n" " init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n" - " send_signer_config, start_auto_config, stop_auto_config, auto_config\n" + " send_signer_config, start_auto_config, stop_auto_config, auto_config, config_checksum\n" "Get help about a subcommand with: help_advanced mms <subcommand>")); m_cmd_binder.set_handler("mms init", boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), @@ -3522,13 +3587,17 @@ simple_wallet::simple_wallet() "auto-send <1|0>\n " " Whether to automatically send newly generated messages right away.\n ")); m_cmd_binder.set_handler("mms send_signer_config", - boost::bind(&simple_wallet::mms, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), tr(USAGE_MMS_SEND_SIGNER_CONFIG), tr("Send completed signer config to all other authorized signers")); m_cmd_binder.set_handler("mms start_auto_config", boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), tr(USAGE_MMS_START_AUTO_CONFIG), tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels")); + m_cmd_binder.set_handler("mms config_checksum", + boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), + tr(USAGE_MMS_CONFIG_CHECKSUM), + tr("Get a checksum that allows signers to easily check for identical MMS configuration")); m_cmd_binder.set_handler("mms stop_auto_config", boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), tr(USAGE_MMS_STOP_AUTO_CONFIG), @@ -3588,7 +3657,7 @@ simple_wallet::simple_wallet() tr(USAGE_NET_STATS), tr("Prints simple network stats")); m_cmd_binder.set_handler("public_nodes", - boost::bind(&simple_wallet::public_nodes, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::public_nodes, _1), tr(USAGE_PUBLIC_NODES), tr("Lists known public nodes")); m_cmd_binder.set_handler("welcome", @@ -3600,17 +3669,21 @@ simple_wallet::simple_wallet() tr(USAGE_VERSION), tr("Returns version information")); m_cmd_binder.set_handler("rpc_payment_info", - boost::bind(&simple_wallet::rpc_payment_info, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::rpc_payment_info, _1), tr(USAGE_RPC_PAYMENT_INFO), tr("Get info about RPC payments to current node")); m_cmd_binder.set_handler("start_mining_for_rpc", - boost::bind(&simple_wallet::start_mining_for_rpc, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::start_mining_for_rpc, _1), tr(USAGE_START_MINING_FOR_RPC), tr("Start mining to pay for RPC access")); m_cmd_binder.set_handler("stop_mining_for_rpc", - boost::bind(&simple_wallet::stop_mining_for_rpc, this, _1), + boost::bind(&simple_wallet::on_command, this, &simple_wallet::stop_mining_for_rpc, _1), tr(USAGE_STOP_MINING_FOR_RPC), tr("Stop mining to pay for RPC access")); + m_cmd_binder.set_handler("show_qr_code", + boost::bind(&simple_wallet::on_command, this, &simple_wallet::show_qr_code, _1), + tr(USAGE_SHOW_QR_CODE), + tr("Show address as QR code")); m_cmd_binder.set_handler("help_advanced", boost::bind(&simple_wallet::on_command, this, &simple_wallet::help_advanced, _1), tr(USAGE_HELP_ADVANCED), @@ -5466,7 +5539,7 @@ void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block m_refresh_progress_reporter.update(height, false); } //---------------------------------------------------------------------------------------------------- -void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time) +void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) { if (m_locked) return; @@ -5477,7 +5550,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, tr("idx ") << subaddr_index; const uint64_t warn_height = m_wallet->nettype() == TESTNET ? 1000000 : m_wallet->nettype() == STAGENET ? 50000 : 1650000; - if (height >= warn_height) + if (height >= warn_height && !is_change) { std::vector<tx_extra_field> tx_extra_fields; parse_tx_extra(tx.extra, tx_extra_fields); // failure ok @@ -10361,6 +10434,14 @@ bool simple_wallet::user_confirms(const std::string &question) return !std::cin.eof() && command_line::is_yes(answer); } +bool simple_wallet::user_confirms_auto_config() +{ + message_writer(console_color_red, true) << tr("WARNING: Using MMS auto-config mechanisms is not trustless"); + message_writer() << tr("A malicious auto-config manager could send you info about own wallets instead of other signers' info"); + message_writer() << tr("If in doubt do not use auto-config or at least compare configs using the \"mms config_checksum\" command"); + return user_confirms("Accept the risks and continue?"); +} + bool simple_wallet::get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound) { bool valid = false; @@ -10513,7 +10594,7 @@ void simple_wallet::show_message(const mms::message &m) case mms::message_type::additional_key_set: case mms::message_type::note: display_content = true; - ms.get_sanitized_message_text(m, sanitized_text); + sanitized_text = mms::message_store::get_sanitized_text(m.content, 1000); break; default: display_content = false; @@ -10862,6 +10943,11 @@ void simple_wallet::mms_next(const std::vector<std::string> &args) { break; } + if (!user_confirms_auto_config()) + { + message_writer() << tr("You can use the \"mms delete\" command to delete any unwanted message"); + break; + } } ms.process_signer_config(state, m.content); ms.stop_auto_config(); @@ -11188,6 +11274,18 @@ void simple_wallet::mms_start_auto_config(const std::vector<std::string> &args) list_signers(ms.get_all_signers()); } +void simple_wallet::mms_config_checksum(const std::vector<std::string> &args) +{ + if (args.size() != 0) + { + fail_msg_writer() << tr("Usage: mms config_checksum"); + return; + } + mms::message_store& ms = m_wallet->get_message_store(); + LOCK_IDLE_SCOPE(); + message_writer() << ms.get_config_checksum(); +} + void simple_wallet::mms_stop_auto_config(const std::vector<std::string> &args) { if (args.size() != 0) @@ -11218,6 +11316,10 @@ void simple_wallet::mms_auto_config(const std::vector<std::string> &args) fail_msg_writer() << tr("Invalid auto-config token"); return; } + if (!user_confirms_auto_config()) + { + return; + } mms::authorized_signer me = ms.get_signer(0); if (me.auto_config_running) { @@ -11330,6 +11432,10 @@ bool simple_wallet::mms(const std::vector<std::string> &args) { mms_start_auto_config(mms_args); } + else if (sub_command == "config_checksum") + { + mms_config_checksum(mms_args); + } else if (sub_command == "stop_auto_config") { mms_stop_auto_config(mms_args); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 59818b303..5154ff1ef 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019, The Monero Project +// Copyright (c) 2014-2020, The Monero Project // // All rights reserved. // @@ -53,7 +53,7 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "wallet.simplewallet" // Hardcode Monero's donation address (see #1447) -constexpr const char MONERO_DONATION_ADDR[] = "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A"; +constexpr const char MONERO_DONATION_ADDR[] = "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H"; /*! * \namespace cryptonote @@ -258,6 +258,7 @@ namespace cryptonote bool rpc_payment_info(const std::vector<std::string> &args); bool start_mining_for_rpc(const std::vector<std::string> &args); bool stop_mining_for_rpc(const std::vector<std::string> &args); + bool show_qr_code(const std::vector<std::string> &args); bool net_stats(const std::vector<std::string>& args); bool public_nodes(const std::vector<std::string>& args); bool welcome(const std::vector<std::string>& args); @@ -342,7 +343,7 @@ namespace cryptonote //----------------- i_wallet2_callback --------------------- virtual void on_new_block(uint64_t height, const cryptonote::block& block); - virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time); + virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time); virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index); virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index); virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx); @@ -478,6 +479,7 @@ namespace cryptonote void ask_send_all_ready_messages(); void check_for_messages(); bool user_confirms(const std::string &question); + bool user_confirms_auto_config(); bool get_message_from_arg(const std::string &arg, mms::message &m); bool get_number_from_arg(const std::string &arg, uint32_t &number, const uint32_t lower_bound, const uint32_t upper_bound); @@ -498,6 +500,7 @@ namespace cryptonote void mms_help(const std::vector<std::string> &args); void mms_send_signer_config(const std::vector<std::string> &args); void mms_start_auto_config(const std::vector<std::string> &args); + void mms_config_checksum(const std::vector<std::string> &args); void mms_stop_auto_config(const std::vector<std::string> &args); void mms_auto_config(const std::vector<std::string> &args); }; |