graphql-pundit 0.6.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +14 -1
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/README.md +226 -6
- data/graphql-pundit.gemspec +5 -5
- data/lib/graphql-pundit.rb +6 -2
- data/lib/graphql-pundit/authorization.rb +91 -0
- data/lib/graphql-pundit/common.rb +29 -0
- data/lib/graphql-pundit/field.rb +18 -0
- data/lib/graphql-pundit/scope.rb +51 -0
- data/lib/graphql-pundit/version.rb +1 -1
- metadata +15 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c58e3531c4741bc540930aaed36534a6453619aae97fcbf3d16206aa68c354a5
|
4
|
+
data.tar.gz: f6a1e97460f2c5077934fd1ad2b77dd5598be7cfd7191790c215f0963bbc1f13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78f956d0d6028d4d13055844814e518b93c3ac2d678fde2fd7a06d3acd63c8055ef3a9b8ead1c6e594af8496a5b37c8e3c8488ba9fb68ae473cab2e3e22bc5fe
|
7
|
+
data.tar.gz: 3b59cb152f50188dc3077490add56b640c5eb7d31cff3da4a3f14ac843f96e28084fe10c2c1d6626bfc8a2bffdb52ad34e455d9ef5fa02d99ce66186f6882251
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -13,11 +13,15 @@ AllCops:
|
|
13
13
|
- 'bin/setup'
|
14
14
|
- 'bin/spring'
|
15
15
|
- 'bin/update'
|
16
|
+
- 'config/deploy/*.rb'
|
17
|
+
- 'config/mixins/applications/*.rb'
|
18
|
+
- 'data/**/*'
|
16
19
|
- 'db/schema.rb'
|
17
20
|
- 'node_modules/**/*'
|
18
21
|
- 'spec/dummy/**/*'
|
19
22
|
- 'vendor/**/*'
|
20
23
|
- 'repositories/**/*'
|
24
|
+
- 'repos/**/*'
|
21
25
|
- 'tmp/**/*'
|
22
26
|
|
23
27
|
Layout/AlignParameters:
|
@@ -50,12 +54,18 @@ Metrics/LineLength:
|
|
50
54
|
|
51
55
|
Naming/FileName:
|
52
56
|
Exclude:
|
57
|
+
- config/deploy/*.rb
|
58
|
+
- config/mixins/applications/*.rb
|
53
59
|
- lib/git-shell.rb
|
54
60
|
- lib/graphql-pundit.rb
|
55
61
|
- lib/hets-agent.rb
|
56
62
|
- lib/ontohub-models.rb
|
57
63
|
- spec/lib/git-shell_spec.rb
|
58
64
|
|
65
|
+
Naming/UncommunicativeMethodParamName:
|
66
|
+
Exclude:
|
67
|
+
- 'spec/**/*'
|
68
|
+
|
59
69
|
Style/Documentation:
|
60
70
|
Exclude:
|
61
71
|
- 'app/indexers/**/*'
|
@@ -83,5 +93,8 @@ Style/SymbolArray:
|
|
83
93
|
Exclude:
|
84
94
|
- 'db/migrate/**'
|
85
95
|
|
86
|
-
Style/
|
96
|
+
Style/TrailingCommaInArrayLiteral:
|
97
|
+
EnforcedStyleForMultiline: comma
|
98
|
+
|
99
|
+
Style/TrailingCommaInHashLiteral:
|
87
100
|
EnforcedStyleForMultiline: comma
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.5
|
1
|
+
2.5.1
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -6,14 +6,12 @@
|
|
6
6
|
|
7
7
|
# GraphQL::Pundit
|
8
8
|
|
9
|
-
|
10
|
-
|
11
9
|
## Installation
|
12
10
|
|
13
11
|
Add this line to your application's Gemfile:
|
14
12
|
|
15
13
|
```ruby
|
16
|
-
gem 'graphql-pundit'
|
14
|
+
gem 'graphql-pundit', '~> 0.7.0'
|
17
15
|
```
|
18
16
|
|
19
17
|
And then execute:
|
@@ -22,9 +20,231 @@ And then execute:
|
|
22
20
|
$ bundle
|
23
21
|
```
|
24
22
|
|
23
|
+
### Upgrade Notice
|
24
|
+
|
25
|
+
If you're upgrading from an earlier version, make sure to delete your
|
26
|
+
`bootsnap` cache, to avoid a load error (see
|
27
|
+
[this issue](https://github.com/ontohub/graphql-pundit/issues/51)).
|
28
|
+
The cache files are usually located in the `tmp` directory in your
|
29
|
+
repository and are named `bootsnap-compile-cache` and
|
30
|
+
`bootsnap-load-path-cache`.
|
31
|
+
|
25
32
|
## Usage
|
26
33
|
|
27
|
-
###
|
34
|
+
### Class based API (`graphql-ruby >= 1.8`)
|
35
|
+
|
36
|
+
To use `graphql-pundit` with the class based API introduced in `graphql`
|
37
|
+
version 1.8, the used `Field` class must be changed:
|
38
|
+
|
39
|
+
It is recommended to have application-specific base classes, from which the
|
40
|
+
other types inherit (similar to having an `ApplicationController` from which
|
41
|
+
all other controllers inherit). That base class can be used to define a
|
42
|
+
custom field class, on which the new `graphql-pundit` API builds.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class BaseObject < GraphQL::Schema::Object
|
46
|
+
field_class GraphQL::Pundit::Field
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
All other object types now inherit from `BaseObject`, and that is all that is
|
51
|
+
needed to get `graphql-pundit` working with the class based API.
|
52
|
+
|
53
|
+
In case you already use a custom field type, or if you want to use a context
|
54
|
+
key other than `:current_user` to make your current user available, you can
|
55
|
+
include `graphql-pundit`'s functionality into your field type:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class MyFieldType < GraphQL::Schema::Field
|
59
|
+
prepend GraphQL::Pundit::Scope
|
60
|
+
prepend GraphQL::Pundit::Authorization
|
61
|
+
|
62
|
+
current_user :me # if the current_user is passed in as context[:me]
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
When using this, make sure the order of `prepend`s is correct, as you usually want the authorization to happen **first**, which means that it needs to be `prepend`ed **after** the scopes (if you need them).
|
67
|
+
|
68
|
+
#### Usage
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
class Car < BaseObject
|
72
|
+
field :trunk, CarContent, null: true,
|
73
|
+
authorize: true
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
The above example shows the most basic usage of this gem. The example would
|
78
|
+
use `CarPolicy#trunk?` for authorizing access to the field, passing in the
|
79
|
+
parent object (in this case probably a `Car` model).
|
80
|
+
|
81
|
+
##### Options
|
82
|
+
|
83
|
+
Two styles of declaring fields is supported:
|
84
|
+
|
85
|
+
1. the inline style, passing all the options as a hash to the field method
|
86
|
+
2. the block style
|
87
|
+
|
88
|
+
Both styles are presented below side by side.
|
89
|
+
|
90
|
+
###### `authorize` and `authorize!`
|
91
|
+
|
92
|
+
To use authorization on a field, you **must** pass either the `authorize` or
|
93
|
+
`authorize!` option. Both options will cause the field to return `nil` if the
|
94
|
+
access is unauthorized, but `authorize!` will also add an error message (e.g.
|
95
|
+
for usage with mutations).
|
96
|
+
|
97
|
+
`authorize` and `authorize!` can be passed three different things:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
class User < BaseObject
|
101
|
+
# will use the `UserPolicy#display_name?` method
|
102
|
+
field :display_name, ..., authorize: true
|
103
|
+
field :display_name, ... do
|
104
|
+
authorize
|
105
|
+
end
|
106
|
+
|
107
|
+
# will use the passed lambda instead of a policy method
|
108
|
+
field :password_hash, ..., authorize: ->(obj, args, ctx) { ... }
|
109
|
+
field :password_hash, ... do
|
110
|
+
authorize ->(obj, args, ctx) { ... }
|
111
|
+
end
|
112
|
+
|
113
|
+
# will use the `UserPolicy#personal_info?` method
|
114
|
+
field :email, ..., authorize: :personal_info
|
115
|
+
field :email, ... do
|
116
|
+
authorize :personal_info
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
- `true` will trigger the inference mechanism, meaning that the method that will be called on the policy class will be inferred from the (snake_case) field name.
|
122
|
+
- a lambda function that will be called with the parent object, the arguments of the field and the context object; if the lambda returns a truthy value, authorization succeeds; otherwise (including thrown exceptions), authorization fails
|
123
|
+
- a string or a symbol that corresponds to the policy method that should be called **minus the "?"**
|
124
|
+
|
125
|
+
###### `policy`
|
126
|
+
|
127
|
+
`policy` is an optional argument that can also be passed three different values:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
class User < BaseObject
|
131
|
+
# will use the `UserPolicy#display_name?` method (default inference)
|
132
|
+
field :display_name, ..., authorize: true, policy: nil
|
133
|
+
field :display_name do
|
134
|
+
authorize policy: nil
|
135
|
+
end
|
136
|
+
|
137
|
+
# will use OtherUserPolicy#password_hash?
|
138
|
+
field :password_hash, ...,
|
139
|
+
authorize: true,
|
140
|
+
policy: ->(obj, args, ctx) { OtherUserPolicy }
|
141
|
+
field :password_hash, ... do
|
142
|
+
authorize policy: ->(obj, args, ctx) { OtherUserPolicy }
|
143
|
+
end
|
144
|
+
|
145
|
+
# will use MemberPolicy#email?
|
146
|
+
field :email, ..., authorize: true, policy: MemberPolicy
|
147
|
+
field :email, ... do
|
148
|
+
authorize policy: MemberPolicy
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
- `nil` is the default behavior and results in inferring the policy class from the record (see below)
|
154
|
+
- a lambda function that will be called with the parent object, the arguments of the field and the context object; the return value of this function will be used as the policy class
|
155
|
+
- an actual policy class
|
156
|
+
|
157
|
+
###### `record`
|
158
|
+
|
159
|
+
`record` can be used to pass a different value to the policy. Like `policy`,
|
160
|
+
this argument also can receive three different values:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
class User < BaseObject
|
164
|
+
# will use the parent object
|
165
|
+
field :display_name, ..., authorize: true, record: nil
|
166
|
+
field :display_name do
|
167
|
+
authorize record: nil
|
168
|
+
end
|
169
|
+
|
170
|
+
# will use the current user as the record
|
171
|
+
field :password_hash, ...,
|
172
|
+
authorize: true,
|
173
|
+
record: ->(obj, args, ctx) { ctx[:current_user] }
|
174
|
+
field :password_hash, ... do
|
175
|
+
authorize record: ->(obj, args, ctx) { ctx[:current_user] }
|
176
|
+
end
|
177
|
+
|
178
|
+
# will use AccountPolicy#email? with the first account as the record (the policy was inferred from the record class)
|
179
|
+
field :email, ..., authorize: true, record: Account.first
|
180
|
+
field :email, ... do
|
181
|
+
authorize record: Account.first
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
- `nil` is again used for the inference; in this case, the parent object is used
|
187
|
+
- a lambda function, again called with the parent object, the field arguments and the context object; the result will be used as the record
|
188
|
+
- any other value that will be used as the record
|
189
|
+
|
190
|
+
Using `record` can be helpful for e.g. mutations, where you need a value to
|
191
|
+
initialize the policy with, but for mutations there is no parent object.
|
192
|
+
|
193
|
+
###### `before_scope` and `after_scope`
|
194
|
+
|
195
|
+
`before_scope` and `after_scope` can be used to apply Pundit scopes to the
|
196
|
+
fields. Both options can be combined freely within one field. The result of
|
197
|
+
`before_scope` is passed to the resolver as the "parent object", while the
|
198
|
+
result of `after_scope` is returned as the result of the field.
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
class User < BaseObject
|
202
|
+
# will use the `PostPolicy::Scope` before the resolver
|
203
|
+
field :posts, ..., before_scope: true
|
204
|
+
field :posts, ... do
|
205
|
+
before_scope
|
206
|
+
end
|
207
|
+
|
208
|
+
# will use the passed lambda after the resolver
|
209
|
+
field :comments, ..., after_scope: ->(comments, args, ctx) { ... }
|
210
|
+
field :comments, ... do
|
211
|
+
after_scope ->(comments, args, ctx) { ... }
|
212
|
+
end
|
213
|
+
|
214
|
+
# will use the `FriendPolicy::Scope`
|
215
|
+
field :friends, ..., after_scope: FriendPolicy
|
216
|
+
field :friends, ... do
|
217
|
+
after_scope FriendPolicy
|
218
|
+
end
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
- `true` will trigger the inference mechanism, where the policy class, which contains the scope class, is inferred based on either the parent object (for `before_scope`) or the result of the resolver (for `after_scope`).
|
223
|
+
- a lambda function, that will be called with the parent object (for `before_scope`) or the result of the resolver (for `after_scope`), the field arguments and the context
|
224
|
+
- a policy class that contains a `Scope` class (this does not actually have to be a policy class, but could also be a module containing a `Scope` class)
|
225
|
+
|
226
|
+
###### Combining options
|
227
|
+
|
228
|
+
All options can be combined with one another (except `authorize` and `authorize!`; please don't do that). Examples:
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
# MemberPolicy#name? initialized with the parent
|
232
|
+
field :display_name, ..., authorize: :name,
|
233
|
+
policy: MemberPolicy
|
234
|
+
|
235
|
+
# UserPolicy#display_name? initialized with user.account_data
|
236
|
+
field :display_name, ..., do
|
237
|
+
authorize policy: UserPolicy,
|
238
|
+
record: ->(obj, args, ctx) { obj.account_data }
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
### Legacy `define` API
|
243
|
+
|
244
|
+
The legacy `define` based API will be supported until it is removed from the
|
245
|
+
`graphql` gem (as planned for version 1.10).
|
246
|
+
|
247
|
+
#### Add the authorization middleware
|
28
248
|
|
29
249
|
Add the following to your GraphQL schema:
|
30
250
|
|
@@ -42,7 +262,7 @@ By default, `ctx[:current_user]` will be used as the user to authorize. To chang
|
|
42
262
|
GraphQL::Pundit::Instrumenter.new(:me) # will use ctx[:me]
|
43
263
|
```
|
44
264
|
|
45
|
-
|
265
|
+
#### Authorize fields
|
46
266
|
|
47
267
|
For each field you want to authorize via Pundit, add the following code to the field definition:
|
48
268
|
|
@@ -102,7 +322,7 @@ end
|
|
102
322
|
|
103
323
|
If the lambda returns a falsy value or raises a `Pundit::UnauthorizedError` the field will resolve to `nil`, if it returns a truthy value, control will be passed to the resolve function. Of course, this can be used with `authorize!` as well.
|
104
324
|
|
105
|
-
|
325
|
+
#### Scopes
|
106
326
|
|
107
327
|
Pundit scopes are supported by using `before_scope` and `after_scope` in the field definition
|
108
328
|
|
data/graphql-pundit.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'graphql-pundit/version'
|
6
6
|
|
@@ -22,18 +22,18 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
|
25
|
-
spec.add_dependency 'graphql', '>= 1.6.4', '< 1.
|
25
|
+
spec.add_dependency 'graphql', '>= 1.6.4', '< 1.10.0'
|
26
26
|
spec.add_dependency 'pundit', '~> 1.1.0'
|
27
27
|
|
28
28
|
spec.add_development_dependency 'bundler', '~> 1.14'
|
29
29
|
spec.add_development_dependency 'codecov', '~> 0.1.10'
|
30
30
|
spec.add_development_dependency 'fuubar', '~> 2.3.0'
|
31
31
|
spec.add_development_dependency 'pry', '~> 0.11.0'
|
32
|
-
spec.add_development_dependency 'pry-byebug', '~> 3.
|
32
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.6.0'
|
33
33
|
spec.add_development_dependency 'pry-rescue', '~> 1.4.4'
|
34
34
|
spec.add_development_dependency 'pry-stack_explorer', '~> 0.4.9.2'
|
35
35
|
spec.add_development_dependency 'rake', '~> 12.0'
|
36
36
|
spec.add_development_dependency 'rspec', '~> 3.6'
|
37
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
38
|
-
spec.add_development_dependency 'simplecov', '~> 0.
|
37
|
+
spec.add_development_dependency 'rubocop', '~> 0.57.0'
|
38
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
39
39
|
end
|
data/lib/graphql-pundit.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql-pundit/instrumenter'
|
4
|
+
require 'graphql-pundit/field'
|
5
|
+
require 'graphql-pundit/authorization'
|
6
|
+
require 'graphql-pundit/scope'
|
4
7
|
require 'graphql-pundit/version'
|
5
8
|
|
6
9
|
require 'graphql'
|
@@ -15,9 +18,10 @@ module GraphQL
|
|
15
18
|
@raise_unauthorized = raise_unauthorized
|
16
19
|
end
|
17
20
|
|
18
|
-
def call(defn,
|
21
|
+
def call(defn, *args, policy: nil, record: nil)
|
22
|
+
query = args[0] || defn.name
|
19
23
|
opts = {record: record,
|
20
|
-
query: query
|
24
|
+
query: query,
|
21
25
|
policy: policy,
|
22
26
|
raise: raise_unauthorized}
|
23
27
|
if query.respond_to?(:call)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql-pundit/common'
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module Pundit
|
7
|
+
# Authorization methods to be included in the used Field class
|
8
|
+
module Authorization
|
9
|
+
def self.prepended(base)
|
10
|
+
base.include(GraphQL::Pundit::Common)
|
11
|
+
end
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/ParameterLists
|
14
|
+
def initialize(*args, authorize: nil,
|
15
|
+
record: nil,
|
16
|
+
policy: nil,
|
17
|
+
**kwargs, &block)
|
18
|
+
# rubocop:enable Metrics/ParameterLists
|
19
|
+
# authorize! is not a valid variable name
|
20
|
+
authorize_bang = kwargs.delete(:authorize!)
|
21
|
+
@record = record if record
|
22
|
+
@policy = policy if policy
|
23
|
+
@authorize = authorize_bang || authorize
|
24
|
+
@do_raise = !!authorize_bang
|
25
|
+
super(*args, **kwargs, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def authorize(*args, record: nil, policy: nil)
|
29
|
+
@authorize = args[0] || true
|
30
|
+
@record = record if record
|
31
|
+
@policy = policy if policy
|
32
|
+
end
|
33
|
+
|
34
|
+
def authorize!(*args, record: nil, policy: nil)
|
35
|
+
@do_raise = true
|
36
|
+
authorize(*args, record: record, policy: policy)
|
37
|
+
end
|
38
|
+
|
39
|
+
def resolve_field(obj, args, ctx)
|
40
|
+
raise ::Pundit::NotAuthorizedError unless do_authorize(obj, args, ctx)
|
41
|
+
super(obj, args, ctx)
|
42
|
+
rescue ::Pundit::NotAuthorizedError
|
43
|
+
if @do_raise
|
44
|
+
raise GraphQL::ExecutionError, "You're not authorized to do this"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def do_authorize(root, arguments, context)
|
51
|
+
return true unless @authorize
|
52
|
+
return @authorize.call(root, arguments, context) if callable? @authorize
|
53
|
+
|
54
|
+
query = infer_query(@authorize)
|
55
|
+
record = infer_record(@record, root, arguments, context)
|
56
|
+
policy = infer_policy(@policy, record, arguments, context)
|
57
|
+
|
58
|
+
policy.new(context[self.class.current_user], record).public_send query
|
59
|
+
end
|
60
|
+
|
61
|
+
def infer_query(auth_value)
|
62
|
+
# authorize can be callable, true (for inference) or a policy query
|
63
|
+
query = auth_value.equal?(true) ? method_sym : auth_value
|
64
|
+
query.to_s + '?'
|
65
|
+
end
|
66
|
+
|
67
|
+
def infer_record(record, root, arguments, context)
|
68
|
+
# record can be callable, nil (for inference) or just any other value
|
69
|
+
if callable?(record)
|
70
|
+
record.call(root, arguments, context)
|
71
|
+
elsif record.equal?(nil)
|
72
|
+
root
|
73
|
+
else
|
74
|
+
record
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def infer_policy(policy, record, arguments, context)
|
79
|
+
# policy can be callable, nil (for inference) or a policy class
|
80
|
+
if callable?(policy)
|
81
|
+
policy.call(record, arguments, context)
|
82
|
+
elsif policy.equal?(nil)
|
83
|
+
infer_from = model?(record) ? record.model : record
|
84
|
+
::Pundit::PolicyFinder.new(infer_from).policy!
|
85
|
+
else
|
86
|
+
policy
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Pundit
|
5
|
+
# Common methods used for authorization and scopes
|
6
|
+
module Common
|
7
|
+
# Class methods to be included in the Field class
|
8
|
+
module ClassMethods
|
9
|
+
def current_user(current_user = nil)
|
10
|
+
return @current_user unless current_user
|
11
|
+
@current_user = current_user
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
@current_user = :current_user
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
|
20
|
+
def callable?(thing)
|
21
|
+
thing.respond_to?(:call)
|
22
|
+
end
|
23
|
+
|
24
|
+
def model?(thing)
|
25
|
+
thing.respond_to?(:model)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql'
|
4
|
+
require 'graphql-pundit/authorization'
|
5
|
+
require 'graphql-pundit/scope'
|
6
|
+
|
7
|
+
module GraphQL
|
8
|
+
module Pundit
|
9
|
+
if defined?(GraphQL::Schema::Field)
|
10
|
+
# Field class that contains authorization and scope behavior
|
11
|
+
# This only works with graphql >= 1.8.0
|
12
|
+
class Field < GraphQL::Schema::Field
|
13
|
+
prepend GraphQL::Pundit::Scope
|
14
|
+
prepend GraphQL::Pundit::Authorization
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql-pundit/common'
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module Pundit
|
7
|
+
# Scope methods to be included in the used Field class
|
8
|
+
module Scope
|
9
|
+
def self.prepended(base)
|
10
|
+
base.include(GraphQL::Pundit::Common)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*args, before_scope: nil,
|
14
|
+
after_scope: nil,
|
15
|
+
**kwargs, &block)
|
16
|
+
@before_scope = before_scope
|
17
|
+
@after_scope = after_scope
|
18
|
+
super(*args, **kwargs, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def before_scope(scope = true)
|
22
|
+
@before_scope = scope
|
23
|
+
end
|
24
|
+
|
25
|
+
def after_scope(scope = true)
|
26
|
+
@after_scope = scope
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolve_field(obj, args, ctx)
|
30
|
+
before_scope_return = apply_scope(@before_scope, obj, args, ctx)
|
31
|
+
field_return = super(before_scope_return, args, ctx)
|
32
|
+
apply_scope(@after_scope, field_return, args, ctx)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def apply_scope(scope, root, arguments, context)
|
38
|
+
return root unless scope
|
39
|
+
return scope.call(root, arguments, context) if scope.respond_to?(:call)
|
40
|
+
|
41
|
+
scope = infer_scope(root) if scope.equal?(true)
|
42
|
+
scope::Scope.new(context[self.class.current_user], root).resolve
|
43
|
+
end
|
44
|
+
|
45
|
+
def infer_scope(root)
|
46
|
+
infer_from = model?(root) ? root.model : root
|
47
|
+
::Pundit::PolicyFinder.new(infer_from).policy!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-pundit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ontohub Core Developers
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 1.6.4
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 1.
|
22
|
+
version: 1.10.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 1.6.4
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.
|
32
|
+
version: 1.10.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: pundit
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,14 +106,14 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 3.
|
109
|
+
version: 3.6.0
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 3.
|
116
|
+
version: 3.6.0
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: pry-rescue
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -176,28 +176,28 @@ dependencies:
|
|
176
176
|
requirements:
|
177
177
|
- - "~>"
|
178
178
|
- !ruby/object:Gem::Version
|
179
|
-
version: 0.
|
179
|
+
version: 0.57.0
|
180
180
|
type: :development
|
181
181
|
prerelease: false
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
184
|
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
|
-
version: 0.
|
186
|
+
version: 0.57.0
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
188
|
name: simplecov
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|
190
190
|
requirements:
|
191
191
|
- - "~>"
|
192
192
|
- !ruby/object:Gem::Version
|
193
|
-
version: 0.
|
193
|
+
version: 0.16.1
|
194
194
|
type: :development
|
195
195
|
prerelease: false
|
196
196
|
version_requirements: !ruby/object:Gem::Requirement
|
197
197
|
requirements:
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
version: 0.
|
200
|
+
version: 0.16.1
|
201
201
|
description: Pundit authorization support for graphql
|
202
202
|
email:
|
203
203
|
- ontohub-dev-l@ovgu.de
|
@@ -221,11 +221,15 @@ files:
|
|
221
221
|
- bin/setup
|
222
222
|
- graphql-pundit.gemspec
|
223
223
|
- lib/graphql-pundit.rb
|
224
|
+
- lib/graphql-pundit/authorization.rb
|
225
|
+
- lib/graphql-pundit/common.rb
|
226
|
+
- lib/graphql-pundit/field.rb
|
224
227
|
- lib/graphql-pundit/instrumenter.rb
|
225
228
|
- lib/graphql-pundit/instrumenters/after_scope.rb
|
226
229
|
- lib/graphql-pundit/instrumenters/authorization.rb
|
227
230
|
- lib/graphql-pundit/instrumenters/before_scope.rb
|
228
231
|
- lib/graphql-pundit/instrumenters/scope.rb
|
232
|
+
- lib/graphql-pundit/scope.rb
|
229
233
|
- lib/graphql-pundit/version.rb
|
230
234
|
homepage: https://github.com/ontohub/graphql-pundit
|
231
235
|
licenses:
|
@@ -247,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
247
251
|
version: '0'
|
248
252
|
requirements: []
|
249
253
|
rubyforge_project:
|
250
|
-
rubygems_version: 2.6
|
254
|
+
rubygems_version: 2.7.6
|
251
255
|
signing_key:
|
252
256
|
specification_version: 4
|
253
257
|
summary: Pundit authorization support for graphql
|