diff options
| author | Joanna Hulboj <joanna.hulboj@isode.com> | 2019-05-24 09:30:14 (GMT) |
|---|---|---|
| committer | Joanna Hulboj <joanna.hulboj@isode.com> | 2019-05-28 15:14:50 (GMT) |
| commit | f4b6bfbf4c1573e9914185e2ef170f47838ea11a (patch) | |
| tree | b87b2442cda92bb70be95a64b3b8295c37fe8d9f | |
| parent | 09d8ac653493a0bd16cb69664ca28fbfe3c61bbb (diff) | |
| download | swift-f4b6bfbf4c1573e9914185e2ef170f47838ea11a.zip swift-f4b6bfbf4c1573e9914185e2ef170f47838ea11a.tar.bz2 | |
Add check if IPv4, IPv6 are valid JID domain part
When creating a JID we were not checking if a
domain part is a valid IPv4, IPv6 addresses. We were
only checking if the domain is correct according to
internationalized domain name rules which was failing
for IPv6 addresses.
Test-Information:
Unit tests pass on Windows 10 and Ubuntu 18.04.1 LTS
Change-Id: Ia1b67089f6edfdc6a0ebf2d26a7eaab9ce8171c0
| -rw-r--r-- | Swiften/JID/JID.cpp | 41 | ||||
| -rw-r--r-- | Swiften/JID/JID.h | 1 | ||||
| -rw-r--r-- | Swiften/JID/UnitTest/JIDTest.cpp | 46 |
3 files changed, 85 insertions, 3 deletions
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index fff88e9..5c6ea9d 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <Swiften/Base/String.h> | 13 | #include <Swiften/Base/String.h> |
| 14 | #include <Swiften/IDN/IDNConverter.h> | 14 | #include <Swiften/IDN/IDNConverter.h> |
| 15 | #include <Swiften/JID/JID.h> | 15 | #include <Swiften/JID/JID.h> |
| 16 | #include <Swiften/Network/HostAddress.h> | ||
| 16 | 17 | ||
| 17 | #ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER | 18 | #ifndef SWIFTEN_JID_NO_DEFAULT_IDN_CONVERTER |
| 18 | #include <memory> | 19 | #include <memory> |
| @@ -97,14 +98,47 @@ void JID::initializeFromString(const std::string& jid) { | |||
| 97 | } | 98 | } |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 101 | void JID::setComponents(const std::string& node, const std::string& domain, const std::string& resource) { | ||
| 102 | domain_ = domain; | ||
| 103 | try { | ||
| 104 | node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); | ||
| 105 | resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); | ||
| 106 | } | ||
| 107 | catch (...) { | ||
| 108 | valid_ = false; | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | } | ||
| 100 | 112 | ||
| 101 | void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { | 113 | void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { |
| 102 | if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) { | 114 | if (domain.empty() || (hasResource_ && resource.empty())) { |
| 103 | valid_ = false; | 115 | valid_ = false; |
| 104 | return; | 116 | return; |
| 105 | } | 117 | } |
| 106 | 118 | ||
| 107 | if (hasResource_ && resource.empty()) { | 119 | // Handling IPv6 addresses according to RFC 3986 rules |
| 120 | // saying that they are enclosed in square brackets | ||
| 121 | // which we have to remove when passing to HostAddress | ||
| 122 | if (domain.size() > 2 && domain.front() == '[' && domain.back() == ']') { | ||
| 123 | auto inner = std::string(domain.begin() + 1, domain.end() - 1); | ||
| 124 | auto hostAddress = HostAddress::fromString(inner); | ||
| 125 | if (hostAddress && hostAddress->isValid()) { | ||
| 126 | setComponents(node, domain, resource); | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | const auto isAnyOfNonNumericAndNotDot = std::any_of(std::begin(domain), std::end(domain), [](char c) {return !::isdigit(c) && c != '.'; }); | ||
| 132 | |||
| 133 | if (!isAnyOfNonNumericAndNotDot) { | ||
| 134 | auto hostAddress = HostAddress::fromString(domain); | ||
| 135 | if (hostAddress && hostAddress->isValid()) { | ||
| 136 | setComponents(node, domain, resource); | ||
| 137 | return; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | if (!isAnyOfNonNumericAndNotDot || !idnConverter->getIDNAEncoded(domain)) { | ||
| 108 | valid_ = false; | 142 | valid_ = false; |
| 109 | return; | 143 | return; |
| 110 | } | 144 | } |
| @@ -118,7 +152,8 @@ void JID::nameprepAndSetComponents(const std::string& node, const std::string& d | |||
| 118 | domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); | 152 | domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); |
| 119 | } | 153 | } |
| 120 | resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); | 154 | resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); |
| 121 | } catch (...) { | 155 | } |
| 156 | catch (...) { | ||
| 122 | valid_ = false; | 157 | valid_ = false; |
| 123 | return; | 158 | return; |
| 124 | } | 159 | } |
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index dc92f53..e98b796 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h | |||
| @@ -184,6 +184,7 @@ namespace Swift { | |||
| 184 | 184 | ||
| 185 | private: | 185 | private: |
| 186 | void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource); | 186 | void nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource); |
| 187 | void setComponents(const std::string& node, const std::string& domain, const std::string& resource); | ||
| 187 | void initializeFromString(const std::string&); | 188 | void initializeFromString(const std::string&); |
| 188 | 189 | ||
| 189 | private: | 190 | private: |
diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index 0753fb5..894378d 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp | |||
| @@ -71,6 +71,12 @@ class JIDTest : public CppUnit::TestFixture | |||
| 71 | CPPUNIT_TEST(testGetUnescapedNode); | 71 | CPPUNIT_TEST(testGetUnescapedNode); |
| 72 | CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); | 72 | CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); |
| 73 | CPPUNIT_TEST(testStringPrepFailures); | 73 | CPPUNIT_TEST(testStringPrepFailures); |
| 74 | CPPUNIT_TEST(testConstructorWithString_DomainIPv4); | ||
| 75 | CPPUNIT_TEST(testConstructorWithString_DomainNOTIPv4); | ||
| 76 | CPPUNIT_TEST(testConstructorWithString_ValidDomainNOTIPv4); | ||
| 77 | CPPUNIT_TEST(testConstructorWithString_DomainIPv6); | ||
| 78 | CPPUNIT_TEST(testConstructorWithString_DomainInvalidIPv6); | ||
| 79 | CPPUNIT_TEST(testConstructorWithString_DomainIPv6NoBrackets); | ||
| 74 | CPPUNIT_TEST_SUITE_END(); | 80 | CPPUNIT_TEST_SUITE_END(); |
| 75 | 81 | ||
| 76 | public: | 82 | public: |
| @@ -492,6 +498,46 @@ class JIDTest : public CppUnit::TestFixture | |||
| 492 | CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); | 498 | CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); |
| 493 | CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); | 499 | CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); |
| 494 | } | 500 | } |
| 501 | |||
| 502 | void testConstructorWithString_DomainIPv4() { | ||
| 503 | JID testling("foo@192.34.12.1/resource"); | ||
| 504 | |||
| 505 | CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); | ||
| 506 | CPPUNIT_ASSERT_EQUAL(std::string("192.34.12.1"), testling.getDomain()); | ||
| 507 | CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); | ||
| 508 | CPPUNIT_ASSERT(!testling.isBare()); | ||
| 509 | CPPUNIT_ASSERT(testling.isValid()); | ||
| 510 | } | ||
| 511 | |||
| 512 | void testConstructorWithString_DomainNOTIPv4() { | ||
| 513 | JID testling("foo@500.34.12.1/resource"); | ||
| 514 | CPPUNIT_ASSERT(!testling.isValid()); | ||
| 515 | } | ||
| 516 | |||
| 517 | void testConstructorWithString_ValidDomainNOTIPv4() { | ||
| 518 | JID testling("foo@500.34.12.1a/resource"); | ||
| 519 | CPPUNIT_ASSERT(testling.isValid()); | ||
| 520 | } | ||
| 521 | |||
| 522 | void testConstructorWithString_DomainIPv6() { | ||
| 523 | JID testling("foo@[fe80::a857:33ff:febd:3580]/resource"); | ||
| 524 | |||
| 525 | CPPUNIT_ASSERT_EQUAL(std::string("foo"), testling.getNode()); | ||
| 526 | CPPUNIT_ASSERT_EQUAL(std::string("[fe80::a857:33ff:febd:3580]"), testling.getDomain()); | ||
| 527 | CPPUNIT_ASSERT_EQUAL(std::string("resource"), testling.getResource()); | ||
| 528 | CPPUNIT_ASSERT(!testling.isBare()); | ||
| 529 | CPPUNIT_ASSERT(testling.isValid()); | ||
| 530 | } | ||
| 531 | |||
| 532 | void testConstructorWithString_DomainInvalidIPv6() { | ||
| 533 | JID testling("foo@[1111::a1111:1111:111!:!!!!]/resource"); | ||
| 534 | CPPUNIT_ASSERT(!testling.isValid()); | ||
| 535 | } | ||
| 536 | |||
| 537 | void testConstructorWithString_DomainIPv6NoBrackets() { | ||
| 538 | JID testling("foo@fe80::a857:33ff:febd:3580/resource"); | ||
| 539 | CPPUNIT_ASSERT(!testling.isValid()); | ||
| 540 | } | ||
| 495 | }; | 541 | }; |
| 496 | 542 | ||
| 497 | CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); | 543 | CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); |
Swift