From f437cb58bf4556ecd18e570a89036c590ff2c997 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 17 Sep 2014 17:38:15 -0400 Subject: Simplewallet should now resolve urls to addresses Simplewallet should now do a DNS query on an address if it fails to convert the given string to a binary representation of an address (base58->binary). It will prompt the user, telling of what the "url" passed was, what monero address it translated to, and whether or not DNSSEC validation was a success, and ask for a confirmation that these are all acceptable. --- src/simplewallet/simplewallet.cpp | 55 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'src/simplewallet/simplewallet.cpp') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index fbe7c4730..07b2f7935 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -910,8 +911,58 @@ bool simple_wallet::transfer(const std::vector &args_) cryptonote::tx_destination_entry de; if(!get_account_address_from_str(de.addr, m_wallet->testnet(), local_args[i])) { - fail_msg_writer() << "wrong address: " << local_args[i]; - return true; + // if treating as an address fails, try as url + bool dnssec_ok = false; + std::string addr_from_dns; + std::string url = local_args[i]; + + // attempt to get address from dns query + addr_from_dns = tools::wallet2::address_from_url(url, dnssec_ok); + + // if string not empty, see if it's an address + if (addr_from_dns.size()) + { + if (get_account_address_from_str(de.addr, addr_from_dns)) + { + // if it was an address, prompt user for confirmation. + // inform user of DNSSEC validation status as well. + + std::string dnssec_str; + if (dnssec_ok) + { + dnssec_str = "DNSSEC validation PASSED!"; + } + else + { + dnssec_str = "DNSSEC validation FAILED!"; + } + std::stringstream prompt; + prompt << "For URL: " << url + << "," << dnssec_str + << " Monero Address = " << addr_from_dns + << std::endl + << "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 (confirm_dns_ok != "Y" && confirm_dns_ok != "y" && confirm_dns_ok != "Yes" && confirm_dns_ok != "yes") + { + fail_msg_writer() << "User terminated transfer request, disagreed with dns result from url: " << url; + return true; + } + } + else + { + fail_msg_writer() << "Failed to get a monero address from: " << local_args[i]; + return true; + } + } + else + { + fail_msg_writer() << "wrong address: " << local_args[i]; + return true; + } } bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); -- cgit v1.2.3 From c14c7e16839b6cfe32527f2b01a9a1507e3d419e Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 17 Sep 2014 17:38:54 -0400 Subject: change to allow (at least a bit) for multiple TXT records --- src/common/dns_utils.cpp | 15 ++++++++++----- src/common/dns_utils.h | 8 ++++---- src/simplewallet/simplewallet.cpp | 17 ++++++++++------- src/wallet/wallet2.cpp | 21 +++++++++++++++------ src/wallet/wallet2.h | 2 +- tests/unit_tests/address_from_url.cpp | 13 +++++++++---- tests/unit_tests/dns_resolver.cpp | 11 ++++++++--- 7 files changed, 57 insertions(+), 30 deletions(-) (limited to 'src/simplewallet/simplewallet.cpp') diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 2ad98ca27..6755a30b2 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -89,7 +89,7 @@ std::vector DNSResolver::get_ipv4(const std::string& url) { if (result.ptr->havedata) { - for (int i=0; result.ptr->data[i] != NULL; i++) + for (size_t i=0; result.ptr->data[i] != NULL; i++) { char as_str[INET_ADDRSTRLEN]; @@ -115,7 +115,7 @@ std::vector DNSResolver::get_ipv6(const std::string& url) { if (result.ptr->havedata) { - for (int i=0; result.ptr->data[i] != NULL; i++) + for (size_t i=0; result.ptr->data[i] != NULL; i++) { char as_str[INET6_ADDRSTRLEN]; @@ -131,19 +131,24 @@ std::vector DNSResolver::get_ipv6(const std::string& url) return retval; } -std::string DNSResolver::get_txt_record(const std::string& url) +std::vector DNSResolver::get_txt_record(const std::string& url) { ub_result_ptr result; + std::vector records; // call DNS resolver, blocking. if return value not zero, something went wrong if (!ub_resolve(m_data->m_ub_context, url.c_str(), LDNS_RR_TYPE_TXT, LDNS_RR_CLASS_IN, &(result.ptr))) { if (result.ptr->havedata) { - return std::string(result.ptr->data[0]); + for (size_t i=0; result.ptr->data[i] != NULL; i++) + { + records.push_back(result.ptr->data[i]); + } } } - return std::string(); + + return records; } DNSResolver& DNSResolver::instance() diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index ff54c1e07..e57e55861 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -82,15 +82,15 @@ public: std::vector get_ipv6(const std::string& url); /** - * @brief gets a TXT record from a DNS query for the supplied URL; - * if no TXT record present returns an empty string. + * @brief gets all TXT records from a DNS query for the supplied URL; + * if no TXT record present returns an empty vector. * * @param url A string containing a URL to query for * - * @return A string containing a TXT record; or an empty string + * @return A vector of strings containing a TXT record; or an empty vector */ // TODO: modify this to accomodate DNSSEC - std::string get_txt_record(const std::string& url); + std::vector get_txt_record(const std::string& url); /** * @brief Gets the singleton instance of DNSResolver diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 07b2f7935..e2564236b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -913,16 +913,15 @@ bool simple_wallet::transfer(const std::vector &args_) { // if treating as an address fails, try as url bool dnssec_ok = false; - std::string addr_from_dns; std::string url = local_args[i]; // attempt to get address from dns query - addr_from_dns = tools::wallet2::address_from_url(url, dnssec_ok); + auto addresses_from_dns = tools::wallet2::addresses_from_url(url, dnssec_ok); - // if string not empty, see if it's an address - if (addr_from_dns.size()) + // for now, move on only if one address found + if (addresses_from_dns.size() == 1) { - if (get_account_address_from_str(de.addr, addr_from_dns)) + if (get_account_address_from_str(de.addr, addresses_from_dns[0])) { // if it was an address, prompt user for confirmation. // inform user of DNSSEC validation status as well. @@ -938,8 +937,8 @@ bool simple_wallet::transfer(const std::vector &args_) } std::stringstream prompt; prompt << "For URL: " << url - << "," << dnssec_str - << " Monero Address = " << addr_from_dns + << "," << dnssec_str << std::endl + << " Monero Address = " << addresses_from_dns[0] << std::endl << "Is this OK? (Y/n) " ; @@ -958,6 +957,10 @@ bool simple_wallet::transfer(const std::vector &args_) return true; } } + else if (addresses_from_dns.size() > 1) + { + tools::fail_msg_writer() << "Multiple Monero addresses found for given URL: " << url << ", this is not yet supported."; + } else { fail_msg_writer() << "wrong address: " << local_args[i]; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index adc9c1f61..3161f3b16 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -831,21 +831,30 @@ std::vector> split_amounts( * * @return a monero address (as a string) or an empty string */ -std::string wallet2::address_from_url(const std::string& url, bool& dnssec_valid) +std::vector wallet2::addresses_from_url(const std::string& url, bool& dnssec_valid) { // TODO: update this correctly once DNSResolver::get_txt_record() supports it. dnssec_valid = false; - // get txt record - std::string txt = tools::DNSResolver::instance().get_txt_record(url); - if (txt.size()) + std::vector addresses; + // get txt records + auto records = tools::DNSResolver::instance().get_txt_record(url); + + // for each txt record, try to find a monero address in it. + for (auto& rec : records) { - return address_from_txt_record(txt); + std::string addr = address_from_txt_record(rec); + if (addr.size()) + { + addresses.push_back(addr); + } } - return std::string(); + + return addresses; } //---------------------------------------------------------------------------------------------------- +// TODO: parse the string in a less stupid way, probably with regex std::string wallet2::address_from_txt_record(const std::string& s) { // make sure the txt record has "oa1:xmr" and find it diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 6e6d7cafb..90918677e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -196,7 +196,7 @@ namespace tools static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); - static std::string address_from_url(const std::string& url, bool& dnssec_valid); + static std::vector addresses_from_url(const std::string& url, bool& dnssec_valid); static std::string address_from_txt_record(const std::string& s); private: diff --git a/tests/unit_tests/address_from_url.cpp b/tests/unit_tests/address_from_url.cpp index 180257189..22301d568 100644 --- a/tests/unit_tests/address_from_url.cpp +++ b/tests/unit_tests/address_from_url.cpp @@ -85,18 +85,23 @@ TEST(AddressFromURL, Success) std::string addr = "46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em"; bool dnssec_result = false; - std::string res = tools::wallet2::address_from_url("donate.monero.cc", dnssec_result); - EXPECT_STREQ(addr.c_str(), res.c_str()); + std::vector addresses = tools::wallet2::addresses_from_url("donate.monero.cc", dnssec_result); + + EXPECT_EQ(1, addresses.size()); + if (addresses.size() == 1) + { + EXPECT_STREQ(addr.c_str(), addresses[0].c_str()); + } } TEST(AddressFromURL, Failure) { bool dnssec_result = false; - std::string res = tools::wallet2::address_from_url("example.invalid", dnssec_result); + std::vector addresses = tools::wallet2::addresses_from_url("example.invalid", dnssec_result); ASSERT_FALSE(dnssec_result); - ASSERT_STREQ("", res.c_str()); + ASSERT_EQ(0, addresses.size()); } diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp index 3b52a5f40..27e981ef1 100644 --- a/tests/unit_tests/dns_resolver.cpp +++ b/tests/unit_tests/dns_resolver.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include "gtest/gtest.h" @@ -97,8 +98,12 @@ TEST(DNSResolver, IPv6Failure) TEST(DNSResolver, GetTXTRecord) { - std::string txt = tools::DNSResolver::instance().get_txt_record("donate.monero.cc"); - std::cout << "TXT record for donate.monero.cc: " << txt << std::endl; + std::vector records = tools::DNSResolver::instance().get_txt_record("donate.monero.cc"); - EXPECT_STRNE("", txt.c_str()); + EXPECT_NE(0, records.size()); + + for (auto& rec : records) + { + std::cout << "TXT record for donate.monero.cc: " << rec << std::endl; + } } -- cgit v1.2.3 From 24f325a33d149125b7cf5e91615cbc9e5b686a2b Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 17 Sep 2014 18:37:32 -0400 Subject: Fixed artifacts from cherry-picking devel->master --- CMakeLists.txt | 3 ++- src/simplewallet/simplewallet.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/simplewallet/simplewallet.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f8222a35..c9a794c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ cmake_minimum_required(VERSION 2.8.6) +set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + if (NOT DEFINED ENV{DEVELOPER_LOCAL_TOOLS}) message(STATUS "Could not find DEVELOPER_LOCAL_TOOLS in env") set(BOOST_IGNORE_SYSTEM_PATHS_DEFAULT OFF) @@ -44,7 +46,6 @@ endif() message(STATUS "BOOST_IGNORE_SYSTEM_PATHS defaults to ${BOOST_IGNORE_SYSTEM_PATHS_DEFAULT}") option(BOOST_IGNORE_SYSTEM_PATHS "Ignore boost system paths for local boost ins tallation" $BOOST_IGNORE_SYSTEM_PATHS_DEFAULT) - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release") enable_testing() diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index e2564236b..37974088a 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -921,7 +921,7 @@ bool simple_wallet::transfer(const std::vector &args_) // for now, move on only if one address found if (addresses_from_dns.size() == 1) { - if (get_account_address_from_str(de.addr, addresses_from_dns[0])) + if (get_account_address_from_str(de.addr, m_wallet->testnet(), addresses_from_dns[0])) { // if it was an address, prompt user for confirmation. // inform user of DNSSEC validation status as well. @@ -959,7 +959,7 @@ bool simple_wallet::transfer(const std::vector &args_) } else if (addresses_from_dns.size() > 1) { - tools::fail_msg_writer() << "Multiple Monero addresses found for given URL: " << url << ", this is not yet supported."; + fail_msg_writer() << "Multiple Monero addresses found for given URL: " << url << ", this is not yet supported."; } else { -- cgit v1.2.3