From c14c7e16839b6cfe32527f2b01a9a1507e3d419e Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 17 Sep 2014 17:38:54 -0400 Subject: [PATCH] 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(-) 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; + } }