mirror of
https://github.com/samsonjs/rack-attack.git
synced 2026-04-27 15:07:41 +00:00
Merge branch 'master' into patch-3
This commit is contained in:
commit
937cd3ca20
14 changed files with 76 additions and 42 deletions
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
## master (unreleased)
|
## master (unreleased)
|
||||||
* Implement proxy for Dalli with better Memcachier support. (thanks @hakanensari)
|
* Implement proxy for Dalli with better Memcachier support. (thanks @hakanensari)
|
||||||
|
* Rack::Attack.new returns an instance to ease testing (thanks @stevehodgkiss)
|
||||||
|
* Use Rack::Attack::Request subclass of Rack::Request for easier extending (thanks @tristandunn)
|
||||||
|
|
||||||
## v3.0.0 - 15 March 2014
|
## v3.0.0 - 15 March 2014
|
||||||
* Change default blacklisted response to 403 Forbidden (thanks @carpodaster).
|
* Change default blacklisted response to 403 Forbidden (thanks @carpodaster).
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
require 'rack'
|
require 'rack'
|
||||||
module Rack::Attack
|
require 'forwardable'
|
||||||
|
|
||||||
|
class Rack::Attack
|
||||||
autoload :Cache, 'rack/attack/cache'
|
autoload :Cache, 'rack/attack/cache'
|
||||||
autoload :Check, 'rack/attack/check'
|
autoload :Check, 'rack/attack/check'
|
||||||
autoload :Throttle, 'rack/attack/throttle'
|
autoload :Throttle, 'rack/attack/throttle'
|
||||||
|
|
@ -8,7 +10,8 @@ module Rack::Attack
|
||||||
autoload :Track, 'rack/attack/track'
|
autoload :Track, 'rack/attack/track'
|
||||||
autoload :StoreProxy,'rack/attack/store_proxy'
|
autoload :StoreProxy,'rack/attack/store_proxy'
|
||||||
autoload :Fail2Ban, 'rack/attack/fail2ban'
|
autoload :Fail2Ban, 'rack/attack/fail2ban'
|
||||||
autoload :Allow2Ban, 'rack/attack/allow2ban'
|
autoload :Allow2Ban, 'rack/attack/allow2ban'
|
||||||
|
autoload :Request, 'rack/attack/request'
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
|
|
@ -35,35 +38,6 @@ module Rack::Attack
|
||||||
def throttles; @throttles ||= {}; end
|
def throttles; @throttles ||= {}; end
|
||||||
def tracks; @tracks ||= {}; end
|
def tracks; @tracks ||= {}; end
|
||||||
|
|
||||||
def new(app)
|
|
||||||
@app = app
|
|
||||||
|
|
||||||
# Set defaults
|
|
||||||
@notifier ||= ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
|
|
||||||
@blacklisted_response ||= lambda {|env| [403, {}, ["Forbidden\n"]] }
|
|
||||||
@throttled_response ||= lambda {|env|
|
|
||||||
retry_after = env['rack.attack.match_data'][:period] rescue nil
|
|
||||||
[429, {'Retry-After' => retry_after.to_s}, ["Retry later\n"]]
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
req = Rack::Request.new(env)
|
|
||||||
|
|
||||||
if whitelisted?(req)
|
|
||||||
@app.call(env)
|
|
||||||
elsif blacklisted?(req)
|
|
||||||
blacklisted_response[env]
|
|
||||||
elsif throttled?(req)
|
|
||||||
throttled_response[env]
|
|
||||||
else
|
|
||||||
tracked?(req)
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def whitelisted?(req)
|
def whitelisted?(req)
|
||||||
whitelists.any? do |name, whitelist|
|
whitelists.any? do |name, whitelist|
|
||||||
whitelist[req]
|
whitelist[req]
|
||||||
|
|
@ -101,4 +75,37 @@ module Rack::Attack
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Set defaults
|
||||||
|
@notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
|
||||||
|
@blacklisted_response = lambda {|env| [403, {}, ["Forbidden\n"]] }
|
||||||
|
@throttled_response = lambda {|env|
|
||||||
|
retry_after = env['rack.attack.match_data'][:period] rescue nil
|
||||||
|
[429, {'Retry-After' => retry_after.to_s}, ["Retry later\n"]]
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
req = Rack::Attack::Request.new(env)
|
||||||
|
|
||||||
|
if whitelisted?(req)
|
||||||
|
@app.call(env)
|
||||||
|
elsif blacklisted?(req)
|
||||||
|
self.class.blacklisted_response[env]
|
||||||
|
elsif throttled?(req)
|
||||||
|
self.class.throttled_response[env]
|
||||||
|
else
|
||||||
|
tracked?(req)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend Forwardable
|
||||||
|
def_delegators self, :whitelisted?,
|
||||||
|
:blacklisted?,
|
||||||
|
:throttled?,
|
||||||
|
:tracked?
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Allow2Ban < Fail2Ban
|
class Allow2Ban < Fail2Ban
|
||||||
class << self
|
class << self
|
||||||
protected
|
protected
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Blacklist < Check
|
class Blacklist < Check
|
||||||
def initialize(name, block)
|
def initialize(name, block)
|
||||||
super
|
super
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Cache
|
class Cache
|
||||||
|
|
||||||
attr_accessor :prefix
|
attr_accessor :prefix
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Check
|
class Check
|
||||||
attr_reader :name, :block, :type
|
attr_reader :name, :block, :type
|
||||||
def initialize(name, block)
|
def initialize(name, block)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Fail2Ban
|
class Fail2Ban
|
||||||
class << self
|
class << self
|
||||||
def filter(discriminator, options)
|
def filter(discriminator, options)
|
||||||
|
|
|
||||||
6
lib/rack/attack/request.rb
Normal file
6
lib/rack/attack/request.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
module Rack
|
||||||
|
class Attack
|
||||||
|
class Request < ::Rack::Request
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
require 'delegate'
|
require 'delegate'
|
||||||
|
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class StoreProxy
|
class StoreProxy
|
||||||
def self.build(store)
|
def self.build(store)
|
||||||
# RedisStore#increment needs different behavior, so detect that
|
# RedisStore#increment needs different behavior, so detect that
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Throttle
|
class Throttle
|
||||||
MANDATORY_OPTIONS = [:limit, :period]
|
MANDATORY_OPTIONS = [:limit, :period]
|
||||||
attr_reader :name, :limit, :period, :block
|
attr_reader :name, :limit, :period, :block
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Track < Check
|
class Track < Check
|
||||||
def initialize(name, block)
|
def initialize(name, block)
|
||||||
super
|
super
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
VERSION = '3.0.0'
|
VERSION = '3.1.0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Rack
|
module Rack
|
||||||
module Attack
|
class Attack
|
||||||
class Whitelist < Check
|
class Whitelist < Check
|
||||||
def initialize(name, block)
|
def initialize(name, block)
|
||||||
super
|
super
|
||||||
|
|
|
||||||
19
spec/rack_attack_request_spec.rb
Normal file
19
spec/rack_attack_request_spec.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
require_relative 'spec_helper'
|
||||||
|
|
||||||
|
describe 'Rack::Attack' do
|
||||||
|
describe 'helpers' do
|
||||||
|
before do
|
||||||
|
class Rack::Attack::Request
|
||||||
|
def remote_ip
|
||||||
|
ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rack::Attack.whitelist('valid IP') do |req|
|
||||||
|
req.remote_ip == "127.0.0.1"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
allow_ok_requests
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue