sinatra-bouncer 2.0.0 → 3.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/Gemfile.lock +1 -1
- data/README.md +83 -66
- data/RELEASE_NOTES.md +17 -0
- data/lib/sinatra/bouncer/basic_bouncer.rb +34 -55
- data/lib/sinatra/bouncer/rule.rb +105 -21
- data/lib/sinatra/bouncer/version.rb +1 -1
- data/lib/sinatra/bouncer.rb +1 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 849fed52904df15b1cc036685383f197e47aae52bef8283a81decc281fc95660
|
4
|
+
data.tar.gz: 3a3ba41d0d3c2ad70b1c4e48b81558213111d86a750717e2b8f44dea9072ca1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d63e6a5437ef4d71e7183dce458241a8efaebace1c6f95e77766412f2faf2d5d490107a4e925588509dfb8e73b0c2e3a21064e73aae4cb3f98ae0c8465f19dd5
|
7
|
+
data.tar.gz: ca6d627ae51d9ecf6c88ffa21621117adb3af2eee6c83d14846f8ac7a5aa314f9ce4d2d10c30baf192e4a7c435f750bfb5b9bc3c37ed308ee4a5255a8df0eacf
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -5,35 +5,38 @@ routes are permitted based on your own logic.
|
|
5
5
|
|
6
6
|
## Big Picture
|
7
7
|
|
8
|
-
Bouncer
|
8
|
+
Bouncer's syntax looks like:
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
|
11
|
+
# You can define roles to collect permissions together
|
12
|
+
bouncer.role :admins do
|
13
|
+
current_user&.admin?
|
14
|
+
end
|
15
|
+
|
16
|
+
bouncer.rules do
|
12
17
|
# Routes match based on one or more strings.
|
13
|
-
can get: '/',
|
14
|
-
|
15
|
-
|
18
|
+
anyone.can get: '/',
|
19
|
+
post: ['/user/sign-in',
|
20
|
+
'/user/sign-out']
|
16
21
|
|
17
22
|
# Wildcards match anything directly under that path
|
18
|
-
can get: '/lib/js/*'
|
23
|
+
anyone.can get: '/lib/js/*'
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
post: '/admin/actions/*' do
|
23
|
-
current_user.admin?
|
24
|
-
end
|
25
|
+
admins.can get: '/admin/*',
|
26
|
+
post: '/admin/actions/*'
|
25
27
|
|
26
28
|
# ... etc ...
|
27
29
|
end
|
28
|
-
|
29
30
|
```
|
30
31
|
|
31
|
-
|
32
|
+
### Features
|
32
33
|
|
33
34
|
Here's what this Gem provides:
|
34
35
|
|
35
36
|
* **Block-by-default**
|
36
37
|
* Any route must be explicitly allowed
|
38
|
+
* **Role-Oriented**
|
39
|
+
* The [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) is constructed to be easily readable
|
37
40
|
* **Declarative Syntax**
|
38
41
|
* Straightforward syntax reduces complexity of layered permissions
|
39
42
|
* Keeps permissions together for clarity
|
@@ -44,7 +47,7 @@ Here's what this Gem provides:
|
|
44
47
|
* **Forced Boolean Affirmation**
|
45
48
|
* Condition blocks must explicitly return `true`, avoiding accidental truthy values
|
46
49
|
|
47
|
-
|
50
|
+
### Anti-Features
|
48
51
|
|
49
52
|
Bouncer intentionally does not support some concepts.
|
50
53
|
|
@@ -80,7 +83,7 @@ require 'sinatra/bouncer'
|
|
80
83
|
class MyApp < Sinatra::Base
|
81
84
|
register Sinatra::Bouncer
|
82
85
|
|
83
|
-
rules do
|
86
|
+
bouncer.rules do
|
84
87
|
# ... can statements ...
|
85
88
|
end
|
86
89
|
|
@@ -94,7 +97,7 @@ end
|
|
94
97
|
require 'sinatra'
|
95
98
|
require 'sinatra/bouncer'
|
96
99
|
|
97
|
-
rules do
|
100
|
+
bouncer.rules do
|
98
101
|
# ... can statements ...
|
99
102
|
end
|
100
103
|
|
@@ -103,57 +106,77 @@ end
|
|
103
106
|
|
104
107
|
## Usage
|
105
108
|
|
106
|
-
|
109
|
+
Define roles using the `role` method and provide each one with a condition block. Then call `rules` with a block that
|
110
|
+
uses your defined roles with the `#can` or `#can_sometimes` DSL methods to declare which
|
111
|
+
paths are allowed.
|
107
112
|
|
108
113
|
The rules block is run once as part of the configuration phase but the condition blocks are evaluated in the context of
|
109
|
-
the
|
110
|
-
request, which means you will have access to Sinatra helpers,
|
111
|
-
the `request` object, and `params`.
|
114
|
+
the request handler. This means they have access to Sinatra helpers, the `request` object, and `params`.
|
112
115
|
|
113
116
|
```ruby
|
114
117
|
require 'sinatra'
|
115
118
|
require 'sinatra/bouncer'
|
116
119
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
120
|
+
bouncer.role :members do
|
121
|
+
!current_user.nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
bouncer.role :bots do
|
125
|
+
!request.get_header('X-CUSTOM-BOT').nil?
|
126
|
+
end
|
127
|
+
|
128
|
+
bouncer.rules do
|
129
|
+
# example: always allow GET requests to '/' and '/about'; and POST requests to '/sign-in'
|
130
|
+
anyone.can get: ['/', '/about'],
|
131
|
+
post: '/sign-in'
|
121
132
|
|
122
133
|
# example: logged in users can view (GET) member restricted paths and edit their account (POST)
|
123
|
-
|
124
|
-
|
125
|
-
|
134
|
+
members.can get: '/members/*'
|
135
|
+
members.can_sometimes post: '/members/edit-account' do
|
136
|
+
current_user && current_user.id == params[:id]
|
126
137
|
end
|
127
138
|
|
128
|
-
# example:
|
129
|
-
|
130
|
-
!request.get_header('X-CUSTOM_PROP').nil?
|
131
|
-
end
|
139
|
+
# example: require presence of arbitrary request header in the role condition
|
140
|
+
bots.can get: '/bots/*'
|
132
141
|
end
|
133
142
|
|
134
143
|
# ... Sinatra route declarations as normal ...
|
135
144
|
```
|
136
145
|
|
146
|
+
### Role Declarations
|
147
|
+
|
148
|
+
Roles are declared using the `#role` method in your Sinatra config. Each one must be provided a condition block that
|
149
|
+
must return exactly `true` when the role applies.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
# let's pretend that current_user is a helper that returns the user from Warden
|
153
|
+
bouncer.role :admins do
|
154
|
+
current_user&.admin?
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
> **Note:** There is a default role called `anyone` that is always declared for you.
|
159
|
+
|
137
160
|
### HTTP Method and Route Matching
|
138
161
|
|
139
|
-
Both `#can` and `#can_sometimes` accept
|
140
|
-
[HTTP methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) as
|
162
|
+
Both `#can` and `#can_sometimes` accept symbol
|
163
|
+
[HTTP methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) as keys
|
141
164
|
and each key is paired with one or more path strings.
|
142
165
|
|
143
166
|
```ruby
|
144
167
|
# example: single method, single route
|
145
|
-
can get: '/'
|
168
|
+
anyone.can get: '/'
|
146
169
|
|
147
170
|
# example: multiple methods, single route each
|
148
|
-
can get: '/',
|
149
|
-
|
171
|
+
anyone.can get: '/',
|
172
|
+
post: '/blog/action/save'
|
150
173
|
|
151
174
|
# example: multiple methods, multiple routes (using string array syntax)
|
152
|
-
can get: %w[/
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
175
|
+
anyone.can get: %w[/
|
176
|
+
/sign-in
|
177
|
+
/blog/editor],
|
178
|
+
post: %w[/blog/action/save
|
179
|
+
/blog/action/delete]
|
157
180
|
```
|
158
181
|
|
159
182
|
> **Note** Allowing GET implies allowing HEAD, since HEAD is by spec a GET without a response body. The reverse is not
|
@@ -161,55 +184,49 @@ can get: %w[/
|
|
161
184
|
|
162
185
|
#### Wildcards and Special Symbols
|
163
186
|
|
164
|
-
> **Warning** Always be cautious when using wildcards and special symbols to not accidentally open up pathways that
|
165
|
-
> should remain private.
|
166
|
-
|
167
187
|
Provide a wildcard `*` to match any string excluding slash. There is intentionally no syntax for matching wildcards
|
168
188
|
recursively, so nested paths will also need to be declared.
|
169
189
|
|
170
190
|
```ruby
|
171
191
|
# example: match anything directly under the /members/ path
|
172
|
-
can get: '/members/*'
|
192
|
+
members.can get: '/members/*'
|
173
193
|
```
|
174
194
|
|
175
|
-
There
|
176
|
-
|
177
|
-
1. `:any` will match any HTTP method.
|
178
|
-
2. `:all` will match all paths.
|
195
|
+
There is also a special symbol, `:all` that matches all paths. It is intended for rare use
|
196
|
+
with superadmin-type accounts.
|
179
197
|
|
180
198
|
```ruby
|
181
|
-
# this allows
|
182
|
-
can
|
183
|
-
|
184
|
-
# this allows GET on all paths
|
185
|
-
can get: :all
|
199
|
+
# this allows GET on all paths to those in the admin group
|
200
|
+
admins.can get: :all
|
186
201
|
```
|
187
202
|
|
203
|
+
> **Warning** Always be cautious when using wildcards and special symbols to avoid accidentally opening up pathways that
|
204
|
+
> should remain private.
|
205
|
+
|
188
206
|
### Always Allow: `can`
|
189
207
|
|
190
208
|
Any route declared with `#can` will be accepted without further challenge.
|
191
209
|
|
192
210
|
```ruby
|
193
|
-
rules do
|
211
|
+
bouncer.rules do
|
194
212
|
# Anyone can access this path over GET
|
195
|
-
can get: '/login'
|
213
|
+
anyone.can get: '/login'
|
196
214
|
end
|
197
215
|
```
|
198
216
|
|
199
217
|
### Conditionally Allow: `can_sometimes`
|
200
218
|
|
201
|
-
`can_sometimes`
|
202
|
-
|
203
|
-
`can_sometimes` takes a block that will be run once the path is attempted. This block **must return an explicit boolean
|
204
|
-
**
|
205
|
-
(ie. `true` or `false`) to avoid any accidental truthy values creating unwanted access.
|
219
|
+
`can_sometimes` takes a condition block that will be run once the path is attempted. This block **must return an
|
220
|
+
explicit boolean** (ie. `true` or `false`) to avoid any accidental truthy values creating unwanted access.
|
206
221
|
|
207
222
|
```ruby
|
208
|
-
|
209
|
-
|
223
|
+
bouncer.role :users do
|
224
|
+
!current_user.nil?
|
225
|
+
end
|
210
226
|
|
211
|
-
|
212
|
-
|
227
|
+
bouncer.rules do
|
228
|
+
users.can_sometimes post: '/user/save' do
|
229
|
+
current_user.id == params[:id]
|
213
230
|
end
|
214
231
|
end
|
215
232
|
```
|
@@ -217,7 +234,7 @@ end
|
|
217
234
|
### Custom Bounce Behaviour
|
218
235
|
|
219
236
|
The default bounce action is to `halt 403`. Call `bounce_with` with a block to specify your own behaviour. The block is
|
220
|
-
also run in a
|
237
|
+
also run in a Sinatra request handler context, so you can use helpers here as well.
|
221
238
|
|
222
239
|
```ruby
|
223
240
|
require 'sinatra'
|
data/RELEASE_NOTES.md
CHANGED
@@ -19,6 +19,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
19
19
|
|
20
20
|
* none
|
21
21
|
|
22
|
+
## [3.0.0] - 2023-11-21
|
23
|
+
|
24
|
+
### Major Changes
|
25
|
+
|
26
|
+
* Changed rules DSL to be role-oriented
|
27
|
+
* Removed the `:any` HTTP method wildcard
|
28
|
+
* Changed Sinatra API to require calling methods on bouncer object
|
29
|
+
* eg. `rules do ... end` should now be `bouncer.rules do ... end`
|
30
|
+
|
31
|
+
### Minor Changes
|
32
|
+
|
33
|
+
* none
|
34
|
+
|
35
|
+
### Bugfixes
|
36
|
+
|
37
|
+
* none
|
38
|
+
|
22
39
|
## [2.0.0] - 2023-11-13
|
23
40
|
|
24
41
|
### Major Changes
|
@@ -6,81 +6,60 @@ module Sinatra
|
|
6
6
|
module Bouncer
|
7
7
|
# Core implementation of Bouncer logic
|
8
8
|
class BasicBouncer
|
9
|
-
attr_accessor :
|
10
|
-
|
11
|
-
# Enumeration of HTTP method strings based on:
|
12
|
-
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
|
13
|
-
# Ignoring CONNECT and TRACE due to rarity
|
14
|
-
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH].freeze
|
15
|
-
|
16
|
-
# Symbol versions of HTTP_METHODS constant
|
17
|
-
#
|
18
|
-
# @see HTTP_METHODS
|
19
|
-
HTTP_METHOD_SYMBOLS = HTTP_METHODS.collect do |http_method|
|
20
|
-
http_method.downcase.to_sym
|
21
|
-
end.freeze
|
22
|
-
|
23
|
-
# Method symbol used to match any method
|
24
|
-
WILDCARD_METHOD = :any
|
9
|
+
attr_accessor :rules_initializer
|
25
10
|
|
26
11
|
def initialize
|
27
|
-
@
|
28
|
-
[]
|
29
|
-
end
|
12
|
+
@rules = []
|
30
13
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def can(**method_routes)
|
35
|
-
if block_given?
|
36
|
-
hint = 'If you wish to conditionally allow, use #can_sometimes instead.'
|
37
|
-
raise BouncerError, "You cannot provide a block to #can. #{ hint }"
|
14
|
+
role :anyone do
|
15
|
+
true
|
38
16
|
end
|
39
17
|
|
40
|
-
|
41
|
-
|
18
|
+
@rules_initializer = proc {}
|
19
|
+
@bounce_strategy = proc do
|
20
|
+
halt 403
|
42
21
|
end
|
43
22
|
end
|
44
23
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
raise BouncerError,
|
24
|
+
def rules(&block)
|
25
|
+
instance_exec(&block)
|
26
|
+
@rules.each do |rule|
|
27
|
+
raise BouncerError, 'rules block error: missing #can or #can_sometimes call' if rule.incomplete?
|
49
28
|
end
|
29
|
+
end
|
50
30
|
|
51
|
-
|
52
|
-
|
53
|
-
hint = "Must be one of: #{ HTTP_METHOD_SYMBOLS } or :#{ WILDCARD_METHOD }"
|
54
|
-
raise BouncerError, "'#{ method }' is not a known HTTP method key. #{ hint }"
|
55
|
-
end
|
56
|
-
|
57
|
-
paths = [paths] unless paths.respond_to? :collect
|
31
|
+
def can?(method, path, context)
|
32
|
+
method = method.downcase.to_sym unless method.is_a? Symbol
|
58
33
|
|
59
|
-
|
34
|
+
@rules.any? do |rule|
|
35
|
+
rule.allow? method, path, context
|
60
36
|
end
|
61
37
|
end
|
62
38
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
# HEAD requests are equivalent to GET requests without response
|
67
|
-
rulesets += @ruleset[:get] if method == :head
|
39
|
+
def bounce_with(&block)
|
40
|
+
@bounce_strategy = block
|
41
|
+
end
|
68
42
|
|
69
|
-
|
43
|
+
def bounce(instance)
|
44
|
+
instance.instance_exec(&@bounce_strategy)
|
45
|
+
end
|
70
46
|
|
71
|
-
|
72
|
-
|
47
|
+
def role(identifier, &block)
|
48
|
+
raise ArgumentError, 'must provide a role identifier to #role' unless identifier
|
49
|
+
raise ArgumentError, 'must provide a role condition block to #role' unless block
|
50
|
+
raise ArgumentError, "role called '#{ identifier }' already defined" if respond_to? identifier
|
73
51
|
|
74
|
-
|
52
|
+
define_singleton_method identifier do
|
53
|
+
add_rule(&block)
|
75
54
|
end
|
76
55
|
end
|
77
56
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
57
|
+
private
|
58
|
+
|
59
|
+
def add_rule(&block)
|
60
|
+
rule = Rule.new(&block)
|
61
|
+
@rules << rule
|
62
|
+
rule
|
84
63
|
end
|
85
64
|
end
|
86
65
|
|
data/lib/sinatra/bouncer/rule.rb
CHANGED
@@ -2,50 +2,122 @@
|
|
2
2
|
|
3
3
|
module Sinatra
|
4
4
|
module Bouncer
|
5
|
-
# Defines a
|
5
|
+
# Defines a RuleSet to be evaluated with each request
|
6
6
|
class Rule
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
# Enumeration of HTTP method strings based on:
|
8
|
+
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
|
9
|
+
# Ignoring CONNECT and TRACE due to rarity
|
10
|
+
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH].freeze
|
11
|
+
|
12
|
+
# Symbol versions of HTTP_METHODS constant
|
13
|
+
#
|
14
|
+
# @see HTTP_METHODS
|
15
|
+
HTTP_METHOD_SYMBOLS = HTTP_METHODS.collect do |http_method|
|
16
|
+
http_method.downcase.to_sym
|
17
|
+
end.freeze
|
18
|
+
|
19
|
+
def initialize(&block)
|
20
|
+
raise ArgumentError, 'must provide a block to Bouncer::Rule' unless block
|
21
|
+
|
22
|
+
@routes = Hash.new do
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
|
26
|
+
@conditions = [block]
|
27
|
+
end
|
28
|
+
|
29
|
+
def can_sometimes(**method_routes, &block)
|
30
|
+
if method_routes.empty?
|
31
|
+
raise ArgumentError,
|
32
|
+
'must provide a hash where keys are HTTP method symbols and values are one or more path matchers'
|
33
|
+
end
|
34
|
+
|
35
|
+
unless block
|
36
|
+
hint = 'If you wish to always allow, use #can instead.'
|
37
|
+
raise BouncerError, "You must provide a block to #can_sometimes. #{ hint }"
|
38
|
+
end
|
39
|
+
|
40
|
+
method_routes.each do |method, paths|
|
41
|
+
validate_http_method! method
|
42
|
+
|
43
|
+
paths = [paths] unless paths.respond_to? :collect
|
44
|
+
|
45
|
+
@routes[method] += paths.collect { |path| normalize_path path }
|
46
|
+
end
|
47
|
+
|
48
|
+
@conditions << block
|
49
|
+
end
|
12
50
|
|
13
|
-
|
51
|
+
def can(**method_routes)
|
52
|
+
if block_given?
|
53
|
+
hint = 'If you wish to conditionally allow, use #can_sometimes instead.'
|
54
|
+
raise BouncerError, "You cannot provide a block to #can. #{ hint }"
|
14
55
|
end
|
15
56
|
|
16
|
-
|
57
|
+
can_sometimes(**method_routes) do
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def allow?(method, path, context)
|
63
|
+
match_path?(method, path) && @conditions.all? do |condition|
|
64
|
+
rule_passes?(context, &condition)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def incomplete?
|
69
|
+
@routes.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def validate_http_method!(method)
|
75
|
+
return if HTTP_METHOD_SYMBOLS.include?(method)
|
76
|
+
|
77
|
+
raise BouncerError, "'#{ method }' is not a known HTTP method key. Must be one of: #{ HTTP_METHOD_SYMBOLS }"
|
17
78
|
end
|
18
79
|
|
19
80
|
# Determines if the path matches the exact path or wildcard.
|
20
81
|
#
|
21
82
|
# @return `true` if the path matches
|
22
|
-
def match_path?(
|
23
|
-
|
83
|
+
def match_path?(method, trial_path)
|
84
|
+
trial_path = normalize_path trial_path
|
24
85
|
|
25
|
-
|
86
|
+
matchers_for(method).any? do |matcher|
|
87
|
+
return true if matcher == :all
|
26
88
|
|
27
|
-
|
28
|
-
|
89
|
+
matcher_parts = matcher.split '/'
|
90
|
+
trial_parts = trial_path.split '/'
|
91
|
+
matches = matcher_parts.length == trial_parts.length
|
29
92
|
|
30
|
-
|
31
|
-
|
32
|
-
|
93
|
+
matcher_parts.each_index do |i|
|
94
|
+
allowed_segment = matcher_parts[i]
|
95
|
+
given_segment = trial_parts[i]
|
33
96
|
|
34
|
-
|
97
|
+
matches &= given_segment == allowed_segment || allowed_segment == '*'
|
98
|
+
end
|
99
|
+
|
100
|
+
matches
|
35
101
|
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def matchers_for(method)
|
105
|
+
matchers = @routes[method]
|
36
106
|
|
37
|
-
|
107
|
+
matchers += @routes[:get] if method == :head
|
108
|
+
|
109
|
+
matchers
|
38
110
|
end
|
39
111
|
|
40
112
|
# Evaluates the rule's block. Defensively prevents truthy values from the block from allowing a route.
|
41
113
|
#
|
42
114
|
# @raise BouncerError when the rule block is a truthy value but not exactly `true`
|
43
115
|
# @return Exactly `true` or `false`, depending on the result of the rule block
|
44
|
-
def rule_passes?(context)
|
45
|
-
ruling = context.instance_exec(
|
116
|
+
def rule_passes?(context, &rule)
|
117
|
+
ruling = context.instance_exec(&rule)
|
46
118
|
|
47
119
|
unless !ruling || ruling.is_a?(TrueClass)
|
48
|
-
source =
|
120
|
+
source = rule.source_location.join(':')
|
49
121
|
msg = <<~ERR
|
50
122
|
Rule block at does not return explicit true/false.
|
51
123
|
Rules must return explicit true or false to prevent accidental truthy values.
|
@@ -57,6 +129,18 @@ module Sinatra
|
|
57
129
|
|
58
130
|
!!ruling
|
59
131
|
end
|
132
|
+
|
133
|
+
def normalize_path(path)
|
134
|
+
if path == :all
|
135
|
+
path
|
136
|
+
else
|
137
|
+
if path.start_with?('/')
|
138
|
+
path
|
139
|
+
else
|
140
|
+
"/#{ path }"
|
141
|
+
end.downcase
|
142
|
+
end
|
143
|
+
end
|
60
144
|
end
|
61
145
|
end
|
62
146
|
end
|
data/lib/sinatra/bouncer.rb
CHANGED
@@ -34,20 +34,9 @@ module Sinatra
|
|
34
34
|
base_class.set :bouncer, BasicBouncer.new
|
35
35
|
|
36
36
|
base_class.before do
|
37
|
-
|
38
|
-
path = request.path.downcase
|
39
|
-
|
40
|
-
settings.bouncer.bounce(self) unless settings.bouncer.can?(http_method, path, self)
|
37
|
+
settings.bouncer.bounce(self) unless settings.bouncer.can?(request.request_method, request.path, self)
|
41
38
|
end
|
42
39
|
end
|
43
|
-
|
44
|
-
def bounce_with(&block)
|
45
|
-
bouncer.bounce_with = block
|
46
|
-
end
|
47
|
-
|
48
|
-
def rules(&block)
|
49
|
-
settings.bouncer.instance_exec(&block)
|
50
|
-
end
|
51
40
|
end
|
52
41
|
|
53
42
|
register Sinatra::Bouncer
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-bouncer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tenjin Inc
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-11-
|
12
|
+
date: 2023-11-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|