Add 'tags' to event model. Add a dataimport system - currently for MaxMind zip files

This commit is contained in:
Dan Milne
2025-11-11 10:31:36 +11:00
parent 772fae7e8b
commit 26216da9ca
34 changed files with 3580 additions and 14 deletions

View File

@@ -7,7 +7,7 @@
# and classification flags (datacenter, proxy, VPN).
class NetworkRange < ApplicationRecord
# Sources for network range creation
SOURCES = %w[api_imported user_created manual auto_generated inherited].freeze
SOURCES = %w[api_imported user_created manual auto_generated inherited geolite_asn geolite_country].freeze
# Associations
has_many :rules, dependent: :destroy
@@ -29,6 +29,9 @@ class NetworkRange < ApplicationRecord
scope :vpn, -> { where(is_vpn: true) }
scope :user_created, -> { where(source: 'user_created') }
scope :api_imported, -> { where(source: 'api_imported') }
scope :geolite_imported, -> { where(source: ['geolite_asn', 'geolite_country']) }
scope :geolite_asn, -> { where(source: 'geolite_asn') }
scope :geolite_country, -> { where(source: 'geolite_country') }
scope :with_events, -> { where("events_count > 0") }
scope :most_active, -> { order(events_count: :desc) }
@@ -295,4 +298,44 @@ class NetworkRange < ApplicationRecord
# The inherited_intelligence method will pick up the new parent data
end
end
# Import-related class methods
def self.import_stats_by_source
group(:source)
.select(:source, 'COUNT(*) as count', 'MIN(created_at) as first_import', 'MAX(updated_at) as last_update')
.order(:source)
end
def self.geolite_coverage_stats
{
total_networks: geolite_imported.count,
asn_networks: geolite_asn.count,
country_networks: geolite_country.count,
with_asn_data: geolite_imported.where.not(asn: nil).count,
with_country_data: geolite_imported.where.not(country: nil).count,
with_proxy_data: geolite_imported.where(is_proxy: true).count,
unique_countries: geolite_imported.distinct.count(:country),
unique_asns: geolite_imported.distinct.count(:asn),
ipv4_networks: geolite_imported.ipv4.count,
ipv6_networks: geolite_imported.ipv6.count
}
end
def self.find_by_ip_or_network(query)
return none if query.blank?
begin
# Try to parse as IP address first
ip = IPAddr.new(query)
where("network >>= ?", ip.to_s)
rescue IPAddr::InvalidAddressError
# Try to parse as network
begin
network = IPAddr.new(query)
where(network: network.to_s)
rescue IPAddr::InvalidAddressError
none
end
end
end
end