class NetworkRange < ApplicationRecord validates :ip_address, presence: true validates :network_prefix, presence: true, numericality: {greater_than_or_equal_to: 0, less_than_or_equal_to: 128} validates :ip_version, presence: true, inclusion: {in: [4, 6]} # Convenience methods for JSON fields def abuser_scores_hash abuser_scores ? JSON.parse(abuser_scores) : {} end def abuser_scores_hash=(hash) self.abuser_scores = hash.to_json end def additional_data_hash additional_data ? JSON.parse(additional_data) : {} end def additional_data_hash=(hash) self.additional_data = hash.to_json end # Scope methods for common queries scope :ipv4, -> { where(ip_version: 4) } scope :ipv6, -> { where(ip_version: 6) } scope :datacenter, -> { where(is_datacenter: true) } scope :proxy, -> { where(is_proxy: true) } scope :vpn, -> { where(is_vpn: true) } scope :by_country, ->(country) { where(ip_api_country: country) } scope :by_company, ->(company) { where(company: company) } scope :by_asn, ->(asn) { where(asn: asn) } # Find network ranges that contain a specific IP address def self.contains_ip(ip_string) ip_bytes = IPAddr.new(ip_string).hton version = ip_string.include?(":") ? 6 : 4 where(ip_version: version).select do |range| range.contains_ip_bytes?(ip_bytes) end end def contains_ip?(ip_string) contains_ip_bytes?(IPAddr.new(ip_string).hton) end def to_s "#{ip_address_to_s}/#{network_prefix}" end private def contains_ip_bytes?(ip_bytes) # This is a simplified version - you'll need proper network math here # For now, just check if the IP matches exactly ip_address == ip_bytes end def ip_address_to_s # Convert binary IP back to string representation IPAddr.ntop(ip_address) end end