module Webhooks::Outgoing::UriFiltering

def _allowed_uri?(uri)

def _allowed_uri?(uri)
  return true unless uri.present?
  config = Rails.configuration.outgoing_webhooks
  hostname = uri.hostname.downcase
  return false unless config[:allowed_schemes].include?(uri.scheme)
  config[:blocked_hostnames].each do |blocked|
    if blocked.is_a?(Regexp)
      return false if blocked.match?(hostname)
    end
    return false if blocked == hostname
  end
  config[:allowed_hostnames].each do |allowed|
    if allowed.is_a?(Regexp)
      return true if allowed.match?(hostname)
    end
    return true if allowed == hostname
  end
  if config[:custom_allow_callback].present?
    return true if config[:custom_allow_callback].call(self, uri)
  end
  if config[:custom_block_callback].present?
    return false if config[:custom_block_callback].call(self, uri)
  end
  resolved_ip = resolve_ip_from_authoritative(hostname)
  return false if resolved_ip.nil?
  begin
    config[:allowed_cidrs].each do |cidr|
      return true if IPAddr.new(cidr).include?(resolved_ip)
    end
    config[:blocked_cidrs].each do |cidr|
      return false if IPAddr.new(cidr).include?(resolved_ip)
    end
  rescue IPAddr::InvalidAddressError
    return false
  end
  true
end

def allowed_uri?(uri)

def allowed_uri?(uri)
  unless _allowed_uri?(uri)
    config = Rails.configuration.outgoing_webhooks
    if config[:audit_callback].present?
      config[:audit_callback].call(self, uri)
    end
    return false
  end
  true
end

def resolve_ip_from_authoritative(hostname)

def resolve_ip_from_authoritative(hostname)
  begin
    ip = IPAddr.new(hostname)
    return ip.to_s
  rescue IPAddr::InvalidAddressError
    # this is fine, proceed with resolver path
  end
  cache_key = "#{cache_key_with_version}/uri_ip/#{Digest::SHA2.hexdigest(hostname)}"
  cached = Rails.cache.read(cache_key)
  if cached
    return (cached == "invalid") ? nil : cached
  end
  begin
    # This is sort of a half-recursive DNS resolver.
    # We can't implement a full recursive resolver using just Resolv::DNS so instead
    # this asks a public cache for the NS record for the given domain. Then it asks
    # the authoritative nameserver directly for the address and caches it according
    # to the returned TTL.
    config = Rails.configuration.outgoing_webhooks
    ns_resolver = Resolv::DNS.new(nameserver: config[:public_resolvers])
    ns_resolver.timeouts = 1
    domain = PublicSuffix.domain(hostname)
    authoritative = ns_resolver.getresource(domain, Resolv::DNS::Resource::IN::NS)
    authoritative_resolver = Resolv::DNS.new(nameserver: [authoritative.name.to_s])
    authoritative_resolver.timeouts = 1
    resource = authoritative_resolver.getresource(hostname, Resolv::DNS::Resource::IN::A)
    Rails.cache.write(cache_key, resource.address.to_s, expires_in: resource.ttl, race_condition_ttl: 5)
    resource.address.to_s
  rescue ArgumentError
    Rails.cache.write(cache_key, "invalid", expires_in: 10.minutes, race_condition_ttl: 5)
    nil
  end
end