graph_attack 1.1.0 → 1.2.0
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 +5 -5
- data/.circleci/config.yml +6 -9
- data/.github/dependabot.yml +9 -0
- data/.rubocop.yml +120 -13
- data/.ruby-version +1 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +7 -0
- data/Gemfile +2 -0
- data/README.md +39 -3
- data/Rakefile +3 -3
- data/bin/console +1 -0
- data/bin/rake +29 -0
- data/bin/rubocop +29 -0
- data/graph_attack.gemspec +12 -3
- data/lib/graph_attack.rb +10 -0
- data/lib/graph_attack/error.rb +5 -0
- data/lib/graph_attack/metadata.rb +2 -0
- data/lib/graph_attack/rate_limit.rb +50 -0
- data/lib/graph_attack/rate_limited.rb +5 -0
- data/lib/graph_attack/rate_limiter.rb +3 -0
- data/lib/graph_attack/version.rb +3 -1
- metadata +48 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dd5c8edf29d269a309957b279c0690cb46f897ca4e02c8909cd80816b9ce76fb
|
4
|
+
data.tar.gz: ccf872288c199a97d55a36565998e04ca94edc982f1318bd66a67b70140aac9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d7f367fa3125069280b021f6404a19e6a5bcba197ea3c3408b066eadb593e295f2cabcb7d3d4cda5ef0b2a806ac2055dc3943559257aea208dd077a62ff468c
|
7
|
+
data.tar.gz: 52adf301f34c476a6b6f97013175bc0036c588788d158d971ad553d62c86c54ac27ad1be83be6c99a120a0b90bf7b2e4da58455bd2988e9fd523ffa92956c203
|
data/.circleci/config.yml
CHANGED
@@ -6,7 +6,7 @@ version: 2
|
|
6
6
|
jobs:
|
7
7
|
build:
|
8
8
|
docker:
|
9
|
-
- image: circleci/ruby:2.
|
9
|
+
- image: circleci/ruby:2.7.3
|
10
10
|
- image: redis
|
11
11
|
|
12
12
|
working_directory: ~/repo
|
@@ -17,19 +17,16 @@ jobs:
|
|
17
17
|
# Download and cache dependencies
|
18
18
|
- restore_cache:
|
19
19
|
keys:
|
20
|
-
-
|
21
|
-
|
22
|
-
- v1-dependencies-
|
20
|
+
- v2-dependencies-{{ checksum "graph_attack.gemspec" }}
|
21
|
+
- v2-dependencies-
|
23
22
|
|
24
|
-
- run:
|
25
|
-
|
26
|
-
command: |
|
27
|
-
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
23
|
+
- run: gem install bundler:2.0.2
|
24
|
+
- run: bundle install --jobs=4 --retry=3 --path vendor/bundle
|
28
25
|
|
29
26
|
- save_cache:
|
30
27
|
paths:
|
31
28
|
- ./vendor/bundle
|
32
|
-
key:
|
29
|
+
key: v2-dependencies-{{ checksum "graph_attack.gemspec" }}
|
33
30
|
|
34
31
|
# Run tests!
|
35
32
|
- run:
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
- rubocop-rake
|
4
|
+
|
1
5
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
6
|
+
TargetRubyVersion: 2.7
|
3
7
|
DisplayCopNames: true
|
4
8
|
|
5
9
|
# Do not sort gems in Gemfile, since we are grouping them by functionality.
|
@@ -22,20 +26,19 @@ Style/TrailingCommaInHashLiteral:
|
|
22
26
|
Layout/MultilineMethodCallIndentation:
|
23
27
|
EnforcedStyle: indented
|
24
28
|
|
29
|
+
Gemspec/RequiredRubyVersion:
|
30
|
+
Enabled: false
|
31
|
+
|
25
32
|
# Limit method length (default is 10).
|
26
33
|
Metrics/MethodLength:
|
27
34
|
Max: 15
|
28
35
|
|
29
|
-
# Do not require `# frozen_string_literal: true` at the top of every file.
|
30
|
-
FrozenStringLiteralComment:
|
31
|
-
Enabled: false
|
32
|
-
|
33
36
|
# Allow ASCII comments (e.g "…").
|
34
37
|
Style/AsciiComments:
|
35
38
|
Enabled: false
|
36
39
|
|
37
40
|
# Do not comment the class we create, since the name should be self explanatory.
|
38
|
-
Documentation:
|
41
|
+
Style/Documentation:
|
39
42
|
Enabled: false
|
40
43
|
|
41
44
|
# Do not verify the length of the blocks in specs.
|
@@ -43,15 +46,119 @@ Metrics/BlockLength:
|
|
43
46
|
Exclude:
|
44
47
|
- spec/**/*
|
45
48
|
|
46
|
-
# Allow indenting multiline chained operations.
|
47
|
-
Layout/MultilineMethodCallIndentation:
|
48
|
-
EnforcedStyle: indented
|
49
|
-
|
50
49
|
# Prefer `== 0`, `< 0`, `> 0` to `zero?`, `negative?` or `positive?`,
|
51
50
|
# since they don't exist before Ruby 2.3 or Rails 5 and can be ambiguous.
|
52
51
|
Style/NumericPredicate:
|
53
52
|
EnforcedStyle: comparison
|
54
53
|
|
55
|
-
# Allow
|
56
|
-
|
57
|
-
|
54
|
+
# Allow more expectations per example (default 1).
|
55
|
+
RSpec/MultipleExpectations:
|
56
|
+
Max: 5
|
57
|
+
|
58
|
+
# Allow more group nesting (default 3)
|
59
|
+
RSpec/NestedGroups:
|
60
|
+
Max: 5
|
61
|
+
|
62
|
+
# Allow longer examples (default 5)
|
63
|
+
RSpec/ExampleLength:
|
64
|
+
Max: 8
|
65
|
+
|
66
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
67
|
+
Enabled: true
|
68
|
+
|
69
|
+
Layout/SpaceAroundMethodCallOperator:
|
70
|
+
Enabled: true
|
71
|
+
|
72
|
+
Lint/DeprecatedOpenSSLConstant:
|
73
|
+
Enabled: true
|
74
|
+
|
75
|
+
Lint/MixedRegexpCaptureTypes:
|
76
|
+
Enabled: true
|
77
|
+
|
78
|
+
Lint/RaiseException:
|
79
|
+
Enabled: true
|
80
|
+
|
81
|
+
Lint/StructNewOverride:
|
82
|
+
Enabled: true
|
83
|
+
|
84
|
+
Style/ExponentialNotation:
|
85
|
+
Enabled: true
|
86
|
+
|
87
|
+
Style/HashEachMethods:
|
88
|
+
Enabled: true
|
89
|
+
|
90
|
+
Style/HashTransformKeys:
|
91
|
+
Enabled: true
|
92
|
+
|
93
|
+
Style/HashTransformValues:
|
94
|
+
Enabled: true
|
95
|
+
|
96
|
+
Style/RedundantRegexpCharacterClass:
|
97
|
+
Enabled: true
|
98
|
+
|
99
|
+
Style/RedundantRegexpEscape:
|
100
|
+
Enabled: true
|
101
|
+
|
102
|
+
Style/SlicingWithRange:
|
103
|
+
Enabled: true
|
104
|
+
|
105
|
+
Gemspec/DateAssignment: # (new in 1.10)
|
106
|
+
Enabled: true
|
107
|
+
Layout/SpaceBeforeBrackets: # (new in 1.7)
|
108
|
+
Enabled: true
|
109
|
+
Lint/AmbiguousAssignment: # (new in 1.7)
|
110
|
+
Enabled: true
|
111
|
+
Lint/DeprecatedConstants: # (new in 1.8)
|
112
|
+
Enabled: true
|
113
|
+
Lint/DuplicateBranch: # (new in 1.3)
|
114
|
+
Enabled: true
|
115
|
+
Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
|
116
|
+
Enabled: true
|
117
|
+
Lint/EmptyBlock: # (new in 1.1)
|
118
|
+
Enabled: true
|
119
|
+
Lint/EmptyClass: # (new in 1.3)
|
120
|
+
Enabled: true
|
121
|
+
Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
|
122
|
+
Enabled: true
|
123
|
+
Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
|
124
|
+
Enabled: true
|
125
|
+
Lint/NumberedParameterAssignment: # (new in 1.9)
|
126
|
+
Enabled: true
|
127
|
+
Lint/OrAssignmentToConstant: # (new in 1.9)
|
128
|
+
Enabled: true
|
129
|
+
Lint/RedundantDirGlobSort: # (new in 1.8)
|
130
|
+
Enabled: true
|
131
|
+
Lint/SymbolConversion: # (new in 1.9)
|
132
|
+
Enabled: true
|
133
|
+
Lint/ToEnumArguments: # (new in 1.1)
|
134
|
+
Enabled: true
|
135
|
+
Lint/TripleQuotes: # (new in 1.9)
|
136
|
+
Enabled: true
|
137
|
+
Lint/UnexpectedBlockArity: # (new in 1.5)
|
138
|
+
Enabled: true
|
139
|
+
Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
|
140
|
+
Enabled: true
|
141
|
+
Style/ArgumentsForwarding: # (new in 1.1)
|
142
|
+
Enabled: true
|
143
|
+
Style/CollectionCompact: # (new in 1.2)
|
144
|
+
Enabled: true
|
145
|
+
Style/DocumentDynamicEvalDefinition: # (new in 1.1)
|
146
|
+
Enabled: true
|
147
|
+
Style/EndlessMethod: # (new in 1.8)
|
148
|
+
Enabled: true
|
149
|
+
Style/HashConversion: # (new in 1.10)
|
150
|
+
Enabled: true
|
151
|
+
Style/HashExcept: # (new in 1.7)
|
152
|
+
Enabled: true
|
153
|
+
Style/IfWithBooleanLiteralBranches: # (new in 1.9)
|
154
|
+
Enabled: true
|
155
|
+
Style/NegatedIfElseCondition: # (new in 1.2)
|
156
|
+
Enabled: true
|
157
|
+
Style/NilLambda: # (new in 1.3)
|
158
|
+
Enabled: true
|
159
|
+
Style/RedundantArgument: # (new in 1.4)
|
160
|
+
Enabled: true
|
161
|
+
Style/StringChars: # (new in 1.12)
|
162
|
+
Enabled: true
|
163
|
+
Style/SwapValues: # (new in 1.1)
|
164
|
+
Enabled: true
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.7.3
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,19 @@ GraphQL analyser for blocking & throttling.
|
|
8
8
|
|
9
9
|
This gem adds a method to limit access to your GraphQL fields by IP:
|
10
10
|
|
11
|
+
```rb
|
12
|
+
class QueryType < GraphQL::Schema::Object
|
13
|
+
field :some_expensive_field, String, null: false do
|
14
|
+
extension(GraphAttack::RateLimit, threshold: 15, interval: 60)
|
15
|
+
end
|
16
|
+
|
17
|
+
# …
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
<details>
|
22
|
+
<summary>If using GraphQL::Ruby's legacy schema definition</summary>
|
23
|
+
|
11
24
|
```rb
|
12
25
|
QueryType = GraphQL::ObjectType.define do
|
13
26
|
name 'Query'
|
@@ -20,6 +33,8 @@ QueryType = GraphQL::ObjectType.define do
|
|
20
33
|
end
|
21
34
|
```
|
22
35
|
|
36
|
+
</details>
|
37
|
+
|
23
38
|
This would allow only 15 calls per minute by the same IP.
|
24
39
|
|
25
40
|
## Requirements
|
@@ -42,6 +57,9 @@ And then execute:
|
|
42
57
|
$ bundle
|
43
58
|
```
|
44
59
|
|
60
|
+
<details>
|
61
|
+
<summary>If using GraphQL::Ruby's legacy schema definition</summary>
|
62
|
+
|
45
63
|
Add the query analyser to your schema:
|
46
64
|
|
47
65
|
```rb
|
@@ -52,8 +70,10 @@ ApplicationSchema = GraphQL::Schema.define do
|
|
52
70
|
end
|
53
71
|
```
|
54
72
|
|
73
|
+
</details>
|
74
|
+
|
55
75
|
Finally, make sure you add the current user's IP address as `ip:` to the
|
56
|
-
GraphQL context
|
76
|
+
GraphQL context. E.g.:
|
57
77
|
|
58
78
|
```rb
|
59
79
|
class GraphqlController < ApplicationController
|
@@ -74,12 +94,28 @@ end
|
|
74
94
|
|
75
95
|
Use a custom Redis client instead of the default:
|
76
96
|
|
97
|
+
```rb
|
98
|
+
field :some_expensive_field, String, null: false do
|
99
|
+
extension(
|
100
|
+
GraphAttack::RateLimit,
|
101
|
+
threshold: 15,
|
102
|
+
interval: 60,
|
103
|
+
redis_client: Redis.new(url: "…"),
|
104
|
+
)
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
<details>
|
109
|
+
<summary>If using GraphQL::Ruby's legacy schema definition</summary>
|
110
|
+
|
77
111
|
```rb
|
78
112
|
query_analyzer GraphAttack::RateLimiter.new(
|
79
113
|
redis_client: Redis.new(url: "…")
|
80
114
|
)
|
81
115
|
```
|
82
116
|
|
117
|
+
</details>
|
118
|
+
|
83
119
|
## Development
|
84
120
|
|
85
121
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
@@ -109,12 +145,12 @@ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
109
145
|
|
110
146
|
Everyone interacting in the GraphAttack project’s codebases, issue trackers,
|
111
147
|
chat rooms and mailing lists is expected to follow the
|
112
|
-
[code of conduct](https://github.com/sunny/graph_attack/blob/
|
148
|
+
[code of conduct](https://github.com/sunny/graph_attack/blob/main/CODE_OF_CONDUCT.md).
|
113
149
|
|
114
150
|
## License
|
115
151
|
|
116
152
|
This project is licensed under the MIT License - see the
|
117
|
-
[LICENSE.md](https://github.com/sunny/graph_attack/blob/
|
153
|
+
[LICENSE.md](https://github.com/sunny/graph_attack/blob/main/LICENSE.md)
|
118
154
|
file for details.
|
119
155
|
|
120
156
|
## Authors
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Bundler
|
2
4
|
require 'bundler/gem_tasks'
|
3
|
-
require 'rspec/core/rake_task'
|
4
5
|
|
5
|
-
#
|
6
|
+
# RSpec
|
6
7
|
require 'rspec/core/rake_task'
|
7
8
|
RSpec::Core::RakeTask.new(:spec)
|
8
9
|
|
9
|
-
task default: :spec
|
10
10
|
# Rubocop
|
11
11
|
require 'rubocop/rake_task'
|
12
12
|
RuboCop::RakeTask.new(:rubocop)
|
data/bin/console
CHANGED
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'bundler/setup'
|
28
|
+
|
29
|
+
load Gem.bin_path('rake', 'rake')
|
data/bin/rubocop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'bundler/setup'
|
28
|
+
|
29
|
+
load Gem.bin_path('rubocop', 'rubocop')
|
data/graph_attack.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'graph_attack/version'
|
@@ -18,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
18
20
|
spec.bindir = 'exe'
|
19
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
22
|
spec.require_paths = ['lib']
|
23
|
+
spec.required_ruby_version = ['>= 2.5.7', '< 2.8']
|
21
24
|
|
22
25
|
# This gem is an analyser for the GraphQL ruby gem.
|
23
26
|
spec.add_dependency 'graphql', '>= 1.7.9'
|
@@ -26,10 +29,10 @@ Gem::Specification.new do |spec|
|
|
26
29
|
spec.add_dependency 'ratelimit', '>= 1.0.3'
|
27
30
|
|
28
31
|
# Loads local dependencies.
|
29
|
-
spec.add_development_dependency 'bundler', '~>
|
32
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
30
33
|
|
31
34
|
# Development tasks runner.
|
32
|
-
spec.add_development_dependency 'rake', '~>
|
35
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
33
36
|
|
34
37
|
# Testing framework.
|
35
38
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
@@ -38,5 +41,11 @@ Gem::Specification.new do |spec|
|
|
38
41
|
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.3'
|
39
42
|
|
40
43
|
# Ruby code linter.
|
41
|
-
spec.add_development_dependency 'rubocop', '~>
|
44
|
+
spec.add_development_dependency 'rubocop', '~> 1.1'
|
45
|
+
|
46
|
+
# RSpec extension for RuboCop.
|
47
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.2'
|
48
|
+
|
49
|
+
# Rake extension for RuboCop
|
50
|
+
spec.add_development_dependency 'rubocop-rake'
|
42
51
|
end
|
data/lib/graph_attack.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'graphql'
|
2
4
|
require 'ratelimit'
|
5
|
+
|
3
6
|
require 'graphql/tracing'
|
4
7
|
|
5
8
|
require 'graph_attack/version'
|
9
|
+
|
10
|
+
# Class-based schema
|
11
|
+
require 'graph_attack/rate_limit'
|
12
|
+
require 'graph_attack/error'
|
13
|
+
require 'graph_attack/rate_limited'
|
14
|
+
|
15
|
+
# Legacy schema
|
6
16
|
require 'graph_attack/rate_limiter'
|
7
17
|
require 'graph_attack/metadata'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphAttack
|
4
|
+
class RateLimit < GraphQL::Schema::FieldExtension
|
5
|
+
def resolve(object:, arguments:, **_rest)
|
6
|
+
ip = object.context[:ip]
|
7
|
+
raise GraphAttack::Error, 'Missing :ip value on the GraphQL context' unless ip
|
8
|
+
|
9
|
+
return RateLimited.new('Query rate limit exceeded') if calls_exceeded_on_query?(ip)
|
10
|
+
|
11
|
+
yield(object, arguments)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def key
|
17
|
+
"graphql-query-#{field.name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def calls_exceeded_on_query?(ip)
|
21
|
+
rate_limit = Ratelimit.new(ip, redis: redis_client)
|
22
|
+
rate_limit.add(key)
|
23
|
+
rate_limit.exceeded?(
|
24
|
+
key,
|
25
|
+
threshold: threshold,
|
26
|
+
interval: interval,
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def threshold
|
31
|
+
options[:threshold] ||
|
32
|
+
raise(
|
33
|
+
GraphAttack::Error,
|
34
|
+
'Missing "threshold:" option on the GraphAttack::RateLimit extension',
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def interval
|
39
|
+
options[:interval] ||
|
40
|
+
raise(
|
41
|
+
GraphAttack::Error,
|
42
|
+
'Missing "interval:" option on the GraphAttack::RateLimit extension',
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def redis_client
|
47
|
+
options[:redis_client] || Redis.current
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GraphAttack
|
2
4
|
# Query analyser you can add to your GraphQL schema to limit calls by IP.
|
3
5
|
#
|
@@ -7,6 +9,7 @@ module GraphAttack
|
|
7
9
|
#
|
8
10
|
class RateLimiter
|
9
11
|
class Error < StandardError; end
|
12
|
+
|
10
13
|
class RateLimited < GraphQL::AnalysisError; end
|
11
14
|
|
12
15
|
def initialize(redis_client: Redis.new)
|
data/lib/graph_attack/version.rb
CHANGED
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: 1.
|
4
|
+
version: 1.2.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:
|
12
|
+
date: 2021-07-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: graphql
|
@@ -45,28 +45,28 @@ dependencies:
|
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '2.0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '2.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rake
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
62
|
+
version: '13.0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '13.0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rspec
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,14 +101,42 @@ dependencies:
|
|
101
101
|
requirements:
|
102
102
|
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: '
|
104
|
+
version: '1.1'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '
|
111
|
+
version: '1.1'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: rubocop-rspec
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '2.2'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '2.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rubocop-rake
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
112
140
|
description: GraphQL analyser for blocking & throttling
|
113
141
|
email:
|
114
142
|
- fanny@ynote.hk
|
@@ -118,9 +146,11 @@ extensions: []
|
|
118
146
|
extra_rdoc_files: []
|
119
147
|
files:
|
120
148
|
- ".circleci/config.yml"
|
149
|
+
- ".github/dependabot.yml"
|
121
150
|
- ".gitignore"
|
122
151
|
- ".rspec"
|
123
152
|
- ".rubocop.yml"
|
153
|
+
- ".ruby-version"
|
124
154
|
- ".travis.yml"
|
125
155
|
- CHANGELOG.md
|
126
156
|
- CODE_OF_CONDUCT.md
|
@@ -129,10 +159,15 @@ files:
|
|
129
159
|
- README.md
|
130
160
|
- Rakefile
|
131
161
|
- bin/console
|
162
|
+
- bin/rake
|
163
|
+
- bin/rubocop
|
132
164
|
- bin/setup
|
133
165
|
- graph_attack.gemspec
|
134
166
|
- lib/graph_attack.rb
|
167
|
+
- lib/graph_attack/error.rb
|
135
168
|
- lib/graph_attack/metadata.rb
|
169
|
+
- lib/graph_attack/rate_limit.rb
|
170
|
+
- lib/graph_attack/rate_limited.rb
|
136
171
|
- lib/graph_attack/rate_limiter.rb
|
137
172
|
- lib/graph_attack/version.rb
|
138
173
|
homepage: https://github.com/sunny/graph_attack
|
@@ -146,15 +181,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
181
|
requirements:
|
147
182
|
- - ">="
|
148
183
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
184
|
+
version: 2.5.7
|
185
|
+
- - "<"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '2.8'
|
150
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
189
|
requirements:
|
152
190
|
- - ">="
|
153
191
|
- !ruby/object:Gem::Version
|
154
192
|
version: '0'
|
155
193
|
requirements: []
|
156
|
-
|
157
|
-
rubygems_version: 2.6.11
|
194
|
+
rubygems_version: 3.1.6
|
158
195
|
signing_key:
|
159
196
|
specification_version: 4
|
160
197
|
summary: GraphQL analyser for blocking & throttling
|