summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/JID')
-rw-r--r--Swiften/JID/JID.cpp70
-rw-r--r--Swiften/JID/JID.h6
-rw-r--r--Swiften/JID/UnitTest/JIDTest.cpp51
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);