Skip to content

Commit

Permalink
Wallet: Option to export data to ASCII
Browse files Browse the repository at this point in the history
New CLI wallet variable: export-format with options "raw" (the default),
or "hex". "Raw" behaves as before, "hex" forces the wallet to convert
data to ASCII.

On import, we try to decode ASCII first, and if that fails, fall back to
raw in a sort of primitive auto detect.

Implements #2859
  • Loading branch information
tmoravec committed Apr 16, 2019
1 parent 1f809e7 commit e28bc3f
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 27 deletions.
53 changes: 41 additions & 12 deletions src/simplewallet/simplewallet.cpp
Expand Up @@ -1246,7 +1246,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b
}
else
{
bool r = epee::file_io_utils::save_string_to_file(filename, ciphertext);
bool r = m_wallet->save_to_file(filename, ciphertext);
if (!r)
{
fail_msg_writer() << tr("failed to save file ") << filename;
Expand Down Expand Up @@ -1307,7 +1307,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b
{
const std::string &filename = args[n];
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
bool r = m_wallet->load_from_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
Expand Down Expand Up @@ -1618,7 +1618,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
if (!filenames.empty())
filenames += ", ";
filenames += filename;
if (!epee::file_io_utils::save_string_to_file(filename, cryptonote::tx_to_blob(ptx.tx)))
if (!m_wallet->save_to_file(filename, cryptonote::tx_to_blob(ptx.tx)))
{
fail_msg_writer() << tr("Failed to export multisig transaction to file ") << filename;
return true;
Expand Down Expand Up @@ -2704,6 +2704,31 @@ bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std
return true;
}

bool simple_wallet::set_export_format(const std::vector<std::string> &args/* = std::vector<std::string()*/)
{
if (args.size() < 2)
{
fail_msg_writer() << tr("Export format not specified");
return false;
}

if (args[1] == "Hex" || args[1] == "hex")
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Hex);
return true;
}
else if (args[1] == "Raw" || args[1] == "raw")
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Raw);
return true;
}
else
{
fail_msg_writer() << tr("Export format not recognized");
}
return false;
}

bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
Expand Down Expand Up @@ -2891,7 +2916,9 @@ simple_wallet::simple_wallet()
" Set the lookahead sizes for the subaddress hash table.\n "
" Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n "
"segregation-height <n>\n "
" Set to the height of a key reusing fork you want to use, 0 to use default."));
" Set to the height of a key reusing fork you want to use, 0 to use default.\n"
"export-format <\"Raw\"|\"Hex\">\n"
" Save all exported files as raw (binary) or hex (ascii).\n"));
m_cmd_binder.set_handler("encrypted_seed",
boost::bind(&simple_wallet::encrypted_seed, this, _1),
tr("Display the encrypted Electrum-style mnemonic seed."));
Expand Down Expand Up @@ -3257,6 +3284,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "setup-background-mining = " << setup_background_mining_string + tr(" (set this to support the network and to get a chance to receive new monero)");
success_msg_writer() << "device_name = " << m_wallet->device_name();
success_msg_writer() << "export-format = " << (m_wallet->export_format() ? "Hex" : "Raw");
return true;
}
else
Expand Down Expand Up @@ -3315,6 +3343,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
CHECK_SIMPLE_VARIABLE("export-format", set_export_format, tr("\"Raw\" or \"Hex\""));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
Expand Down Expand Up @@ -7345,7 +7374,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)

// read signature file
std::string sig_str;
if (!epee::file_io_utils::load_file_to_string(args[2], sig_str))
if (!m_wallet->load_from_file(args[2], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
Expand Down Expand Up @@ -7459,7 +7488,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
return true;

std::string sig_str;
if (!epee::file_io_utils::load_file_to_string(args[1], sig_str))
if (!m_wallet->load_from_file(args[1], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
Expand Down Expand Up @@ -7553,7 +7582,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
}

std::string sig_str;
if (!epee::file_io_utils::load_file_to_string(args[1], sig_str))
if (!m_wallet->load_from_file(args[1], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
Expand Down Expand Up @@ -8852,7 +8881,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)

std::string filename = args[0];
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
bool r = m_wallet->load_from_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
Expand All @@ -8878,7 +8907,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
std::string signature= args[2];

std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
bool r = m_wallet->load_from_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
Expand Down Expand Up @@ -9077,7 +9106,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
try
{
std::string data = m_wallet->export_outputs_to_str();
bool r = epee::file_io_utils::save_string_to_file(filename, data);
bool r = m_wallet->save_to_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to save file ") << filename;
Expand Down Expand Up @@ -9110,7 +9139,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
std::string filename = args[0];

std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
bool r = m_wallet->load_from_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename;
Expand Down Expand Up @@ -10096,7 +10125,7 @@ void simple_wallet::mms_export(const std::vector<std::string> &args)
if (valid_id)
{
const std::string filename = "mms_message_content";
if (epee::file_io_utils::save_string_to_file(filename, m.content))
if (m_wallet->save_to_file(filename, m.content))
{
success_msg_writer() << tr("Message content saved to: ") << filename;
}
Expand Down
1 change: 1 addition & 0 deletions src/simplewallet/simplewallet.h
Expand Up @@ -145,6 +145,7 @@ namespace cryptonote
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool set_export_format(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
Expand Down
106 changes: 91 additions & 15 deletions src/wallet/wallet2.cpp
Expand Up @@ -134,6 +134,8 @@ using namespace cryptonote;
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1";

static const std::string HEX_OUTPUT_MAGIC = "MoneroHexDataV1";

namespace
{
std::string get_default_ringdb_path()
Expand Down Expand Up @@ -1083,7 +1085,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_unattended(unattended),
m_devices_registered(false),
m_device_last_key_image_sync(0),
m_use_dns(true)
m_use_dns(true),
m_export_format(ExportFormat::Raw)
{
}

Expand Down Expand Up @@ -3614,7 +3617,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
std::string tmp_file_name = keys_file_name + ".new";
std::string buf;
r = ::serialization::dump_binary(keys_file_data, buf);
r = r && epee::file_io_utils::save_string_to_file(tmp_file_name, buf);
r = r && save_to_file(tmp_file_name, buf);
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);

unlock_keys_file();
Expand Down Expand Up @@ -3671,7 +3674,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
wallet2::keys_file_data keys_file_data;
std::string buf;
bool encrypted_secret_keys = false;
bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
bool r = load_from_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);

// Decrypt the contents
Expand Down Expand Up @@ -5170,7 +5173,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
wallet2::cache_file_data cache_file_data;
std::string buf;
bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max());
bool r = load_from_file(m_wallet_file, buf, std::numeric_limits<size_t>::max());
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);

// try to read it as an encrypted cache
Expand Down Expand Up @@ -5440,7 +5443,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
binary_archive<true> oar(oss);
bool success = ::serialization::serialize(oar, cache_file_data);
if (success) {
success = epee::file_io_utils::save_string_to_file(new_file, oss.str());
success = save_to_file(new_file, oss.str());
}
THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file);
#else
Expand Down Expand Up @@ -6067,7 +6070,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
std::string ciphertext = dump_tx_to_str(ptx_vector);
if (ciphertext.empty())
return false;
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const
Expand Down Expand Up @@ -6109,7 +6112,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode);
return false;
}
if (!epee::file_io_utils::load_file_to_string(unsigned_filename.c_str(), s))
if (!load_from_file(unsigned_filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << unsigned_filename);
return false;
Expand Down Expand Up @@ -6330,7 +6333,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
return false;
}

if (!epee::file_io_utils::save_string_to_file(signed_filename, ciphertext))
if (!save_to_file(signed_filename, ciphertext))
{
LOG_PRINT_L0("Failed to save file to " << signed_filename);
return false;
Expand All @@ -6342,7 +6345,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
{
std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx));
std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex))
if (!save_to_file(raw_filename, tx_as_hex))
{
LOG_PRINT_L0("Failed to save file to " << raw_filename);
return false;
Expand Down Expand Up @@ -6390,7 +6393,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return false;
}

if (!epee::file_io_utils::load_file_to_string(signed_filename.c_str(), s))
if (!load_from_file(signed_filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << signed_filename);
return false;
Expand Down Expand Up @@ -6521,7 +6524,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi
std::string ciphertext = save_multisig_tx(txs);
if (ciphertext.empty())
return false;
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
Expand Down Expand Up @@ -6549,7 +6552,7 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const
std::string ciphertext = save_multisig_tx(ptx_vector);
if (ciphertext.empty())
return false;
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
Expand Down Expand Up @@ -6640,7 +6643,7 @@ bool wallet2::load_multisig_tx_from_file(const std::string &filename, multisig_t
LOG_PRINT_L0("File " << filename << " does not exist: " << errcode);
return false;
}
if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s))
if (!load_from_file(filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << filename);
return false;
Expand Down Expand Up @@ -11537,7 +11540,7 @@ bool wallet2::export_key_images(const std::string &filename) const
// encrypt data, keep magic plaintext
PERF_TIMER(export_key_images_encrypt);
std::string ciphertext = encrypt_with_view_secret_key(data);
return epee::file_io_utils::save_string_to_file(filename, magic + ciphertext);
return save_to_file(filename, magic + ciphertext);
}

//----------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -11602,7 +11605,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
{
PERF_TIMER(import_key_images_fsu);
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
bool r = load_from_file(filename, data);

THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename);

Expand Down Expand Up @@ -13007,6 +13010,79 @@ void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &st
THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error");
}
//----------------------------------------------------------------------------------------------------

bool wallet2::save_to_file(const std::string& path_to_file, const std::string& raw) const
{
if (m_export_format == ExportFormat::Hex)
{
std::string h = HEX_OUTPUT_MAGIC + "\n";
h.append(epee::string_tools::buff_to_hex_nodelimer(raw));

// Split the long string into multiple lines, similarly to how openssl
// prints certificates.
for (size_t i = 63; i < h.length(); i += 64)
{
h.insert(i, 1, '\n');
}

h.insert(h.end(), '\n');

return epee::file_io_utils::save_string_to_file(path_to_file, h);
}
else
{
return epee::file_io_utils::save_string_to_file(path_to_file, raw);
}
}
//----------------------------------------------------------------------------------------------------

bool wallet2::load_from_file(const std::string& path_to_file, std::string& target_str,
size_t max_size) const
{
std::string data;
bool r = epee::file_io_utils::load_file_to_string(path_to_file, data, max_size);
if (!r)
{
return false;
}

// Ignore any whitespace.
// We try to convert the version without whitespace from hex to binary.
// If that fails, we stick to the original data (hence the copy).
std::string without_whitespace(data);
without_whitespace.erase(
std::remove_if(
without_whitespace.begin(),
without_whitespace.end(),
[](char c){ return (c =='\r' || c =='\t' || c == ' ' || c == '\n'); }),
without_whitespace.end());

if (0 != without_whitespace.compare(0, HEX_OUTPUT_MAGIC.length(), HEX_OUTPUT_MAGIC))
{
// It's NOT our hex dump.
target_str = std::move(data);
return true;
}
// It's apparently our hex dump.

without_whitespace.erase(0, HEX_OUTPUT_MAGIC.length());
r = epee::string_tools::validate_hex(without_whitespace.size(), without_whitespace);
if (!r)
{
return false;
}

std::string binbuff;
r = epee::string_tools::parse_hexstr_to_binbuff(without_whitespace, binbuff);
if (!r)
{
return false;
}

target_str = std::move(binbuff);
return true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const
{
KECCAK_CTX state;
Expand Down

0 comments on commit e28bc3f

Please sign in to comment.