Class: Aikido::Zen::Sinks::ActionController::BlockRequestChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/aikido/zen/sinks/action_controller.rb

Overview

Implements the “middleware” for blocking requests (i.e.: rate-limiting or blocking user/bots) in Rails apps, where we need to check at the end of the ‘before_action` chain, rather than in an actual Rack middleware, to allow for calls to `Zen.track_user` being made from before_actions in the host app, thus allowing block/rate-limit by user ID rather than solely by IP.

Instance Method Summary collapse

Constructor Details

#initialize(zen: Aikido::Zen, config: Aikido::Zen.config, settings: Aikido::Zen.runtime_settings, detached_agent: Aikido::Zen.detached_agent) ⇒ BlockRequestChecker

Returns a new instance of BlockRequestChecker.



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/aikido/zen/sinks/action_controller.rb', line 12

def initialize(
  zen: Aikido::Zen,
  config: Aikido::Zen.config,
  settings: Aikido::Zen.runtime_settings,
  detached_agent: Aikido::Zen.detached_agent
)
  @zen = zen
  @config = config
  @settings = settings
  @detached_agent = detached_agent
end

Instance Method Details

#block?(controller) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/aikido/zen/sinks/action_controller.rb', line 24

def block?(controller)
  # The abstract controller running the callback is typically an ActionController
  # but it may also be an ActionMailer. ActionMailer does not respond to request.
  # This feature requires a request object to perform checks and enforce blocking.
  return false unless controller.respond_to?(:request)

  context = controller.request.env[Aikido::Zen::ENV_KEY]
  request = context.request

  return false if @settings.bypassed_ips.include?(request.client_ip)

  if should_block_user?(request)
    status, headers, body = @config.blocked_responder.call(request, :user)
    controller.headers.update(headers)
    controller.render plain: Array(body).join, status: status

    return true
  end

  if should_throttle?(request)
    @zen.track_rate_limited_request(request)
    status, headers, body = @config.rate_limited_responder.call(request)
    controller.headers.update(headers)
    controller.render plain: Array(body).join, status: status

    return true
  end

  false
end