Migrate to Postgresql for better network handling. Add more user functionality.
This commit is contained in:
@@ -268,11 +268,114 @@ class Event < ApplicationRecord
|
||||
headers.transform_keys(&:downcase)
|
||||
end
|
||||
|
||||
# GeoIP enrichment methods
|
||||
# Network range resolution methods
|
||||
def matching_network_ranges
|
||||
return [] unless ip_address.present?
|
||||
|
||||
NetworkRange.contains_ip(ip_address).map do |range|
|
||||
{
|
||||
range: range,
|
||||
cidr: range.cidr,
|
||||
prefix_length: range.prefix_length,
|
||||
specificity: range.prefix_length,
|
||||
intelligence: range.inherited_intelligence
|
||||
}
|
||||
end.sort_by { |r| -r[:specificity] } # Most specific first
|
||||
end
|
||||
|
||||
def most_specific_range
|
||||
matching_network_ranges.first
|
||||
end
|
||||
|
||||
def broadest_range
|
||||
matching_network_ranges.last
|
||||
end
|
||||
|
||||
def network_intelligence
|
||||
most_specific_range&.dig(:intelligence) || {}
|
||||
end
|
||||
|
||||
def company
|
||||
network_intelligence[:company]
|
||||
end
|
||||
|
||||
def asn
|
||||
network_intelligence[:asn]
|
||||
end
|
||||
|
||||
def asn_org
|
||||
network_intelligence[:asn_org]
|
||||
end
|
||||
|
||||
def is_datacenter?
|
||||
network_intelligence[:is_datacenter] || false
|
||||
end
|
||||
|
||||
def is_proxy?
|
||||
network_intelligence[:is_proxy] || false
|
||||
end
|
||||
|
||||
def is_vpn?
|
||||
network_intelligence[:is_vpn] || false
|
||||
end
|
||||
|
||||
# IP validation
|
||||
def valid_ipv4?
|
||||
return false unless ip_address.present?
|
||||
|
||||
IPAddr.new(ip_address).ipv4?
|
||||
rescue IPAddr::InvalidAddressError
|
||||
false
|
||||
end
|
||||
|
||||
def valid_ipv6?
|
||||
return false unless ip_address.present?
|
||||
|
||||
IPAddr.new(ip_address).ipv6?
|
||||
rescue IPAddr::InvalidAddressError
|
||||
false
|
||||
end
|
||||
|
||||
def valid_ip?
|
||||
valid_ipv4? || valid_ipv6?
|
||||
end
|
||||
|
||||
# Rules affecting this IP
|
||||
def matching_rules
|
||||
return Rule.none unless ip_address.present?
|
||||
|
||||
# Get all network ranges that contain this IP
|
||||
range_ids = matching_network_ranges.map { |r| r[:range].id }
|
||||
|
||||
# Find rules for those ranges, ordered by priority (most specific first)
|
||||
Rule.network_rules
|
||||
.where(network_range_id: range_ids)
|
||||
.enabled
|
||||
.includes(:network_range)
|
||||
.order('masklen(network_ranges.network) DESC')
|
||||
end
|
||||
|
||||
def active_blocking_rules
|
||||
matching_rules.where(action: 'deny')
|
||||
end
|
||||
|
||||
def has_blocking_rules?
|
||||
active_blocking_rules.exists?
|
||||
end
|
||||
|
||||
# GeoIP enrichment methods (now uses network range data when available)
|
||||
def enrich_geo_location!
|
||||
return if ip_address.blank?
|
||||
return if country_code.present? # Already has geo data
|
||||
|
||||
# First try to get from network range
|
||||
network_info = network_intelligence
|
||||
if network_info[:country].present?
|
||||
update!(country_code: network_info[:country])
|
||||
return
|
||||
end
|
||||
|
||||
# Fallback to direct lookup
|
||||
country = GeoIpService.lookup_country(ip_address)
|
||||
update!(country_code: country) if country.present?
|
||||
rescue => e
|
||||
@@ -282,13 +385,21 @@ class Event < ApplicationRecord
|
||||
# Class method to enrich multiple events
|
||||
def self.enrich_geo_location_batch(events = nil)
|
||||
events ||= where(country_code: [nil, '']).where.not(ip_address: [nil, ''])
|
||||
geo_service = GeoIpService.new
|
||||
updated_count = 0
|
||||
|
||||
events.find_each do |event|
|
||||
next if event.country_code.present?
|
||||
|
||||
country = geo_service.lookup_country(event.ip_address)
|
||||
# Try network range first
|
||||
network_info = event.network_intelligence
|
||||
if network_info[:country].present?
|
||||
event.update!(country_code: network_info[:country])
|
||||
updated_count += 1
|
||||
next
|
||||
end
|
||||
|
||||
# Fallback to direct lookup
|
||||
country = GeoIpService.lookup_country(event.ip_address)
|
||||
if country.present?
|
||||
event.update!(country_code: country)
|
||||
updated_count += 1
|
||||
@@ -303,6 +414,11 @@ class Event < ApplicationRecord
|
||||
return country_code if country_code.present?
|
||||
return nil if ip_address.blank?
|
||||
|
||||
# First try network range
|
||||
network_info = network_intelligence
|
||||
return network_info[:country] if network_info[:country].present?
|
||||
|
||||
# Fallback to direct lookup
|
||||
GeoIpService.lookup_country(ip_address)
|
||||
rescue => e
|
||||
Rails.logger.error "GeoIP lookup failed for #{ip_address}: #{e.message}"
|
||||
@@ -311,16 +427,19 @@ class Event < ApplicationRecord
|
||||
|
||||
# Check if event has valid geo location data
|
||||
def has_geo_data?
|
||||
country_code.present? || city.present?
|
||||
country_code.present? || city.present? || network_intelligence[:country].present?
|
||||
end
|
||||
|
||||
# Get full geo location details
|
||||
def geo_location
|
||||
network_info = network_intelligence
|
||||
|
||||
{
|
||||
country_code: country_code,
|
||||
country_code: country_code || network_info[:country],
|
||||
city: city,
|
||||
ip_address: ip_address,
|
||||
has_data: has_geo_data?
|
||||
has_data: has_geo_data?,
|
||||
network_intelligence: network_info
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user