Yeh
This commit is contained in:
@@ -236,9 +236,36 @@ class Rule < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
# For path_pattern rules, include segment IDs and match type
|
||||
if path_pattern_rule?
|
||||
format[:conditions] = {
|
||||
segment_ids: path_segment_ids,
|
||||
match_type: path_match_type
|
||||
}
|
||||
end
|
||||
|
||||
format
|
||||
end
|
||||
|
||||
# Path pattern rule helper methods
|
||||
def path_segment_ids
|
||||
conditions&.dig("segment_ids") || []
|
||||
end
|
||||
|
||||
def path_match_type
|
||||
conditions&.dig("match_type")
|
||||
end
|
||||
|
||||
def path_segments_text
|
||||
return [] if path_segment_ids.empty?
|
||||
PathSegment.where(id: path_segment_ids).order(:id).pluck(:segment)
|
||||
end
|
||||
|
||||
def path_pattern_display
|
||||
return nil unless path_pattern_rule?
|
||||
"/" + path_segments_text.join("/")
|
||||
end
|
||||
|
||||
# Class methods for rule creation
|
||||
def self.create_network_rule(cidr, action: 'deny', user: nil, **options)
|
||||
network_range = NetworkRange.find_or_create_by_cidr(cidr, user: user, source: 'user_created')
|
||||
@@ -252,6 +279,42 @@ class Rule < ApplicationRecord
|
||||
)
|
||||
end
|
||||
|
||||
def self.create_path_pattern_rule(pattern:, match_type:, action: 'deny', user: nil, **options)
|
||||
# Parse pattern string to segments (case-insensitive)
|
||||
segments = pattern.split('/').reject(&:blank?).map(&:downcase)
|
||||
|
||||
if segments.empty?
|
||||
raise ArgumentError, "Pattern must contain at least one path segment"
|
||||
end
|
||||
|
||||
unless %w[exact prefix suffix contains].include?(match_type)
|
||||
raise ArgumentError, "Match type must be one of: exact, prefix, suffix, contains"
|
||||
end
|
||||
|
||||
# Find or create PathSegment entries
|
||||
segment_ids = segments.map do |seg|
|
||||
PathSegment.find_or_create_segment(seg).id
|
||||
end
|
||||
|
||||
create!(
|
||||
waf_rule_type: 'path_pattern',
|
||||
waf_action: action,
|
||||
conditions: {
|
||||
segment_ids: segment_ids,
|
||||
match_type: match_type,
|
||||
original_pattern: pattern
|
||||
},
|
||||
metadata: {
|
||||
segments: segments,
|
||||
pattern_display: "/" + segments.join("/")
|
||||
},
|
||||
user: user,
|
||||
source: options[:source] || 'manual',
|
||||
priority: options[:priority] || 50,
|
||||
**options.except(:source, :priority)
|
||||
)
|
||||
end
|
||||
|
||||
def self.create_surgical_block(ip_address, parent_cidr, user: nil, reason: nil, **options)
|
||||
# Create block rule for parent range
|
||||
network_range = NetworkRange.find_or_create_by_cidr(parent_cidr, user: user, source: 'user_created')
|
||||
@@ -418,10 +481,24 @@ class Rule < ApplicationRecord
|
||||
end
|
||||
|
||||
def validate_path_pattern_conditions
|
||||
patterns = conditions&.dig("patterns")
|
||||
segment_ids = conditions&.dig("segment_ids")
|
||||
match_type = conditions&.dig("match_type")
|
||||
|
||||
if patterns.blank? || !patterns.is_a?(Array)
|
||||
errors.add(:conditions, "must include 'patterns' array for path_pattern rules")
|
||||
if segment_ids.blank? || !segment_ids.is_a?(Array)
|
||||
errors.add(:conditions, "must include 'segment_ids' array for path_pattern rules")
|
||||
end
|
||||
|
||||
unless %w[exact prefix suffix contains].include?(match_type)
|
||||
errors.add(:conditions, "match_type must be one of: exact, prefix, suffix, contains")
|
||||
end
|
||||
|
||||
# Validate that all segment IDs exist
|
||||
if segment_ids.is_a?(Array) && segment_ids.any?
|
||||
existing_ids = PathSegment.where(id: segment_ids).pluck(:id)
|
||||
missing_ids = segment_ids - existing_ids
|
||||
if missing_ids.any?
|
||||
errors.add(:conditions, "references non-existent path segment IDs: #{missing_ids.join(', ')}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user