graphql-pundit 0.6.0 → 0.7.1
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 +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
|