diff --git a/app/controllers/concerns/valid_request.rb b/app/controllers/concerns/valid_request.rb index 56f44aaee..39ee0b59a 100644 --- a/app/controllers/concerns/valid_request.rb +++ b/app/controllers/concerns/valid_request.rb @@ -34,6 +34,8 @@ module ValidRequest "#{URL.protocol || request.protocol}#{request.host_with_port}#{options}" when Proc _compute_redirect_to_location request, instance_eval(&options) + when Array + url_for else url_for(options) end.delete("\0\r\n") diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index c101108d8..7d5925a72 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -46,6 +46,12 @@ module Rack end end + throttle("forgot_password_throttle", limit: 3, period: 1) do |request| + if request.path.starts_with?("/users/password") && request.post? + request.track_and_return_ip + end + end + throttle("api_write_throttle", limit: 1, period: 1) do |request| api_endpoint = request.path.starts_with?("/api/") if api_endpoint && (request.put? || request.post? || request.delete?) diff --git a/spec/initializers/rack_attack_spec.rb b/spec/initializers/rack_attack_spec.rb index bf0b1f3c8..baa576ca2 100644 --- a/spec/initializers/rack_attack_spec.rb +++ b/spec/initializers/rack_attack_spec.rb @@ -1,17 +1,15 @@ require "rails_helper" -describe Rack, ".attack", type: :request, throttle: true do +describe Rack, ".attack", throttle: true, type: :request do before do - cache_db = ActiveSupport::Cache.lookup_store(:redis_cache_store) - allow(Rails).to receive(:cache) { cache_db } - cache_db.redis.flushdb + allow(Rails).to receive(:cache) { ActiveSupport::Cache.lookup_store(:redis_cache_store) } allow(Honeycomb).to receive(:add_field) - ENV["FASTLY_API_KEY"] = "12345" end after do ENV["FASTLY_API_KEY"] = nil + Rails.cache.clear end describe "search_throttle" do @@ -171,4 +169,22 @@ describe Rack, ".attack", type: :request, throttle: true do end # rubocop:enable RSpec/AnyInstance, RSpec/ExampleLength end + + describe "forgot_password_throttle" do + it "throttles after 3 attempts" do + params = { user: { email: "yo@email.com" } } + admin_headers = { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" } + + Timecop.freeze do + 3.times do + post "/users/password", params: params, headers: admin_headers + expect(response).to have_http_status(:found) + end + 3.times do + post "/users/password", params: params, headers: admin_headers + expect(response).to have_http_status(:too_many_requests) + end + end + end + end end