better_rate_limit 0.1.2 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -62
- data/.travis.yml +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +12 -1
- data/lib/action_controller/better_rate_limit.rb +38 -13
- data/lib/better_rate_limit.rb +17 -0
- data/lib/better_rate_limit/configuration.rb +11 -0
- data/lib/better_rate_limit/limit.rb +75 -0
- data/lib/better_rate_limit/throttle.rb +10 -0
- data/lib/better_rate_limit/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd081be677a01d7f69d7e6e6ada8a3172d84d6ee74fbf7ccab5d5fbecb89ee58
|
4
|
+
data.tar.gz: 2817642bfee1165564273b8b36ae434e02e7135c6e63a887a4c178c4558d3752
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdd3fda987a39c8027d47ddec7b6112e089a609aaabd3a924e71a76417619b69284416183d68744ea05fa55b47e1cead0d04cb99ddb33937e6db97f578d784db
|
7
|
+
data.tar.gz: 7b03b579af9be74f8669af5531d254580b0f384232dc5cb295f6d4cbcea7ca3525d42ee41105f0c08dd121c6a68d91544e06dd38a7044bd0b4062cc6007077c5
|
data/.gitignore
CHANGED
@@ -1,61 +1,3 @@
|
|
1
|
-
<<<<<<< HEAD
|
2
|
-
*.gem
|
3
|
-
*.rbc
|
4
|
-
/.config
|
5
|
-
/coverage/
|
6
|
-
/InstalledFiles
|
7
|
-
/pkg/
|
8
|
-
/spec/reports/
|
9
|
-
/spec/examples.txt
|
10
|
-
/test/tmp/
|
11
|
-
/test/version_tmp/
|
12
|
-
/tmp/
|
13
|
-
|
14
|
-
# Used by dotenv library to load environment variables.
|
15
|
-
# .env
|
16
|
-
|
17
|
-
# Ignore Byebug command history file.
|
18
|
-
.byebug_history
|
19
|
-
|
20
|
-
## Specific to RubyMotion:
|
21
|
-
.dat*
|
22
|
-
.repl_history
|
23
|
-
build/
|
24
|
-
*.bridgesupport
|
25
|
-
build-iPhoneOS/
|
26
|
-
build-iPhoneSimulator/
|
27
|
-
|
28
|
-
## Specific to RubyMotion (use of CocoaPods):
|
29
|
-
#
|
30
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
31
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
32
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
33
|
-
#
|
34
|
-
# vendor/Pods/
|
35
|
-
|
36
|
-
## Documentation cache and generated files:
|
37
|
-
/.yardoc/
|
38
|
-
/_yardoc/
|
39
|
-
/doc/
|
40
|
-
/rdoc/
|
41
|
-
|
42
|
-
## Environment normalization:
|
43
|
-
/.bundle/
|
44
|
-
/vendor/bundle
|
45
|
-
/lib/bundler/man/
|
46
|
-
|
47
|
-
# for a library or gem, you might want to ignore these files since the code is
|
48
|
-
# intended to run in multiple environments; otherwise, check them in:
|
49
|
-
# Gemfile.lock
|
50
|
-
# .ruby-version
|
51
|
-
# .ruby-gemset
|
52
|
-
|
53
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
54
|
-
.rvmrc
|
55
|
-
|
56
|
-
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
57
|
-
# .rubocop-https?--*
|
58
|
-
=======
|
59
1
|
/.bundle/
|
60
2
|
/.yardoc
|
61
3
|
/_yardoc/
|
@@ -64,7 +6,5 @@ build-iPhoneSimulator/
|
|
64
6
|
/pkg/
|
65
7
|
/spec/reports/
|
66
8
|
/tmp/
|
67
|
-
|
68
|
-
|
69
|
-
.rspec_status
|
70
|
-
>>>>>>> init gem
|
9
|
+
*.gem
|
10
|
+
.byebug_history
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
better_rate_limit (0.1.
|
4
|
+
better_rate_limit (0.1.5)
|
5
5
|
actionpack (>= 5.0)
|
6
6
|
redis (>= 3.3)
|
7
7
|
|
@@ -59,7 +59,7 @@ GEM
|
|
59
59
|
rails-html-sanitizer (1.3.0)
|
60
60
|
loofah (~> 2.3)
|
61
61
|
rake (12.3.3)
|
62
|
-
redis (4.2.
|
62
|
+
redis (4.2.5)
|
63
63
|
thread_safe (0.3.6)
|
64
64
|
timecop (0.9.1)
|
65
65
|
tzinfo (1.2.7)
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# BetterRateLimit
|
2
|
+
[](https://travis-ci.org/upscopeio/better_rate_limit)
|
3
|
+
[](https://badge.fury.io/rb/better_rate_limit)
|
2
4
|
|
3
5
|
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/better_rate_limit`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
6
|
|
@@ -7,7 +9,7 @@ Welcome to your new gem! In this directory, you'll find the files you need to be
|
|
7
9
|
Add this line to your application's Gemfile:
|
8
10
|
|
9
11
|
```ruby
|
10
|
-
gem 'better_rate_limit'
|
12
|
+
gem 'better_rate_limit'
|
11
13
|
```
|
12
14
|
|
13
15
|
And then execute:
|
@@ -39,6 +41,15 @@ ActiveSupport::Notifications.subscribe /rate_limit/ do |_name, _start, _finish,
|
|
39
41
|
end
|
40
42
|
```
|
41
43
|
|
44
|
+
### Configuration
|
45
|
+
You can ignore the throttle by using the following configuration
|
46
|
+
```ruby
|
47
|
+
BetterRateLimit.configure do |config|
|
48
|
+
config.ignore = true
|
49
|
+
end
|
50
|
+
```
|
51
|
+
Useful to ignore the throttle on tests.
|
52
|
+
|
42
53
|
## Development
|
43
54
|
|
44
55
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -1,23 +1,26 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
require 'better_rate_limit/throttle'
|
3
|
+
require 'better_rate_limit/limit'
|
3
4
|
|
4
5
|
module ActionController
|
5
6
|
module BetterRateLimit
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
|
8
9
|
module ClassMethods
|
9
|
-
def rate_limit(max,
|
10
|
-
rate_limits <<
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
def rate_limit(max, options)
|
11
|
+
rate_limits << Limit.build(max, controller_path, {
|
12
|
+
if: options[:if],
|
13
|
+
unless: options[:unless],
|
14
|
+
every: options[:every],
|
15
|
+
name: options[:name] || controller_path,
|
16
|
+
scope: options[:scope] || -> { real_ip },
|
17
|
+
only: options[:only] || [],
|
18
|
+
except: options[:except] || [],
|
19
|
+
clear_if: options[:clear_if]
|
18
20
|
})
|
19
21
|
|
20
22
|
before_action :perform_rate_limiting
|
23
|
+
after_action :clear_keys
|
21
24
|
end
|
22
25
|
|
23
26
|
def rate_limits
|
@@ -41,6 +44,20 @@ module ActionController
|
|
41
44
|
render file: 'public/429.html', status: :too_many_requests, layout: false
|
42
45
|
end
|
43
46
|
|
47
|
+
def clear_keys
|
48
|
+
rate_limits = self.class.all_rate_limits.filter(&:clear_if_present?)
|
49
|
+
return if rate_limits.empty?
|
50
|
+
|
51
|
+
rate_limits.each do |rate_limit|
|
52
|
+
should_clear = rate_limit.clear_if.is_a?(Proc) ? instance_exec(&rate_limit.clear_if) : send(rate_limit.clear_if)
|
53
|
+
next unless should_clear
|
54
|
+
|
55
|
+
scope = rate_limit.scope.is_a?(Proc) ? instance_exec(&rate_limit.scope) : send(rate_limit.scope)
|
56
|
+
scope = scope.to_param if scope.respond_to?(:to_param)
|
57
|
+
::BetterRateLimit::Throttle.clear(rate_limit.key(scope))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
44
61
|
private
|
45
62
|
|
46
63
|
def json?
|
@@ -52,7 +69,17 @@ module ActionController
|
|
52
69
|
end
|
53
70
|
|
54
71
|
def under_rate_limit?(limit)
|
55
|
-
if limit.
|
72
|
+
if limit.has_if_condition?
|
73
|
+
if_condition = limit._if.is_a?(Proc) ? instance_exec(&limit._if) : send(limit._if)
|
74
|
+
return true unless if_condition
|
75
|
+
end
|
76
|
+
|
77
|
+
if limit.has_unless_condition?
|
78
|
+
unless_condition = limit._unless.is_a?(Proc) ? instance_exec(&limit._unless) : send(limit._unless)
|
79
|
+
return true if unless_condition
|
80
|
+
end
|
81
|
+
|
82
|
+
if limit.controller_path_is?(controller_path)
|
56
83
|
return true if action_name.to_sym.in?([limit.except].flatten)
|
57
84
|
return true if !limit.only.empty? && !action_name.to_sym.in?([limit.only].flatten)
|
58
85
|
end
|
@@ -60,9 +87,7 @@ module ActionController
|
|
60
87
|
scope = limit.scope.is_a?(Proc) ? instance_exec(&limit.scope) : send(limit.scope)
|
61
88
|
scope = scope.to_param if scope.respond_to?(:to_param)
|
62
89
|
|
63
|
-
|
64
|
-
|
65
|
-
::BetterRateLimit::Throttle.allow? key, limit: limit.max, time_window: limit.every
|
90
|
+
::BetterRateLimit::Throttle.allow? limit.key(scope), limit: limit.max, time_window: limit.every
|
66
91
|
end
|
67
92
|
end
|
68
93
|
end
|
data/lib/better_rate_limit.rb
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
require 'action_controller'
|
2
|
+
require 'better_rate_limit/configuration'
|
3
|
+
|
4
|
+
module BetterRateLimit
|
5
|
+
class << self
|
6
|
+
def configuration
|
7
|
+
@configuration ||= Configuration.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def configure
|
11
|
+
yield configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset_configuration
|
15
|
+
@configuration = Configuration.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
2
19
|
|
3
20
|
module ActionController
|
4
21
|
autoload :BetterRateLimit, 'action_controller/better_rate_limit'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Limit
|
2
|
+
def self.build(max, controller_path, options)
|
3
|
+
options.assert_valid_keys(:if, :unless, :every, :name, :scope, :only, :except, :clear_if)
|
4
|
+
new(max, controller_path, {
|
5
|
+
if: options[:if],
|
6
|
+
unless: options[:unless],
|
7
|
+
every: options[:every],
|
8
|
+
name: options[:name],
|
9
|
+
scope: options[:scope],
|
10
|
+
only: options[:only],
|
11
|
+
except: options[:except],
|
12
|
+
clear_if: options[:clear_if]
|
13
|
+
})
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :max, :controller_path
|
17
|
+
|
18
|
+
def initialize(max, controller_path, options)
|
19
|
+
@max = max
|
20
|
+
@controller_path = controller_path
|
21
|
+
@options = options
|
22
|
+
end
|
23
|
+
|
24
|
+
def _if
|
25
|
+
@options[:if]
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
@options[:name]
|
30
|
+
end
|
31
|
+
|
32
|
+
def every
|
33
|
+
@options[:every]
|
34
|
+
end
|
35
|
+
|
36
|
+
def _unless
|
37
|
+
@options[:unless]
|
38
|
+
end
|
39
|
+
|
40
|
+
def except
|
41
|
+
@options[:except]
|
42
|
+
end
|
43
|
+
|
44
|
+
def only
|
45
|
+
@options[:only]
|
46
|
+
end
|
47
|
+
|
48
|
+
def scope
|
49
|
+
@options[:scope]
|
50
|
+
end
|
51
|
+
|
52
|
+
def clear_if
|
53
|
+
@options[:clear_if]
|
54
|
+
end
|
55
|
+
|
56
|
+
def clear_if_present?
|
57
|
+
@options[:clear_if].present?
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_if_condition?
|
61
|
+
_if.present?
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_unless_condition?
|
65
|
+
_unless.present?
|
66
|
+
end
|
67
|
+
|
68
|
+
def controller_path_is?(controller_path)
|
69
|
+
self.controller_path == controller_path
|
70
|
+
end
|
71
|
+
|
72
|
+
def key(key_scope)
|
73
|
+
['controller_throttle', name, max, every, key_scope].join(':')
|
74
|
+
end
|
75
|
+
end
|
@@ -10,6 +10,8 @@ module BetterRateLimit
|
|
10
10
|
|
11
11
|
class << self
|
12
12
|
def throttle(key, limit:, time_window:)
|
13
|
+
return true if BetterRateLimit.configuration.ignore
|
14
|
+
|
13
15
|
now = Time.now.utc
|
14
16
|
timestamps_count = redis_client.llen key
|
15
17
|
|
@@ -21,11 +23,14 @@ module BetterRateLimit
|
|
21
23
|
true
|
22
24
|
else
|
23
25
|
first = redis_client.lpop(key)
|
26
|
+
|
24
27
|
redis_client.multi do
|
25
28
|
redis_client.rpush key, now
|
26
29
|
redis_client.expire key, time_window.to_i
|
27
30
|
end
|
28
31
|
|
32
|
+
return false unless first
|
33
|
+
|
29
34
|
passing = first.to_time(:utc) < time_window.ago
|
30
35
|
|
31
36
|
unless passing
|
@@ -37,6 +42,11 @@ module BetterRateLimit
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
45
|
+
def clear(key)
|
46
|
+
redis_client.del(key)
|
47
|
+
redis_client.del("failing-rate-limits:#{key}")
|
48
|
+
end
|
49
|
+
|
40
50
|
alias allow? throttle
|
41
51
|
|
42
52
|
def notify(key)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_rate_limit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pablo Fonseca
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-07-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -58,6 +58,8 @@ files:
|
|
58
58
|
- bin/setup
|
59
59
|
- lib/action_controller/better_rate_limit.rb
|
60
60
|
- lib/better_rate_limit.rb
|
61
|
+
- lib/better_rate_limit/configuration.rb
|
62
|
+
- lib/better_rate_limit/limit.rb
|
61
63
|
- lib/better_rate_limit/redis_connection.rb
|
62
64
|
- lib/better_rate_limit/throttle.rb
|
63
65
|
- lib/better_rate_limit/version.rb
|