graph_attack 2.1.0 → 2.3.0

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: de17498105231eb4dd5b5135cf8e7683680cafc409a66acf6fddbaa6f6735b36
4
- data.tar.gz: 60308e8ccff6fb80b4b5013975f9ea4903cb037b16997030635ace4557211f17
3
+ metadata.gz: e5c8d6555e219c82d4a4120f699037145c83a8c6ab5d890aa0f7a75f9560db2c
4
+ data.tar.gz: da27f205db905e6a6b3c05dd34b50d4057908372c86bae9b53b8f7cb8ef86e09
5
5
  SHA512:
6
- metadata.gz: 41706b8ea7768bf2d3220c6803f91c29a20640b177c8c443cf64a3462310dd939d4dfa92ffd2fd9f874bd6f256e50031ffbf893f5f4a58846fd7299191e12169
7
- data.tar.gz: 873abb6b86cb16f3575cff878cd2be3d0c47723b472b2949a6f4c0f9c6164996fa3b72142ce3e74a71952c5da89eac400a346a43607f174fa2e28862c5dd8d57
6
+ metadata.gz: 81506f5a365831038e0fff051d7ef707e4903c561bc8cbbe7148a2ff79daef43ec98e26699331163a42e07328dcd2b08797682155d91b78b54f145809d080dd6
7
+ data.tar.gz: 964047fc9a4e4516bdb1d6c0ae899e7fdc484c44c83268e9e7dd6fc13ffb563bdba43a4ba6b3a1cecf8ed538c61ec1804eac64fac7418d1094280280d87aeff1
data/.rubocop.yml CHANGED
@@ -69,7 +69,7 @@ RSpec/NestedGroups:
69
69
 
70
70
  # Allow longer examples (default 5)
71
71
  RSpec/ExampleLength:
72
- Max: 8
72
+ Max: 15
73
73
 
74
74
  Layout/EmptyLinesAroundAttributeAccessor:
75
75
  Enabled: true
data/CHANGELOG.md CHANGED
@@ -1,6 +1,27 @@
1
1
  unreleased
2
2
  ----------
3
3
 
4
+ v2.3.0
5
+ ------
6
+
7
+ Feature:
8
+ - Add configuration for setting defaults. E.g.:
9
+
10
+ ```rb
11
+ GraphAttack.configure do |config|
12
+ # config.threshold = 15
13
+ # config.interval = 60
14
+ # config.on = :ip
15
+ # config.redis_client = Redis.new
16
+ end
17
+ ```
18
+
19
+ v2.2.0
20
+ ------
21
+
22
+ Feature:
23
+ - Skip throttling when rate limited field is nil (#19)
24
+
4
25
  v2.1.0
5
26
  ------
6
27
 
data/README.md CHANGED
@@ -58,6 +58,8 @@ class GraphqlController < ApplicationController
58
58
  end
59
59
  ```
60
60
 
61
+ If that key is `nil`, throttling will be disabled.
62
+
61
63
  ## Configuration
62
64
 
63
65
  ### Custom context key
@@ -83,6 +85,20 @@ extension GraphAttack::RateLimit,
83
85
  redis_client: Redis.new(url: "…")
84
86
  ```
85
87
 
88
+ ### Common configuration
89
+
90
+ To have a default configuration for all rate-limited fields, you can create an
91
+ initializer:
92
+
93
+ ```rb
94
+ GraphAttack.configure do |config|
95
+ # config.threshold = 15
96
+ # config.interval = 60
97
+ # config.on = :ip
98
+ # config.redis_client = Redis.new
99
+ end
100
+ ```
101
+
86
102
  ## Development
87
103
 
88
104
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
@@ -102,7 +118,7 @@ tests and linting are pristine by calling `bundle && bin/rake`, then create a
102
118
  commit for this version, for example with:
103
119
 
104
120
  ```sh
105
- git add .
121
+ git add --patch
106
122
  git commit -m v`ruby -rbundler/setup -rgraph_attack/version -e "puts GraphAttack::VERSION"`
107
123
  ```
108
124
 
data/graph_attack.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'graphql', '>= 1.7.9'
30
30
 
31
31
  # A Redis-backed rate limiter.
32
- spec.add_dependency 'ratelimit', '>= 1.0.3'
32
+ spec.add_dependency 'ratelimit', '>= 1.0.4'
33
33
 
34
34
  # Loads local dependencies.
35
35
  spec.add_development_dependency 'bundler', '~> 2.0'
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphAttack
4
+ # Store the config
5
+ class Configuration
6
+ # Number of calls allowed.
7
+ attr_accessor :threshold
8
+
9
+ # Time interval in seconds.
10
+ attr_accessor :interval
11
+
12
+ # Key on the context on which to differentiate users.
13
+ attr_accessor :on
14
+
15
+ # Use a custom Redis client.
16
+ attr_accessor :redis_client
17
+
18
+ def initialize
19
+ @threshold = nil
20
+ @interval = nil
21
+ @on = :ip
22
+ @redis_client = Redis.new
23
+ end
24
+ end
25
+
26
+ class << self
27
+ attr_writer :configuration
28
+
29
+ def configuration
30
+ @configuration ||= Configuration.new
31
+ end
32
+
33
+ def configure
34
+ yield(configuration)
35
+ end
36
+ end
37
+ end
@@ -3,13 +3,13 @@
3
3
  module GraphAttack
4
4
  class RateLimit < GraphQL::Schema::FieldExtension
5
5
  def resolve(object:, arguments:, **_rest)
6
- rate_limited_field = object.context[rate_limited_key]
7
- unless rate_limited_field
8
- raise GraphAttack::Error,
9
- "Missing :#{rate_limited_key} value on the GraphQL context"
6
+ rate_limited_field = object.context[on]
7
+
8
+ unless object.context.key?(on)
9
+ raise GraphAttack::Error, "Missing :#{on} key on the GraphQL context"
10
10
  end
11
11
 
12
- if calls_exceeded_on_query?(rate_limited_field)
12
+ if rate_limited_field && calls_exceeded_on_query?(rate_limited_field)
13
13
  return RateLimited.new('Query rate limit exceeded')
14
14
  end
15
15
 
@@ -19,22 +19,21 @@ module GraphAttack
19
19
  private
20
20
 
21
21
  def key
22
- on = "-#{options[:on]}" if options[:on]
23
- "graphql-query-#{field.name}#{on}"
22
+ suffix = "-#{on}" if on != :ip
23
+
24
+ "graphql-query-#{field.name}#{suffix}"
24
25
  end
25
26
 
26
27
  def calls_exceeded_on_query?(rate_limited_field)
27
28
  rate_limit = Ratelimit.new(rate_limited_field, redis: redis_client)
28
29
  rate_limit.add(key)
29
- rate_limit.exceeded?(
30
- key,
31
- threshold: threshold,
32
- interval: interval,
33
- )
30
+
31
+ rate_limit.exceeded?(key, threshold: threshold, interval: interval)
34
32
  end
35
33
 
36
34
  def threshold
37
35
  options[:threshold] ||
36
+ GraphAttack.configuration.threshold ||
38
37
  raise(
39
38
  GraphAttack::Error,
40
39
  'Missing "threshold:" option on the GraphAttack::RateLimit extension',
@@ -43,6 +42,7 @@ module GraphAttack
43
42
 
44
43
  def interval
45
44
  options[:interval] ||
45
+ GraphAttack.configuration.interval ||
46
46
  raise(
47
47
  GraphAttack::Error,
48
48
  'Missing "interval:" option on the GraphAttack::RateLimit extension',
@@ -50,11 +50,11 @@ module GraphAttack
50
50
  end
51
51
 
52
52
  def redis_client
53
- options[:redis_client] || Redis.current
53
+ options[:redis_client] || GraphAttack.configuration.redis_client
54
54
  end
55
55
 
56
- def rate_limited_key
57
- options[:on] || :ip
56
+ def on
57
+ options[:on] || GraphAttack.configuration.on
58
58
  end
59
59
  end
60
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphAttack
4
- VERSION = '2.1.0'
4
+ VERSION = '2.3.0'
5
5
  end
data/lib/graph_attack.rb CHANGED
@@ -6,7 +6,7 @@ require 'graphql/tracing'
6
6
 
7
7
  require 'graph_attack/version'
8
8
 
9
- # Class-based schema
9
+ require 'graph_attack/configuration'
10
10
  require 'graph_attack/error'
11
11
  require 'graph_attack/rate_limit'
12
12
  require 'graph_attack/rate_limited'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graph_attack
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fanny Cheung
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-08-07 00:00:00.000000000 Z
12
+ date: 2023-02-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: graphql
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 1.0.3
34
+ version: 1.0.4
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: 1.0.3
41
+ version: 1.0.4
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +164,7 @@ files:
164
164
  - bin/setup
165
165
  - graph_attack.gemspec
166
166
  - lib/graph_attack.rb
167
+ - lib/graph_attack/configuration.rb
167
168
  - lib/graph_attack/error.rb
168
169
  - lib/graph_attack/rate_limit.rb
169
170
  - lib/graph_attack/rate_limited.rb