2015-07-29 21:56:37 +00:00
|
|
|
#include "Transaction.hpp"
|
2015-07-22 20:23:42 +00:00
|
|
|
#include "Wallet.hpp"
|
2015-07-29 21:56:37 +00:00
|
|
|
|
2015-07-23 13:32:29 +00:00
|
|
|
#include <graphene/utilities/key_conversion.hpp>
|
2015-07-29 21:56:37 +00:00
|
|
|
#include <graphene/chain/protocol/fee_schedule.hpp>
|
|
|
|
|
|
2015-07-22 20:59:22 +00:00
|
|
|
#include <fc/crypto/aes.hpp>
|
|
|
|
|
#include <fc/io/json.hpp>
|
2015-07-22 20:23:42 +00:00
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
QString toQString(public_key_type k) { return QString::fromStdString(fc::variant(k).as_string()); }
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
Wallet::Wallet(QObject* parent)
|
2015-07-23 14:56:07 +00:00
|
|
|
:QObject(parent)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Wallet::~Wallet()
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
bool Wallet::open(QString file_path)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-24 17:57:47 +00:00
|
|
|
fc::path p(file_path.toStdString());
|
|
|
|
|
if( !fc::exists(p) )
|
2015-07-22 20:59:22 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
ilog("Unable to open wallet file '${f}'; it does not exist", ("f",p));
|
2015-07-22 20:59:22 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
_data = fc::json::from_file(p).as<wallet_file>();
|
2015-07-23 13:32:29 +00:00
|
|
|
|
|
|
|
|
for( const auto& key : _data.encrypted_private_keys )
|
|
|
|
|
{
|
|
|
|
|
if( key.second.label != string() )
|
2015-07-24 17:57:47 +00:00
|
|
|
_label_to_key[QString::fromStdString(key.second.label)] = toQString(key.first);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( key.second.encrypted_private_key.size() )
|
2015-07-29 19:50:12 +00:00
|
|
|
_available_private_keys.insert(key.first);
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
2015-07-22 20:59:22 +00:00
|
|
|
_wallet_file_path = p;
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
Q_EMIT isOpenChanged(true);
|
2015-07-22 20:59:22 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::isOpen()const
|
|
|
|
|
{
|
|
|
|
|
return _wallet_file_path != fc::path();
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::close()
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-22 20:23:42 +00:00
|
|
|
save();
|
2015-07-22 20:59:22 +00:00
|
|
|
_wallet_file_path = fc::path();
|
2015-07-29 19:50:12 +00:00
|
|
|
Q_EMIT isOpenChanged(false);
|
2015-07-22 20:23:42 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::save()
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
|
|
|
|
/// TODO: backup existing wallet file first.
|
2015-07-29 19:50:12 +00:00
|
|
|
fc::json::save_to_file(_data, _wallet_file_path);
|
2015-07-22 20:23:42 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::saveAs(QString file_path)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-23 13:32:29 +00:00
|
|
|
fc::path p(file_path.toStdString());
|
|
|
|
|
if( fc::exists(p) ) return false;
|
2015-07-29 19:50:12 +00:00
|
|
|
fc::json::save_to_file(_data, _wallet_file_path);
|
2015-07-23 13:32:29 +00:00
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::create(QString file_path, QString password, QString brain_key)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( isOpen() ) return false;
|
|
|
|
|
if( password == QString() ) return false;
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
fc::path p(file_path.toStdString());
|
|
|
|
|
if( fc::exists(p) )
|
2015-07-22 20:59:22 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
ilog("Unable to create wallet file '${f}' because a file with that name already exists.", ("f",p));
|
2015-07-22 20:59:22 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( brain_key == QString() )
|
|
|
|
|
{
|
|
|
|
|
auto key = fc::ecc::private_key::generate().get_secret();
|
|
|
|
|
brain_key.fromStdString( fc::variant(key).as_string() );
|
|
|
|
|
}
|
|
|
|
|
auto brainkey = brain_key.toStdString();
|
|
|
|
|
auto pw_str = password.toStdString();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto password_hash = fc::sha512::hash(pw_str.c_str(), pw_str.size());
|
|
|
|
|
_decrypted_master_key = fc::sha512::hash(fc::ecc::private_key::generate().get_secret());
|
|
|
|
|
_data.master_key_digest = fc::sha512::hash(_decrypted_master_key);
|
|
|
|
|
_data.encrypted_master_key = fc::aes_encrypt(password_hash, fc::raw::pack(_decrypted_master_key));
|
2015-07-22 20:59:22 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
_data.brain_key_digest = fc::sha512::hash(brainkey.c_str(), brainkey.size());
|
|
|
|
|
_data.encrypted_brain_key = fc::aes_encrypt(_decrypted_master_key, fc::raw::pack(brainkey));
|
2015-07-22 20:59:22 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QFileInfo(file_path).absoluteDir().mkpath(".");
|
|
|
|
|
fc::json::save_to_file(_data, p);
|
2015-07-22 20:59:22 +00:00
|
|
|
_wallet_file_path = p;
|
2015-07-29 19:50:12 +00:00
|
|
|
ilog("Created wallet file '${f}'", ("f", p));
|
2015-07-22 20:59:22 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::loadBrainKey(QString brain_key)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
|
|
|
|
|
|
|
|
|
if( brain_key == QString() ) return false;
|
|
|
|
|
auto brainkey = brain_key.toStdString();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
if( _data.brain_key_digest != fc::sha512::hash(brainkey.c_str(), brainkey.size()) )
|
2015-07-22 20:59:22 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
_brain_key = brain_key;
|
|
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::purgeBrainKey()
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
|
|
|
|
_data.encrypted_brain_key.resize(0);
|
|
|
|
|
_brain_key = QString();
|
|
|
|
|
return save();
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::hasBrainKey()const
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
|
|
|
|
return _brain_key != QString() || _data.encrypted_brain_key.size();
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-22 20:59:22 +00:00
|
|
|
QString Wallet::getBrainKey()
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return QString();
|
|
|
|
|
if( isLocked() ) return QString();
|
|
|
|
|
|
|
|
|
|
if( _brain_key != QString() )
|
|
|
|
|
return _brain_key;
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto dec_brain_key = fc::aes_decrypt(_decrypted_master_key, _data.encrypted_brain_key);
|
2015-07-22 20:59:22 +00:00
|
|
|
auto dec_brain_key_str = fc::raw::unpack<string>(dec_brain_key);
|
2015-07-29 19:50:12 +00:00
|
|
|
_brain_key.fromStdString(dec_brain_key_str);
|
2015-07-22 20:59:22 +00:00
|
|
|
return _brain_key;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::isLocked()const
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return true;
|
2015-07-29 19:50:12 +00:00
|
|
|
return _decrypted_master_key == fc::sha512();
|
|
|
|
|
}
|
|
|
|
|
bool Wallet::unlock(QString password)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
if( !isLocked() ) return true;
|
|
|
|
|
auto pw_str = password.toStdString();
|
|
|
|
|
auto password_hash = fc::sha512::hash(pw_str.c_str(), pw_str.size());
|
|
|
|
|
auto plain_txt = fc::aes_decrypt(password_hash, _data.encrypted_master_key);
|
|
|
|
|
_decrypted_master_key = fc::raw::unpack<fc::sha512>(plain_txt);
|
|
|
|
|
if( _data.master_key_digest != fc::sha512::hash(_decrypted_master_key) )
|
|
|
|
|
_decrypted_master_key = fc::sha512();
|
|
|
|
|
|
|
|
|
|
Q_EMIT isLockedChanged(isLocked());
|
|
|
|
|
return !isLocked();
|
|
|
|
|
} catch (const fc::exception& e) {
|
|
|
|
|
elog(e.to_detail_string());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Wallet::lock()
|
|
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
|
|
|
|
_brain_key = QString();
|
|
|
|
|
_decrypted_master_key = fc::sha512();
|
2015-07-23 14:56:07 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
Q_EMIT isLockedChanged(isLocked());
|
2015-07-22 20:59:22 +00:00
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::changePassword(QString new_password)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-22 22:37:00 +00:00
|
|
|
if( isLocked() ) return false;
|
|
|
|
|
|
|
|
|
|
auto pw_str = new_password.toStdString();
|
2015-07-29 19:50:12 +00:00
|
|
|
auto password_hash = fc::sha512::hash(pw_str.c_str(), pw_str.size());
|
|
|
|
|
_data.encrypted_master_key = fc::aes_encrypt(password_hash, fc::raw::pack(_decrypted_master_key));
|
2015-07-22 22:37:00 +00:00
|
|
|
|
|
|
|
|
save();
|
|
|
|
|
|
|
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::hasPrivateKey(QString pubkey, bool include_with_brain_key)
|
2015-07-23 14:56:07 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
auto pub = fc::variant(pubkey.toStdString()).as<public_key_type>();
|
2015-07-23 14:56:07 +00:00
|
|
|
auto itr = _data.encrypted_private_keys.find(pub);
|
|
|
|
|
if( itr == _data.encrypted_private_keys.end() )
|
|
|
|
|
return false;
|
2015-07-24 17:57:47 +00:00
|
|
|
if( itr->second.encrypted_private_key.size() )
|
2015-07-23 14:56:07 +00:00
|
|
|
return true;
|
|
|
|
|
if( include_with_brain_key && itr->second.brain_sequence >= 0 )
|
|
|
|
|
{
|
|
|
|
|
if( !itr->second.owner )
|
|
|
|
|
return true;
|
2015-07-29 19:50:12 +00:00
|
|
|
return hasPrivateKey(toQString(*itr->second.owner), include_with_brain_key);
|
2015-07-23 14:56:07 +00:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-07-22 20:23:42 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getPrivateKey(QString pubkey)
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
|
|
|
|
if( !isOpen() ) return QString();
|
|
|
|
|
if( isLocked() ) return QString();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto pub = fc::variant(pubkey.toStdString()).as<public_key_type>();
|
|
|
|
|
auto itr = _data.encrypted_private_keys.find(pub);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( itr == _data.encrypted_private_keys.end() )
|
|
|
|
|
return QString();
|
|
|
|
|
if( itr->second.encrypted_private_key.size() == 0 )
|
|
|
|
|
return QString();
|
2015-07-29 19:50:12 +00:00
|
|
|
auto plain = fc::aes_decrypt(_decrypted_master_key, itr->second.encrypted_private_key);
|
|
|
|
|
return QString::fromStdString(fc::raw::unpack<std::string>(plain));
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getPublicKey(QString wif_private_key)const
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
auto priv = graphene::utilities::wif_to_key(wif_private_key.toStdString());
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !priv ) return QString();
|
|
|
|
|
|
|
|
|
|
auto pub = public_key_type(priv->get_public_key());
|
2015-07-23 14:56:07 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
return QString::fromStdString(fc::variant(pub).as_string());
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getActivePrivateKey(QString owner_pub_key, uint32_t seq)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return QString();
|
2015-07-23 13:32:29 +00:00
|
|
|
if( isLocked() ) return QString();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto owner_wif_private_key = getPrivateKey(owner_pub_key);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( owner_wif_private_key == QString() ) return QString();
|
|
|
|
|
|
|
|
|
|
auto seed = (owner_wif_private_key + " " + QString::number(seq)).toStdString();
|
2015-07-29 19:50:12 +00:00
|
|
|
auto secret = fc::sha256::hash(fc::sha512::hash(seed.c_str(), seed.size()));
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto wif = graphene::utilities::key_to_wif(secret);
|
|
|
|
|
auto priv_key = graphene::utilities::wif_to_key(wif);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !priv_key ) return QString();
|
|
|
|
|
|
|
|
|
|
public_key_type active_pub_key(priv_key->get_public_key());
|
2015-07-29 19:50:12 +00:00
|
|
|
_data.encrypted_private_keys[active_pub_key].encrypted_private_key = fc::aes_encrypt(_decrypted_master_key, fc::raw::pack(wif));
|
|
|
|
|
_data.encrypted_private_keys[active_pub_key].owner = fc::variant(owner_pub_key.toStdString()).as<public_key_type>();
|
2015-07-23 14:56:07 +00:00
|
|
|
_data.encrypted_private_keys[active_pub_key].brain_sequence = seq;
|
2015-07-23 13:32:29 +00:00
|
|
|
_available_private_keys.insert( active_pub_key );
|
|
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
return QString::fromStdString(wif);
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getOwnerPrivateKey(uint32_t seq)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return QString();
|
2015-07-23 13:32:29 +00:00
|
|
|
if( isLocked() ) return QString();
|
|
|
|
|
if( !hasBrainKey() ) return QString();
|
|
|
|
|
|
|
|
|
|
auto seed = (getBrainKey() + " " + QString::number(seq)).toStdString();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto secret = fc::sha256::hash(fc::sha512::hash(seed.c_str(), seed.size()));
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto wif = graphene::utilities::key_to_wif(secret);
|
|
|
|
|
auto priv_key = graphene::utilities::wif_to_key(wif);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !priv_key ) return QString();
|
|
|
|
|
|
|
|
|
|
public_key_type owner_pub_key(priv_key->get_public_key());
|
2015-07-29 19:50:12 +00:00
|
|
|
_data.encrypted_private_keys[owner_pub_key].encrypted_private_key = fc::aes_encrypt(_decrypted_master_key, fc::raw::pack(wif));
|
2015-07-23 14:56:07 +00:00
|
|
|
_data.encrypted_private_keys[owner_pub_key].brain_sequence = seq;
|
2015-07-29 19:50:12 +00:00
|
|
|
_available_private_keys.insert(owner_pub_key);
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
return QString::fromStdString(wif);
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getActivePublicKey(QString active_pub, uint32_t seq)
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
return getPublicKey(getActivePrivateKey(active_pub, seq));
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getOwnerPublicKey(uint32_t seq)
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
return getPublicKey(getOwnerPrivateKey(seq));
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getKeyLabel(QString pubkey)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return QString();
|
2015-07-23 13:32:29 +00:00
|
|
|
public_key_type key = fc::variant( pubkey.toStdString() ).as<public_key_type>();
|
2015-07-29 19:50:12 +00:00
|
|
|
auto itr = _data.encrypted_private_keys.find(key);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( itr == _data.encrypted_private_keys.end() )
|
|
|
|
|
return QString();
|
2015-07-29 19:50:12 +00:00
|
|
|
return QString::fromStdString(itr->second.label);
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* The same label may not be assigned to more than one key, this method will
|
2015-07-24 17:57:47 +00:00
|
|
|
* fail if a key with the same label already exists.
|
2015-07-23 13:32:29 +00:00
|
|
|
*
|
|
|
|
|
* @return true if the label was set
|
|
|
|
|
*/
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::setKeyLabel(QString pubkey, QString label)
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
|
|
|
|
if( label == QString() ) // clear the label
|
|
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
auto pub = fc::variant(pubkey.toStdString()).as<public_key_type>();
|
2015-07-23 13:32:29 +00:00
|
|
|
auto old_label = _data.encrypted_private_keys[pub].label;
|
|
|
|
|
_data.encrypted_private_keys[pub].label = string();
|
|
|
|
|
if( old_label.size() )
|
2015-07-29 19:50:12 +00:00
|
|
|
_label_to_key.erase(QString::fromStdString(old_label));
|
2015-07-23 13:32:29 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto itr = _label_to_key.find(label);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( itr != _label_to_key.end() )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
_label_to_key[label] = pubkey;
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto pub = fc::variant(pubkey.toStdString()).as<public_key_type>();
|
2015-07-23 13:32:29 +00:00
|
|
|
_data.encrypted_private_keys[pub].label = label.toStdString();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QList<QPair<QString,QString>> Wallet::getAllPublicKeys(bool only_if_private)const
|
2015-07-23 13:32:29 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
QList< QPair<QString,QString>> result;
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !isOpen() ) return result;
|
|
|
|
|
|
|
|
|
|
for( const auto& item : _data.encrypted_private_keys )
|
|
|
|
|
{
|
|
|
|
|
if( only_if_private && !item.second.encrypted_private_key.size() ) continue;
|
2015-07-29 19:50:12 +00:00
|
|
|
result.push_back(qMakePair(toQString(item.first), QString::fromStdString(item.second.label)));
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
QString Wallet::getPublicKey(QString label)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
if( !isOpen() ) return QString::null;
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto itr = _label_to_key.find(label);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( itr != _label_to_key.end() )
|
2015-07-29 19:50:12 +00:00
|
|
|
return QString::null;
|
2015-07-23 13:32:29 +00:00
|
|
|
|
|
|
|
|
return itr->second;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** imports a public key and assigns it a label */
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::importPublicKey(QString pubkey, QString label)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
return setKeyLabel(pubkey, label);
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
/**
|
2015-07-22 20:23:42 +00:00
|
|
|
* @param wifkey a private key in (WIF) Wallet Import Format
|
2015-07-24 17:57:47 +00:00
|
|
|
* @pre !isLocked()
|
2015-07-22 20:23:42 +00:00
|
|
|
**/
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::importPrivateKey(QString wifkey, QString label)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-23 13:32:29 +00:00
|
|
|
if( isLocked() ) return false;
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto priv = graphene::utilities::wif_to_key(wifkey.toStdString());
|
|
|
|
|
if (!priv) return false;
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto p = priv->get_public_key();
|
|
|
|
|
auto pub = toQString(p);
|
|
|
|
|
importPublicKey(pub, label);
|
2015-07-23 13:32:29 +00:00
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
_data.encrypted_private_keys[p].encrypted_private_key = fc::aes_encrypt(_decrypted_master_key, fc::raw::pack(wifkey.toStdString()));
|
2015-07-23 13:32:29 +00:00
|
|
|
_available_private_keys.insert(p);
|
|
|
|
|
|
|
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** removes the key, its lablel and its private key */
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::removePublicKey(QString pubkey)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-23 13:32:29 +00:00
|
|
|
auto pub = fc::variant( pubkey.toStdString() ).as<public_key_type>();
|
|
|
|
|
_available_private_keys.erase(pub);
|
|
|
|
|
|
|
|
|
|
auto itr = _data.encrypted_private_keys.find(pub);
|
|
|
|
|
if( itr != _data.encrypted_private_keys.end() )
|
|
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
_label_to_key.erase(QString::fromStdString(itr->second.label));
|
2015-07-23 13:32:29 +00:00
|
|
|
_data.encrypted_private_keys.erase(itr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-07-22 20:23:42 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 17:57:47 +00:00
|
|
|
/** removes only the private key, keeping the public key and label
|
2015-07-23 13:32:29 +00:00
|
|
|
*
|
|
|
|
|
* @pre isOpen() && !isLocked()
|
|
|
|
|
**/
|
2015-07-29 19:50:12 +00:00
|
|
|
bool Wallet::removePrivateKey(QString pubkey)
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
2015-07-22 20:59:22 +00:00
|
|
|
if( !isOpen() ) return false;
|
2015-07-23 13:32:29 +00:00
|
|
|
if( isLocked() ) return false;
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto pub = fc::variant(pubkey.toStdString()).as<public_key_type>();
|
2015-07-23 13:32:29 +00:00
|
|
|
_data.encrypted_private_keys[pub].encrypted_private_key.resize(0);
|
|
|
|
|
_available_private_keys.erase(pub);
|
|
|
|
|
|
|
|
|
|
return true;
|
2015-07-22 20:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @pre !isLocked()
|
|
|
|
|
*/
|
2015-07-29 19:50:12 +00:00
|
|
|
vector<signature_type> Wallet::signDigest(const digest_type& d, const set<public_key_type>& keys)const
|
2015-07-22 20:23:42 +00:00
|
|
|
{
|
|
|
|
|
vector<signature_type> result;
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !isOpen() ) return result;
|
|
|
|
|
if( isLocked() ) return result;
|
|
|
|
|
|
|
|
|
|
result.reserve( keys.size() );
|
|
|
|
|
|
|
|
|
|
for( const auto& key : keys )
|
|
|
|
|
{
|
2015-07-29 19:50:12 +00:00
|
|
|
auto itr = _data.encrypted_private_keys.find(key);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( itr == _data.encrypted_private_keys.end() )
|
|
|
|
|
return vector<signature_type>();
|
|
|
|
|
if( itr->second.encrypted_private_key.size() == 0 )
|
|
|
|
|
return vector<signature_type>();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
auto plain_wif = fc::aes_decrypt(_decrypted_master_key, itr->second.encrypted_private_key);
|
2015-07-23 13:32:29 +00:00
|
|
|
auto wif = fc::raw::unpack<std::string>(plain_wif);
|
2015-07-29 19:50:12 +00:00
|
|
|
auto priv = graphene::utilities::wif_to_key(wif);
|
2015-07-23 13:32:29 +00:00
|
|
|
if( !priv ) return vector<signature_type>();
|
|
|
|
|
|
2015-07-29 19:50:12 +00:00
|
|
|
result.push_back(priv->sign_compact(d));
|
2015-07-23 13:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-22 20:23:42 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const flat_set<public_key_type>& Wallet::getAvailablePrivateKeys()const
|
|
|
|
|
{
|
|
|
|
|
return _available_private_keys;
|
|
|
|
|
}
|