Lots of updates

This commit is contained in:
Dan Milne
2025-11-11 16:54:52 +11:00
parent 26216da9ca
commit cc8213f87a
41 changed files with 1463 additions and 614 deletions

View File

@@ -12,14 +12,14 @@ class Dsn < ApplicationRecord
def full_dsn_url
# Generate a complete DSN URL like Sentry does
# Format: https://{key}@{domain}/api/events
# Format: https://{key}@{domain}
domain = ENV['BAFFLE_HOST'] ||
Rails.application.config.action_mailer.default_url_options[:host] ||
ENV['RAILS_HOST'] ||
'localhost:3000'
protocol = Rails.env.development? ? 'http' : 'https'
"#{protocol}://#{key}@#{domain}/api/events"
"#{protocol}://#{key}@#{domain}"
end
def api_endpoint_url
@@ -30,7 +30,7 @@ class Dsn < ApplicationRecord
'localhost:3000'
protocol = Rails.env.development? ? 'http' : 'https'
"#{protocol}://#{domain}/api/events"
"#{protocol}://#{domain}"
end
private

View File

@@ -133,25 +133,11 @@ class NetworkRange < ApplicationRecord
# Find nearest parent with intelligence data
def parent_with_intelligence
# Use Postgres network operators to find parent ranges directly
cidr_str = network.to_s
if cidr_str.include?('/')
addr_parts = network_address.split('.')
case addr_parts.length
when 4 # IPv4
new_prefix = [prefix_length - 8, 16].max
parent_cidr = "#{addr_parts[0]}.#{addr_parts[1]}.#{addr_parts[2]}.0/#{new_prefix}"
else # IPv6 - skip for now
nil
end
else
nil
end
return nil unless parent_cidr
NetworkRange.where("network <<= ?::inet AND masklen(network) < ?", parent_cidr, prefix_length)
.where.not(asn: nil)
# Find all parent ranges (networks that contain this network)
# and look for any with intelligence data, ordered by specificity
NetworkRange.where("?::inet <<= network", network.to_s)
.where("masklen(network) < ?", prefix_length)
.where("(asn IS NOT NULL OR company IS NOT NULL OR country IS NOT NULL OR is_datacenter = true OR is_vpn = true OR is_proxy = true)")
.order("masklen(network) DESC")
.first
end
@@ -238,6 +224,28 @@ class NetworkRange < ApplicationRecord
self.additional_data = hash.to_json
end
# Network data accessors for different data sources
# network_data is a JSONB column with namespaced data:
# {
# geolite: {...}, # MaxMind GeoLite2 data
# ipapi: {...}, # IPAPI.is enrichment data
# abuseipdb: {...}, # Future: AbuseIPDB data
# shodan: {...} # Future: Shodan data
# }
def network_data_for(source)
network_data&.dig(source.to_s) || {}
end
def set_network_data(source, data)
self.network_data ||= {}
self.network_data[source.to_s] = data
end
# Check if we have network data from a specific source
def has_network_data_from?(source)
network_data&.key?(source.to_s) && network_data[source.to_s].present?
end
# String representations
def to_s
cidr
@@ -267,6 +275,19 @@ class NetworkRange < ApplicationRecord
rules.enabled.where("expires_at IS NULL OR expires_at > ?", Time.current)
end
# Check if this network range needs WAF policy evaluation
# Returns true if:
# - Never been evaluated, OR
# - Any WafPolicy has been updated since last evaluation
def needs_policy_evaluation?
return true if policies_evaluated_at.nil?
latest_policy_update = WafPolicy.maximum(:updated_at)
return false if latest_policy_update.nil? # No policies exist
policies_evaluated_at < latest_policy_update
end
private
def set_default_source

18
app/models/setting.rb Normal file
View File

@@ -0,0 +1,18 @@
class Setting < ApplicationRecord
validates :key, presence: true, uniqueness: true
# Get a setting value by key, with optional fallback
def self.get(key, default = nil)
find_by(key: key)&.value || default
end
# Set a setting value by key
def self.set(key, value)
find_or_initialize_by(key: key).update(value: value)
end
# Convenience method for ipapi.is API key
def self.ipapi_key
get('ipapi_key', ENV['IPAPI_KEY'])
end
end