diff options
Diffstat (limited to 'Swiften/JID/JID.cpp')
| -rw-r--r-- | Swiften/JID/JID.cpp | 138 | 
1 files changed, 76 insertions, 62 deletions
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index c82674d..eb72014 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -1,25 +1,19 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ -#define SWIFTEN_CACHE_JID_PREP -  #include <sstream>  #include <string>  #include <vector> -#ifdef SWIFTEN_CACHE_JID_PREP -#include <mutex> -#include <unordered_map> -#endif -  #include <boost/optional.hpp>  #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> @@ -28,15 +22,6 @@  using namespace Swift; -#ifdef SWIFTEN_CACHE_JID_PREP -typedef std::unordered_map<std::string, std::string> PrepCache; - -static std::mutex namePrepCacheMutex; -static PrepCache nodePrepCache; -static PrepCache domainPrepCache; -static PrepCache resourcePrepCache; -#endif -  static const std::vector<char> escapedChars = {' ', '"', '&', '\'', '/', '<', '>', '@', ':'};  static IDNConverter* idnConverter = nullptr; @@ -87,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; @@ -104,74 +116,76 @@ void JID::initializeFromString(const std::string& jid) {          hasResource_ = false;          bare = jid;      } -    std::pair<std::string,std::string> nodeAndDomain = String::getSplittedAtFirst(bare, '@'); -    if (nodeAndDomain.second.empty()) { -        nameprepAndSetComponents("", nodeAndDomain.first, resource); +    auto firstMatch = bare.find('@'); +    if (firstMatch != bare.npos) { +        nameprepAndSetComponents(bare.substr(0, firstMatch), bare.substr(firstMatch + 1), resource);      }      else { -        nameprepAndSetComponents(nodeAndDomain.first, nodeAndDomain.second, resource); +        nameprepAndSetComponents("", bare, resource);      }  } - -void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { -    if (domain.empty() || !idnConverter->getIDNAEncoded(domain)) { +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;      } +} -    if (hasResource_ && resource.empty()) { +void JID::nameprepAndSetComponents(const std::string& node, const std::string& domain, const std::string& resource) { +    if (domain.empty() || (hasResource_ && resource.empty())) {          valid_ = false;          return;      } -#ifndef SWIFTEN_CACHE_JID_PREP -    node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); -    domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); -    resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); -#else -    std::unique_lock<std::mutex> lock(namePrepCacheMutex); - -    std::pair<PrepCache::iterator, bool> r; - -    r = nodePrepCache.insert(std::make_pair(node, std::string())); -    if (r.second) { -        try { -            r.first->second = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); -        } -        catch (...) { -            nodePrepCache.erase(r.first); -            valid_ = false; + +    // 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;          }      } -    node_ = r.first->second; -    r = domainPrepCache.insert(std::make_pair(domain, std::string())); -    if (r.second) { -        try { -            r.first->second = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep); -        } -        catch (...) { -            domainPrepCache.erase(r.first); -            valid_ = false; +    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;          }      } -    domain_ = r.first->second; -    r = resourcePrepCache.insert(std::make_pair(resource, std::string())); -    if (r.second) { -        try { -            r.first->second = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); +    if (!isAnyOfNonNumericAndNotDot || !idnConverter->getIDNAEncoded(domain)) { +        valid_ = false; +        return; +    } + +    try { +        node_ = idnConverter->getStringPrepared(node, IDNConverter::XMPPNodePrep); +        if (domain.back() == '.') { +            domain_ = idnConverter->getStringPrepared(domain.substr(0, domain.size() - 1), IDNConverter::NamePrep);          } -        catch (...) { -            resourcePrepCache.erase(r.first); -            valid_ = false; -            return; +        else { +            domain_ = idnConverter->getStringPrepared(domain, IDNConverter::NamePrep);          } +        resource_ = idnConverter->getStringPrepared(resource, IDNConverter::XMPPResourcePrep); +    } +    catch (...) { +        valid_ = false; +        return;      } -    resource_ = r.first->second; -#endif      if (domain_.empty()) {          valid_ = false;  | 
 Swift