rabarber 1.3.1 → 1.4.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +36 -19
- data/lib/rabarber/configuration.rb +14 -6
- data/lib/rabarber/controllers/concerns/authorization.rb +10 -6
- data/lib/rabarber/logger.rb +33 -4
- data/lib/rabarber/missing/roles.rb +1 -3
- data/lib/rabarber/models/concerns/has_roles.rb +20 -11
- data/lib/rabarber/railtie.rb +5 -0
- data/lib/rabarber/version.rb +1 -1
- data/lib/rabarber.rb +2 -0
- data/rabarber.gemspec +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bcddaf07627eb382c58a733150e460348527476d2234f65fe0db2760bce6206f
|
|
4
|
+
data.tar.gz: 3d1bbfab2a57d860bcb9656cadb5606d09674f887a58b96db0897c3516aed5d2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e5ae51e17b580757cc427f269b43155ca3ea5eda5b4813be5d023c273f2271d96108639e24c1921ace823de4cc06b43c03372eb98d64f6d4376f9628e7b6d616
|
|
7
|
+
data.tar.gz: 232a9ded49264955b8cf7d22de5a1443947dd84d90f44f15f6dc9c9346ee7b1cee56afa85a55bf44bf5325bb1d26e17e6fcf0b8076d3f14381a9bb43254038ab
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 1.4.0
|
|
2
|
+
|
|
3
|
+
- Add 'Audit trail' feature: Logging of role assignments, revocations, and unauthorized access attempts
|
|
4
|
+
- Add `audit_trail_enabled` configuration option, allowing to enable or disable the audit trail
|
|
5
|
+
- Deprecate `when_actions_missing` and `when_roles_missing` configuration options (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48))
|
|
6
|
+
|
|
1
7
|
## 1.3.1
|
|
2
8
|
|
|
3
9
|
- Add `Rabarber::Role.assignees_for` method
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](http://badge.fury.io/rb/rabarber)
|
|
4
4
|
[](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml)
|
|
5
5
|
|
|
6
|
-
Rabarber is a role-based authorization library for Ruby on Rails, designed
|
|
6
|
+
Rabarber is a role-based authorization library for Ruby on Rails, primarily designed for use in the web layer of your application but not limited to that. It provides a set of tools for managing user roles and defining authorization rules, along with audit logging for enhanced security.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -63,26 +63,33 @@ If specific customization is required, Rabarber can be configured by using `.con
|
|
|
63
63
|
|
|
64
64
|
```rb
|
|
65
65
|
Rabarber.configure do |config|
|
|
66
|
+
config.audit_trail_enabled = true
|
|
66
67
|
config.cache_enabled = true
|
|
67
68
|
config.current_user_method = :current_user
|
|
68
69
|
config.must_have_roles = false
|
|
69
|
-
config.
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
config.when_unauthorized = -> (controller) {
|
|
71
|
+
if controller.request.format.html?
|
|
72
|
+
controller.redirect_back fallback_location: controller.root_path
|
|
73
|
+
else
|
|
74
|
+
controller.head :unauthorized
|
|
75
|
+
end
|
|
76
|
+
}
|
|
72
77
|
end
|
|
73
78
|
```
|
|
74
79
|
|
|
80
|
+
- `audit_trail_enabled` must be a boolean determining whether the audit trail functionality is enabled. _The audit trail is enabled by default._
|
|
75
81
|
- `cache_enabled` must be a boolean determining whether roles are cached. _Roles are cached by default to avoid unnecessary database queries._ If you want to disable caching, set this option to `false`. If caching is enabled and you need to clear the cache, use `Rabarber::Cache.clear` method.
|
|
76
|
-
|
|
77
82
|
- `current_user_method` must be a symbol representing the method that returns the currently authenticated user. _The default value is `:current_user`._
|
|
78
|
-
|
|
79
83
|
- `must_have_roles` must be a boolean determining whether a user with no roles can access endpoints permitted to everyone. _The default value is `false` (allowing users without roles to access endpoints permitted to everyone)._
|
|
84
|
+
- `when_unauthorized` must be a proc where you can define the behaviour when access is not authorized. Lambda argument `controller` is an instance of the controller where the code is executed. _By default, the user is redirected back if the request format is HTML; otherwise, a 401 Unauthorized response is sent._
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
### Deprecated Configuration Options
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
The following configuration options are deprecated and will be removed in the next major version (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48)):
|
|
84
89
|
|
|
85
|
-
- `
|
|
90
|
+
- `when_actions_missing` must be a proc where you can define the behaviour when the action specified in `grant_access` method cannot be found in the controller. Lambda argument `missing_actions` is an array of symbols, e.g., `[:index]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, an error is raised when action is missing._
|
|
91
|
+
|
|
92
|
+
- `when_roles_missing` must be a proc where you can define the behaviour when the roles specified in `grant_access` method cannot be found in the database. Lambda argument `missing_roles` is an array of symbols, e.g., `[:admin]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController", action: "index" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, a warning is logged when roles are missing._
|
|
86
93
|
|
|
87
94
|
## Roles
|
|
88
95
|
|
|
@@ -97,20 +104,20 @@ end
|
|
|
97
104
|
|
|
98
105
|
This adds the following methods:
|
|
99
106
|
|
|
100
|
-
**`#assign_roles`**
|
|
107
|
+
**`#assign_roles(*roles, create_new: true)`**
|
|
101
108
|
|
|
102
109
|
To assign roles, use:
|
|
103
110
|
|
|
104
111
|
```rb
|
|
105
112
|
user.assign_roles(:accountant, :marketer)
|
|
106
113
|
```
|
|
107
|
-
By default,
|
|
114
|
+
By default, it will automatically create any roles that don't exist. If you want to assign only existing roles and prevent the creation of new ones, use the method with `create_new: false` argument:
|
|
108
115
|
```rb
|
|
109
116
|
user.assign_roles(:accountant, :marketer, create_new: false)
|
|
110
117
|
```
|
|
111
118
|
The method returns an array of roles assigned to the user.
|
|
112
119
|
|
|
113
|
-
**`#revoke_roles`**
|
|
120
|
+
**`#revoke_roles(*roles)`**
|
|
114
121
|
|
|
115
122
|
To revoke roles, use:
|
|
116
123
|
|
|
@@ -121,7 +128,7 @@ If any of the specified roles doesn't exist or the user doesn't have the role yo
|
|
|
121
128
|
|
|
122
129
|
The method returns an array of roles assigned to the user.
|
|
123
130
|
|
|
124
|
-
**`#has_role
|
|
131
|
+
**`#has_role?(*roles)`**
|
|
125
132
|
|
|
126
133
|
To check whether the user has a role, use:
|
|
127
134
|
|
|
@@ -143,7 +150,7 @@ user.roles
|
|
|
143
150
|
|
|
144
151
|
To manipulate roles directly, you can use `Rabarber::Role` methods:
|
|
145
152
|
|
|
146
|
-
**`.add`**
|
|
153
|
+
**`.add(role)`**
|
|
147
154
|
|
|
148
155
|
To add a new role, use:
|
|
149
156
|
|
|
@@ -153,7 +160,7 @@ Rabarber::Role.add(:admin)
|
|
|
153
160
|
|
|
154
161
|
This will create a new role with the specified name and return `true`. If the role already exists, it will return `false`.
|
|
155
162
|
|
|
156
|
-
**`.rename`**
|
|
163
|
+
**`.rename(old_role_name, new_role_name, force: false)`**
|
|
157
164
|
|
|
158
165
|
To rename a role, use:
|
|
159
166
|
|
|
@@ -167,7 +174,7 @@ The method won't rename the role and will return `false` if it is assigned to an
|
|
|
167
174
|
Rabarber::Role.rename(:admin, :administrator, force: true)
|
|
168
175
|
```
|
|
169
176
|
|
|
170
|
-
**`.remove`**
|
|
177
|
+
**`.remove(role, force: false)`**
|
|
171
178
|
|
|
172
179
|
To remove a role, use:
|
|
173
180
|
|
|
@@ -190,7 +197,7 @@ If you need to list all the role names available in your application, use:
|
|
|
190
197
|
Rabarber::Role.names
|
|
191
198
|
```
|
|
192
199
|
|
|
193
|
-
**`.assignees_for`**
|
|
200
|
+
**`.assignees_for(role)`**
|
|
194
201
|
|
|
195
202
|
To get all the users to whom the role is assigned, use:
|
|
196
203
|
|
|
@@ -208,7 +215,7 @@ class ApplicationController < ActionController::Base
|
|
|
208
215
|
...
|
|
209
216
|
end
|
|
210
217
|
```
|
|
211
|
-
This adds `.grant_access` method which allows you to define the authorization rules.
|
|
218
|
+
This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method which allows you to define the authorization rules.
|
|
212
219
|
|
|
213
220
|
The most basic usage of the method is as follows:
|
|
214
221
|
|
|
@@ -323,7 +330,7 @@ This means that `Crm::InvoicesController` is still accessible to `admin` but is
|
|
|
323
330
|
|
|
324
331
|
## View Helpers
|
|
325
332
|
|
|
326
|
-
Rabarber also provides a couple of helpers that can be used in views: `visible_to` and `hidden_from`. To use them, simply include `Rabarber::Helpers` in the desired helper. Usually it is `ApplicationHelper`, but it can be any helper of your choice.
|
|
333
|
+
Rabarber also provides a couple of helpers that can be used in views: `visible_to(*roles, &block)` and `hidden_from(*roles, &block)`. To use them, simply include `Rabarber::Helpers` in the desired helper. Usually it is `ApplicationHelper`, but it can be any helper of your choice.
|
|
327
334
|
|
|
328
335
|
```rb
|
|
329
336
|
module ApplicationHelper
|
|
@@ -346,6 +353,16 @@ The usage is straightforward:
|
|
|
346
353
|
<% end %>
|
|
347
354
|
```
|
|
348
355
|
|
|
356
|
+
## Audit Trail
|
|
357
|
+
|
|
358
|
+
Rabarber supports audit trail, which provides a record of user access control activity. This feature logs the following events:
|
|
359
|
+
|
|
360
|
+
- Role assignments to users
|
|
361
|
+
- Role revocations from users
|
|
362
|
+
- Unauthorized access attempts
|
|
363
|
+
|
|
364
|
+
The logs are written to the file `log/rabarber_audit.log` unless the `audit_trail_enabled` configuration option is set to `false`.
|
|
365
|
+
|
|
349
366
|
## Problems?
|
|
350
367
|
|
|
351
368
|
Facing a problem or want to suggest an enhancement?
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "singleton"
|
|
4
|
-
|
|
5
3
|
module Rabarber
|
|
6
4
|
class Configuration
|
|
7
5
|
include Singleton
|
|
8
6
|
|
|
9
|
-
attr_reader :cache_enabled, :current_user_method, :must_have_roles,
|
|
7
|
+
attr_reader :audit_trail_enabled, :cache_enabled, :current_user_method, :must_have_roles,
|
|
10
8
|
:when_actions_missing, :when_roles_missing, :when_unauthorized
|
|
11
9
|
|
|
12
10
|
def initialize
|
|
11
|
+
@audit_trail_enabled = default_audit_trail_enabled
|
|
13
12
|
@cache_enabled = default_cache_enabled
|
|
14
13
|
@current_user_method = default_current_user_method
|
|
15
14
|
@must_have_roles = default_must_have_roles
|
|
@@ -18,6 +17,12 @@ module Rabarber
|
|
|
18
17
|
@when_unauthorized = default_when_unauthorized
|
|
19
18
|
end
|
|
20
19
|
|
|
20
|
+
def audit_trail_enabled=(value)
|
|
21
|
+
@audit_trail_enabled = Rabarber::Input::Types::Boolean.new(
|
|
22
|
+
value, Rabarber::ConfigurationError, "Configuration 'audit_trail_enabled' must be a Boolean"
|
|
23
|
+
).process
|
|
24
|
+
end
|
|
25
|
+
|
|
21
26
|
def cache_enabled=(value)
|
|
22
27
|
@cache_enabled = Rabarber::Input::Types::Boolean.new(
|
|
23
28
|
value, Rabarber::ConfigurationError, "Configuration 'cache_enabled' must be a Boolean"
|
|
@@ -56,6 +61,10 @@ module Rabarber
|
|
|
56
61
|
|
|
57
62
|
private
|
|
58
63
|
|
|
64
|
+
def default_audit_trail_enabled
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
59
68
|
def default_cache_enabled
|
|
60
69
|
true
|
|
61
70
|
end
|
|
@@ -70,21 +79,20 @@ module Rabarber
|
|
|
70
79
|
|
|
71
80
|
def default_when_actions_missing
|
|
72
81
|
-> (missing_actions, context) {
|
|
73
|
-
raise
|
|
82
|
+
raise(Rabarber::Error, "'grant_access' method called with non-existent actions: #{missing_actions}, context: '#{context[:controller]}'")
|
|
74
83
|
}
|
|
75
84
|
end
|
|
76
85
|
|
|
77
86
|
def default_when_roles_missing
|
|
78
87
|
-> (missing_roles, context) {
|
|
79
88
|
delimiter = context[:action] ? "#" : ""
|
|
80
|
-
message = "
|
|
89
|
+
message = "'grant_access' method called with non-existent roles: #{missing_roles}, context: '#{context[:controller]}#{delimiter}#{context[:action]}'"
|
|
81
90
|
Rabarber::Logger.log(:warn, message)
|
|
82
91
|
}
|
|
83
92
|
end
|
|
84
93
|
|
|
85
94
|
def default_when_unauthorized
|
|
86
95
|
-> (controller) do
|
|
87
|
-
Rabarber::Logger.log(:warn, "Unauthorized attempt")
|
|
88
96
|
if controller.request.format.html?
|
|
89
97
|
controller.redirect_back fallback_location: controller.main_app.root_path
|
|
90
98
|
else
|
|
@@ -28,14 +28,18 @@ module Rabarber
|
|
|
28
28
|
Rabarber::Missing::Actions.new(self.class).handle
|
|
29
29
|
Rabarber::Missing::Roles.new(self.class).handle
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
roleable = send(Rabarber::Configuration.instance.current_user_method)
|
|
32
32
|
|
|
33
|
-
Rabarber::
|
|
34
|
-
|
|
33
|
+
return if Rabarber::Core::Permissions.access_granted?(
|
|
34
|
+
roleable ? roleable.roles : [], self.class, action_name.to_sym, self
|
|
35
|
+
)
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
Rabarber::Logger.audit(
|
|
38
|
+
:warn,
|
|
39
|
+
"[Unauthorized Attempt] #{Rabarber::Logger.roleable_identity(roleable, with_roles: true)} attempted to access '#{request.path}'"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
Rabarber::Configuration.instance.when_unauthorized.call(self)
|
|
39
43
|
end
|
|
40
44
|
end
|
|
41
45
|
end
|
data/lib/rabarber/logger.rb
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Rabarber
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
class Logger
|
|
5
|
+
include Singleton
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
attr_reader :rails_logger, :audit_logger
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@rails_logger = Rails.logger
|
|
11
|
+
@audit_logger = ::Logger.new(Rails.root.join("log/rabarber_audit.log"))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def log(log_level, message)
|
|
16
|
+
instance.rails_logger.tagged("Rabarber") { instance.rails_logger.public_send(log_level, message) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def audit(log_level, message)
|
|
20
|
+
return unless Rabarber::Configuration.instance.audit_trail_enabled
|
|
21
|
+
|
|
22
|
+
instance.audit_logger.public_send(log_level, message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def roleable_identity(roleable, with_roles:)
|
|
26
|
+
if roleable
|
|
27
|
+
model_name = roleable.model_name.human
|
|
28
|
+
primary_key = roleable.class.primary_key
|
|
29
|
+
roleable_id = roleable.public_send(primary_key)
|
|
30
|
+
|
|
31
|
+
roles = with_roles ? ", roles: #{roleable.roles}" : ""
|
|
32
|
+
|
|
33
|
+
"#{model_name} with #{primary_key}: '#{roleable_id}'#{roles}"
|
|
34
|
+
else
|
|
35
|
+
"Unauthenticated user"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
9
38
|
end
|
|
10
39
|
end
|
|
11
40
|
end
|
|
@@ -16,9 +16,7 @@ module Rabarber
|
|
|
16
16
|
action_rules.each do |controller, controller_action_rules|
|
|
17
17
|
controller_action_rules.each do |action_rule|
|
|
18
18
|
missing_roles = action_rule.roles - all_roles
|
|
19
|
-
if missing_roles.any?
|
|
20
|
-
missing_list << Rabarber::Missing::Item.new(missing_roles, controller, action_rule.action)
|
|
21
|
-
end
|
|
19
|
+
missing_list << Rabarber::Missing::Item.new(missing_roles, controller, action_rule.action) if missing_roles.any?
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
end
|
|
@@ -5,9 +5,7 @@ module Rabarber
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
|
-
if defined?(@@included) && @@included != name
|
|
9
|
-
raise Rabarber::Error, "Rabarber::HasRoles can only be included once"
|
|
10
|
-
end
|
|
8
|
+
raise Rabarber::Error, "Rabarber::HasRoles can only be included once" if defined?(@@included) && @@included != name
|
|
11
9
|
|
|
12
10
|
@@included = name
|
|
13
11
|
|
|
@@ -27,26 +25,37 @@ module Rabarber
|
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
def assign_roles(*role_names, create_new: true)
|
|
30
|
-
|
|
28
|
+
processed_role_names = process_role_names(role_names)
|
|
31
29
|
|
|
32
|
-
create_new_roles(
|
|
30
|
+
create_new_roles(processed_role_names) if create_new
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
roles_to_assign = Rabarber::Role.where(name: processed_role_names) - rabarber_roles
|
|
35
33
|
|
|
36
|
-
if
|
|
34
|
+
if roles_to_assign.any?
|
|
37
35
|
delete_roleable_cache
|
|
38
|
-
rabarber_roles <<
|
|
36
|
+
rabarber_roles << roles_to_assign
|
|
37
|
+
|
|
38
|
+
Rabarber::Logger.audit(
|
|
39
|
+
:info,
|
|
40
|
+
"[Role Assignment] #{Rabarber::Logger.roleable_identity(self, with_roles: false)} has been assigned the following roles: #{roles_to_assign.pluck(:name).map(&:to_sym)}, current roles: #{roles}"
|
|
41
|
+
)
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
roles
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
def revoke_roles(*role_names)
|
|
45
|
-
|
|
48
|
+
processed_role_names = process_role_names(role_names)
|
|
49
|
+
roles_to_revoke = Rabarber::Role.where(name: processed_role_names.intersection(roles))
|
|
46
50
|
|
|
47
|
-
if
|
|
51
|
+
if roles_to_revoke.any?
|
|
48
52
|
delete_roleable_cache
|
|
49
|
-
self.rabarber_roles
|
|
53
|
+
self.rabarber_roles -= roles_to_revoke
|
|
54
|
+
|
|
55
|
+
Rabarber::Logger.audit(
|
|
56
|
+
:info,
|
|
57
|
+
"[Role Revocation] #{Rabarber::Logger.roleable_identity(self, with_roles: false)} has been revoked from the following roles: #{roles_to_revoke.pluck(:name).map(&:to_sym)}, current roles: #{roles}"
|
|
58
|
+
)
|
|
50
59
|
end
|
|
51
60
|
|
|
52
61
|
roles
|
data/lib/rabarber/railtie.rb
CHANGED
|
@@ -8,6 +8,11 @@ module Rabarber
|
|
|
8
8
|
app.config.after_initialize do
|
|
9
9
|
Rabarber::Missing::Actions.new.handle
|
|
10
10
|
Rabarber::Missing::Roles.new.handle if Rabarber::Role.table_exists?
|
|
11
|
+
|
|
12
|
+
Rabarber::Logger.log(
|
|
13
|
+
:warn,
|
|
14
|
+
"DEPRECATION WARNING: Configurations 'when_actions_missing' and 'when_roles_missing' are deprecated and will be removed in v2.0.0"
|
|
15
|
+
)
|
|
11
16
|
end
|
|
12
17
|
end
|
|
13
18
|
end
|
data/lib/rabarber/version.rb
CHANGED
data/lib/rabarber.rb
CHANGED
data/rabarber.gemspec
CHANGED
|
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
|
7
7
|
spec.version = Rabarber::VERSION
|
|
8
8
|
spec.authors = ["enjaku4", "trafium"]
|
|
9
9
|
spec.email = ["rabarber_gem@icloud.com"]
|
|
10
|
-
|
|
10
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
11
11
|
spec.summary = "Simple role-based authorization library for Ruby on Rails."
|
|
12
12
|
spec.homepage = "https://github.com/enjaku4/rabarber"
|
|
13
13
|
spec.license = "MIT"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rabarber
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- enjaku4
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2024-03-
|
|
12
|
+
date: 2024-03-17 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rails
|
|
@@ -65,7 +65,8 @@ files:
|
|
|
65
65
|
homepage: https://github.com/enjaku4/rabarber
|
|
66
66
|
licenses:
|
|
67
67
|
- MIT
|
|
68
|
-
metadata:
|
|
68
|
+
metadata:
|
|
69
|
+
rubygems_mfa_required: 'true'
|
|
69
70
|
post_install_message:
|
|
70
71
|
rdoc_options: []
|
|
71
72
|
require_paths:
|
|
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
81
82
|
- !ruby/object:Gem::Version
|
|
82
83
|
version: '0'
|
|
83
84
|
requirements: []
|
|
84
|
-
rubygems_version: 3.
|
|
85
|
+
rubygems_version: 3.2.33
|
|
85
86
|
signing_key:
|
|
86
87
|
specification_version: 4
|
|
87
88
|
summary: Simple role-based authorization library for Ruby on Rails.
|