#include "source/extensions/transport_sockets/tls/cert_validator/san_matcher.h"

#include <memory>

#include "envoy/config/core/v3/extension.pb.h"
#include "envoy/extensions/transport_sockets/tls/v3/common.pb.h"
#include "envoy/registry/registry.h"
#include "envoy/ssl/certificate_validation_context_config.h"

#include "source/extensions/transport_sockets/tls/utility.h"

namespace Envoy {
namespace Extensions {
namespace TransportSockets {
namespace Tls {

bool StringSanMatcher::match(const GENERAL_NAME* general_name) const {
  if (general_name->type != general_name_type_) {
    return false;
  }
  // For DNS SAN, if the StringMatcher type is exact, we have to follow DNS matching semantics.
  const std::string san = Utility::generalNameAsString(general_name);
  return general_name->type == GEN_DNS &&
                 matcher_.matcher().match_pattern_case() ==
                     envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kExact
             ? Utility::dnsNameMatch(matcher_.matcher().exact(), absl::string_view(san))
             : matcher_.match(san);
}

SanMatcherPtr createStringSanMatcher(
    envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher const& matcher) {
  // Verify that a new san type has not been added.
  static_assert(envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::SanType_MAX ==
                4);

  switch (matcher.san_type()) {
    PANIC_ON_PROTO_ENUM_SENTINEL_VALUES;
  case envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::DNS:
    return SanMatcherPtr{std::make_unique<StringSanMatcher>(GEN_DNS, matcher.matcher())};
  case envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::EMAIL:
    return SanMatcherPtr{std::make_unique<StringSanMatcher>(GEN_EMAIL, matcher.matcher())};
  case envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::URI:
    return SanMatcherPtr{std::make_unique<StringSanMatcher>(GEN_URI, matcher.matcher())};
  case envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::IP_ADDRESS:
    return SanMatcherPtr{std::make_unique<StringSanMatcher>(GEN_IPADD, matcher.matcher())};
  case envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::SAN_TYPE_UNSPECIFIED:
    PANIC("unhandled value");
  }
  return nullptr;
}

} // namespace Tls
} // namespace TransportSockets
} // namespace Extensions
} // namespace Envoy
