diff --git a/config/application.rb b/config/application.rb index 1a050ddd8..16f0a28a1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -76,6 +76,7 @@ module PracticalDeveloper config.eager_load_paths += Dir["#{config.root}/lib"] config.middleware.use Rack::Deflater + config.middleware.insert_after ActionDispatch::RemoteIp, Rack::Attack config.i18n.load_path += Dir[Rails.root.join("config/locales/**/*.yml")] diff --git a/config/initializers/rack/attack.rb b/config/initializers/rack/attack.rb index 3174d8dab..559676904 100644 --- a/config/initializers/rack/attack.rb +++ b/config/initializers/rack/attack.rb @@ -1,23 +1,29 @@ +Rails.application.reloader.to_prepare do + Dir.glob(Rails.root.join("lib/rack/attack/*.rb")).each do |filename| + require_dependency filename + end +end + Rack::Attack.throttled_response_retry_after_header = true module Rack class Attack throttle("search_throttle", limit: 5, period: 1) do |request| if request.path.starts_with?("/search/") - track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) + track_and_return_ip(request) end end throttle("api_throttle", limit: 3, period: 1) do |request| if request.path.starts_with?("/api/") && request.get? - track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) + track_and_return_ip(request) end end throttle("api_write_throttle", limit: 1, period: 1) do |request| if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?) Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"]) - ip_address = track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) + ip_address = track_and_return_ip(request) if request.env["HTTP_API_KEY"].present? "#{ip_address}-#{request.env['HTTP_API_KEY']}" elsif ip_address.present? @@ -27,19 +33,25 @@ module Rack end throttle("site_hits", limit: 40, period: 2) do |request| - track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) + track_and_return_ip(request) end throttle("tag_throttle", limit: 2, period: 1) do |request| if tag_request?(request) - track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) + track_and_return_ip(request) end end - def self.track_and_return_ip(ip_address) + def self.track_and_return_ip(req) + ip_address = if ApplicationConfig["FASTLY_API_KEY"].present? + req.env["HTTP_FASTLY_CLIENT_IP"] + else + req.remote_ip + end return if ip_address.blank? - Honeycomb.add_field("fastly_client_ip", ip_address) + Honeycomb.add_field("fastly_client_ip", req.env["HTTP_FASTLY_CLIENT_IP"]) + Honeycomb.add_field("remote_ip", req.remote_ip) ip_address.to_s end diff --git a/lib/rack/attack/request.rb b/lib/rack/attack/request.rb new file mode 100644 index 000000000..070fde8ce --- /dev/null +++ b/lib/rack/attack/request.rb @@ -0,0 +1,9 @@ +module Rack + class Attack + class Request < ::Rack::Request + def remote_ip + @remote_ip ||= ActionDispatch::Request.new(env).remote_ip + end + end + end +end diff --git a/spec/initializers/rack/attack_spec.rb b/spec/initializers/rack/attack_spec.rb index e34d7fc59..dbb286e05 100644 --- a/spec/initializers/rack/attack_spec.rb +++ b/spec/initializers/rack/attack_spec.rb @@ -6,6 +6,11 @@ describe Rack::Attack, type: :request, throttle: true do allow(Rails).to receive(:cache) { cache_db } cache_db.redis.flushdb allow(Honeycomb).to receive(:add_field) + ENV["FASTLY_API_KEY"] = "12345" + end + + after do + ENV["FASTLY_API_KEY"] = nil end describe "search_throttle" do