109 lines
3.0 KiB
Ruby
109 lines
3.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class RuleSet < ApplicationRecord
|
|
has_many :rules, dependent: :destroy
|
|
|
|
validates :name, presence: true, uniqueness: true
|
|
validates :slug, presence: true, uniqueness: true
|
|
|
|
scope :enabled, -> { where(enabled: true) }
|
|
scope :by_priority, -> { order(priority: :desc, created_at: :desc) }
|
|
|
|
before_validation :generate_slug, if: :name?
|
|
before_validation :set_default_values
|
|
|
|
# Rule Types
|
|
RULE_TYPES = %w[ip cidr path user_agent parameter method rate_limit country].freeze
|
|
ACTIONS = %w[allow deny challenge rate_limit].freeze
|
|
|
|
def to_waf_rules
|
|
return [] unless enabled?
|
|
|
|
rules.enabled.by_priority.map do |rule|
|
|
{
|
|
id: rule.id,
|
|
type: rule.rule_type,
|
|
target: rule.target,
|
|
action: rule.action,
|
|
conditions: rule.conditions,
|
|
priority: rule.priority,
|
|
expires_at: rule.expires_at
|
|
}
|
|
end
|
|
end
|
|
|
|
def add_rule(rule_type, target, action, conditions: {}, expires_at: nil, priority: 100)
|
|
rules.create!(
|
|
rule_type: rule_type,
|
|
target: target,
|
|
action: action,
|
|
conditions: conditions,
|
|
expires_at: expires_at,
|
|
priority: priority
|
|
)
|
|
end
|
|
|
|
def remove_rule(rule_id)
|
|
rules.find(rule_id).destroy
|
|
end
|
|
|
|
def block_ip(ip_address, expires_at: nil, reason: nil)
|
|
add_rule('ip', ip_address, 'deny', expires_at: expires_at, priority: 1000)
|
|
end
|
|
|
|
def allow_ip(ip_address, expires_at: nil)
|
|
add_rule('ip', ip_address, 'allow', expires_at: expires_at, priority: 1000)
|
|
end
|
|
|
|
def block_cidr(cidr, expires_at: nil, reason: nil)
|
|
add_rule('cidr', cidr, 'deny', expires_at: expires_at, priority: 900)
|
|
end
|
|
|
|
def block_path(path, conditions: {}, expires_at: nil)
|
|
add_rule('path', path, 'deny', conditions: conditions, expires_at: expires_at, priority: 500)
|
|
end
|
|
|
|
def block_user_agent(user_agent_pattern, expires_at: nil)
|
|
add_rule('user_agent', user_agent_pattern, 'deny', expires_at: expires_at, priority: 600)
|
|
end
|
|
|
|
def push_to_agents!
|
|
# This would integrate with the agent distribution system
|
|
Rails.logger.info "Pushing rule set '#{name}' with #{rules.count} rules to agents"
|
|
|
|
# Broadcast update to connected projects
|
|
projects = Project.where(id: projects_subscription || [])
|
|
projects.each(&:broadcast_rules_refresh)
|
|
end
|
|
|
|
def active_projects
|
|
return Project.none unless projects_subscription.present?
|
|
|
|
Project.where(id: projects_subscription).enabled
|
|
end
|
|
|
|
def subscribe_project(project)
|
|
subscriptions = projects_subscription || []
|
|
subscriptions << project.id unless subscriptions.include?(project.id)
|
|
update(projects_subscription: subscriptions.uniq)
|
|
end
|
|
|
|
def unsubscribe_project(project)
|
|
subscriptions = projects_subscription || []
|
|
subscriptions.delete(project.id)
|
|
update(projects_subscription: subscriptions)
|
|
end
|
|
|
|
private
|
|
|
|
def generate_slug
|
|
self.slug = name&.parameterize&.downcase
|
|
end
|
|
|
|
def set_default_values
|
|
self.enabled = true if enabled.nil?
|
|
self.priority = 100 if priority.nil?
|
|
self.projects_subscription = [] if projects_subscription.nil?
|
|
end
|
|
end
|