diff --git a/config/initializers/rack/attack.rb b/config/initializers/rack/attack.rb index 57953c159..9219c96e4 100644 --- a/config/initializers/rack/attack.rb +++ b/config/initializers/rack/attack.rb @@ -2,37 +2,45 @@ Rack::Attack.throttled_response_retry_after_header = true class Rack::Attack throttle("search_throttle", limit: 5, period: 1) do |request| - if request.path.starts_with?("/search/") && request.env["HTTP_FASTLY_CLIENT_IP"].present? - Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) - request.env["HTTP_FASTLY_CLIENT_IP"].to_s + return if request.env["HTTP_FASTLY_CLIENT_IP"].blank? + + if request.path.starts_with?("/search/") + track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) end end throttle("api_throttle", limit: 3, period: 1) do |request| - if request.path.starts_with?("/api/") && request.get? && request.env["HTTP_FASTLY_CLIENT_IP"].present? - Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) - request.env["HTTP_FASTLY_CLIENT_IP"].to_s + return if request.env["HTTP_FASTLY_CLIENT_IP"].blank? + + if request.path.starts_with?("/api/") && request.get? + track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) end end throttle("api_write_throttle", limit: 1, period: 1) do |request| + return if request.env["HTTP_FASTLY_CLIENT_IP"].blank? + if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?) - Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"]) - request.env["HTTP_API_KEY"] + track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) end end throttle("site_hits", limit: 40, period: 2) do |request| - if request.env["HTTP_FASTLY_CLIENT_IP"].present? - Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) - request.env["HTTP_FASTLY_CLIENT_IP"].to_s - end + return if request.env["HTTP_FASTLY_CLIENT_IP"].blank? + + track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) end throttle("message_throttle", limit: 2, period: 1) do |request| - if request.path.starts_with?("/messages") && request.post? && request.env["HTTP_FASTLY_CLIENT_IP"].present? - Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"]) - request.env["HTTP_FASTLY_CLIENT_IP"].to_s + return if request.env["HTTP_FASTLY_CLIENT_IP"].blank? + + if request.path.starts_with?("/messages") && request.post? + track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"]) end end + + def self.track_and_return_ip(ip_address) + Honeycomb.add_field("fastly_client_ip", ip_address) + ip_address.to_s + end end diff --git a/spec/initializers/rack/attack_spec.rb b/spec/initializers/rack/attack_spec.rb index 144700d39..6c9358789 100644 --- a/spec/initializers/rack/attack_spec.rb +++ b/spec/initializers/rack/attack_spec.rb @@ -49,21 +49,21 @@ describe Rack::Attack, type: :request, throttle: true do let(:api_secret) { create(:api_secret) } let(:another_api_secret) { create(:api_secret) } - it "throttles api write endpoints based on api-key" do - headers = { "api-key" => api_secret.secret, "content-type" => "application/json" } - dif_headers = { "api-key" => another_api_secret.secret, "content-type" => "application/json" } - params = { body_markdown: "", title: Faker::Book.title } + it "throttles api write endpoints based on IP" do + headers = { "api-key" => api_secret.secret, "content-type" => "application/json", "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" } + dif_headers = { "api-key" => another_api_secret.secret, "content-type" => "application/json", "HTTP_FASTLY_CLIENT_IP" => "1.1.1.1" } + params = { article: { body_markdown: "", title: Faker::Book.title } }.to_json Timecop.freeze do - valid_response = post api_articles_path, params: { article: params }.to_json, headers: headers - throttled_response = post api_articles_path, params: { article: params }.to_json, headers: headers - new_api_response = post api_articles_path, params: { article: params }.to_json, headers: dif_headers + valid_response = post api_articles_path, params: params, headers: headers + throttled_response = post api_articles_path, params: params, headers: headers + new_api_response = post api_articles_path, params: params, headers: dif_headers expect(valid_response).not_to eq(429) expect(throttled_response).to eq(429) expect(new_api_response).not_to eq(429) - expect(Honeycomb).to have_received(:add_field).with("user_api_key", api_secret.secret).exactly(2).times - expect(Honeycomb).to have_received(:add_field).with("user_api_key", another_api_secret.secret) + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8").exactly(3).times + expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "1.1.1.1").exactly(2).times end end end