Sha256: 80c81c40103409427a6ae760996e574209e0e675b0e4914043f31d2e8e799f2f

Contents?: true

Size: 1.97 KB

Versions: 5

Compression:

Stored size: 1.97 KB

Contents

# frozen_string_literal: true

require 'ipaddr'
require 'interval_tree'

module Legitbot
  module Validators
    #
    # In a bot matcher:
    # `ip_ranges ip, range, ip, ...`
    # `ip_ranges do [ip, range, ...]; end`
    module IpRanges
      class << self
        def included(base)
          base.extend ClassMethods
        end
      end

      def valid_ip?
        self.class.valid_ip?(@ip)
      end

      module ClassMethods # :nodoc:
        FAMILIES = %i[ipv4 ipv6].freeze
        EMPTY_GENERATOR = proc { [] }

        def ip_ranges(*ips, &block)
          @ip_ranges = partition_ips(ips.flatten) unless ips.empty?
          @ip_ranges_loader = block_given? ? block : EMPTY_GENERATOR
          @ip_loader_mutex = Mutex.new
        end

        def check_ranges?
          instance_variable_defined?(:@ip_ranges_loader)
        end

        def valid_ip?(ip)
          return true unless check_ranges?
          return true if valid_ips.empty?

          obj = IPAddr.new(ip)
          ranges = valid_ips[obj.ipv4? ? :ipv4 : :ipv6].search(obj.to_i)
          !ranges.empty?
        end

        def valid_ips
          @ip_loader_mutex.synchronize do
            @ip_ranges ||= load_ips
          end
        end

        def reload_ips
          @ip_loader_mutex.synchronize do
            @ip_ranges = load_ips
          end
        end

        def load_ips
          partition_ips(@ip_ranges_loader.call)
        end

        # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
        def partition_ips(ips)
          return [] if ips.empty?

          ips
            .map { |cidr| IPAddr.new(cidr) }
            .partition(&:ipv4?)
            .each_with_index
            .map do |list, index|
              ranges = list.map(&:to_range).map do |r|
                (r.begin.to_i..r.end.to_i)
              end
              [FAMILIES[index], IntervalTree::Tree.new(ranges)]
            end.to_h
        end
        # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
      end
    end
  end
end

Version data entries

5 entries across 5 versions & 1 rubygems

Version Path
legitbot-1.0.0 lib/legitbot/validators/ip_ranges.rb
legitbot-0.4.3 lib/legitbot/validators/ip_ranges.rb
legitbot-0.4.2 lib/legitbot/validators/ip_ranges.rb
legitbot-0.4.1 lib/legitbot/validators/ip_ranges.rb
legitbot-0.4.0 lib/legitbot/validators/ip_ranges.rb