Move OpenAlias console input back from libs

Library code should definitely not ask for console input unless
it's clearly an input function. Delegating the user interaction
part to the caller means it can now be used by a GUI, or have a
decision algorithm better adapted to a particular caller.
This commit is contained in:
moneromooo-monero 2017-07-27 11:28:53 +01:00
parent ab594cfee9
commit cb0b559451
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
7 changed files with 113 additions and 64 deletions

View file

@ -26,12 +26,9 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "common/command_line.h"
#include "common/i18n.h"
#include "common/dns_utils.h" #include "common/dns_utils.h"
#include "common/i18n.h"
#include "cryptonote_basic/cryptonote_basic_impl.h" #include "cryptonote_basic/cryptonote_basic_impl.h"
#include <cstring>
#include <sstream>
// check local first (in the event of static or in-source compilation of libunbound) // check local first (in the event of static or in-source compilation of libunbound)
#include "unbound.h" #include "unbound.h"
@ -405,7 +402,7 @@ std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec
return addresses; return addresses;
} }
std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, bool cli_confirm) std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm)
{ {
// attempt to get address from dns query // attempt to get address from dns query
auto addresses = addresses_from_url(url, dnssec_valid); auto addresses = addresses_from_url(url, dnssec_valid);
@ -414,44 +411,7 @@ std::string get_account_address_as_str_from_url(const std::string& url, bool& dn
LOG_ERROR("wrong address: " << url); LOG_ERROR("wrong address: " << url);
return {}; return {};
} }
// for now, move on only if one address found return dns_confirm(url, addresses, dnssec_valid);
if (addresses.size() > 1)
{
LOG_ERROR("not yet supported: Multiple Monero addresses found for given URL: " << url);
return {};
}
if (!cli_confirm)
return addresses[0];
// prompt user for confirmation.
// inform user of DNSSEC validation status as well.
std::string dnssec_str;
if (dnssec_valid)
{
dnssec_str = tr("DNSSEC validation passed");
}
else
{
dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!");
}
std::stringstream prompt;
prompt << tr("For URL: ") << url
<< ", " << dnssec_str << std::endl
<< tr(" Monero Address = ") << addresses[0]
<< std::endl
<< tr("Is this OK? (Y/n) ")
;
// prompt the user for confirmation given the dns query and dnssec status
std::string confirm_dns_ok = command_line::input_line(prompt.str());
if (std::cin.eof())
{
return {};
}
if (!command_line::is_yes(confirm_dns_ok))
{
std::cout << tr("you have cancelled the transfer request") << std::endl;
return {};
}
return addresses[0];
} }
namespace namespace

View file

@ -163,7 +163,7 @@ namespace dns_utils
std::string address_from_txt_record(const std::string& s); std::string address_from_txt_record(const std::string& s);
std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid); std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid);
std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, bool cli_confirm = true); std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> confirm_dns);
bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls); bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);

View file

@ -308,13 +308,13 @@ namespace cryptonote {
, crypto::hash8& payment_id , crypto::hash8& payment_id
, bool testnet , bool testnet
, const std::string& str_or_url , const std::string& str_or_url
, bool cli_confirm , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm
) )
{ {
if (get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url)) if (get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url))
return true; return true;
bool dnssec_valid; bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, cli_confirm); std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm);
return !address_str.empty() && return !address_str.empty() &&
get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str); get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str);
} }
@ -323,12 +323,12 @@ namespace cryptonote {
cryptonote::account_public_address& address cryptonote::account_public_address& address
, bool testnet , bool testnet
, const std::string& str_or_url , const std::string& str_or_url
, bool cli_confirm , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm
) )
{ {
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
return get_account_address_from_str_or_url(address, has_payment_id, payment_id, testnet, str_or_url, cli_confirm); return get_account_address_from_str_or_url(address, has_payment_id, payment_id, testnet, str_or_url, dns_confirm);
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {

View file

@ -67,6 +67,15 @@ namespace cryptonote {
}; };
#pragma pack (pop) #pragma pack (pop)
namespace
{
std::string return_first_address(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};
return addresses[0];
}
}
/************************************************************************/ /************************************************************************/
/* Cryptonote helper functions */ /* Cryptonote helper functions */
@ -109,14 +118,14 @@ namespace cryptonote {
, crypto::hash8& payment_id , crypto::hash8& payment_id
, bool testnet , bool testnet
, const std::string& str_or_url , const std::string& str_or_url
, bool cli_confirm = true , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
); );
bool get_account_address_from_str_or_url( bool get_account_address_from_str_or_url(
cryptonote::account_public_address& address cryptonote::account_public_address& address
, bool testnet , bool testnet
, const std::string& str_or_url , const std::string& str_or_url
, bool cli_confirm = true , std::function<std::string(const std::string&, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
); );
bool is_coinbase(const transaction& tx); bool is_coinbase(const transaction& tx);

View file

@ -256,7 +256,8 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, true, args.front())) if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, true, args.front()))
{ {
bool dnssec_valid; bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid); std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid,
[](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];});
if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, false, address_str)) if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, false, address_str))
{ {
if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, true, address_str)) if(!cryptonote::get_account_integrated_address_from_str(adr, has_payment_id, payment_id, true, address_str))

View file

@ -281,6 +281,42 @@ namespace
{ {
return boost::lexical_cast<std::string>(version >> 16) + "." + boost::lexical_cast<std::string>(version & 0xffff); return boost::lexical_cast<std::string>(version >> 16) + "." + boost::lexical_cast<std::string>(version & 0xffff);
} }
std::string oa_prompter(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};
// prompt user for confirmation.
// inform user of DNSSEC validation status as well.
std::string dnssec_str;
if (dnssec_valid)
{
dnssec_str = tr("DNSSEC validation passed");
}
else
{
dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!");
}
std::stringstream prompt;
prompt << tr("For URL: ") << url
<< ", " << dnssec_str << std::endl
<< tr(" Monero Address = ") << addresses[0]
<< std::endl
<< tr("Is this OK? (Y/n) ")
;
// prompt the user for confirmation given the dns query and dnssec status
std::string confirm_dns_ok = command_line::input_line(prompt.str());
if (std::cin.eof())
{
return {};
}
if (!command_line::is_yes(confirm_dns_ok))
{
std::cout << tr("you have cancelled the transfer request") << std::endl;
return {};
}
return addresses[0];
}
} }
@ -2215,7 +2251,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
cryptonote::tx_destination_entry de; cryptonote::tx_destination_entry de;
bool has_payment_id; bool has_payment_id;
crypto::hash8 new_payment_id; crypto::hash8 new_payment_id;
if (!cryptonote::get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i])) if (!cryptonote::get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -2713,7 +2749,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
bool has_payment_id; bool has_payment_id;
crypto::hash8 new_payment_id; crypto::hash8 new_payment_id;
cryptonote::account_public_address address; cryptonote::account_public_address address;
if (!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[0])) if (!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[0], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -3273,7 +3309,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1])) if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -3375,7 +3411,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), local_args[2])) if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), local_args[2], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -3527,7 +3563,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1])) if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), args[1], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -4045,7 +4081,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id8; crypto::hash8 payment_id8;
if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), args[1])) if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), args[1], oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;
@ -4236,7 +4272,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), address_string)) if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), address_string, oa_prompter))
{ {
fail_msg_writer() << tr("failed to parse address"); fail_msg_writer() << tr("failed to parse address");
return true; return true;

View file

@ -352,10 +352,25 @@ namespace tools
cryptonote::tx_destination_entry de; cryptonote::tx_destination_entry de;
bool has_payment_id; bool has_payment_id;
crypto::hash8 new_payment_id; crypto::hash8 new_payment_id;
if(!get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), it->address, false)) er.message = "";
if(!get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), it->address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Monero address found at ") + url;
return {};
}
return addresses[0];
}))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address; if (er.message.empty())
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
return false; return false;
} }
de.amount = it->amount; de.amount = it->amount;
@ -1018,10 +1033,23 @@ namespace tools
cryptonote::account_public_address address; cryptonote::account_public_address address;
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id; crypto::hash8 payment_id;
if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), req.address, false)) er.message = "";
if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Monero address found at ") + url;
return {};
}
return addresses[0];
}))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "";
return false; return false;
} }
@ -1412,10 +1440,25 @@ namespace tools
bool has_payment_id; bool has_payment_id;
crypto::hash8 payment_id8; crypto::hash8 payment_id8;
crypto::hash payment_id = cryptonote::null_hash; crypto::hash payment_id = cryptonote::null_hash;
if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), req.address, false)) er.message = "";
if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
if (!dnssec_valid)
{
er.message = std::string("Invalid DNSSEC for ") + url;
return {};
}
if (addresses.empty())
{
er.message = std::string("No Monero address found at ") + url;
return {};
}
return addresses[0];
}))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address; if (er.message.empty())
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
return false; return false;
} }
if (has_payment_id) if (has_payment_id)