diff --git a/libraries/api/wallet_api.json b/libraries/api/wallet_api.json index 50c077ef6..88ce68a26 100644 --- a/libraries/api/wallet_api.json +++ b/libraries/api/wallet_api.json @@ -171,6 +171,32 @@ ], "prerequisites" : ["wallet_unlocked"] }, + { + "method_name": "wallet_import_keys_from_json", + "description": "Imports anything that looks like a private key from the given JSON file.", + "return_type": "void", + "parameters" : + [ + { + "name" : "json_filename", + "type" : "filename", + "description" : "the full path and filename of JSON wallet to import", + "example" : "/path/to/exported_wallet.json" + }, + { + "name" : "imported_wallet_passphrase", + "type" : "passphrase", + "description" : "passphrase for encrypted keys" + }, + { + "name" : "account", + "type" : "account_name", + "description" : "Account into which to import keys." + } + ], + "prerequisites" : ["json_authenticated"], + "aliases" : ["import_keys_from_json"] + }, { "method_name": "wallet_close", "description": "Closes the curent wallet if one is open", diff --git a/libraries/client/wallet_api.cpp b/libraries/client/wallet_api.cpp index 558f45ee2..c264a8df5 100644 --- a/libraries/client/wallet_api.cpp +++ b/libraries/client/wallet_api.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include @@ -71,6 +73,72 @@ void detail::client_impl::wallet_backup_restore( const fc::path& json_filename, reschedule_delegate_loop(); } +// This should be able to get an encrypted private key or WIF key out of any reasonable JSON object. +void read_keys( const fc::variant& vo, vector& keys, const string& password ) +{ + ilog("@n read_keys"); + ilog("@n ${o}", ("o", vo)); + try { + auto wif_key = vo.as_string(); + auto key = bts::utilities::wif_to_key( wif_key ); + if( key.valid() ) + keys.push_back(*key); + } + catch (...) { + ilog("@n I couldn't parse that as a wif key: ${vo}", ("vo", vo)); + } + try { + auto bytes = vo.as>(); + fc::sha512 password_bytes = fc::sha512::hash( password.c_str(), password.size() ); + const auto plain_text = fc::aes_decrypt( password_bytes, bytes ); + keys.push_back( fc::raw::unpack( plain_text ) ); + } + catch (const fc::exception& e) { + ilog("@n I couldn't parse that as a byte array: ${vo}", ("vo", vo)); + ilog("@n ${e}", ("e", e)); + } + try { + auto obj = vo.get_object(); + ilog("@n it's an object ${o}", ("o", obj)); + for( auto kv : obj ) + { + read_keys( kv.value(), keys, password ); + } + } catch (...) { + ilog("@n I couldn't parse that as an object: ${o}", ("o", vo)); + } + try { + auto arr = vo.as>(); + for( auto obj : arr ) + { + read_keys( obj, keys, password ); + } + ilog("@n it's an object ${o}", ("o", vo)); + } catch (...) { + ilog("@n I couldn't parse that as an array: ${o}", ("o", vo)); + } + ilog("@n I couldn't parse that as anything!: ${o}", ("o", vo)); +} + +void detail::client_impl::wallet_import_keys_from_json( const fc::path& json_filename, + const string& imported_wallet_passphrase, + const string& account ) +{ + FC_ASSERT( fc::exists( json_filename ) ); + FC_ASSERT( _wallet->is_open() ); + + vector keys; + auto object = fc::json::from_file( json_filename ); + + read_keys( object, keys, imported_wallet_passphrase ); + ilog("@n Read keys: ${keys}", ("keys", keys)); + for( auto key : keys ) + { + _wallet->import_private_key( key, account, false ); + ilog("@n imported key: ${key}", ("key", key)); + } +} + bool detail::client_impl::wallet_set_automatic_backups( bool enabled ) { _wallet->set_automatic_backups( enabled );