better_rate_limit 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8202a0675862d02c311bc2c05f294d5adf1a1add2e5cf65aa401edcb0c159d5
4
- data.tar.gz: b94eb54339bdd7347dbc83f4ac95f87f413671227c89e072bbc0d56bc5a5fb65
3
+ metadata.gz: 1a5f2843da29693ce0d4c9ea1f12ac6310b4cf69bb135b5a4050a267b620f0ec
4
+ data.tar.gz: 9ad1cecfb14d92490bab3e4eb92d9886142c4cc9cbb3196b4c983934286bde56
5
5
  SHA512:
6
- metadata.gz: '07802df810af301f0d5d1fd8f1bd4f924b535e1dddc98575faa20ec20093d88777f27dc9f99cd6d17d7dd9163ea5760300af5b266ae5a5e120cb03c31c0ee2ea'
7
- data.tar.gz: 2659222d45eb6a1d2a6559ef78c8a64fefd7e0c66a06d38b96810782063059037d6f8da8a6453b55aa8adc9c7d6e70b7c98797405c9b4258b908ed339c788d89
6
+ metadata.gz: 119b058e9262c95a42566a6e4d2eec5b9f710e81d3de68e24623cc775d609d35d42e90dcc6e3975aa580c1a9b1b14884e6adeeaf4f8601856d543d336402eb5d
7
+ data.tar.gz: 5563b6847aa143b96dcf6f9ff2faa72deb41d58158022709a9f2e54880b34695745da4fc189560c84874da7cce1dd40eefd2874867acae3469e37b080f1888ca
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
- # rspec failure tracking
69
- .rspec_status
70
- >>>>>>> init gem
9
+ *.gem
10
+ .byebug_history
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- better_rate_limit (0.1.2)
4
+ better_rate_limit (0.1.3)
5
5
  actionpack (>= 5.0)
6
6
  redis (>= 3.3)
7
7
 
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  # BetterRateLimit
2
+ [![Build Status](https://travis-ci.org/upscopeio/better_rate_limit.svg?branch=master)](https://travis-ci.org/upscopeio/better_rate_limit)
3
+ [![Gem Version](https://badge.fury.io/rb/better_rate_limit.svg)](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', git: 'https://github.com/upscopeio/better_rate_limit'
12
+ gem 'better_rate_limit'
11
13
  ```
12
14
 
13
15
  And then execute:
@@ -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, every:, name: nil, scope: -> { real_ip }, only: [], except: [])
10
- rate_limits << OpenStruct.new({
11
- max: max,
12
- every: every,
13
- name: name || controller_path,
14
- scope: scope,
15
- only: only,
16
- except: except,
17
- controller_path: controller_path
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.controller_path == controller_path
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
- key = ['controller_throttle', limit.name, limit.max, limit.every, scope].join(':')
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
@@ -0,0 +1,71 @@
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_present?
53
+ @options[:clear_if].present?
54
+ end
55
+
56
+ def has_if_condition?
57
+ _if.present?
58
+ end
59
+
60
+ def has_unless_condition?
61
+ _unless.present?
62
+ end
63
+
64
+ def controller_path_is?(controller_path)
65
+ self.controller_path == controller_path
66
+ end
67
+
68
+ def key(key_scope)
69
+ ['controller_throttle', name, max, every, key_scope].join(':')
70
+ end
71
+ end
@@ -37,6 +37,11 @@ module BetterRateLimit
37
37
  end
38
38
  end
39
39
 
40
+ def clear(key)
41
+ redis_client.del(key)
42
+ redis_client.del("failing-rate-limits:#{key}")
43
+ end
44
+
40
45
  alias allow? throttle
41
46
 
42
47
  def notify(key)
@@ -1,3 +1,3 @@
1
1
  module BetterRateLimit
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
4
+ version: 0.1.3
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: 2020-08-10 00:00:00.000000000 Z
12
+ date: 2021-02-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -58,6 +58,7 @@ 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/limit.rb
61
62
  - lib/better_rate_limit/redis_connection.rb
62
63
  - lib/better_rate_limit/throttle.rb
63
64
  - lib/better_rate_limit/version.rb
@@ -82,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
83
  - !ruby/object:Gem::Version
83
84
  version: '0'
84
85
  requirements: []
85
- rubygems_version: 3.1.4
86
+ rubygems_version: 3.0.8
86
87
  signing_key:
87
88
  specification_version: 4
88
89
  summary: Rate limit requests