aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet/simplewallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r--src/simplewallet/simplewallet.cpp212
1 files changed, 181 insertions, 31 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index d45ef3d7c..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
@@ -143,6 +150,7 @@ enum TransferType {
};
static std::string get_human_readable_timespan(std::chrono::seconds seconds);
+static std::string get_human_readable_timespan(uint64_t seconds);
namespace
{
@@ -182,6 +190,7 @@ namespace
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
@@ -207,7 +216,7 @@ namespace
const char* USAGE_CHECK_SPEND_PROOF("check_spend_proof <txid> <signature_file> [<message>]");
const char* USAGE_GET_RESERVE_PROOF("get_reserve_proof (all|<amount>) [<message>]");
const char* USAGE_CHECK_RESERVE_PROOF("check_reserve_proof <address> <signature_file> [<message>]");
- const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
const char* USAGE_UNSPENT_OUTPUTS("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
const char* USAGE_RESCAN_BC("rescan_bc [hard|soft|keep_ki] [start_height=0]");
const char* USAGE_SET_TX_NOTE("set_tx_note <txid> [free text note]");
@@ -248,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>");
@@ -267,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");
@@ -2386,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();
@@ -3142,9 +3209,12 @@ 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::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",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_below, _1),
tr(USAGE_SWEEP_BELOW),
@@ -3206,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),
@@ -3338,7 +3408,7 @@ simple_wallet::simple_wallet()
"** Set of address indices used as inputs in this transfer."));
m_cmd_binder.set_handler("export_transfers",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::export_transfers, _1),
- tr("export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
+ tr("export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
tr("Export to CSV the incoming/outgoing transfers within an optional height range."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::unspent_outputs, _1),
@@ -3455,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),
@@ -3517,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),
@@ -3583,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",
@@ -3595,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),
@@ -5461,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;
@@ -5472,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
@@ -5576,14 +5654,19 @@ boost::optional<epee::wipeable_string> simple_wallet::on_device_pin_request()
return pwd_container->password();
}
//----------------------------------------------------------------------------------------------------
-boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool on_device)
+boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool & on_device)
{
- if (on_device){
- message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
- return boost::none;
+ if (on_device) {
+ std::string accepted = input_line(tr(
+ "Device asks for passphrase. Do you want to enter the passphrase on device (Y) (or on the host (N))?"));
+ if (std::cin.eof() || command_line::is_yes(accepted)) {
+ message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
+ return boost::none;
+ }
}
PAUSE_READLINE();
+ on_device = false;
std::string msg = tr("Enter device passphrase");
auto pwd_container = tools::password_container::prompt(false, msg.c_str());
THROW_WALLET_EXCEPTION_IF(!pwd_container, tools::error::password_entry_failed, tr("Failed to read device passphrase"));
@@ -5748,15 +5831,19 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
- uint64_t blocks_to_unlock;
- uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock);
+ uint64_t blocks_to_unlock, time_to_unlock;
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock, &time_to_unlock);
std::string unlock_time_message;
- if (blocks_to_unlock > 0)
+ if (blocks_to_unlock > 0 && time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%lu block(s) and %s to unlock)") % blocks_to_unlock % get_human_readable_timespan(time_to_unlock)).str();
+ else if (blocks_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
+ else if (time_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%s to unlock)") % get_human_readable_timespan(time_to_unlock)).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
+ std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -6221,6 +6308,7 @@ bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx>
}
return true;
}
+//----------------------------------------------------------------------------------------------------
void simple_wallet::check_for_inactivity_lock(bool user)
{
if (m_locked)
@@ -6745,7 +6833,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
{
- sweep_main(0, true, args_);
+ sweep_main(m_current_subaddress_account, 0, true, args_);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -6856,18 +6944,22 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args_)
+bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
{
- auto print_usage = [below]()
+ auto print_usage = [this, account, below]()
{
if (below)
{
PRINT_USAGE(USAGE_SWEEP_BELOW);
}
- else
+ else if (account == m_current_subaddress_account)
{
PRINT_USAGE(USAGE_SWEEP_ALL);
}
+ else
+ {
+ PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
+ }
};
if (args_.size() == 0)
{
@@ -7041,7 +7133,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices);
if (ptx_vector.empty())
{
@@ -7381,7 +7473,27 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{
- sweep_main(0, false, args_);
+ sweep_main(m_current_subaddress_account, 0, false, args_);
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
+{
+ auto local_args = args_;
+ if (local_args.empty())
+ {
+ PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
+ return true;
+ }
+ uint32_t account = 0;
+ if (!epee::string_tools::get_xtype_from_string(account, local_args[0]))
+ {
+ fail_msg_writer() << tr("Invalid account");
+ return true;
+ }
+ local_args.erase(local_args.begin());
+
+ sweep_main(account, 0, false, local_args);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -7398,7 +7510,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold");
return true;
}
- sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ sweep_main(m_current_subaddress_account, below, false, std::vector<std::string>(++args_.begin(), args_.end()));
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -8233,6 +8345,11 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
return sw::tr("a long time");
}
//----------------------------------------------------------------------------------------------------
+static std::string get_human_readable_timespan(uint64_t seconds)
+{
+ return get_human_readable_timespan(std::chrono::seconds(seconds));
+}
+//----------------------------------------------------------------------------------------------------
// mutates local_args as it parses and consumes arguments
bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vector<transfer_view>& transfers)
{
@@ -8495,7 +8612,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() > 4) {
- fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
return true;
}
@@ -8548,7 +8665,7 @@ bool simple_wallet::export_transfers(const std::vector<std::string>& args_)
std::vector<std::string> local_args = args_;
if(local_args.size() > 5) {
- fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
+ fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
return true;
}
@@ -10317,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;
@@ -10469,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;
@@ -10818,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();
@@ -11144,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)
@@ -11174,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)
{
@@ -11286,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);