Add WafPolicies
This commit is contained in:
@@ -32,10 +32,36 @@ class Event < ApplicationRecord
|
||||
scope :by_ip, ->(ip) { where(ip_address: ip) }
|
||||
scope :by_user_agent, ->(user_agent) { where(user_agent: user_agent) }
|
||||
scope :by_waf_action, ->(waf_action) { where(waf_action: waf_action) }
|
||||
scope :blocked, -> { where(waf_action: ['block', 'deny']) }
|
||||
scope :allowed, -> { where(waf_action: ['allow', 'pass']) }
|
||||
scope :blocked, -> { where(waf_action: :deny) }
|
||||
scope :allowed, -> { where(waf_action: :allow) }
|
||||
scope :rate_limited, -> { where(waf_action: 'rate_limit') }
|
||||
|
||||
# Network-based filtering scopes
|
||||
scope :by_company, ->(company) {
|
||||
joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
|
||||
.where("network_ranges.company ILIKE ?", "%#{company}%")
|
||||
}
|
||||
|
||||
scope :by_network_type, ->(type) {
|
||||
joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
|
||||
.case(type)
|
||||
.when("datacenter") { where("network_ranges.is_datacenter = ?", true) }
|
||||
.when("vpn") { where("network_ranges.is_vpn = ?", true) }
|
||||
.when("proxy") { where("network_ranges.is_proxy = ?", true) }
|
||||
.when("standard") { where("network_ranges.is_datacenter = ? AND network_ranges.is_vpn = ? AND network_ranges.is_proxy = ?", false, false, false) }
|
||||
.else { none }
|
||||
}
|
||||
|
||||
scope :by_asn, ->(asn) {
|
||||
joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
|
||||
.where("network_ranges.asn = ?", asn.to_i)
|
||||
}
|
||||
|
||||
scope :by_network_cidr, ->(cidr) {
|
||||
joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
|
||||
.where("network_ranges.network = ?", cidr)
|
||||
}
|
||||
|
||||
# Path prefix matching using range queries (uses B-tree index efficiently)
|
||||
scope :with_path_prefix, ->(prefix_segment_ids) {
|
||||
return none if prefix_segment_ids.blank?
|
||||
@@ -112,10 +138,7 @@ class Event < ApplicationRecord
|
||||
server_name: normalized_payload["server_name"],
|
||||
environment: normalized_payload["environment"],
|
||||
|
||||
# Geographic data
|
||||
country_code: normalized_payload.dig("geo", "country_code"),
|
||||
city: normalized_payload.dig("geo", "city"),
|
||||
|
||||
|
||||
# WAF agent info
|
||||
agent_version: normalized_payload.dig("agent", "version"),
|
||||
agent_name: normalized_payload.dig("agent", "name")
|
||||
@@ -269,7 +292,7 @@ class Event < ApplicationRecord
|
||||
def matching_network_ranges
|
||||
return [] unless ip_address.present?
|
||||
|
||||
NetworkRange.contains_ip(ip_address).map do |range|
|
||||
NetworkRange.contains_ip(ip_address.to_s).map do |range|
|
||||
{
|
||||
range: range,
|
||||
cidr: range.cidr,
|
||||
@@ -360,86 +383,34 @@ class Event < ApplicationRecord
|
||||
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
|
||||
Rails.logger.error "Failed to enrich geo location for event #{id}: #{e.message}"
|
||||
end
|
||||
|
||||
# Class method to enrich multiple events
|
||||
def self.enrich_geo_location_batch(events = nil)
|
||||
events ||= where(country_code: [nil, '']).where.not(ip_address: [nil, ''])
|
||||
updated_count = 0
|
||||
|
||||
events.find_each do |event|
|
||||
next if event.country_code.present?
|
||||
|
||||
# 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
|
||||
end
|
||||
end
|
||||
|
||||
updated_count
|
||||
end
|
||||
|
||||
# Lookup country code for this event's IP
|
||||
def lookup_country
|
||||
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}"
|
||||
nil
|
||||
end
|
||||
|
||||
# Check if event has valid geo location data
|
||||
def has_geo_data?
|
||||
country_code.present? || city.present? || network_intelligence[:country].present?
|
||||
end
|
||||
|
||||
# Get full geo location details
|
||||
# Get full geo location details from network range
|
||||
def geo_location
|
||||
network_info = network_intelligence
|
||||
|
||||
{
|
||||
country_code: country_code || network_info[:country],
|
||||
city: city,
|
||||
country_code: network_info[:country],
|
||||
ip_address: ip_address,
|
||||
has_data: has_geo_data?,
|
||||
has_data: network_info[:country].present?,
|
||||
network_intelligence: network_info
|
||||
}
|
||||
end
|
||||
|
||||
# Check if event has valid geo location data via network range
|
||||
def has_geo_data?
|
||||
network_intelligence[:country].present?
|
||||
end
|
||||
|
||||
# Lookup country code for this event's IP via network range
|
||||
def lookup_country
|
||||
return nil if ip_address.blank?
|
||||
|
||||
network_info = network_intelligence
|
||||
network_info[:country]
|
||||
rescue => e
|
||||
Rails.logger.error "Network lookup failed for #{ip_address}: #{e.message}"
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_normalize?
|
||||
@@ -483,11 +454,7 @@ class Event < ApplicationRecord
|
||||
self.server_name = payload["server_name"]
|
||||
self.environment = payload["environment"]
|
||||
|
||||
# Extract geographic data
|
||||
geo_data = payload.dig("geo") || {}
|
||||
self.country_code = geo_data["country_code"]
|
||||
self.city = geo_data["city"]
|
||||
|
||||
|
||||
# Extract agent info
|
||||
agent_data = payload.dig("agent") || {}
|
||||
self.agent_version = agent_data["version"]
|
||||
|
||||
Reference in New Issue
Block a user