rokku 0.7.0 → 2.0.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/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +0 -0
- data/CODE_OF_CONDUCT.md +0 -0
- data/Gemfile +0 -0
- data/Gemfile.lock +7 -92
- data/LICENSE.txt +0 -0
- data/README.md +155 -15
- data/Rakefile +0 -0
- data/lib/rokku/commands/commands.rb +124 -76
- data/lib/rokku/version.rb +1 -1
- data/lib/rokku.rb +22 -17
- data/rokku.gemspec +2 -8
- metadata +12 -82
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7979320c7f0685c0a6e117a611864ab3720646f1d932262bbb8f9ad58dca169
|
|
4
|
+
data.tar.gz: 78806b988c5c551d0ed83987b36642beb42d260432791188c7a67abd46c04360
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 66263f59a47f0fb1befc22b5cefd31299c5e1aeb6230de6fa782d72cfaac6aad88d7fdf06f2e3abd1269e66a00802007b2541ee52f10a04f8629be70b7a4a80b
|
|
7
|
+
data.tar.gz: a20785060356177fcbfa8b457b7ac52fe90931073f9185ea386c043131ab29e47bc4e9808ff19246b129159e0ea42b879187b9f08c38636c3bfe935731f88adf
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.0
|
data/.travis.yml
CHANGED
|
File without changes
|
data/CODE_OF_CONDUCT.md
CHANGED
|
File without changes
|
data/Gemfile
CHANGED
|
File without changes
|
data/Gemfile.lock
CHANGED
|
@@ -1,107 +1,22 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rokku (0.
|
|
5
|
-
hanami-controller (~> 1.0)
|
|
6
|
-
hanami-router (~> 1.0)
|
|
4
|
+
rokku (2.0.0)
|
|
7
5
|
|
|
8
6
|
GEM
|
|
9
7
|
remote: https://rubygems.org/
|
|
10
8
|
specs:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
concurrent-ruby (~> 1.0)
|
|
14
|
-
dry-core (~> 0.4, >= 0.4.7)
|
|
15
|
-
dry-equalizer (~> 0.2)
|
|
16
|
-
dry-container (0.7.2)
|
|
17
|
-
concurrent-ruby (~> 1.0)
|
|
18
|
-
dry-configurable (~> 0.1, >= 0.1.3)
|
|
19
|
-
dry-core (0.4.10)
|
|
20
|
-
concurrent-ruby (~> 1.0)
|
|
21
|
-
dry-equalizer (0.3.0)
|
|
22
|
-
dry-initializer (1.4.1)
|
|
23
|
-
dry-logic (0.4.2)
|
|
24
|
-
dry-container (~> 0.2, >= 0.2.6)
|
|
25
|
-
dry-core (~> 0.2)
|
|
26
|
-
dry-equalizer (~> 0.2)
|
|
27
|
-
dry-struct (0.3.1)
|
|
28
|
-
dry-configurable (~> 0.1)
|
|
29
|
-
dry-core (~> 0.3)
|
|
30
|
-
dry-equalizer (~> 0.2)
|
|
31
|
-
dry-types (~> 0.9, >= 0.9.0)
|
|
32
|
-
ice_nine (~> 0.11)
|
|
33
|
-
dry-types (0.11.1)
|
|
34
|
-
concurrent-ruby (~> 1.0)
|
|
35
|
-
dry-configurable (~> 0.1)
|
|
36
|
-
dry-container (~> 0.3)
|
|
37
|
-
dry-core (~> 0.2, >= 0.2.1)
|
|
38
|
-
dry-equalizer (~> 0.2)
|
|
39
|
-
dry-logic (~> 0.4, >= 0.4.0)
|
|
40
|
-
inflecto (~> 0.0.0, >= 0.0.2)
|
|
41
|
-
hanami-controller (1.3.3)
|
|
42
|
-
hanami-utils (~> 1.3)
|
|
43
|
-
rack (~> 2.0)
|
|
44
|
-
hanami-model (1.3.2)
|
|
45
|
-
concurrent-ruby (~> 1.0)
|
|
46
|
-
dry-logic (~> 0.4.2, < 0.5)
|
|
47
|
-
dry-types (~> 0.11.0)
|
|
48
|
-
hanami-utils (~> 1.3)
|
|
49
|
-
rom (~> 3.3, >= 3.3.3)
|
|
50
|
-
rom-repository (~> 1.4)
|
|
51
|
-
rom-sql (~> 1.3, >= 1.3.5)
|
|
52
|
-
hanami-router (1.3.2)
|
|
53
|
-
hanami-utils (~> 1.3)
|
|
54
|
-
http_router (= 0.11.2)
|
|
55
|
-
rack (~> 2.0)
|
|
56
|
-
hanami-utils (1.3.6)
|
|
57
|
-
concurrent-ruby (~> 1.0)
|
|
58
|
-
transproc (~> 1.0)
|
|
59
|
-
http_router (0.11.2)
|
|
60
|
-
rack (>= 1.0.0)
|
|
61
|
-
url_mount (~> 0.2.1)
|
|
62
|
-
ice_nine (0.11.2)
|
|
63
|
-
inflecto (0.0.2)
|
|
64
|
-
minitest (5.13.0)
|
|
65
|
-
rack (2.2.3)
|
|
66
|
-
rake (10.5.0)
|
|
67
|
-
rom (3.3.3)
|
|
68
|
-
concurrent-ruby (~> 1.0)
|
|
69
|
-
dry-core (~> 0.3)
|
|
70
|
-
dry-equalizer (~> 0.2)
|
|
71
|
-
dry-initializer (~> 1.3)
|
|
72
|
-
dry-types (~> 0.9, >= 0.9.4)
|
|
73
|
-
rom-mapper (~> 0.5, >= 0.5.1)
|
|
74
|
-
rom-mapper (0.5.1)
|
|
75
|
-
dry-core (~> 0.2, >= 0.2.3)
|
|
76
|
-
dry-equalizer (~> 0.2)
|
|
77
|
-
transproc (~> 1.0)
|
|
78
|
-
rom-repository (1.4.0)
|
|
79
|
-
dry-core (~> 0.3, >= 0.3.1)
|
|
80
|
-
dry-struct (~> 0.3)
|
|
81
|
-
rom (~> 3.3)
|
|
82
|
-
rom-mapper (~> 0.5)
|
|
83
|
-
rom-sql (1.3.5)
|
|
84
|
-
dry-core (~> 0.3)
|
|
85
|
-
dry-equalizer (~> 0.2)
|
|
86
|
-
dry-types (~> 0.11.0)
|
|
87
|
-
rom (~> 3.2, >= 3.2.2)
|
|
88
|
-
sequel (~> 4.43)
|
|
89
|
-
sequel (4.49.0)
|
|
90
|
-
transproc (1.1.1)
|
|
91
|
-
url_mount (0.2.1)
|
|
92
|
-
rack
|
|
9
|
+
minitest (5.26.1)
|
|
10
|
+
rake (13.3.1)
|
|
93
11
|
|
|
94
12
|
PLATFORMS
|
|
95
|
-
|
|
13
|
+
x86_64-linux
|
|
96
14
|
|
|
97
15
|
DEPENDENCIES
|
|
98
16
|
bundler (~> 2.0)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
hanami-router (~> 1.0)
|
|
102
|
-
minitest (~> 5.0)
|
|
103
|
-
rake (~> 10.0)
|
|
17
|
+
minitest (~> 5.25)
|
|
18
|
+
rake (~> 13.0)
|
|
104
19
|
rokku!
|
|
105
20
|
|
|
106
21
|
BUNDLED WITH
|
|
107
|
-
2.
|
|
22
|
+
2.2.3
|
data/LICENSE.txt
CHANGED
|
File without changes
|
data/README.md
CHANGED
|
@@ -6,8 +6,10 @@ Rokku (ロック - lock) offers authorization for [Hanami web applications](http
|
|
|
6
6
|
|
|
7
7
|
Authorization was setup as inspired by [this blog post](http://billpatrianakos.me/blog/2013/10/22/authorize-users-based-on-roles-and-permissions-without-a-gem/). It supports the generation of policy files for each controller where authorized roles are specified for each action.
|
|
8
8
|
|
|
9
|
+
**Note:** For Hanami 1.3 support, see the [0.7.0 branch](https://github.com/sebastjan-hribar/rokku/tree/0.7.0) or install Rokku 0.7.0.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
## 1. Installation
|
|
11
13
|
|
|
12
14
|
Add this line to your application's Gemfile:
|
|
13
15
|
|
|
@@ -24,34 +26,73 @@ Or install it yourself as:
|
|
|
24
26
|
$ gem install rokku
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
Rokku
|
|
29
|
+
Rokku 2.0 needs to be included in the action:
|
|
28
30
|
|
|
29
31
|
```ruby
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
# auto_register: false
|
|
33
|
+
# frozen_string_literal: true
|
|
34
|
+
|
|
35
|
+
require "hanami/action"
|
|
36
|
+
require "dry/monads"
|
|
37
|
+
require "rokku"
|
|
38
|
+
|
|
39
|
+
module MyApplication
|
|
40
|
+
class Action < Hanami::Action
|
|
41
|
+
# Provide `Success` and `Failure` for pattern matching on operation results
|
|
42
|
+
include Dry::Monads[:result]
|
|
32
43
|
include Hanami::Rokku
|
|
44
|
+
|
|
45
|
+
handle_exception "ROM::TupleCountMismatchError" => :handle_not_found
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def handle_not_found(request, response, exception)
|
|
50
|
+
response.status = 404
|
|
51
|
+
response.format = :html
|
|
52
|
+
response.body = "Not found"
|
|
53
|
+
end
|
|
33
54
|
end
|
|
34
55
|
end
|
|
35
56
|
```
|
|
36
57
|
|
|
37
|
-
## Usage
|
|
58
|
+
## 2. Usage
|
|
38
59
|
|
|
39
|
-
### Role based authorization
|
|
60
|
+
### 2.1 Role based authorization
|
|
40
61
|
|
|
41
|
-
#### Prerequisites
|
|
42
|
-
|
|
43
|
-
For example, the
|
|
62
|
+
#### 2.1.1 Prerequisites
|
|
63
|
+
Prior to authorizing the user, retrieve the entity from the database and assign it to a variable `user` so it can be passed to the `authorized?` method. Rokku supports `roles` both as a type of `Array` and `String`.
|
|
64
|
+
For example, the `user.roles` could either be a simple string like 'admin' or an array of roles like `['level_1', 'level_2', 'level_3']`.
|
|
65
|
+
|
|
66
|
+
### 2.2 Policy creation
|
|
67
|
+
Rokku supports policy creation for either the main application or for a specific slice. Application policies are created in the `app/policies` folder, while the slice policies are created in the `slices/'slice name'/policies`. See the two command examples below.
|
|
44
68
|
|
|
45
69
|
```ruby
|
|
46
|
-
rokku -
|
|
70
|
+
rokku -p tasks -a myapp #=> app/policies/tasks_policy.rb
|
|
47
71
|
```
|
|
48
|
-
The above CLI command will generate a policy file for the application mightyPoster (not the project) and the controller post. The file will be generated as `myProject/lib/mightyPoster/policies/PostPolicy.rb`
|
|
49
72
|
|
|
50
|
-
|
|
73
|
+
```ruby
|
|
74
|
+
rokku -p tasks -s admin #=> app/slices/admin/policies/tasks_policy.rb
|
|
75
|
+
```
|
|
51
76
|
|
|
52
77
|
**The command must be run in the project root folder.**
|
|
53
78
|
|
|
79
|
+
**Flags:**
|
|
80
|
+
* -p, --policy => policy
|
|
81
|
+
* -s, --slice => slice
|
|
82
|
+
* -a, --app => application
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
#### 2.2.1 Naming requirements
|
|
86
|
+
For multi part names snake case must be used.
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
rokku -p admin_tasks -s admin_tickets #=> app/slices/admin_tickets/policies/admin_tasks_policy.rb
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
### 2.3 Verifying authorization
|
|
54
94
|
Once the file is generated, the authorized roles variables in the initialize block for required actions need to be uncommented and supplied with specific roles.
|
|
95
|
+
|
|
55
96
|
For example:
|
|
56
97
|
|
|
57
98
|
```ruby
|
|
@@ -61,17 +102,116 @@ For example:
|
|
|
61
102
|
@authorized_roles_for_update = ['admin']
|
|
62
103
|
```
|
|
63
104
|
|
|
64
|
-
Then we can check if a user is authorized for the `
|
|
105
|
+
Then we can check if a user is authorized for the `AdminTickets` slice, `AdminTasks` resources and the `Update`action.
|
|
65
106
|
|
|
66
107
|
```ruby
|
|
67
|
-
authorized?(
|
|
108
|
+
authorized?(user)
|
|
68
109
|
```
|
|
69
110
|
|
|
70
|
-
|
|
111
|
+
The `authorized?` method checks if the specified user has the required role and permission to access the action. It returns true or false and provides the basis for further actions in either case.
|
|
112
|
+
|
|
113
|
+
Rokku supports 2 modes of arguments specification: automatic and manual.
|
|
114
|
+
Automatic fits most cases, since the app or slice name, resource name and action are automatically extracted.
|
|
115
|
+
|
|
116
|
+
With manual it's possible to do cross-namespace authorization checks and multiple permission checks. For example it's possible to check for authorization for `EndGames` in
|
|
117
|
+
an action for `ChessOpenings`.
|
|
118
|
+
|
|
119
|
+
* Automatic
|
|
120
|
+
|
|
121
|
+
`authorized?(current_user)`
|
|
122
|
+
|
|
123
|
+
* Manual
|
|
124
|
+
|
|
125
|
+
`authorized?(current_user, namespace: "ChessBase", resource: "ChessOpenings", action: "destroy")`
|
|
126
|
+
|
|
127
|
+
The namespace argument can either be the main application name or s slice name.
|
|
128
|
+
|
|
129
|
+
#### 2.2.1 Naming requirements
|
|
130
|
+
For multi part names PascalCase must be used as shown in the above example for **Manual**.
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## 2.4 Authorization verification in a share code module
|
|
134
|
+
It is possible to enable session handling in a share code module as provided by Hanami.
|
|
135
|
+
To do this, create an authentication module in **app/actions/authentication.rb**.
|
|
136
|
+
The example below shows also how to custom values to replace default values in
|
|
137
|
+
actions.
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
module ChessBase
|
|
141
|
+
module Actions
|
|
142
|
+
module Authorization
|
|
143
|
+
|
|
144
|
+
def self.included(action_class)
|
|
145
|
+
action_class.class_eval do
|
|
146
|
+
include Deps["repos.user_repo"]
|
|
147
|
+
before :check_authorization
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
def check_authorization(request, response)
|
|
154
|
+
user_id = request.session[:current_user]
|
|
155
|
+
user = user_repo.find_by_id(user_id) if user_id
|
|
156
|
+
|
|
157
|
+
if authorized?(user) == false
|
|
158
|
+
response.flash[:failed_notice] = "You tried to visit an URL you are not authorized for."
|
|
159
|
+
response.redirect_to '/'
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
We can then simply include the `Authorization` module in actions, where required.
|
|
168
|
+
|
|
169
|
+
However, if we include this in the base action class, it will be available in all
|
|
170
|
+
actions and there is no need for separate includes in actions:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
#
|
|
174
|
+
#
|
|
175
|
+
module MyApplication
|
|
176
|
+
class Action < Hanami::Action
|
|
177
|
+
# Provide `Success` and `Failure` for pattern matching on operation results
|
|
178
|
+
include Dry::Monads[:result]
|
|
179
|
+
include Hanami::Rokku
|
|
180
|
+
include Xpresstube::Actions::Authorization
|
|
181
|
+
|
|
182
|
+
handle_exception "ROM::TupleCountMismatchError" => :handle_not_found
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
#
|
|
186
|
+
#
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**_Disabling the authorization shared module in specific actions_**
|
|
190
|
+
|
|
191
|
+
Sometimes we might not want to check for authorized user. For example,
|
|
192
|
+
doing so in the `login` action will cause an infinite loop. There we can
|
|
193
|
+
disable the module by overwriting the desired methods in the action:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
def check_authorization; end
|
|
199
|
+
```
|
|
71
200
|
|
|
72
201
|
|
|
73
202
|
### Changelog
|
|
74
203
|
|
|
204
|
+
#### 2.0.0
|
|
205
|
+
|
|
206
|
+
**Breaking Changes:**
|
|
207
|
+
- Supports Hanami ~> 2.0 applications only.
|
|
208
|
+
- Application policies are now created in `app/policies`.
|
|
209
|
+
- Slice policies are now created in `slices/my_slice/policies`.
|
|
210
|
+
- Rokku must be explicitly included in the base action: `include Hanami::Rokku`.
|
|
211
|
+
- Rokku 2.0.0 doesn't rely on instance variable like `@user` anymore. Instead, a `user` variable must be passed as an argument to a method.
|
|
212
|
+
|
|
213
|
+
For Hanami 1.3 support, use Rokku 0.7.0.
|
|
214
|
+
|
|
75
215
|
#### 0.7.0
|
|
76
216
|
|
|
77
217
|
* Policies are now scoped under application module so it is possible to have two `Dashboard` policies for two different applications.
|
data/Rakefile
CHANGED
|
File without changes
|
|
@@ -5,20 +5,27 @@ module Commands
|
|
|
5
5
|
def self.run
|
|
6
6
|
options = {}
|
|
7
7
|
optparse = OptionParser.new do |opts|
|
|
8
|
-
opts.banner = "\nHanami authorization policy generator
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
opts.banner = "\nHanami 2.x authorization policy generator
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
rokku -p tasks -a myapp # Main app: app/policies/tasks_policy.rb
|
|
12
|
+
rokku -p tasks -s admin # Slice: slices/admin/policies/tasks_policy.rb
|
|
13
|
+
Flags:
|
|
14
|
+
\n"
|
|
15
|
+
|
|
16
|
+
opts.on("-p", "--policy POLICY", "Specify a policy name (e.g., tasks, users, posts) - REQUIRED.") do |policy|
|
|
17
|
+
options[:policy] = policy
|
|
15
18
|
end
|
|
16
|
-
|
|
17
|
-
opts.on("-
|
|
18
|
-
options[:
|
|
19
|
+
|
|
20
|
+
opts.on("-a", "--app APP", "Specify the main app name (e.g., myapp, mytasks) - used for main app policies.") do |app|
|
|
21
|
+
options[:app] = app
|
|
19
22
|
end
|
|
20
|
-
|
|
21
|
-
opts.on("-
|
|
23
|
+
|
|
24
|
+
opts.on("-s", "--slice SLICE", "Specify a slice name (e.g., admin, api) - used for slice policies.") do |slice|
|
|
25
|
+
options[:slice] = slice
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
opts.on("-h", "--help", "Display help.") do
|
|
22
29
|
puts opts
|
|
23
30
|
exit
|
|
24
31
|
end
|
|
@@ -26,82 +33,123 @@ module Commands
|
|
|
26
33
|
|
|
27
34
|
begin
|
|
28
35
|
optparse.parse!
|
|
29
|
-
puts "Add flag -h or --help to see usage instructions." if options.empty?
|
|
30
|
-
mandatory = [:app_name, :policy]
|
|
31
|
-
missing = mandatory.select{ |arg| options[arg].nil? }
|
|
32
|
-
unless missing.empty?
|
|
33
|
-
raise OptionParser::MissingArgument.new(missing.join(', '))
|
|
34
|
-
end
|
|
35
|
-
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
|
36
|
-
puts $!.to_s
|
|
37
|
-
puts optparse
|
|
38
|
-
exit
|
|
39
|
-
end
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
if options.empty?
|
|
38
|
+
puts "Error: no options prodived."
|
|
39
|
+
puts optparse
|
|
40
|
+
exit 1
|
|
41
|
+
end
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
unless options[:policy]
|
|
44
|
+
puts "Error: Policy name is required (-p or --policy)."
|
|
45
|
+
puts optparse
|
|
46
|
+
exit 1
|
|
47
|
+
end
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def initialize(roles)
|
|
58
|
-
@user_roles = roles
|
|
59
|
-
# Uncomment the required roles and add the
|
|
60
|
-
# appropriate user role to the @authorized_roles* array.
|
|
61
|
-
# @authorized_roles_for_new = []
|
|
62
|
-
# @authorized_roles_for_create = []
|
|
63
|
-
# @authorized_roles_for_show = []
|
|
64
|
-
# @authorized_roles_for_index = []
|
|
65
|
-
# @authorized_roles_for_edit = []
|
|
66
|
-
# @authorized_roles_for_update = []
|
|
67
|
-
# @authorized_roles_for_destroy = []
|
|
68
|
-
end
|
|
49
|
+
if options[:app] && options[:slice]
|
|
50
|
+
puts "Error: Cannot specify both --app and --slice."
|
|
51
|
+
puts "Use --app for main app policies, --slice for slice policies."
|
|
52
|
+
puts optparse
|
|
53
|
+
exit 1
|
|
54
|
+
end
|
|
69
55
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
unless options[:app] || options[:slice]
|
|
57
|
+
puts "Error: Must specify either --app or --slice."
|
|
58
|
+
puts "Use --app for main app policies, --slice for slice policies."
|
|
59
|
+
puts optparse
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
64
|
+
puts "Error: #{e.message}"
|
|
65
|
+
puts optparse
|
|
66
|
+
exit 1
|
|
67
|
+
end
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
puts "Generating policy: #{options.inspect}"
|
|
70
|
+
generate_policy(options[:policy], app_name: options[:app], slice_name: options[:slice])
|
|
71
|
+
end
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
private
|
|
74
|
+
# The generate_policy method creates the policy file at the main
|
|
75
|
+
# application or slice level for Hanami 2.x applications.
|
|
76
|
+
# By default all actions to check against are commented out.
|
|
85
77
|
|
|
86
|
-
|
|
87
|
-
(@authorized_roles_for_edit & @user_roles).any?
|
|
88
|
-
end
|
|
78
|
+
# Uncomment the needed actions and define appropriate user roles.
|
|
89
79
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
def self.generate_policy(policy_name, app_name: nil, slice_name: nil)
|
|
81
|
+
if slice_name
|
|
82
|
+
namespace = slice_name.split("_").map(&:downcase).map(&:capitalize).join
|
|
83
|
+
folder_namespace = slice_name.split("_").map(&:downcase).join("_")
|
|
84
|
+
policies_dir = "slices/#{folder_namespace}/policies"
|
|
85
|
+
elsif app_name
|
|
86
|
+
namespace = app_name.split("_").map(&:downcase).map(&:capitalize).join
|
|
87
|
+
policies_dir = "app/policies"
|
|
88
|
+
else
|
|
89
|
+
raise ArgumentError, "Please specify either app_name or slice_name."
|
|
90
|
+
end
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
policy_class_name = "#{policy_name.split("_").map(&:downcase).map(&:capitalize).join}Policy"
|
|
93
|
+
|
|
94
|
+
policy_content = <<~RUBY
|
|
95
|
+
# frozen_string_literal: true
|
|
96
|
+
|
|
97
|
+
module #{namespace}
|
|
98
|
+
class #{policy_class_name}
|
|
99
|
+
def initialize(roles)
|
|
100
|
+
@user_roles = roles
|
|
101
|
+
# Uncomment the required roles and add the
|
|
102
|
+
# appropriate user role to the @authorized_roles* array.
|
|
103
|
+
# @authorized_roles_for_new = []
|
|
104
|
+
# @authorized_roles_for_create = []
|
|
105
|
+
# @authorized_roles_for_show = []
|
|
106
|
+
# @authorized_roles_for_index = []
|
|
107
|
+
# @authorized_roles_for_edit = []
|
|
108
|
+
# @authorized_roles_for_update = []
|
|
109
|
+
# @authorized_roles_for_destroy = []
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def new?
|
|
113
|
+
(@authorized_roles_for_new & @user_roles).any?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def create?
|
|
117
|
+
(@authorized_roles_for_create & @user_roles).any?
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def show?
|
|
121
|
+
(@authorized_roles_for_show & @user_roles).any?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def index?
|
|
125
|
+
(@authorized_roles_for_index & @user_roles).any?
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def edit?
|
|
129
|
+
(@authorized_roles_for_edit & @user_roles).any?
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def update?
|
|
133
|
+
(@authorized_roles_for_update & @user_roles).any?
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def destroy?
|
|
137
|
+
(@authorized_roles_for_destroy & @user_roles).any?
|
|
138
|
+
end
|
|
96
139
|
end
|
|
97
140
|
end
|
|
141
|
+
RUBY
|
|
142
|
+
|
|
143
|
+
FileUtils.mkdir_p(policies_dir) unless File.directory?(policies_dir)
|
|
144
|
+
policy_file = "#{policies_dir}/#{policy_name.downcase}_policy.rb"
|
|
145
|
+
|
|
146
|
+
if File.exist?(policy_file)
|
|
147
|
+
puts "Policy already exists: #{policy_file}."
|
|
148
|
+
puts "Skipping generation."
|
|
149
|
+
else
|
|
150
|
+
File.write(policy_file, policy_content)
|
|
151
|
+
puts "✓ Generated policy: #{policy_file}."
|
|
152
|
+
puts " Namespace: #{namespace}::#{policy_class_name}."
|
|
98
153
|
end
|
|
99
|
-
TXT
|
|
100
|
-
|
|
101
|
-
FileUtils.mkdir_p "lib/#{app_name.downcase}/policies" unless File.directory?("lib/#{app_name.downcase}/policies")
|
|
102
|
-
unless File.file?("lib/#{app_name.downcase}/policies/#{controller}Policy.rb")
|
|
103
|
-
File.open("lib/#{app_name.downcase}/policies/#{controller}Policy.rb", 'w') { |file| file.write(policy_txt) }
|
|
104
|
-
end
|
|
105
|
-
puts("Generated policy: lib/#{app_name.downcase}/policies/#{controller}Policy.rb") if File.file?("lib/#{app_name.downcase}/policies/#{controller}Policy.rb")
|
|
106
154
|
end
|
|
107
155
|
end
|
data/lib/rokku/version.rb
CHANGED
data/lib/rokku.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'rokku/version'
|
|
2
|
-
require 'hanami/controller'
|
|
3
2
|
|
|
4
3
|
module Hanami
|
|
5
4
|
module Rokku
|
|
@@ -10,23 +9,29 @@ module Hanami
|
|
|
10
9
|
# and permission to access the action. It returns true or false and
|
|
11
10
|
# provides the basis for further actions in either case.
|
|
12
11
|
#
|
|
13
|
-
#
|
|
12
|
+
# There are 2 modes of arguments specification possible: automatic and manual.
|
|
13
|
+
# Automatic fits most cases. With manual it's possible to do
|
|
14
|
+
# cross-namespace authorization checks and multiple permission checks.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
# Automatic
|
|
17
|
+
# authorized?(current_user)
|
|
18
|
+
#
|
|
19
|
+
# Manual
|
|
20
|
+
# authorized?(current_user, namespace: "ChessBase", resource: "ChessOpenings", action: "destroy")
|
|
21
|
+
#
|
|
22
|
+
# The namespace argument can either be the main application name or s slice name.
|
|
23
|
+
|
|
24
|
+
def authorized?(user, namespace: nil, resource: nil, action: nil)
|
|
25
|
+
if namespace.nil? || resource.nil? || action.nil?
|
|
26
|
+
namespace = self.class.to_s.split("::")[0]
|
|
27
|
+
resource = self.class.to_s.split("::")[2]
|
|
28
|
+
action = self.class.to_s.split("::")[3]
|
|
22
29
|
end
|
|
23
|
-
Object.const_get("#{application}::#{controller.downcase.capitalize}Policy").new(roles).send("#{action.downcase}?")
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
input_roles = user.roles
|
|
32
|
+
roles = input_roles.is_a?(String) ? [input_roles] : input_roles
|
|
33
|
+
|
|
34
|
+
Object.const_get("#{namespace}::#{resource}Policy").new(roles).send("#{action.downcase}?")
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
|
-
end
|
|
37
|
+
end
|
data/rokku.gemspec
CHANGED
|
@@ -25,12 +25,6 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.require_paths = ["lib"]
|
|
26
26
|
|
|
27
27
|
spec.add_development_dependency "bundler", "~> 2.0"
|
|
28
|
-
spec.add_development_dependency "rake", "~>
|
|
29
|
-
spec.add_development_dependency "minitest", "~> 5.
|
|
30
|
-
spec.add_development_dependency 'hanami-model', '~> 1.0'
|
|
31
|
-
spec.add_development_dependency 'hanami-controller', "~> 1.0"
|
|
32
|
-
spec.add_development_dependency 'hanami-router', "~> 1.0"
|
|
33
|
-
|
|
34
|
-
spec.add_runtime_dependency 'hanami-controller', "~> 1.0"
|
|
35
|
-
spec.add_runtime_dependency 'hanami-router', "~> 1.0"
|
|
28
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
29
|
+
spec.add_development_dependency "minitest", "~> 5.25"
|
|
36
30
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rokku
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastjan Hribar
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -30,99 +30,29 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '13.0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '13.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: minitest
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '5.
|
|
47
|
+
version: '5.25'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '5.
|
|
55
|
-
|
|
56
|
-
name: hanami-model
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '1.0'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '1.0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: hanami-controller
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '1.0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '1.0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: hanami-router
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '1.0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '1.0'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: hanami-controller
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - "~>"
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '1.0'
|
|
104
|
-
type: :runtime
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - "~>"
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '1.0'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: hanami-router
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - "~>"
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '1.0'
|
|
118
|
-
type: :runtime
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - "~>"
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '1.0'
|
|
125
|
-
description:
|
|
54
|
+
version: '5.25'
|
|
55
|
+
description:
|
|
126
56
|
email:
|
|
127
57
|
- sebastjan.hribar@gmail.com
|
|
128
58
|
executables:
|
|
@@ -133,6 +63,7 @@ extensions: []
|
|
|
133
63
|
extra_rdoc_files: []
|
|
134
64
|
files:
|
|
135
65
|
- ".gitignore"
|
|
66
|
+
- ".ruby-version"
|
|
136
67
|
- ".travis.yml"
|
|
137
68
|
- CODE_OF_CONDUCT.md
|
|
138
69
|
- Gemfile
|
|
@@ -152,7 +83,7 @@ licenses:
|
|
|
152
83
|
- MIT
|
|
153
84
|
metadata:
|
|
154
85
|
homepage_uri: https://github.com/sebastjan-hribar/rokku
|
|
155
|
-
post_install_message:
|
|
86
|
+
post_install_message:
|
|
156
87
|
rdoc_options: []
|
|
157
88
|
require_paths:
|
|
158
89
|
- lib
|
|
@@ -167,9 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
167
98
|
- !ruby/object:Gem::Version
|
|
168
99
|
version: '0'
|
|
169
100
|
requirements: []
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
signing_key:
|
|
101
|
+
rubygems_version: 3.2.3
|
|
102
|
+
signing_key:
|
|
173
103
|
specification_version: 4
|
|
174
104
|
summary: Rokku is a small authorization library for Hanami projects.
|
|
175
105
|
test_files: []
|