device/trezor: passphrase entry on host
- simple device callback object added. Device can request passphrase/PIN entry via the callback or notify user some action is required - callback is routed to wallet2, which routes the callback to i_wallet_callback so CLI or GUI wallets can support passphrase entry for HW tokens - wallet: device open needs wallet callback first - passphrase protected device needs wallet callback so user can enter passphrase
This commit is contained in:
parent
58ce16d4d9
commit
318cc78457
|
@ -80,6 +80,14 @@ namespace hw {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class i_device_callback {
|
||||||
|
public:
|
||||||
|
virtual void on_button_request() {}
|
||||||
|
virtual void on_pin_request(epee::wipeable_string & pin) {}
|
||||||
|
virtual void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase) {}
|
||||||
|
virtual ~i_device_callback() = default;
|
||||||
|
};
|
||||||
|
|
||||||
class device {
|
class device {
|
||||||
protected:
|
protected:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -129,6 +137,7 @@ namespace hw {
|
||||||
virtual device_type get_type() const = 0;
|
virtual device_type get_type() const = 0;
|
||||||
|
|
||||||
virtual device_protocol_t device_protocol() const { return PROTOCOL_DEFAULT; };
|
virtual device_protocol_t device_protocol() const { return PROTOCOL_DEFAULT; };
|
||||||
|
virtual void set_callback(i_device_callback * callback) {};
|
||||||
|
|
||||||
/* ======================================================================= */
|
/* ======================================================================= */
|
||||||
/* LOCKER */
|
/* LOCKER */
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace trezor {
|
||||||
|
|
||||||
const uint32_t device_trezor_base::DEFAULT_BIP44_PATH[] = {0x8000002c, 0x80000080, 0x80000000};
|
const uint32_t device_trezor_base::DEFAULT_BIP44_PATH[] = {0x8000002c, 0x80000080, 0x80000000};
|
||||||
|
|
||||||
device_trezor_base::device_trezor_base() {
|
device_trezor_base::device_trezor_base(): m_callback(nullptr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,10 +332,6 @@ namespace trezor {
|
||||||
MDEBUG("on_passhprase_state_request");
|
MDEBUG("on_passhprase_state_request");
|
||||||
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
|
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
|
||||||
|
|
||||||
if (m_callback){
|
|
||||||
m_callback->on_passphrase_state_request(msg->state());
|
|
||||||
}
|
|
||||||
|
|
||||||
messages::common::PassphraseStateAck m;
|
messages::common::PassphraseStateAck m;
|
||||||
resp = call_raw(&m);
|
resp = call_raw(&m);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,17 +57,6 @@ namespace trezor {
|
||||||
#ifdef WITH_DEVICE_TREZOR
|
#ifdef WITH_DEVICE_TREZOR
|
||||||
class device_trezor_base;
|
class device_trezor_base;
|
||||||
|
|
||||||
/**
|
|
||||||
* Trezor device callbacks
|
|
||||||
*/
|
|
||||||
class trezor_callback {
|
|
||||||
public:
|
|
||||||
virtual void on_button_request() {};
|
|
||||||
virtual void on_pin_request(epee::wipeable_string & pin) {};
|
|
||||||
virtual void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase) {};
|
|
||||||
virtual void on_passphrase_state_request(const std::string & state) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TREZOR device template with basic functions
|
* TREZOR device template with basic functions
|
||||||
*/
|
*/
|
||||||
|
@ -79,7 +68,7 @@ namespace trezor {
|
||||||
mutable boost::mutex command_locker;
|
mutable boost::mutex command_locker;
|
||||||
|
|
||||||
std::shared_ptr<Transport> m_transport;
|
std::shared_ptr<Transport> m_transport;
|
||||||
std::shared_ptr<trezor_callback> m_callback;
|
i_device_callback * m_callback;
|
||||||
|
|
||||||
std::string full_name;
|
std::string full_name;
|
||||||
|
|
||||||
|
@ -218,7 +207,11 @@ namespace trezor {
|
||||||
return m_transport;
|
return m_transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<trezor_callback> getCallback(){
|
void set_callback(i_device_callback * callback) override {
|
||||||
|
m_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
i_device_callback * get_callback(){
|
||||||
return m_callback;
|
return m_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3786,6 +3786,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
|
||||||
{
|
{
|
||||||
auto rc = tools::wallet2::make_new(vm, false, password_prompter);
|
auto rc = tools::wallet2::make_new(vm, false, password_prompter);
|
||||||
m_wallet = std::move(rc.first);
|
m_wallet = std::move(rc.first);
|
||||||
|
m_wallet->callback(this);
|
||||||
if (!m_wallet)
|
if (!m_wallet)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
@ -3893,7 +3894,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
|
||||||
epee::wipeable_string password;
|
epee::wipeable_string password;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto rc = tools::wallet2::make_from_file(vm, false, m_wallet_file, password_prompter);
|
auto rc = tools::wallet2::make_from_file(vm, false, "", password_prompter);
|
||||||
m_wallet = std::move(rc.first);
|
m_wallet = std::move(rc.first);
|
||||||
password = std::move(std::move(rc.second).password());
|
password = std::move(std::move(rc.second).password());
|
||||||
if (!m_wallet)
|
if (!m_wallet)
|
||||||
|
@ -3901,6 +3902,8 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_wallet->callback(this);
|
||||||
|
m_wallet->load(m_wallet_file, password);
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
bool ready;
|
bool ready;
|
||||||
uint32_t threshold, total;
|
uint32_t threshold, total;
|
||||||
|
@ -4304,6 +4307,38 @@ boost::optional<epee::wipeable_string> simple_wallet::on_get_password(const char
|
||||||
return pwd_container->password();
|
return pwd_container->password();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void simple_wallet::on_button_request()
|
||||||
|
{
|
||||||
|
message_writer(console_color_white, false) << tr("Device requires attention");
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void simple_wallet::on_pin_request(epee::wipeable_string & pin)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
rdln::suspend_readline pause_readline;
|
||||||
|
#endif
|
||||||
|
std::string msg = tr("Enter device PIN");
|
||||||
|
auto pwd_container = tools::password_container::prompt(false, msg.c_str());
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!pwd_container, tools::error::password_entry_failed, tr("Failed to read device PIN"));
|
||||||
|
pin = pwd_container->password();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void simple_wallet::on_passphrase_request(bool on_device, epee::wipeable_string & passphrase)
|
||||||
|
{
|
||||||
|
if (on_device){
|
||||||
|
message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
rdln::suspend_readline pause_readline;
|
||||||
|
#endif
|
||||||
|
std::string msg = tr("Enter device passphrase");
|
||||||
|
auto pwd_container = tools::password_container::prompt(false, msg.c_str());
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!pwd_container, tools::error::password_entry_failed, tr("Failed to read device passphrase"));
|
||||||
|
passphrase = pwd_container->password();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bool is_init)
|
bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bool is_init)
|
||||||
{
|
{
|
||||||
if (!try_connect_to_daemon(is_init))
|
if (!try_connect_to_daemon(is_init))
|
||||||
|
|
|
@ -287,6 +287,9 @@ namespace cryptonote
|
||||||
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index);
|
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index);
|
||||||
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx);
|
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx);
|
||||||
virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason);
|
virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason);
|
||||||
|
virtual void on_button_request();
|
||||||
|
virtual void on_pin_request(epee::wipeable_string & pin);
|
||||||
|
virtual void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase);
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
friend class refresh_progress_reporter_t;
|
friend class refresh_progress_reporter_t;
|
||||||
|
|
|
@ -818,6 +818,24 @@ wallet_keys_unlocker::~wallet_keys_unlocker()
|
||||||
w.encrypt_keys(key);
|
w.encrypt_keys(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wallet_device_callback::on_button_request()
|
||||||
|
{
|
||||||
|
if (wallet)
|
||||||
|
wallet->on_button_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wallet_device_callback::on_pin_request(epee::wipeable_string & pin)
|
||||||
|
{
|
||||||
|
if (wallet)
|
||||||
|
wallet->on_pin_request(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wallet_device_callback::on_passphrase_request(bool on_device, epee::wipeable_string & passphrase)
|
||||||
|
{
|
||||||
|
if (wallet)
|
||||||
|
wallet->on_passphrase_request(on_device, passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
||||||
m_multisig_rescan_info(NULL),
|
m_multisig_rescan_info(NULL),
|
||||||
m_multisig_rescan_k(NULL),
|
m_multisig_rescan_k(NULL),
|
||||||
|
@ -929,7 +947,7 @@ std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_from_file(
|
||||||
return {nullptr, password_container{}};
|
return {nullptr, password_container{}};
|
||||||
}
|
}
|
||||||
auto wallet = make_basic(vm, unattended, opts, password_prompter);
|
auto wallet = make_basic(vm, unattended, opts, password_prompter);
|
||||||
if (wallet)
|
if (wallet && !wallet_file.empty())
|
||||||
{
|
{
|
||||||
wallet->load(wallet_file, pwd->password());
|
wallet->load(wallet_file, pwd->password());
|
||||||
}
|
}
|
||||||
|
@ -1071,15 +1089,16 @@ bool wallet2::reconnect_device()
|
||||||
hw::device &hwdev = lookup_device(m_device_name);
|
hw::device &hwdev = lookup_device(m_device_name);
|
||||||
hwdev.set_name(m_device_name);
|
hwdev.set_name(m_device_name);
|
||||||
hwdev.set_network_type(m_nettype);
|
hwdev.set_network_type(m_nettype);
|
||||||
|
hwdev.set_callback(get_device_callback());
|
||||||
r = hwdev.init();
|
r = hwdev.init();
|
||||||
if (!r){
|
if (!r){
|
||||||
LOG_PRINT_L2("Could not init device");
|
MERROR("Could not init device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = hwdev.connect();
|
r = hwdev.connect();
|
||||||
if (!r){
|
if (!r){
|
||||||
LOG_PRINT_L2("Could not connect to the device");
|
MERROR("Could not connect to the device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3441,6 +3460,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
|
||||||
hw::device &hwdev = lookup_device(m_device_name);
|
hw::device &hwdev = lookup_device(m_device_name);
|
||||||
THROW_WALLET_EXCEPTION_IF(!hwdev.set_name(m_device_name), error::wallet_internal_error, "Could not set device name " + m_device_name);
|
THROW_WALLET_EXCEPTION_IF(!hwdev.set_name(m_device_name), error::wallet_internal_error, "Could not set device name " + m_device_name);
|
||||||
hwdev.set_network_type(m_nettype);
|
hwdev.set_network_type(m_nettype);
|
||||||
|
hwdev.set_callback(get_device_callback());
|
||||||
THROW_WALLET_EXCEPTION_IF(!hwdev.init(), error::wallet_internal_error, "Could not initialize the device " + m_device_name);
|
THROW_WALLET_EXCEPTION_IF(!hwdev.init(), error::wallet_internal_error, "Could not initialize the device " + m_device_name);
|
||||||
THROW_WALLET_EXCEPTION_IF(!hwdev.connect(), error::wallet_internal_error, "Could not connect to the device " + m_device_name);
|
THROW_WALLET_EXCEPTION_IF(!hwdev.connect(), error::wallet_internal_error, "Could not connect to the device " + m_device_name);
|
||||||
m_account.set_device(hwdev);
|
m_account.set_device(hwdev);
|
||||||
|
@ -3947,6 +3967,7 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
|
||||||
auto &hwdev = lookup_device(device_name);
|
auto &hwdev = lookup_device(device_name);
|
||||||
hwdev.set_name(device_name);
|
hwdev.set_name(device_name);
|
||||||
hwdev.set_network_type(m_nettype);
|
hwdev.set_network_type(m_nettype);
|
||||||
|
hwdev.set_callback(get_device_callback());
|
||||||
|
|
||||||
m_account.create_from_device(hwdev);
|
m_account.create_from_device(hwdev);
|
||||||
m_key_device_type = m_account.get_device().get_type();
|
m_key_device_type = m_account.get_device().get_type();
|
||||||
|
@ -11940,4 +11961,29 @@ uint64_t wallet2::get_segregation_fork_height() const
|
||||||
void wallet2::generate_genesis(cryptonote::block& b) const {
|
void wallet2::generate_genesis(cryptonote::block& b) const {
|
||||||
cryptonote::generate_genesis_block(b, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
|
cryptonote::generate_genesis_block(b, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
|
||||||
}
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
wallet_device_callback * wallet2::get_device_callback()
|
||||||
|
{
|
||||||
|
if (!m_device_callback){
|
||||||
|
m_device_callback.reset(new wallet_device_callback(this));
|
||||||
|
}
|
||||||
|
return m_device_callback.get();
|
||||||
|
}//----------------------------------------------------------------------------------------------------
|
||||||
|
void wallet2::on_button_request()
|
||||||
|
{
|
||||||
|
if (0 != m_callback)
|
||||||
|
m_callback->on_button_request();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void wallet2::on_pin_request(epee::wipeable_string & pin)
|
||||||
|
{
|
||||||
|
if (0 != m_callback)
|
||||||
|
m_callback->on_pin_request(pin);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void wallet2::on_passphrase_request(bool on_device, epee::wipeable_string & passphrase)
|
||||||
|
{
|
||||||
|
if (0 != m_callback)
|
||||||
|
m_callback->on_passphrase_request(on_device, passphrase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,11 +98,26 @@ namespace tools
|
||||||
virtual void on_lw_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
virtual void on_lw_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
||||||
virtual void on_lw_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
virtual void on_lw_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
||||||
virtual void on_lw_money_spent(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
virtual void on_lw_money_spent(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
|
||||||
|
// Device callbacks
|
||||||
|
virtual void on_button_request() {}
|
||||||
|
virtual void on_pin_request(epee::wipeable_string & pin) {}
|
||||||
|
virtual void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase) {}
|
||||||
// Common callbacks
|
// Common callbacks
|
||||||
virtual void on_pool_tx_removed(const crypto::hash &txid) {}
|
virtual void on_pool_tx_removed(const crypto::hash &txid) {}
|
||||||
virtual ~i_wallet2_callback() {}
|
virtual ~i_wallet2_callback() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class wallet_device_callback : public hw::i_device_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wallet_device_callback(wallet2 * wallet): wallet(wallet) {};
|
||||||
|
void on_button_request() override;
|
||||||
|
void on_pin_request(epee::wipeable_string & pin) override;
|
||||||
|
void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase) override;
|
||||||
|
private:
|
||||||
|
wallet2 * wallet;
|
||||||
|
};
|
||||||
|
|
||||||
struct tx_dust_policy
|
struct tx_dust_policy
|
||||||
{
|
{
|
||||||
uint64_t dust_threshold;
|
uint64_t dust_threshold;
|
||||||
|
@ -154,6 +169,7 @@ namespace tools
|
||||||
{
|
{
|
||||||
friend class ::Serialization_portability_wallet_Test;
|
friend class ::Serialization_portability_wallet_Test;
|
||||||
friend class wallet_keys_unlocker;
|
friend class wallet_keys_unlocker;
|
||||||
|
friend class wallet_device_callback;
|
||||||
public:
|
public:
|
||||||
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
|
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
|
||||||
|
|
||||||
|
@ -1285,6 +1301,11 @@ namespace tools
|
||||||
void setup_new_blockchain();
|
void setup_new_blockchain();
|
||||||
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
|
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
|
||||||
|
|
||||||
|
wallet_device_callback * get_device_callback();
|
||||||
|
void on_button_request();
|
||||||
|
void on_pin_request(epee::wipeable_string & pin);
|
||||||
|
void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase);
|
||||||
|
|
||||||
cryptonote::account_base m_account;
|
cryptonote::account_base m_account;
|
||||||
boost::optional<epee::net_utils::http::login> m_daemon_login;
|
boost::optional<epee::net_utils::http::login> m_daemon_login;
|
||||||
std::string m_daemon_address;
|
std::string m_daemon_address;
|
||||||
|
@ -1396,6 +1417,7 @@ namespace tools
|
||||||
bool m_devices_registered;
|
bool m_devices_registered;
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
BOOST_CLASS_VERSION(tools::wallet2, 26)
|
BOOST_CLASS_VERSION(tools::wallet2, 26)
|
||||||
|
|
|
@ -219,6 +219,14 @@ namespace tools
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
struct password_entry_failed : public wallet_runtime_error
|
||||||
|
{
|
||||||
|
explicit password_entry_failed(std::string&& loc, const std::string &msg = "Password entry failed")
|
||||||
|
: wallet_runtime_error(std::move(loc), msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
const char* const file_error_messages[] = {
|
const char* const file_error_messages[] = {
|
||||||
"file already exists",
|
"file already exists",
|
||||||
"file not found",
|
"file not found",
|
||||||
|
|
Loading…
Reference in New Issue