Tidy up homepage and navigation

This commit is contained in:
Dan Milne
2025-11-09 20:58:13 +11:00
parent c9e2992fe0
commit 1f4428348d
56 changed files with 2822 additions and 955 deletions

View File

@@ -3,15 +3,14 @@
class RulesController < ApplicationController
# Follow proper before_action order:
# 1. Authentication/Authorization
allow_unauthenticated_access only: [:index, :show]
# All actions require authentication
# 2. Resource loading
before_action :set_rule, only: [:show, :edit, :update, :disable, :enable]
before_action :set_project, only: [:index, :show]
# GET /rules
def index
@rules = policy_scope(Rule).includes(:user, :network_range).order(created_at: :desc)
@pagy, @rules = pagy(policy_scope(Rule).includes(:user, :network_range).order(created_at: :desc))
@rule_types = Rule::RULE_TYPES
@actions = Rule::ACTIONS
end
@@ -43,6 +42,9 @@ class RulesController < ApplicationController
@rule_types = Rule::RULE_TYPES
@actions = Rule::ACTIONS
# Process additional form data for quick create
process_quick_create_parameters
# Handle network range creation if CIDR is provided
if params[:cidr].present? && @rule.network_rule?
network_range = NetworkRange.find_or_create_by(cidr: params[:cidr]) do |range|
@@ -53,8 +55,17 @@ class RulesController < ApplicationController
@rule.network_range = network_range
end
# Calculate priority automatically based on rule type
calculate_rule_priority
if @rule.save
redirect_to @rule, notice: 'Rule was successfully created.'
# For quick create from NetworkRange page, redirect back to network range
if params[:rule][:network_range_id].present? && request.referer&.include?('/network_ranges/')
network_range = NetworkRange.find(params[:rule][:network_range_id])
redirect_to network_range, notice: 'Rule was successfully created.'
else
redirect_to @rule, notice: 'Rule was successfully created.'
end
else
render :new, status: :unprocessable_entity
end
@@ -122,13 +133,236 @@ class RulesController < ApplicationController
params.require(:rule).permit(permitted)
end
def set_project
# For now, use the first project or create a default one
@project = Project.first || Project.create!(
name: 'Default Project',
slug: 'default',
public_key: SecureRandom.hex(32)
)
def calculate_rule_priority
return unless @rule
case @rule.rule_type
when 'network'
# For network rules, priority based on prefix specificity
if @rule.network_range
prefix = @rule.network_range.prefix_length
@rule.priority = case prefix
when 32 then 200 # /32 single IP
when 31 then 190
when 30 then 180
when 29 then 170
when 28 then 160
when 27 then 150
when 26 then 140
when 25 then 130
when 24 then 120
when 23 then 110
when 22 then 100
when 21 then 90
when 20 then 80
when 19 then 70
when 18 then 60
when 17 then 50
when 16 then 40
when 15 then 30
when 14 then 20
when 13 then 10
else 0
end
else
@rule.priority = 100 # Default for network rules without range
end
when 'protocol_violation'
@rule.priority = 95
when 'method_enforcement'
@rule.priority = 90
when 'path_pattern'
@rule.priority = 85
when 'header_pattern', 'query_pattern'
@rule.priority = 80
when 'body_signature'
@rule.priority = 75
when 'rate_limit'
@rule.priority = 70
when 'composite'
@rule.priority = 65
else
@rule.priority = 50 # Default priority
end
end
def process_quick_create_parameters
return unless @rule
# Handle rate limiting parameters
if @rule.rate_limit_rule? && params[:rate_limit].present? && params[:rate_window].present?
rate_limit_data = {
limit: params[:rate_limit].to_i,
window_seconds: params[:rate_window].to_i,
scope: 'per_ip'
}
# Update conditions with rate limit data
@rule.conditions ||= {}
@rule.conditions.merge!(rate_limit_data)
end
end
# Handle redirect URL
if @rule.action == 'redirect' && params[:redirect_url].present?
@rule.metadata ||= {}
if @rule.metadata.is_a?(String)
begin
@rule.metadata = JSON.parse(@rule.metadata)
rescue JSON::ParserError
@rule.metadata = {}
end
end
@rule.metadata.merge!({
redirect_url: params[:redirect_url],
redirect_status: 302
})
end
# Parse metadata if it's a string that looks like JSON
if @rule.metadata.is_a?(String) && @rule.metadata.starts_with?('{')
begin
@rule.metadata = JSON.parse(@rule.metadata)
rescue JSON::ParserError
# Keep as string if not valid JSON
end
end
# Add reason to metadata if provided
if params.dig(:rule, :metadata).present?
if @rule.metadata.is_a?(Hash)
@rule.metadata['reason'] = params[:rule][:metadata]
else
@rule.metadata = { 'reason' => params[:rule][:metadata] }
end
end
end
private
def set_rule
@rule = Rule.find(params[:id])
end
def rule_params
permitted = [
:rule_type,
:action,
:metadata,
:expires_at,
:enabled,
:source,
:network_range_id
]
# Only include conditions for non-network rules
if params[:rule][:rule_type] != 'network'
permitted << :conditions
end
params.require(:rule).permit(permitted)
end
def calculate_rule_priority
return unless @rule
case @rule.rule_type
when 'network'
# For network rules, priority based on prefix specificity
if @rule.network_range
prefix = @rule.network_range.prefix_length
@rule.priority = case prefix
when 32 then 200 # /32 single IP
when 31 then 190
when 30 then 180
when 29 then 170
when 28 then 160
when 27 then 150
when 26 then 140
when 25 then 130
when 24 then 120
when 23 then 110
when 22 then 100
when 21 then 90
when 20 then 80
when 19 then 70
when 18 then 60
when 17 then 50
when 16 then 40
when 15 then 30
when 14 then 20
when 13 then 10
else 0
end
else
@rule.priority = 100 # Default for network rules without range
end
when 'protocol_violation'
@rule.priority = 95
when 'method_enforcement'
@rule.priority = 90
when 'path_pattern'
@rule.priority = 85
when 'header_pattern', 'query_pattern'
@rule.priority = 80
when 'body_signature'
@rule.priority = 75
when 'rate_limit'
@rule.priority = 70
when 'composite'
@rule.priority = 65
else
@rule.priority = 50 # Default priority
end
end
def process_quick_create_parameters
return unless @rule
# Handle rate limiting parameters
if @rule.rate_limit_rule? && params[:rate_limit].present? && params[:rate_window].present?
rate_limit_data = {
limit: params[:rate_limit].to_i,
window_seconds: params[:rate_window].to_i,
scope: 'per_ip'
}
# Update conditions with rate limit data
@rule.conditions ||= {}
@rule.conditions.merge!(rate_limit_data)
end
# Handle redirect URL
if @rule.action == 'redirect' && params[:redirect_url].present?
@rule.metadata ||= {}
if @rule.metadata.is_a?(String)
begin
@rule.metadata = JSON.parse(@rule.metadata)
rescue JSON::ParserError
@rule.metadata = {}
end
end
@rule.metadata.merge!({
redirect_url: params[:redirect_url],
redirect_status: 302
})
end
# Parse metadata if it's a string that looks like JSON
if @rule.metadata.is_a?(String) && @rule.metadata.starts_with?('{')
begin
@rule.metadata = JSON.parse(@rule.metadata)
rescue JSON::ParserError
# Keep as string if not valid JSON
end
end
# Add reason to metadata if provided
if params.dig(:rule, :metadata).present?
if @rule.metadata.is_a?(Hash)
@rule.metadata['reason'] = params[:rule][:metadata]
else
@rule.metadata = { 'reason' => params[:rule][:metadata] }
end
end
end
end