Fix mobile view menu popout. Add an option SENTRY_DSN support, which uses rails event reporting
This commit is contained in:
120
config/initializers/sentry_subscriber.rb
Normal file
120
config/initializers/sentry_subscriber.rb
Normal file
@@ -0,0 +1,120 @@
|
||||
# Sentry subscriber for CSP violations via Structured Event Reporting
|
||||
# This subscriber only sends events to Sentry if Sentry is properly initialized
|
||||
|
||||
Rails.application.config.after_initialize do
|
||||
# Only register the subscriber if Sentry is available and configured
|
||||
if defined?(Sentry) && Sentry.initialized?
|
||||
|
||||
module CspViolationSentrySubscriber
|
||||
def self.emit(event_data)
|
||||
# Extract relevant CSP violation data
|
||||
csp_data = event_data[:data] || {}
|
||||
|
||||
# Build a descriptive message for Sentry
|
||||
violated_directive = csp_data[:violated_directive]
|
||||
blocked_uri = csp_data[:blocked_uri]
|
||||
document_uri = csp_data[:document_uri]
|
||||
|
||||
message = "CSP Violation: #{violated_directive}"
|
||||
message += " - Blocked: #{blocked_uri}" if blocked_uri.present?
|
||||
message += " - On: #{document_uri}" if document_uri.present?
|
||||
|
||||
# Extract domain from blocked_uri for better classification
|
||||
blocked_domain = extract_domain(blocked_uri) if blocked_uri.present?
|
||||
|
||||
# Determine severity based on violation type
|
||||
level = determine_severity(violated_directive, blocked_uri)
|
||||
|
||||
# Send to Sentry with rich context
|
||||
Sentry.capture_message(
|
||||
message,
|
||||
level: level,
|
||||
tags: {
|
||||
csp_violation: true,
|
||||
violated_directive: violated_directive,
|
||||
blocked_domain: blocked_domain,
|
||||
document_domain: extract_domain(document_uri),
|
||||
user_authenticated: csp_data[:current_user_id].present?
|
||||
},
|
||||
extra: {
|
||||
# Full CSP report data
|
||||
csp_violation_details: csp_data,
|
||||
# Additional context for security analysis
|
||||
request_context: {
|
||||
user_agent: csp_data[:user_agent],
|
||||
ip_address: csp_data[:ip_address],
|
||||
session_id: csp_data[:session_id],
|
||||
timestamp: csp_data[:timestamp]
|
||||
}
|
||||
},
|
||||
user: csp_data[:current_user_id] ? { id: csp_data[:current_user_id] } : nil
|
||||
)
|
||||
|
||||
# Log to Rails logger for redundancy
|
||||
Rails.logger.info "CSP violation sent to Sentry: #{message}"
|
||||
rescue => e
|
||||
# Ensure subscriber errors don't break the CSP reporting flow
|
||||
Rails.logger.error "Failed to send CSP violation to Sentry: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n") if Rails.env.development?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Extract domain from URI for better analysis
|
||||
def self.extract_domain(uri)
|
||||
return nil if uri.blank?
|
||||
|
||||
begin
|
||||
parsed = URI.parse(uri)
|
||||
parsed.host
|
||||
rescue URI::InvalidURIError
|
||||
# Handle cases where URI might be malformed or just a path
|
||||
if uri.start_with?('/')
|
||||
nil # It's a relative path, no domain
|
||||
else
|
||||
uri.split('/').first # Best effort extraction
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Determine severity level based on violation type
|
||||
def self.determine_severity(violated_directive, blocked_uri)
|
||||
return :warning unless violated_directive.present?
|
||||
|
||||
case violated_directive.to_sym
|
||||
when :script_src, :script_src_elem, :script_src_attr
|
||||
# Script violations are highest priority (XSS risk)
|
||||
:error
|
||||
when :style_src, :style_src_elem, :style_src_attr
|
||||
# Style violations are moderate risk
|
||||
:warning
|
||||
when :img_src
|
||||
# Image violations are typically lower priority
|
||||
:info
|
||||
when :connect_src
|
||||
# Network violations are important
|
||||
:warning
|
||||
when :font_src, :media_src
|
||||
# Font/media violations are lower priority
|
||||
:info
|
||||
when :frame_src, :child_src
|
||||
# Frame violations can be security critical
|
||||
:error
|
||||
when :default_src
|
||||
# Default src violations are important
|
||||
:warning
|
||||
else
|
||||
# Unknown or custom directives
|
||||
:warning
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Register the subscriber for CSP violation events
|
||||
Rails.event.subscribe("csp.violation", CspViolationSentrySubscriber)
|
||||
|
||||
Rails.logger.info "CSP violation Sentry subscriber registered"
|
||||
else
|
||||
Rails.logger.info "Sentry not initialized - CSP violations will only be logged locally"
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user