diff options
Diffstat (limited to 'Swiften/JID')
-rw-r--r-- | Swiften/JID/JID.cpp | 70 | ||||
-rw-r--r-- | Swiften/JID/JID.h | 6 | ||||
-rw-r--r-- | Swiften/JID/UnitTest/JIDTest.cpp | 51 |
3 files changed, 124 insertions, 3 deletions
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index fff88e9..eb72014 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -13,6 +13,7 @@ #include <Swiften/Base/String.h> #include <Swiften/IDN/IDNConverter.h> #include <Swiften/JID/JID.h> +#include <Swiften/Network/HostAddress.h> #ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER #include <memory> @@ -71,6 +72,33 @@ JID::JID(const std::string& node, const std::string& domain, const std::string& nameprepAndSetComponents(node, domain, resource); } +JID::JID(const JID& other) { + this->operator=(other); +} + +JID::JID(JID&& other) { + this->operator=(std::move(other)); +} + +JID& JID::operator=(const JID& other) { + valid_ = other.valid_; + node_ = other.node_; + domain_ = other.domain_; + hasResource_ = other.hasResource_; + resource_ = other.resource_; + return *this; +} + +JID& JID::operator=(JID&& other) { + valid_ = other.valid_; + other.valid_ = false; + node_ = std::move(other.node_); + domain_ = std::move(other.domain_); + hasResource_ = other.hasResource_; + resource_ = std::move(other.resource_); + return *this; +} + void JID::initializeFromString(const std::string& jid) { if (String::beginsWith(jid, '@')) { valid_ = false; @@ -97,14 +125,49 @@ void JID::initializeFromString(const std::string& jid) { } } +void JID::setComponents(const std::string& node, const std::string& domain, const std::string& resource) { + domain_ = domain; + try { + node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); + resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); + } + catch (...) { + valid_ = false; + return; + } +} void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { - if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) { + if (domain.empty() || (hasResource_ && resource.empty())) { valid_ = false; return; } - if (hasResource_ && resource.empty()) { + // Handling IPv6 addresses according to RFC 3986 rules + // saying that they are enclosed in square brackets + // which we have to remove when passing to HostAddress + if (domain.size() > 2 && domain.front() == '[' && domain.back() == ']') { + auto inner = std::string(domain.begin() + 1, domain.end() - 1); + auto hostAddress = HostAddress::fromString(inner); + if (hostAddress && hostAddress->isValid()) { + setComponents(node, domain, resource); + return; + } + } + + const auto isAnyOfNonNumericAndNotDot = std::any_of(std::begin(domain), std::end(domain), [](char c) {return !::isdigit(c) && c != '.'; }); + const auto isDomainAllNumeric = std::all_of(std::begin(domain), std::end(domain), [](char c) {return ::isdigit(c) ; }); + + //Prevent Windows validating non-dotted integers as OK if it can unpack them + if (!isAnyOfNonNumericAndNotDot && !isDomainAllNumeric) { + auto hostAddress = HostAddress::fromString(domain); + if (hostAddress && hostAddress->isValid()) { + setComponents(node, domain, resource); + return; + } + } + + if (!isAnyOfNonNumericAndNotDot || !idnConverter->getIDNAEncoded(domain)) { valid_ = false; return; } @@ -118,7 +181,8 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); } resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); - } catch (...) { + } + catch (...) { valid_ = false; return; } diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index dc92f53..aecc7cb 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h @@ -75,6 +75,11 @@ namespace Swift { */ JID(const std::string& node, const std::string& domain, const std::string& resource); + JID(const JID& other); + JID(JID&& other); + JID& operator=(const JID& other); + JID& operator=(JID&& other); + /** * @return Is a correctly-formatted JID. */ @@ -184,6 +189,7 @@ namespace Swift { private: void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource); + void setComponents(const std::string& node, const std::string& domain, const std::string& resource); void initializeFromString(const std::string&); private: diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index 0753fb5..fc7583f 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp @@ -24,6 +24,7 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testConstructorWithString_OnlyDomainDotStrippedOff); CPPUNIT_TEST(testConstructorWithString_InvalidOnlyDomainSingleDot); CPPUNIT_TEST(testConstructorWithString_InvalidDomain); + CPPUNIT_TEST(testConstructorWithString_InvalidDomainOnlyDigits); CPPUNIT_TEST(testConstructorWithString_InvalidDomainEmptyLabel); CPPUNIT_TEST(testConstructorWithString_UpperCaseNode); CPPUNIT_TEST(testConstructorWithString_UpperCaseDomain); @@ -71,6 +72,12 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testGetUnescapedNode); CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); CPPUNIT_TEST(testStringPrepFailures); + CPPUNIT_TEST(testConstructorWithString_DomainIPv4); + CPPUNIT_TEST(testConstructorWithString_DomainNOTIPv4); + CPPUNIT_TEST(testConstructorWithString_ValidDomainNOTIPv4); + CPPUNIT_TEST(testConstructorWithString_DomainIPv6); + CPPUNIT_TEST(testConstructorWithString_DomainInvalidIPv6); + CPPUNIT_TEST(testConstructorWithString_DomainIPv6NoBrackets); CPPUNIT_TEST_SUITE_END(); public: @@ -156,6 +163,10 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT(!JID("foo@bar,baz").isValid()); } + void testConstructorWithString_InvalidDomainOnlyDigits() { + CPPUNIT_ASSERT(!JID("1234").isValid()); + } + void testConstructorWithString_InvalidDomainEmptyLabel() { CPPUNIT_ASSERT(!JID("foo@bar..").isValid()); } @@ -492,6 +503,46 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); } + + void testConstructorWithString_DomainIPv4() { + JID testling("foo@192.34.12.1/resource"); + + CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("192.34.12.1"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); + CPPUNIT_ASSERT(!testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainNOTIPv4() { + JID testling("foo@500.34.12.1/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_ValidDomainNOTIPv4() { + JID testling("foo@500.34.12.1a/resource"); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainIPv6() { + JID testling("foo@[fe80::a857:33ff:febd:3580]/resource"); + + CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); + CPPUNIT_ASSERT_EQUAL(std::string("[fe80::a857:33ff:febd:3580]"), testling.getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); + CPPUNIT_ASSERT(!testling.isBare()); + CPPUNIT_ASSERT(testling.isValid()); + } + + void testConstructorWithString_DomainInvalidIPv6() { + JID testling("foo@[1111::a1111:1111:111!:!!!!]/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } + + void testConstructorWithString_DomainIPv6NoBrackets() { + JID testling("foo@fe80::a857:33ff:febd:3580/resource"); + CPPUNIT_ASSERT(!testling.isValid()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); |