Wallet: Option to export data to ASCII

New CLI wallet variable: export-format with options "binary" (the default),
or "ascii". "Binary" behaves as before, "ascii" forces the wallet to convert
data to ASCII using base64.

Reading files from the disk tries to auto detect what format has been
used (using a magic string added when exporting the data).

Implements https://github.com/monero-project/monero/issues/2859
This commit is contained in:
Tadeas Moravec 2019-04-10 11:20:12 +02:00
parent cdfa2e58df
commit 63186a01ce
No known key found for this signature in database
GPG key ID: AE1066CC94FA7B49
4 changed files with 170 additions and 37 deletions

View file

@ -1254,7 +1254,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b
} }
else else
{ {
bool r = epee::file_io_utils::save_string_to_file(filename, ciphertext); bool r = m_wallet->save_to_file(filename, ciphertext);
if (!r) if (!r)
{ {
fail_msg_writer() << tr("failed to save file ") << filename; fail_msg_writer() << tr("failed to save file ") << filename;
@ -1315,7 +1315,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b
{ {
const std::string &filename = args[n]; const std::string &filename = args[n];
std::string data; 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) if (!r)
{ {
fail_msg_writer() << tr("failed to read file ") << filename; fail_msg_writer() << tr("failed to read file ") << filename;
@ -1626,7 +1626,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
if (!filenames.empty()) if (!filenames.empty())
filenames += ", "; filenames += ", ";
filenames += filename; 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; fail_msg_writer() << tr("Failed to export multisig transaction to file ") << filename;
return true; return true;
@ -2712,6 +2712,35 @@ bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std
return true; 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 true;
}
if (boost::algorithm::iequals(args[1], "ascii"))
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Ascii);
}
else if (boost::algorithm::iequals(args[1], "binary"))
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Binary);
}
else
{
fail_msg_writer() << tr("Export format not recognized.");
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
m_wallet->rewrite(m_wallet_file, pwd_container->password());
}
return true;
}
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{ {
if(args.empty()) if(args.empty())
@ -2912,7 +2941,9 @@ simple_wallet::simple_wallet()
"setup-background-mining <1|0>\n " "setup-background-mining <1|0>\n "
" Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n " " Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n "
"device-name <device_name[:device_spec]>\n " "device-name <device_name[:device_spec]>\n "
" Device name for hardware wallet.")); " Device name for hardware wallet.\n "
"export-format <\"binary\"|\"ascii\">\n "
" Save all exported files as binary (cannot be copied and pasted) or ascii (can be).\n "));
m_cmd_binder.set_handler("encrypted_seed", m_cmd_binder.set_handler("encrypted_seed",
boost::bind(&simple_wallet::encrypted_seed, this, _1), boost::bind(&simple_wallet::encrypted_seed, this, _1),
tr("Display the encrypted Electrum-style mnemonic seed.")); tr("Display the encrypted Electrum-style mnemonic seed."));
@ -3278,6 +3309,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "track-uses = " << m_wallet->track_uses(); success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "setup-background-mining = " << setup_background_mining_string; success_msg_writer() << "setup-background-mining = " << setup_background_mining_string;
success_msg_writer() << "device-name = " << m_wallet->device_name(); success_msg_writer() << "device-name = " << m_wallet->device_name();
success_msg_writer() << "export-format = " << (m_wallet->export_format() == tools::wallet2::ExportFormat::Ascii ? "ascii" : "binary");
return true; return true;
} }
else else
@ -3336,6 +3368,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("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("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("device-name", set_device_name, tr("<device_name[:device_spec]>"));
CHECK_SIMPLE_VARIABLE("export-format", set_export_format, tr("\"binary\" or \"ascii\""));
} }
fail_msg_writer() << tr("set: unrecognized argument(s)"); fail_msg_writer() << tr("set: unrecognized argument(s)");
return true; return true;
@ -7312,7 +7345,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
{ {
std::string sig_str = m_wallet->get_tx_proof(txid, info.address, info.is_subaddress, args.size() == 3 ? args[2] : ""); std::string sig_str = m_wallet->get_tx_proof(txid, info.address, info.is_subaddress, args.size() == 3 ? args[2] : "");
const std::string filename = "monero_tx_proof"; const std::string filename = "monero_tx_proof";
if (epee::file_io_utils::save_string_to_file(filename, sig_str)) if (m_wallet->save_to_file(filename, sig_str, true))
success_msg_writer() << tr("signature file saved to: ") << filename; success_msg_writer() << tr("signature file saved to: ") << filename;
else else
fail_msg_writer() << tr("failed to save signature file"); fail_msg_writer() << tr("failed to save signature file");
@ -7440,7 +7473,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
// read signature file // read signature file
std::string sig_str; 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"); fail_msg_writer() << tr("failed to load signature file");
return true; return true;
@ -7524,7 +7557,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
{ {
const std::string sig_str = m_wallet->get_spend_proof(txid, args.size() == 2 ? args[1] : ""); const std::string sig_str = m_wallet->get_spend_proof(txid, args.size() == 2 ? args[1] : "");
const std::string filename = "monero_spend_proof"; const std::string filename = "monero_spend_proof";
if (epee::file_io_utils::save_string_to_file(filename, sig_str)) if (m_wallet->save_to_file(filename, sig_str, true))
success_msg_writer() << tr("signature file saved to: ") << filename; success_msg_writer() << tr("signature file saved to: ") << filename;
else else
fail_msg_writer() << tr("failed to save signature file"); fail_msg_writer() << tr("failed to save signature file");
@ -7554,7 +7587,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
return true; return true;
std::string sig_str; 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"); fail_msg_writer() << tr("failed to load signature file");
return true; return true;
@ -7613,7 +7646,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
{ {
const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : ""); const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : "");
const std::string filename = "monero_reserve_proof"; const std::string filename = "monero_reserve_proof";
if (epee::file_io_utils::save_string_to_file(filename, sig_str)) if (m_wallet->save_to_file(filename, sig_str, true))
success_msg_writer() << tr("signature file saved to: ") << filename; success_msg_writer() << tr("signature file saved to: ") << filename;
else else
fail_msg_writer() << tr("failed to save signature file"); fail_msg_writer() << tr("failed to save signature file");
@ -7648,7 +7681,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
} }
std::string sig_str; 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"); fail_msg_writer() << tr("failed to load signature file");
return true; return true;
@ -9011,7 +9044,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
std::string filename = args[0]; std::string filename = args[0];
std::string data; 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) if (!r)
{ {
fail_msg_writer() << tr("failed to read file ") << filename; fail_msg_writer() << tr("failed to read file ") << filename;
@ -9037,7 +9070,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
std::string signature= args[2]; std::string signature= args[2];
std::string data; 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) if (!r)
{ {
fail_msg_writer() << tr("failed to read file ") << filename; fail_msg_writer() << tr("failed to read file ") << filename;
@ -9255,7 +9288,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args_)
try try
{ {
std::string data = m_wallet->export_outputs_to_str(all); std::string data = m_wallet->export_outputs_to_str(all);
bool r = epee::file_io_utils::save_string_to_file(filename, data); bool r = m_wallet->save_to_file(filename, data);
if (!r) if (!r)
{ {
fail_msg_writer() << tr("failed to save file ") << filename; fail_msg_writer() << tr("failed to save file ") << filename;
@ -9288,7 +9321,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
std::string filename = args[0]; std::string filename = args[0];
std::string data; 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) if (!r)
{ {
fail_msg_writer() << tr("failed to read file ") << filename; fail_msg_writer() << tr("failed to read file ") << filename;
@ -9489,7 +9522,7 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_
tx_to_blob(ptx.tx, blob); tx_to_blob(ptx.tx, blob);
const std::string blob_hex = epee::string_tools::buff_to_hex_nodelimer(blob); const std::string blob_hex = epee::string_tools::buff_to_hex_nodelimer(blob);
const std::string filename = "raw_monero_tx" + (ptx_vector.size() == 1 ? "" : ("_" + std::to_string(i++))); const std::string filename = "raw_monero_tx" + (ptx_vector.size() == 1 ? "" : ("_" + std::to_string(i++)));
if (epee::file_io_utils::save_string_to_file(filename, blob_hex)) if (m_wallet->save_to_file(filename, blob_hex, true))
success_msg_writer(true) << tr("Transaction successfully saved to ") << filename << tr(", txid ") << txid; success_msg_writer(true) << tr("Transaction successfully saved to ") << filename << tr(", txid ") << txid;
else else
fail_msg_writer() << tr("Failed to save transaction to ") << filename << tr(", txid ") << txid; fail_msg_writer() << tr("Failed to save transaction to ") << filename << tr(", txid ") << txid;
@ -10274,7 +10307,7 @@ void simple_wallet::mms_export(const std::vector<std::string> &args)
if (valid_id) if (valid_id)
{ {
const std::string filename = "mms_message_content"; 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; success_msg_writer() << tr("Message content saved to: ") << filename;
} }

View file

@ -146,6 +146,7 @@ namespace cryptonote
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>()); 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_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_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 help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args); bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args);

View file

@ -40,6 +40,7 @@
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
#include <boost/range/adaptor/transformed.hpp> #include <boost/range/adaptor/transformed.hpp>
#include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/stringize.hpp>
#include <openssl/evp.h>
#include "include_base_utils.h" #include "include_base_utils.h"
using namespace epee; using namespace epee;
@ -138,6 +139,8 @@ using namespace cryptonote;
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1"; static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1"; static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1";
static const std::string ASCII_OUTPUT_MAGIC = "MoneroAsciiDataV1";
namespace namespace
{ {
std::string get_default_ringdb_path() std::string get_default_ringdb_path()
@ -1143,7 +1146,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_device_last_key_image_sync(0), m_device_last_key_image_sync(0),
m_use_dns(true), m_use_dns(true),
m_offline(false), m_offline(false),
m_rpc_version(0) m_rpc_version(0),
m_export_format(ExportFormat::Binary)
{ {
} }
@ -3647,6 +3651,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_original_keys_available ? 1 : 0); value2.SetInt(m_original_keys_available ? 1 : 0);
json.AddMember("original_keys_available", value2, json.GetAllocator()); json.AddMember("original_keys_available", value2, json.GetAllocator());
value2.SetInt(m_export_format);
json.AddMember("export_format", value2, json.GetAllocator());
value2.SetUint(1); value2.SetUint(1);
json.AddMember("encrypted_secret_keys", value2, json.GetAllocator()); json.AddMember("encrypted_secret_keys", value2, json.GetAllocator());
@ -3684,7 +3691,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 tmp_file_name = keys_file_name + ".new";
std::string buf; std::string buf;
r = ::serialization::dump_binary(keys_file_data, 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); CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
unlock_keys_file(); unlock_keys_file();
@ -3741,7 +3748,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
wallet2::keys_file_data keys_file_data; wallet2::keys_file_data keys_file_data;
std::string buf; std::string buf;
bool encrypted_secret_keys = false; 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); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents // Decrypt the contents
@ -3754,7 +3761,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject()) if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
// The contents should be JSON if the wallet follows the new format. // The contents should be JSON if the wallet follows the new format.
if (json.Parse(account_data.c_str()).HasParseError()) if (json.Parse(account_data.c_str()).HasParseError())
{ {
@ -3793,6 +3799,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false; m_original_keys_available = false;
m_export_format = ExportFormat::Binary;
m_device_name = ""; m_device_name = "";
m_device_derivation_path = ""; m_device_derivation_path = "";
m_key_device_type = hw::device::device_type::SOFTWARE; m_key_device_type = hw::device::device_type::SOFTWARE;
@ -3954,6 +3961,9 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false);
encrypted_secret_keys = field_encrypted_secret_keys; encrypted_secret_keys = field_encrypted_secret_keys;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, export_format, ExportFormat, Int, false, Binary);
m_export_format = field_export_format;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string()); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string());
if (m_device_name.empty()) if (m_device_name.empty())
{ {
@ -4101,7 +4111,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
wallet2::keys_file_data keys_file_data; wallet2::keys_file_data keys_file_data;
std::string buf; std::string buf;
bool encrypted_secret_keys = false; 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); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents // Decrypt the contents
@ -4186,7 +4196,7 @@ void wallet2::create_keys_file(const std::string &wallet_, bool watch_only, cons
if (create_address_file) if (create_address_file)
{ {
r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true);
if(!r) MERROR("String with address text not saved"); if(!r) MERROR("String with address text not saved");
} }
} }
@ -4208,7 +4218,7 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri
rapidjson::Document json; rapidjson::Document json;
wallet2::keys_file_data keys_file_data; wallet2::keys_file_data keys_file_data;
std::string buf; std::string buf;
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); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents // Decrypt the contents
@ -4757,7 +4767,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
if (boost::filesystem::exists(m_wallet_file + ".address.txt")) if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
{ {
r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true);
if(!r) MERROR("String with address text not saved"); if(!r) MERROR("String with address text not saved");
} }
} }
@ -5266,7 +5276,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{ {
wallet2::cache_file_data cache_file_data; wallet2::cache_file_data cache_file_data;
std::string buf; 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); THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
// try to read it as an encrypted cache // try to read it as an encrypted cache
@ -5501,7 +5511,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
{ {
// save address to the new file // save address to the new file
const std::string address_file = m_wallet_file + ".address.txt"; const std::string address_file = m_wallet_file + ".address.txt";
r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype)); r = save_to_file(address_file, m_account.get_public_address_str(m_nettype), true);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
} }
// remove old wallet file // remove old wallet file
@ -5536,7 +5546,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
binary_archive<true> oar(oss); binary_archive<true> oar(oss);
bool success = ::serialization::serialize(oar, cache_file_data); bool success = ::serialization::serialize(oar, cache_file_data);
if (success) { 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); THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file);
#else #else
@ -6164,7 +6174,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
std::string ciphertext = dump_tx_to_str(ptx_vector); std::string ciphertext = dump_tx_to_str(ptx_vector);
if (ciphertext.empty()) if (ciphertext.empty())
return false; 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 std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const
@ -6206,7 +6216,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode); LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode);
return false; 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); LOG_PRINT_L0("Failed to load from " << unsigned_filename);
return false; return false;
@ -6427,7 +6437,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
return false; 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); LOG_PRINT_L0("Failed to save file to " << signed_filename);
return false; return false;
@ -6439,7 +6449,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 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))); 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); LOG_PRINT_L0("Failed to save file to " << raw_filename);
return false; return false;
@ -6487,7 +6497,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return false; 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); LOG_PRINT_L0("Failed to load from " << signed_filename);
return false; return false;
@ -6618,7 +6628,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi
std::string ciphertext = save_multisig_tx(txs); std::string ciphertext = save_multisig_tx(txs);
if (ciphertext.empty()) if (ciphertext.empty())
return false; 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 wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
@ -6646,7 +6656,7 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const
std::string ciphertext = save_multisig_tx(ptx_vector); std::string ciphertext = save_multisig_tx(ptx_vector);
if (ciphertext.empty()) if (ciphertext.empty())
return false; 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 bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
@ -6737,7 +6747,7 @@ bool wallet2::load_multisig_tx_from_file(const std::string &filename, multisig_t
LOG_PRINT_L0("File " << filename << " does not exist: " << errcode); LOG_PRINT_L0("File " << filename << " does not exist: " << errcode);
return false; 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); LOG_PRINT_L0("Failed to load from " << filename);
return false; return false;
@ -11633,7 +11643,7 @@ bool wallet2::export_key_images(const std::string &filename, bool all) const
// encrypt data, keep magic plaintext // encrypt data, keep magic plaintext
PERF_TIMER(export_key_images_encrypt); PERF_TIMER(export_key_images_encrypt);
std::string ciphertext = encrypt_with_view_secret_key(data); 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);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -11698,7 +11708,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
{ {
PERF_TIMER(import_key_images_fsu); PERF_TIMER(import_key_images_fsu);
std::string data; 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); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename);
@ -13102,6 +13112,83 @@ 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"); 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, bool is_printable) const
{
if (is_printable || m_export_format == ExportFormat::Binary)
{
return epee::file_io_utils::save_string_to_file(path_to_file, raw);
}
FILE *fp = fopen(path_to_file.c_str(), "w+");
// Save the result b/c we need to close the fp before returning success/failure.
int write_result = PEM_write(fp, ASCII_OUTPUT_MAGIC.c_str(), "", (const unsigned char *) raw.c_str(), raw.length());
fclose(fp);
if (write_result == 0)
{
return false;
}
else
{
return true;
}
}
//----------------------------------------------------------------------------------------------------
bool wallet2::load_from_file(const std::string& path_to_file, std::string& target_str,
size_t max_size)
{
std::string data;
bool r = epee::file_io_utils::load_file_to_string(path_to_file, data, max_size);
if (!r)
{
return false;
}
if (!boost::algorithm::contains(boost::make_iterator_range(data.begin(), data.end()), ASCII_OUTPUT_MAGIC))
{
// It's NOT our ascii dump.
target_str = std::move(data);
return true;
}
// Creating a BIO and calling PEM_read_bio instead of simpler PEM_read
// to avoid reading the file from disk twice.
BIO* b = BIO_new_mem_buf((const void*) data.data(), data.length());
char *name = NULL;
char *header = NULL;
unsigned char *openssl_data = NULL;
long len = 0;
// Save the result b/c we need to free the data before returning success/failure.
int success = PEM_read_bio(b, &name, &header, &openssl_data, &len);
try
{
target_str = std::string((const char*) openssl_data, len);
}
catch (...)
{
success = 0;
}
OPENSSL_free((void *) name);
OPENSSL_free((void *) header);
OPENSSL_free((void *) openssl_data);
BIO_free(b);
if (success == 0)
{
return false;
}
else
{
return true;
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const
{ {
KECCAK_CTX state; KECCAK_CTX state;

View file

@ -227,6 +227,11 @@ private:
BackgroundMiningNo = 2, BackgroundMiningNo = 2,
}; };
enum ExportFormat {
Binary = 0,
Ascii,
};
static const char* tr(const char* str); static const char* tr(const char* str);
static bool has_testnet_option(const boost::program_options::variables_map& vm); static bool has_testnet_option(const boost::program_options::variables_map& vm);
@ -1050,6 +1055,8 @@ private:
void device_name(const std::string & device_name) { m_device_name = device_name; } void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; } const std::string & device_derivation_path() const { return m_device_derivation_path; }
void device_derivation_path(const std::string &device_derivation_path) { m_device_derivation_path = device_derivation_path; } void device_derivation_path(const std::string &device_derivation_path) { m_device_derivation_path = device_derivation_path; }
const ExportFormat & export_format() const { return m_export_format; }
inline void set_export_format(const ExportFormat& export_format) { m_export_format = export_format; }
bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const; bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys); void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys);
@ -1300,6 +1307,9 @@ private:
bool frozen(const crypto::key_image &ki) const; bool frozen(const crypto::key_image &ki) const;
bool frozen(const transfer_details &td) const; bool frozen(const transfer_details &td) const;
bool save_to_file(const std::string& path_to_file, const std::string& binary, bool is_printable = false) const;
static bool load_from_file(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000);
uint64_t get_bytes_sent() const; uint64_t get_bytes_sent() const;
uint64_t get_bytes_received() const; uint64_t get_bytes_received() const;
@ -1546,6 +1556,8 @@ private:
std::shared_ptr<tools::Notify> m_tx_notify; std::shared_ptr<tools::Notify> m_tx_notify;
std::unique_ptr<wallet_device_callback> m_device_callback; std::unique_ptr<wallet_device_callback> m_device_callback;
ExportFormat m_export_format;
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 28) BOOST_CLASS_VERSION(tools::wallet2, 28)