pundit 2.5.0 → 2.5.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/CHANGELOG.md +5 -0
- data/README.md +1 -1
- data/lib/pundit/authorization.rb +18 -0
- data/lib/pundit/cache_store/legacy_store.rb +3 -0
- data/lib/pundit/cache_store/null_store.rb +3 -0
- data/lib/pundit/cache_store.rb +2 -0
- data/lib/pundit/context.rb +13 -0
- data/lib/pundit/error.rb +71 -0
- data/lib/pundit/helper.rb +16 -0
- data/lib/pundit/policy_finder.rb +11 -0
- data/lib/pundit/railtie.rb +1 -0
- data/lib/pundit/rspec.rb +2 -0
- data/lib/pundit/version.rb +1 -1
- data/lib/pundit.rb +10 -69
- metadata +4 -68
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -26
- data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +0 -8
- data/.github/pull_request_template.md +0 -9
- data/.github/workflows/main.yml +0 -147
- data/.github/workflows/push_gem.yml +0 -33
- data/.gitignore +0 -19
- data/.rubocop.yml +0 -73
- data/.rubocop_ignore_git.yml +0 -7
- data/.yardopts +0 -1
- data/CODE_OF_CONDUCT.md +0 -28
- data/CONTRIBUTING.md +0 -31
- data/Gemfile +0 -28
- data/Rakefile +0 -21
- data/config/rubocop-rspec.yml +0 -5
- data/pundit.gemspec +0 -31
- data/spec/authorization_spec.rb +0 -331
- data/spec/generators_spec.rb +0 -43
- data/spec/policies/post_policy_spec.rb +0 -49
- data/spec/policy_finder_spec.rb +0 -191
- data/spec/pundit/helper_spec.rb +0 -18
- data/spec/pundit_spec.rb +0 -474
- data/spec/rspec_dsl_spec.rb +0 -81
- data/spec/simple_cov_check_action_formatter.rb +0 -79
- data/spec/spec_helper.rb +0 -35
- data/spec/support/lib/controller.rb +0 -38
- data/spec/support/lib/custom_cache.rb +0 -19
- data/spec/support/lib/instance_tracking.rb +0 -20
- data/spec/support/models/article.rb +0 -4
- data/spec/support/models/article_tag.rb +0 -7
- data/spec/support/models/artificial_blog.rb +0 -7
- data/spec/support/models/blog.rb +0 -4
- data/spec/support/models/comment.rb +0 -5
- data/spec/support/models/comment_four_five_six.rb +0 -5
- data/spec/support/models/comment_scope.rb +0 -13
- data/spec/support/models/comments_relation.rb +0 -15
- data/spec/support/models/customer/post.rb +0 -11
- data/spec/support/models/default_scope_contains_error.rb +0 -5
- data/spec/support/models/dummy_current_user.rb +0 -7
- data/spec/support/models/foo.rb +0 -4
- data/spec/support/models/post.rb +0 -25
- data/spec/support/models/post_four_five_six.rb +0 -9
- data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +0 -7
- data/spec/support/models/project_one_two_three/tag_four_five_six.rb +0 -11
- data/spec/support/models/wiki.rb +0 -4
- data/spec/support/policies/article_tag_other_name_policy.rb +0 -13
- data/spec/support/policies/base_policy.rb +0 -23
- data/spec/support/policies/blog_policy.rb +0 -5
- data/spec/support/policies/comment_policy.rb +0 -11
- data/spec/support/policies/criteria_policy.rb +0 -5
- data/spec/support/policies/default_scope_contains_error_policy.rb +0 -10
- data/spec/support/policies/denier_policy.rb +0 -7
- data/spec/support/policies/dummy_current_user_policy.rb +0 -9
- data/spec/support/policies/nil_class_policy.rb +0 -17
- data/spec/support/policies/post_policy.rb +0 -36
- data/spec/support/policies/project/admin/comment_policy.rb +0 -15
- data/spec/support/policies/project/comment_policy.rb +0 -17
- data/spec/support/policies/project/criteria_policy.rb +0 -7
- data/spec/support/policies/project/post_policy.rb +0 -13
- data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +0 -6
- data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +0 -6
- data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +0 -6
- data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +0 -6
- data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +0 -6
- data/spec/support/policies/publication_policy.rb +0 -13
- data/spec/support/policies/wiki_policy.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c6f7c834aabbea0d1c74b4101d67a936f0c062db2c5a67dcb45c824d0a1f80e
|
4
|
+
data.tar.gz: 651d652baa3a1f511e794b80f4e514b5e2bb74f75abeaa184dff48dae63e27bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4081cc21e4827985808334e5753a6b6f812743308cc251f8e4923b0b3a73c41b64bb6da64da57919ac62672537e3d464b187f0d28811a0aaab9c17ea9354ec5
|
7
|
+
data.tar.gz: a7868288d12d4f63cc95b5d18f54bfdafbcf586c7f415a713713f1f520140c2f7c353572cdab770baf16f5525ec4fc369679fd5e640233360b743f34d66580d9
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Pundit
|
2
2
|
|
3
3
|
[](https://github.com/varvet/pundit/actions/workflows/main.yml)
|
4
|
-
[](https://qlty.sh/gh/varvet/projects/pundit)
|
5
5
|
[](https://inch-ci.org/github/varvet/pundit)
|
6
6
|
[](https://badge.fury.io/rb/pundit)
|
7
7
|
|
data/lib/pundit/authorization.rb
CHANGED
@@ -9,6 +9,7 @@ module Pundit
|
|
9
9
|
# end
|
10
10
|
# @see #pundit
|
11
11
|
# @api public
|
12
|
+
# @since v2.2.0
|
12
13
|
module Authorization
|
13
14
|
extend ActiveSupport::Concern
|
14
15
|
|
@@ -30,6 +31,7 @@ module Pundit
|
|
30
31
|
# @return [Pundit::Context]
|
31
32
|
# @see #pundit_user
|
32
33
|
# @see #policies
|
34
|
+
# @since v2.3.2
|
33
35
|
def pundit
|
34
36
|
@pundit ||= Pundit::Context.new(
|
35
37
|
user: pundit_user,
|
@@ -45,6 +47,7 @@ module Pundit
|
|
45
47
|
# @see #pundit
|
46
48
|
# @see #pundit_reset!
|
47
49
|
# @return [Object] the user object to be used with pundit
|
50
|
+
# @since v0.2.2
|
48
51
|
def pundit_user
|
49
52
|
current_user
|
50
53
|
end
|
@@ -59,6 +62,7 @@ module Pundit
|
|
59
62
|
# with the correct context for the new pundit_user.
|
60
63
|
#
|
61
64
|
# @return [void]
|
65
|
+
# @since v2.5.0
|
62
66
|
def pundit_reset!
|
63
67
|
@pundit = nil
|
64
68
|
@_pundit_policies = nil
|
@@ -81,6 +85,7 @@ module Pundit
|
|
81
85
|
# @return [record] Always returns the passed object record
|
82
86
|
# @see Pundit::Context#authorize
|
83
87
|
# @see #verify_authorized
|
88
|
+
# @since v0.1.0
|
84
89
|
def authorize(record, query = nil, policy_class: nil)
|
85
90
|
query ||= "#{action_name}?"
|
86
91
|
|
@@ -94,6 +99,7 @@ module Pundit
|
|
94
99
|
# @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
|
95
100
|
# @return [void]
|
96
101
|
# @see #verify_authorized
|
102
|
+
# @since v1.0.0
|
97
103
|
def skip_authorization
|
98
104
|
@_pundit_policy_authorized = :skipped
|
99
105
|
end
|
@@ -101,6 +107,7 @@ module Pundit
|
|
101
107
|
# @return [Boolean] wether or not authorization has been performed
|
102
108
|
# @see #authorize
|
103
109
|
# @see #skip_authorization
|
110
|
+
# @since v1.0.0
|
104
111
|
def pundit_policy_authorized?
|
105
112
|
!!@_pundit_policy_authorized
|
106
113
|
end
|
@@ -115,6 +122,7 @@ module Pundit
|
|
115
122
|
# @return [void]
|
116
123
|
# @see #authorize
|
117
124
|
# @see #skip_authorization
|
125
|
+
# @since v0.1.0
|
118
126
|
def verify_authorized
|
119
127
|
raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
|
120
128
|
end
|
@@ -124,6 +132,7 @@ module Pundit
|
|
124
132
|
# Cache of policies. You should not rely on this method.
|
125
133
|
#
|
126
134
|
# @api private
|
135
|
+
# @since v1.0.0
|
127
136
|
def policies
|
128
137
|
@_pundit_policies ||= {}
|
129
138
|
end
|
@@ -137,6 +146,7 @@ module Pundit
|
|
137
146
|
# @see https://github.com/varvet/pundit#policies
|
138
147
|
# @param record [Object] the object we're retrieving the policy for
|
139
148
|
# @return [Object] instance of policy class with query methods
|
149
|
+
# @since v0.1.0
|
140
150
|
def policy(record)
|
141
151
|
pundit.policy!(record)
|
142
152
|
end
|
@@ -149,6 +159,7 @@ module Pundit
|
|
149
159
|
# @param scope [Object] the object we're retrieving the policy scope for
|
150
160
|
# @param policy_scope_class [#resolve] the policy scope class we want to force use of
|
151
161
|
# @return [#resolve, nil] instance of scope class which can resolve to a scope
|
162
|
+
# @since v0.1.0
|
152
163
|
def policy_scope(scope, policy_scope_class: nil)
|
153
164
|
@_pundit_policy_scoped = true
|
154
165
|
policy_scope_class ? policy_scope_class.new(pundit_user, scope).resolve : pundit_policy_scope(scope)
|
@@ -159,6 +170,7 @@ module Pundit
|
|
159
170
|
# @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
|
160
171
|
# @return [void]
|
161
172
|
# @see #verify_policy_scoped
|
173
|
+
# @since v1.0.0
|
162
174
|
def skip_policy_scope
|
163
175
|
@_pundit_policy_scoped = :skipped
|
164
176
|
end
|
@@ -166,6 +178,7 @@ module Pundit
|
|
166
178
|
# @return [Boolean] wether or not policy scoping has been performed
|
167
179
|
# @see #policy_scope
|
168
180
|
# @see #skip_policy_scope
|
181
|
+
# @since v1.0.0
|
169
182
|
def pundit_policy_scoped?
|
170
183
|
!!@_pundit_policy_scoped
|
171
184
|
end
|
@@ -181,6 +194,7 @@ module Pundit
|
|
181
194
|
# @return [void]
|
182
195
|
# @see #policy_scope
|
183
196
|
# @see #skip_policy_scope
|
197
|
+
# @since v0.2.1
|
184
198
|
def verify_policy_scoped
|
185
199
|
raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
|
186
200
|
end
|
@@ -190,6 +204,7 @@ module Pundit
|
|
190
204
|
# Cache of policy scope. You should not rely on this method.
|
191
205
|
#
|
192
206
|
# @api private
|
207
|
+
# @since v1.0.0
|
193
208
|
def policy_scopes
|
194
209
|
@_pundit_policy_scopes ||= {}
|
195
210
|
end
|
@@ -206,6 +221,7 @@ module Pundit
|
|
206
221
|
# @note This also memoizes the instance with `scope` as the key.
|
207
222
|
# @see Pundit::Helper#policy_scope
|
208
223
|
# @api private
|
224
|
+
# @since v1.0.0
|
209
225
|
def pundit_policy_scope(scope)
|
210
226
|
policy_scopes[scope] ||= pundit.policy_scope!(scope)
|
211
227
|
end
|
@@ -228,6 +244,7 @@ module Pundit
|
|
228
244
|
# @param action [Symbol, String] the name of the action being performed on the record (e.g. `:update`).
|
229
245
|
# If omitted then this defaults to the Rails controller action name.
|
230
246
|
# @return [Hash{String => Object}] the permitted attributes
|
247
|
+
# @since v1.0.0
|
231
248
|
def permitted_attributes(record, action = action_name)
|
232
249
|
policy = policy(record)
|
233
250
|
method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
|
@@ -242,6 +259,7 @@ module Pundit
|
|
242
259
|
#
|
243
260
|
# @param record [Object] the object we're retrieving params for
|
244
261
|
# @return [ActionController::Parameters] the params
|
262
|
+
# @since v2.0.0
|
245
263
|
def pundit_params_for(record)
|
246
264
|
params.require(PolicyFinder.new(record).param_key)
|
247
265
|
end
|
@@ -7,7 +7,9 @@ module Pundit
|
|
7
7
|
# The original cache mechanism used by Pundit.
|
8
8
|
#
|
9
9
|
# @api private
|
10
|
+
# @since v2.3.2
|
10
11
|
class LegacyStore
|
12
|
+
# @since v2.3.2
|
11
13
|
def initialize(hash = {})
|
12
14
|
@store = hash
|
13
15
|
end
|
@@ -15,6 +17,7 @@ module Pundit
|
|
15
17
|
# A cache store that uses only the record as a cache key, and ignores the user.
|
16
18
|
#
|
17
19
|
# @note `nil` results are not cached.
|
20
|
+
# @since v2.3.2
|
18
21
|
def fetch(user:, record:)
|
19
22
|
_ = user
|
20
23
|
@store[record] ||= yield
|
@@ -8,10 +8,12 @@ module Pundit
|
|
8
8
|
#
|
9
9
|
# @see Pundit::Context#initialize
|
10
10
|
# @api private
|
11
|
+
# @since v2.3.2
|
11
12
|
class NullStore
|
12
13
|
@instance = new
|
13
14
|
|
14
15
|
class << self
|
16
|
+
# @since v2.3.2
|
15
17
|
# @return [NullStore] the singleton instance
|
16
18
|
attr_reader :instance
|
17
19
|
end
|
@@ -19,6 +21,7 @@ module Pundit
|
|
19
21
|
# Always yields, does not cache anything.
|
20
22
|
# @yield
|
21
23
|
# @return [any] whatever the block returns.
|
24
|
+
# @since v2.3.2
|
22
25
|
def fetch(*, **)
|
23
26
|
yield
|
24
27
|
end
|
data/lib/pundit/cache_store.rb
CHANGED
@@ -5,12 +5,14 @@ module Pundit
|
|
5
5
|
#
|
6
6
|
# Cache stores are used to cache policy lookups, so you get the same policy
|
7
7
|
# instance for the same record.
|
8
|
+
# @since v2.3.2
|
8
9
|
module CacheStore
|
9
10
|
# @!group Cache Store Interface
|
10
11
|
|
11
12
|
# @!method fetch(user:, record:, &block)
|
12
13
|
# Looks up a stored policy or generate a new one.
|
13
14
|
#
|
15
|
+
# @since v2.3.2
|
14
16
|
# @note This is a method template, but the method does not exist in this module.
|
15
17
|
# @param user [Object] the user that initiated the action
|
16
18
|
# @param record [Object] the object being accessed
|
data/lib/pundit/context.rb
CHANGED
@@ -25,10 +25,13 @@ module Pundit
|
|
25
25
|
# context.authorize(Post.find(id), query: :show?)
|
26
26
|
# end
|
27
27
|
# end
|
28
|
+
#
|
29
|
+
# @since v2.3.2
|
28
30
|
class Context
|
29
31
|
# @see Pundit::Authorization#pundit
|
30
32
|
# @param user later passed to policies and scopes
|
31
33
|
# @param policy_cache [#fetch] cache store for policies (see e.g. {CacheStore::NullStore})
|
34
|
+
# @since v2.3.2
|
32
35
|
def initialize(user:, policy_cache: CacheStore::NullStore.instance)
|
33
36
|
@user = user
|
34
37
|
@policy_cache = policy_cache
|
@@ -36,10 +39,12 @@ module Pundit
|
|
36
39
|
|
37
40
|
# @api public
|
38
41
|
# @see #initialize
|
42
|
+
# @since v2.3.2
|
39
43
|
attr_reader :user
|
40
44
|
|
41
45
|
# @api private
|
42
46
|
# @see #initialize
|
47
|
+
# @since v2.3.2
|
43
48
|
attr_reader :policy_cache
|
44
49
|
|
45
50
|
# @!group Policies
|
@@ -53,6 +58,7 @@ module Pundit
|
|
53
58
|
# @param policy_class [Class] the policy class we want to force use of
|
54
59
|
# @raise [NotAuthorizedError] if the given query method returned false
|
55
60
|
# @return [Object] Always returns the passed object record
|
61
|
+
# @since v2.3.2
|
56
62
|
def authorize(possibly_namespaced_record, query:, policy_class:)
|
57
63
|
record = pundit_model(possibly_namespaced_record)
|
58
64
|
policy = if policy_class
|
@@ -72,6 +78,7 @@ module Pundit
|
|
72
78
|
# @param record [Object] the object we're retrieving the policy for
|
73
79
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
74
80
|
# @return [Object, nil] instance of policy class with query methods
|
81
|
+
# @since v2.3.2
|
75
82
|
def policy(record)
|
76
83
|
cached_find(record, &:policy)
|
77
84
|
end
|
@@ -83,6 +90,7 @@ module Pundit
|
|
83
90
|
# @raise [NotDefinedError] if the policy cannot be found
|
84
91
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
85
92
|
# @return [Object] instance of policy class with query methods
|
93
|
+
# @since v2.3.2
|
86
94
|
def policy!(record)
|
87
95
|
cached_find(record, &:policy!)
|
88
96
|
end
|
@@ -97,6 +105,7 @@ module Pundit
|
|
97
105
|
# @param scope [Object] the object we're retrieving the policy scope for
|
98
106
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
99
107
|
# @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
|
108
|
+
# @since v2.3.2
|
100
109
|
def policy_scope(scope)
|
101
110
|
policy_scope_class = policy_finder(scope).scope
|
102
111
|
return unless policy_scope_class
|
@@ -117,6 +126,7 @@ module Pundit
|
|
117
126
|
# @raise [NotDefinedError] if the policy scope cannot be found
|
118
127
|
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
119
128
|
# @return [Scope{#resolve}] instance of scope class which can resolve to a scope
|
129
|
+
# @since v2.3.2
|
120
130
|
def policy_scope!(scope)
|
121
131
|
policy_scope_class = policy_finder(scope).scope!
|
122
132
|
|
@@ -144,6 +154,7 @@ module Pundit
|
|
144
154
|
# @yieldreturn [#new(user, model)]
|
145
155
|
# @return [Policy, nil] an instantiated policy
|
146
156
|
# @raise [InvalidConstructorError] if policy can't be instantated
|
157
|
+
# @since v2.3.2
|
147
158
|
def cached_find(record)
|
148
159
|
policy_cache.fetch(user: user, record: record) do
|
149
160
|
klass = yield policy_finder(record)
|
@@ -163,6 +174,7 @@ module Pundit
|
|
163
174
|
#
|
164
175
|
# @api private
|
165
176
|
# @return [PolicyFinder]
|
177
|
+
# @since v2.3.2
|
166
178
|
def policy_finder(record)
|
167
179
|
PolicyFinder.new(record)
|
168
180
|
end
|
@@ -170,6 +182,7 @@ module Pundit
|
|
170
182
|
# Given a possibly namespaced record, return the actual record.
|
171
183
|
#
|
172
184
|
# @api private
|
185
|
+
# @since v2.3.2
|
173
186
|
def pundit_model(record)
|
174
187
|
record.is_a?(Array) ? record.last : record
|
175
188
|
end
|
data/lib/pundit/error.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pundit
|
4
|
+
# @api private
|
5
|
+
# @since v1.0.0
|
6
|
+
# To avoid name clashes with common Error naming when mixing in Pundit,
|
7
|
+
# keep it here with compact class style definition.
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
# Error that will be raised when authorization has failed
|
11
|
+
# @since v0.1.0
|
12
|
+
class NotAuthorizedError < Error
|
13
|
+
# @see #initialize
|
14
|
+
# @since v0.2.3
|
15
|
+
attr_reader :query
|
16
|
+
# @see #initialize
|
17
|
+
# @since v0.2.3
|
18
|
+
attr_reader :record
|
19
|
+
# @see #initialize
|
20
|
+
# @since v0.2.3
|
21
|
+
attr_reader :policy
|
22
|
+
|
23
|
+
# @since v1.0.0
|
24
|
+
#
|
25
|
+
# @overload initialize(message)
|
26
|
+
# Create an error with a simple error message.
|
27
|
+
# @param [String] message A simple error message string.
|
28
|
+
#
|
29
|
+
# @overload initialize(options)
|
30
|
+
# Create an error with the specified attributes.
|
31
|
+
# @param [Hash] options The error options.
|
32
|
+
# @option options [String] :message Optional custom error message. Will default to a generalized message.
|
33
|
+
# @option options [Symbol] :query The name of the policy method that was checked.
|
34
|
+
# @option options [Object] :record The object that was being checked with the policy.
|
35
|
+
# @option options [Class] :policy The class of policy that was used for the check.
|
36
|
+
def initialize(options = {})
|
37
|
+
if options.is_a? String
|
38
|
+
message = options
|
39
|
+
else
|
40
|
+
@query = options[:query]
|
41
|
+
@record = options[:record]
|
42
|
+
@policy = options[:policy]
|
43
|
+
|
44
|
+
message = options.fetch(:message) do
|
45
|
+
record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
|
46
|
+
"not allowed to #{policy.class}##{query} #{record_name}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
super(message)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Error that will be raised if a policy or policy scope constructor is not called correctly.
|
55
|
+
# @since v2.0.0
|
56
|
+
class InvalidConstructorError < Error; end
|
57
|
+
|
58
|
+
# Error that will be raised if a controller action has not called the
|
59
|
+
# `authorize` or `skip_authorization` methods.
|
60
|
+
# @since v0.2.3
|
61
|
+
class AuthorizationNotPerformedError < Error; end
|
62
|
+
|
63
|
+
# Error that will be raised if a controller action has not called the
|
64
|
+
# `policy_scope` or `skip_policy_scope` methods.
|
65
|
+
# @since v0.3.0
|
66
|
+
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
67
|
+
|
68
|
+
# Error that will be raised if a policy or policy scope is not defined.
|
69
|
+
# @since v0.1.0
|
70
|
+
class NotDefinedError < Error; end
|
71
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pundit
|
4
|
+
# Rails view helpers, to allow a slightly different view-specific
|
5
|
+
# implementation of the methods in {Pundit::Authorization}.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
# @since v1.0.0
|
9
|
+
module Helper
|
10
|
+
# @see Pundit::Authorization#pundit_policy_scope
|
11
|
+
# @since v1.0.0
|
12
|
+
def policy_scope(scope)
|
13
|
+
pundit_policy_scope(scope)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/pundit/policy_finder.rb
CHANGED
@@ -5,6 +5,7 @@ require "active_support/core_ext/string/inflections"
|
|
5
5
|
|
6
6
|
module Pundit
|
7
7
|
# Finds policy and scope classes for given object.
|
8
|
+
# @since v0.1.0
|
8
9
|
# @api public
|
9
10
|
# @example
|
10
11
|
# user = User.find(params[:id])
|
@@ -16,12 +17,15 @@ module Pundit
|
|
16
17
|
# A constant applied to the end of the class name to find the policy class.
|
17
18
|
#
|
18
19
|
# @api private
|
20
|
+
# @since v2.5.0
|
19
21
|
SUFFIX = "Policy"
|
20
22
|
|
21
23
|
# @see #initialize
|
24
|
+
# @since v0.1.0
|
22
25
|
attr_reader :object
|
23
26
|
|
24
27
|
# @param object [any] the object to find policy and scope classes for
|
28
|
+
# @since v0.1.0
|
25
29
|
def initialize(object)
|
26
30
|
@object = object
|
27
31
|
end
|
@@ -32,6 +36,7 @@ module Pundit
|
|
32
36
|
# scope = finder.scope #=> UserPolicy::Scope
|
33
37
|
# scope.resolve #=> <#ActiveRecord::Relation ...>
|
34
38
|
#
|
39
|
+
# @since v0.1.0
|
35
40
|
def scope
|
36
41
|
"#{policy}::Scope".safe_constantize
|
37
42
|
end
|
@@ -43,6 +48,7 @@ module Pundit
|
|
43
48
|
# policy.show? #=> true
|
44
49
|
# policy.update? #=> false
|
45
50
|
#
|
51
|
+
# @since v0.1.0
|
46
52
|
def policy
|
47
53
|
klass = find(object)
|
48
54
|
klass.is_a?(String) ? klass.safe_constantize : klass
|
@@ -51,6 +57,7 @@ module Pundit
|
|
51
57
|
# @return [Scope{#resolve}] scope class which can resolve to a scope
|
52
58
|
# @raise [NotDefinedError] if scope could not be determined
|
53
59
|
#
|
60
|
+
# @since v0.1.0
|
54
61
|
def scope!
|
55
62
|
scope or raise NotDefinedError, "unable to find scope `#{find(object)}::Scope` for `#{object.inspect}`"
|
56
63
|
end
|
@@ -58,12 +65,14 @@ module Pundit
|
|
58
65
|
# @return [Class] policy class with query methods
|
59
66
|
# @raise [NotDefinedError] if policy could not be determined
|
60
67
|
#
|
68
|
+
# @since v0.1.0
|
61
69
|
def policy!
|
62
70
|
policy or raise NotDefinedError, "unable to find policy `#{find(object)}` for `#{object.inspect}`"
|
63
71
|
end
|
64
72
|
|
65
73
|
# @return [String] the name of the key this object would have in a params hash
|
66
74
|
#
|
75
|
+
# @since v1.1.0
|
67
76
|
def param_key # rubocop:disable Metrics/AbcSize
|
68
77
|
model = object.is_a?(Array) ? object.last : object
|
69
78
|
|
@@ -83,6 +92,7 @@ module Pundit
|
|
83
92
|
# Uses recursion to handle namespaces.
|
84
93
|
#
|
85
94
|
# @return [String, Class] the policy class, or its name.
|
95
|
+
# @since v0.2.0
|
86
96
|
def find(subject)
|
87
97
|
if subject.is_a?(Array)
|
88
98
|
modules = subject.dup
|
@@ -107,6 +117,7 @@ module Pundit
|
|
107
117
|
# - Supports object instances.
|
108
118
|
#
|
109
119
|
# @return [String, Class] the class, or its name.
|
120
|
+
# @since v1.1.0
|
110
121
|
def find_class_name(subject)
|
111
122
|
if subject.respond_to?(:model_name)
|
112
123
|
subject.model_name
|
data/lib/pundit/railtie.rb
CHANGED
data/lib/pundit/rspec.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "pundit"
|
3
4
|
# Array#to_sentence
|
4
5
|
require "active_support/core_ext/array/conversions"
|
5
6
|
|
6
7
|
module Pundit
|
7
8
|
# Namespace for Pundit's RSpec integration.
|
9
|
+
# @since v0.1.0
|
8
10
|
module RSpec
|
9
11
|
# Namespace for Pundit's RSpec matchers.
|
10
12
|
module Matchers
|
data/lib/pundit/version.rb
CHANGED
data/lib/pundit.rb
CHANGED
@@ -3,83 +3,30 @@
|
|
3
3
|
require "active_support"
|
4
4
|
|
5
5
|
require "pundit/version"
|
6
|
+
require "pundit/error"
|
6
7
|
require "pundit/policy_finder"
|
7
|
-
require "pundit/authorization"
|
8
8
|
require "pundit/context"
|
9
|
+
require "pundit/authorization"
|
10
|
+
require "pundit/helper"
|
9
11
|
require "pundit/cache_store"
|
10
12
|
require "pundit/cache_store/null_store"
|
11
13
|
require "pundit/cache_store/legacy_store"
|
12
14
|
require "pundit/railtie" if defined?(Rails)
|
13
15
|
|
14
|
-
# @api private
|
15
|
-
# To avoid name clashes with common Error naming when mixing in Pundit,
|
16
|
-
# keep it here with compact class style definition.
|
17
|
-
class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
|
18
|
-
|
19
16
|
# Hello? Yes, this is Pundit.
|
20
17
|
#
|
21
18
|
# @api public
|
22
19
|
module Pundit
|
23
20
|
# @api private
|
21
|
+
# @since v1.0.0
|
24
22
|
# @deprecated See {Pundit::PolicyFinder}
|
25
23
|
SUFFIX = Pundit::PolicyFinder::SUFFIX
|
26
24
|
|
27
25
|
# @api private
|
28
26
|
# @private
|
27
|
+
# @since v0.1.0
|
29
28
|
module Generators; end
|
30
29
|
|
31
|
-
# Error that will be raised when authorization has failed
|
32
|
-
class NotAuthorizedError < Error
|
33
|
-
# @see #initialize
|
34
|
-
attr_reader :query
|
35
|
-
# @see #initialize
|
36
|
-
attr_reader :record
|
37
|
-
# @see #initialize
|
38
|
-
attr_reader :policy
|
39
|
-
|
40
|
-
# @overload initialize(message)
|
41
|
-
# Create an error with a simple error message.
|
42
|
-
# @param [String] message A simple error message string.
|
43
|
-
#
|
44
|
-
# @overload initialize(options)
|
45
|
-
# Create an error with the specified attributes.
|
46
|
-
# @param [Hash] options The error options.
|
47
|
-
# @option options [String] :message Optional custom error message. Will default to a generalized message.
|
48
|
-
# @option options [Symbol] :query The name of the policy method that was checked.
|
49
|
-
# @option options [Object] :record The object that was being checked with the policy.
|
50
|
-
# @option options [Class] :policy The class of policy that was used for the check.
|
51
|
-
def initialize(options = {})
|
52
|
-
if options.is_a? String
|
53
|
-
message = options
|
54
|
-
else
|
55
|
-
@query = options[:query]
|
56
|
-
@record = options[:record]
|
57
|
-
@policy = options[:policy]
|
58
|
-
|
59
|
-
message = options.fetch(:message) do
|
60
|
-
record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
|
61
|
-
"not allowed to #{policy.class}##{query} #{record_name}"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
super(message)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Error that will be raised if a policy or policy scope constructor is not called correctly.
|
70
|
-
class InvalidConstructorError < Error; end
|
71
|
-
|
72
|
-
# Error that will be raised if a controller action has not called the
|
73
|
-
# `authorize` or `skip_authorization` methods.
|
74
|
-
class AuthorizationNotPerformedError < Error; end
|
75
|
-
|
76
|
-
# Error that will be raised if a controller action has not called the
|
77
|
-
# `policy_scope` or `skip_policy_scope` methods.
|
78
|
-
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
79
|
-
|
80
|
-
# Error that will be raised if a policy or policy scope is not defined.
|
81
|
-
class NotDefinedError < Error; end
|
82
|
-
|
83
30
|
def self.included(base)
|
84
31
|
location = caller_locations(1, 1).first
|
85
32
|
warn <<~WARNING
|
@@ -91,6 +38,7 @@ module Pundit
|
|
91
38
|
|
92
39
|
class << self
|
93
40
|
# @see Pundit::Context#authorize
|
41
|
+
# @since v1.0.0
|
94
42
|
def authorize(user, record, query, policy_class: nil, cache: nil)
|
95
43
|
context = if cache
|
96
44
|
policy_cache = CacheStore::LegacyStore.new(cache)
|
@@ -103,34 +51,27 @@ module Pundit
|
|
103
51
|
end
|
104
52
|
|
105
53
|
# @see Pundit::Context#policy_scope
|
54
|
+
# @since v0.1.0
|
106
55
|
def policy_scope(user, *args, **kwargs, &block)
|
107
56
|
Context.new(user: user).policy_scope(*args, **kwargs, &block)
|
108
57
|
end
|
109
58
|
|
110
59
|
# @see Pundit::Context#policy_scope!
|
60
|
+
# @since v0.1.0
|
111
61
|
def policy_scope!(user, *args, **kwargs, &block)
|
112
62
|
Context.new(user: user).policy_scope!(*args, **kwargs, &block)
|
113
63
|
end
|
114
64
|
|
115
65
|
# @see Pundit::Context#policy
|
66
|
+
# @since v0.1.0
|
116
67
|
def policy(user, *args, **kwargs, &block)
|
117
68
|
Context.new(user: user).policy(*args, **kwargs, &block)
|
118
69
|
end
|
119
70
|
|
120
71
|
# @see Pundit::Context#policy!
|
72
|
+
# @since v0.1.0
|
121
73
|
def policy!(user, *args, **kwargs, &block)
|
122
74
|
Context.new(user: user).policy!(*args, **kwargs, &block)
|
123
75
|
end
|
124
76
|
end
|
125
|
-
|
126
|
-
# Rails view helpers, to allow a slightly different view-specific
|
127
|
-
# implementation of the methods in {Pundit::Authorization}.
|
128
|
-
#
|
129
|
-
# @api private
|
130
|
-
module Helper
|
131
|
-
# @see Pundit::Authorization#pundit_policy_scope
|
132
|
-
def policy_scope(scope)
|
133
|
-
pundit_policy_scope(scope)
|
134
|
-
end
|
135
|
-
end
|
136
77
|
end
|