Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add import/export private key functionality to simplewallet #225

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 136 additions & 22 deletions src/SimpleWallet/SimpleWallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C
m_consoleHandler.setHandler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining [<number_of_threads>] - Start mining in daemon");
m_consoleHandler.setHandler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
//m_consoleHandler.setHandler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
m_consoleHandler.setHandler("export_keys", boost::bind(&simple_wallet::export_keys, this, _1), "Show the private spend and view keys of the opened wallet");
m_consoleHandler.setHandler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
m_consoleHandler.setHandler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers");
m_consoleHandler.setHandler("list_transfers", boost::bind(&simple_wallet::listTransfers, this, _1), "Show all known transfers");
Expand Down Expand Up @@ -516,13 +517,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) {
}

if (m_generate_new.empty() && m_wallet_file_arg.empty()) {
std::cout << "Nor 'generate-new-wallet' neither 'wallet-file' argument was specified.\nWhat do you want to do?\n[O]pen existing wallet, [G]enerate new wallet file or [E]xit.\n";
std::cout << "Nor 'generate-new-wallet' neither 'wallet-file' argument was specified.\nWhat do you want to do?\n[O]pen existing wallet, [G]enerate new wallet file, [I]mport wallet or [E]xit.\n";
char c;
do {
std::string answer;
std::getline(std::cin, answer);
c = answer[0];
if (!(c == 'O' || c == 'G' || c == 'E' || c == 'o' || c == 'g' || c == 'e')) {
if (!(c == 'O' || c == 'G' || c == 'E' || c == 'I' || c == 'o' || c == 'g' || c == 'e' || c == 'i')) {
std::cout << "Unknown command: " << c <<std::endl;
} else {
break;
Expand All @@ -541,7 +542,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) {
boost::algorithm::trim(userInput);
} while (userInput.empty());

if (c == 'g' || c == 'G') {
if (c == 'i' || c == 'I') {
m_import_new = userInput;
} else if (c == 'g' || c == 'G') {
m_generate_new = userInput;
} else {
m_wallet_file_arg = userInput;
Expand All @@ -554,9 +557,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) {
}

std::string walletFileName;
if (!m_generate_new.empty()) {
if (!m_generate_new.empty() || !m_import_new.empty()) {
std::string ignoredString;
WalletHelper::prepareFileNames(m_generate_new, ignoredString, walletFileName);
if (!m_generate_new.empty()) {
WalletHelper::prepareFileNames(m_generate_new, ignoredString, walletFileName);
} else if (!m_import_new.empty()) {
WalletHelper::prepareFileNames(m_import_new, ignoredString, walletFileName);
}
boost::system::error_code ignore;
if (boost::filesystem::exists(walletFileName, ignore)) {
fail_msg_writer() << walletFileName << " already exists";
Expand Down Expand Up @@ -615,30 +622,74 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) {

if (!writeAddressFile(walletAddressFile, m_wallet->getAddress())) {
logger(WARNING, BRIGHT_RED) << "Couldn't write wallet address file: " + walletAddressFile;
}
} else {
m_wallet.reset(new WalletLegacy(m_currency, *m_node));
}
} else if (!m_import_new.empty()) {
std::string walletAddressFile = prepareWalletAddressFilename(m_import_new);
boost::system::error_code ignore;
if (boost::filesystem::exists(walletAddressFile, ignore)) {
logger(ERROR, BRIGHT_RED) << "Address file already exists: " + walletAddressFile;
return false;
}

try {
m_wallet_file = tryToOpenWalletOrLoadKeysOrThrow(logger, m_wallet, m_wallet_file_arg, pwd_container.password());
} catch (const std::exception& e) {
fail_msg_writer() << "failed to load wallet: " << e.what();
return false;
}
std::string private_spend_key_string;
std::string private_view_key_string;

do {
std::cout << "Private Spend Key: ";
std::getline(std::cin, private_spend_key_string);
boost::algorithm::trim(private_spend_key_string);
} while (private_spend_key_string.empty());

do {
std::cout << "Private View Key: ";
std::getline(std::cin, private_view_key_string);
boost::algorithm::trim(private_view_key_string);
} while (private_view_key_string.empty());

Crypto::Hash private_spend_key_hash;
Crypto::Hash private_view_key_hash;
size_t size;
if (!Common::fromHex(private_spend_key_string, &private_spend_key_hash, sizeof(private_spend_key_hash), size) || size != sizeof(private_spend_key_hash)) {
return false;
}
if (!Common::fromHex(private_view_key_string, &private_view_key_hash, sizeof(private_view_key_hash), size) || size != sizeof(private_spend_key_hash)) {
return false;
}
Crypto::SecretKey private_spend_key = *(struct Crypto::SecretKey *) &private_spend_key_hash;
Crypto::SecretKey private_view_key = *(struct Crypto::SecretKey *) &private_view_key_hash;

m_wallet->addObserver(this);
m_node->addObserver(static_cast<INodeObserver*>(this));
if (!new_wallet(private_spend_key, private_view_key, walletFileName, pwd_container.password())) {
logger(ERROR, BRIGHT_RED) << "account creation failed";
return false;
}

logger(INFO, BRIGHT_WHITE) << "Opened wallet: " << m_wallet->getAddress();
if (!writeAddressFile(walletAddressFile, m_wallet->getAddress())) {
logger(WARNING, BRIGHT_RED) << "Couldn't write wallet address file: " + walletAddressFile;
}
} else {
m_wallet.reset(new WalletLegacy(m_currency, *m_node));

success_msg_writer() <<
"**********************************************************************\n" <<
"Use \"help\" command to see the list of available commands.\n" <<
"**********************************************************************";
}
try {
m_wallet_file = tryToOpenWalletOrLoadKeysOrThrow(logger, m_wallet, m_wallet_file_arg, pwd_container.password());
} catch (const std::exception& e) {
fail_msg_writer() << "failed to load wallet: " << e.what();
return false;
}

m_wallet->addObserver(this);
m_node->addObserver(static_cast<INodeObserver*>(this));

logger(INFO, BRIGHT_WHITE) << "Opened wallet: " << m_wallet->getAddress();

success_msg_writer() <<
"**********************************************************************\n" <<
"Use \"help\" command to see the list of available commands.\n" <<
"**********************************************************************";
}

return true;
}

//----------------------------------------------------------------------------------------------------
bool simple_wallet::deinit() {
m_wallet->removeObserver(this);
Expand Down Expand Up @@ -706,6 +757,59 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(Crypto::SecretKey &secret_key, Crypto::SecretKey &view_key, const std::string &wallet_file, const std::string& password) {
m_wallet_file = wallet_file;

m_wallet.reset(new WalletLegacy(m_currency, *m_node.get()));
m_node->addObserver(static_cast<INodeObserver*>(this));
m_wallet->addObserver(this);
try {
m_initResultPromise.reset(new std::promise<std::error_code>());
std::future<std::error_code> f_initError = m_initResultPromise->get_future();

AccountKeys wallet_keys;
wallet_keys.spendSecretKey = secret_key;
wallet_keys.viewSecretKey = view_key;
Crypto::secret_key_to_public_key(wallet_keys.spendSecretKey, wallet_keys.address.spendPublicKey);
Crypto::secret_key_to_public_key(wallet_keys.viewSecretKey, wallet_keys.address.viewPublicKey);

m_wallet->initWithKeys(wallet_keys, password);
auto initError = f_initError.get();
m_initResultPromise.reset(nullptr);
if (initError) {
fail_msg_writer() << "failed to generate new wallet: " << initError.message();
return false;
}

try {
CryptoNote::WalletHelper::storeWallet(*m_wallet, m_wallet_file);
} catch (std::exception& e) {
fail_msg_writer() << "failed to save new wallet: " << e.what();
throw;
}

AccountKeys keys;
m_wallet->getAccountKeys(keys);

logger(INFO, BRIGHT_WHITE) <<
"Imported wallet: " << m_wallet->getAddress() << std::endl;
}
catch (const std::exception& e) {
fail_msg_writer() << "failed to import wallet: " << e.what();
return false;
}

success_msg_writer() <<
"**********************************************************************\n" <<
"Your wallet has been imported.\n" <<
"Use \"help\" command to see the list of available commands.\n" <<
"Always use \"exit\" command when closing simplewallet to save\n" <<
"current session's state. Otherwise, you will possibly need to synchronize \n" <<
"your wallet again. Your wallet key is NOT under risk anyway.\n" <<
"**********************************************************************";
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::close_wallet()
{
try {
Expand Down Expand Up @@ -877,6 +981,16 @@ void simple_wallet::synchronizationProgressUpdated(uint32_t current, uint32_t to
}
}

bool simple_wallet::export_keys(const std::vector<std::string>& args/* = std::vector<std::string>()*/) {
AccountKeys keys;
m_wallet->getAccountKeys(keys);
success_msg_writer(true) << "Private spend key: " << Common::podToHex(keys.spendSecretKey);
success_msg_writer(true) << "Private view key: " << Common::podToHex(keys.viewSecretKey);

return true;
}


bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/) {
success_msg_writer() << "available balance: " << m_currency.formatAmount(m_wallet->actualBalance()) <<
", locked amount: " << m_currency.formatAmount(m_wallet->pendingBalance());
Expand Down
3 changes: 3 additions & 0 deletions src/SimpleWallet/SimpleWallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace CryptoNote
bool run_console_handler();

bool new_wallet(const std::string &wallet_file, const std::string& password);
bool new_wallet(Crypto::SecretKey &secret_key, Crypto::SecretKey &view_key, const std::string &wallet_file, const std::string& password);
bool open_wallet(const std::string &wallet_file, const std::string& password);
bool close_wallet();

Expand All @@ -83,6 +84,7 @@ namespace CryptoNote
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
bool export_keys(const std::vector<std::string> &args = std::vector<std::string>());
bool show_incoming_transfers(const std::vector<std::string> &args);
bool show_payments(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args);
Expand Down Expand Up @@ -154,6 +156,7 @@ namespace CryptoNote
private:
std::string m_wallet_file_arg;
std::string m_generate_new;
std::string m_import_new;
std::string m_import_path;

std::string m_daemon_address;
Expand Down