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) ⇒ BlockRequestChecker



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

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

Instance Method Details

#block?(controller) ⇒ Boolean



22
23
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 22

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]
  return false if context.nil?

  request = context.request

  return false if @zen.request_bypassed?

  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