Class: Reputable::Middleware
- Inherits:
-
Object
- Object
- Reputable::Middleware
- Defined in:
- lib/reputable/middleware.rb
Overview
Rack middleware for automatic request tracking
RESILIENCE: This middleware is designed to NEVER break your application.
- Disable entirely via ENV: REPUTABLE_ENABLED=false
- All errors are caught and logged silently
- Circuit breaker prevents repeated failures from impacting performance
- Async mode (default) runs tracking in a separate thread
Constant Summary collapse
- DEFAULT_SKIP_PATHS =
%w[ /health /healthz /ready /readyz /live /livez /metrics /favicon.ico ].freeze
- DEFAULT_SKIP_EXTENSIONS =
%w[ .js .css .png .jpg .jpeg .gif .svg .ico .woff .woff2 .ttf .eot .map ].freeze
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, options = {}) ⇒ Middleware
constructor
A new instance of Middleware.
Constructor Details
#initialize(app, options = {}) ⇒ Middleware
Returns a new instance of Middleware.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/reputable/middleware.rb', line 41 def initialize(app, = {}) @app = app @skip_paths = .fetch(:skip_paths, DEFAULT_SKIP_PATHS) @skip_path_prefixes = Array([:skip_path_prefixes]) @skip_extensions = .fetch(:skip_extensions, DEFAULT_SKIP_EXTENSIONS) @skip_if = [:skip_if] @skip_ips = Array([:skip_ips]) @skip_user_agents = Array([:skip_user_agents]).map(&:downcase) @skip_query_params = Array([:skip_query_params]).map(&:downcase) @tag_builder = [:tag_builder] @async = .fetch(:async, true) @track_request = .key?(:track_request) ? [:track_request] : nil @reputation_gate = .fetch(:reputation_gate, false) @expose_reputation = .fetch(:expose_reputation, true) @challenge_action = .fetch(:challenge_action, :verify) @block_action = .fetch(:block_action, :blocked_page_remote) @challenge_redirect_status = .fetch(:challenge_redirect_status, 302) @blocked_redirect_status = .fetch(:blocked_redirect_status, 302) @blocked_redirect_url = [:blocked_redirect_url] @verification_force_challenge = .fetch(:verification_force_challenge, false) @verification_failure_url = [:verification_failure_url] @verification_session_id = [:verification_session_id] @verified_session_keys = Array(.fetch(:verified_session_keys, [:reputable_verified_at, :reputable_verified])) @blocked_page_options = .fetch(:blocked_page, {}) @blocked_page_path = [:blocked_page_path] @ignore_xhr = .fetch(:ignore_xhr, false) end |
Instance Method Details
#call(env) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/reputable/middleware.rb', line 69 def call(env) # Generate a unique request ID for reconciliation with JS tracking # This ID is exposed to views so it can be included in the JS snippet env['reputable.request_id'] = SecureRandom.uuid ip = extract_ip(env) env["reputable.ip"] = ip path = env["PATH_INFO"] || "/" # Check for verification return parameters and verify signature if present handle_verification_return(env) # Optional: render blocked page path directly if (blocked_response = handle_blocked_page_request(env)) return blocked_response end # Optional: enforce reputation gate before app if (gate_response = safe_reputation_gate(env)) return gate_response end # Optional: expose reputation context for views/controllers safe_apply_reputation_context(env) if @expose_reputation # ALWAYS process the request first - tracking must never block status, headers, response = @app.call(env) # Only attempt tracking if enabled and not skipped # All tracking is wrapped in rescue to ensure it never fails safe_track_request(env) # Single summary line for requests that passed through without intervention if Reputable.verbose? rep_status = env["reputable.reputation_status"] Reputable.logger&.info("[Reputable] #{env['REQUEST_METHOD']} #{path} ip=#{ip} status=#{rep_status || 'unknown'} gate=#{@reputation_gate} result=pass") end [status, headers, response] end |