sinatra-bouncer 1.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -7
- data/.rubocop.yml +1 -9
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -3
- data/Gemfile.lock +92 -0
- data/README.md +231 -54
- data/RELEASE_NOTES.md +170 -0
- data/lib/sinatra/bouncer/basic_bouncer.rb +34 -37
- data/lib/sinatra/bouncer/rule.rb +114 -22
- data/lib/sinatra/bouncer/version.rb +1 -1
- data/lib/sinatra/bouncer.rb +6 -37
- data/sinatra_bouncer.gemspec +4 -1
- metadata +5 -14
- data/tests/integrations/dev_defines_legal_routes.feature +0 -57
- data/tests/integrations/dev_installs_bouncer.feature +0 -12
- data/tests/integrations/step_definitions/given.rb +0 -36
- data/tests/integrations/step_definitions/then.rb +0 -9
- data/tests/integrations/step_definitions/when.rb +0 -11
- data/tests/integrations/support/env.rb +0 -30
- data/tests/integrations/support/helpers.rb +0 -55
- data/tests/integrations/support/types.rb +0 -21
- data/tests/spec/basic_bouncer_spec.rb +0 -148
- data/tests/spec/rule_spec.rb +0 -67
- data/tests/spec/spec_helper.rb +0 -11
- data/tests/test_app.rb +0 -9
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
src_dir = File.expand_path('../../..', __dir__)
|
4
|
-
$LOAD_PATH.unshift(src_dir) unless $LOAD_PATH.include?(src_dir)
|
5
|
-
|
6
|
-
require 'simplecov'
|
7
|
-
|
8
|
-
SimpleCov.command_name 'spec'
|
9
|
-
|
10
|
-
require 'capybara/cucumber'
|
11
|
-
require 'rspec/expectations'
|
12
|
-
|
13
|
-
require 'tests/test_app'
|
14
|
-
|
15
|
-
# == CAPYBARA ==
|
16
|
-
Capybara.app = Sinatra::Application
|
17
|
-
|
18
|
-
# Set this to whatever the server's normal port is for you. Sinatra is 4567; rack 9292 by default.
|
19
|
-
# Also note: you have to be running the server for this to work.
|
20
|
-
Capybara.asset_host = 'http://localhost:4567'
|
21
|
-
|
22
|
-
# == REGULAR SETTINGS ==
|
23
|
-
Before do
|
24
|
-
Capybara.reset_sessions!
|
25
|
-
Capybara.app.settings.bouncer.instance_variable_get(:@ruleset).clear
|
26
|
-
|
27
|
-
@allowed_once_paths = []
|
28
|
-
end
|
29
|
-
|
30
|
-
World(RSpec::Matchers)
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Helper methods for Cucumber steps
|
4
|
-
module HelperMethods
|
5
|
-
# TEST_TMP_ROOT = Pathname.new(Dir.mktmpdir('bouncer_test_')).expand_path.freeze
|
6
|
-
# TEST_TMP_LOG = (TEST_TMP_ROOT / 'log').expand_path.freeze
|
7
|
-
|
8
|
-
# Data conversion helpers for Cucumber steps
|
9
|
-
module Conversion
|
10
|
-
def extract_list(list_string)
|
11
|
-
(list_string || '').split(',').map(&:strip)
|
12
|
-
end
|
13
|
-
|
14
|
-
def symrow(table)
|
15
|
-
table.symbolic_hashes.first
|
16
|
-
end
|
17
|
-
|
18
|
-
def symtable(table)
|
19
|
-
table.map_headers do |header|
|
20
|
-
header.tr(' ', '_').downcase.to_sym
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def parse_bool(string)
|
25
|
-
!(string =~ /t|y/i).nil?
|
26
|
-
end
|
27
|
-
|
28
|
-
def parse_phone(string)
|
29
|
-
string.to_s.split(/:\s+/)
|
30
|
-
end
|
31
|
-
|
32
|
-
def parse_duration(string)
|
33
|
-
scalar, unit = string.split(/\s/)
|
34
|
-
|
35
|
-
return nil if unit.nil? || unit.empty?
|
36
|
-
|
37
|
-
unit = "#{ unit }s" unless unit.end_with?('s')
|
38
|
-
|
39
|
-
unit_map = {
|
40
|
-
years: 365.25 * 86400,
|
41
|
-
months: 30 * 86400,
|
42
|
-
weeks: 7 * 86400,
|
43
|
-
days: 86400,
|
44
|
-
hours: 3600,
|
45
|
-
minutes: 60,
|
46
|
-
seconds: 1
|
47
|
-
}
|
48
|
-
|
49
|
-
scalar.to_i * unit_map[unit.downcase.to_sym]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Inject the HelperMethods into the Cucumber test context
|
55
|
-
World(HelperMethods, HelperMethods::Conversion)
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
ParameterType(name: 'path',
|
4
|
-
regexp: %r{/(?:\S+/?)*},
|
5
|
-
type: Pathname,
|
6
|
-
transformer: lambda do |str|
|
7
|
-
Pathname.new(str)
|
8
|
-
end)
|
9
|
-
|
10
|
-
ParameterType(name: 'boolean',
|
11
|
-
regexp: /(enabled|disabled|true|false|on|off|yes|no)/,
|
12
|
-
transformer: lambda do |str|
|
13
|
-
%w[enabled true on yes].include? str.downcase
|
14
|
-
end)
|
15
|
-
|
16
|
-
ParameterType(name: 'html element',
|
17
|
-
regexp: /<(\S+)>/,
|
18
|
-
type: String,
|
19
|
-
transformer: lambda do |str|
|
20
|
-
str
|
21
|
-
end)
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'spec_helper'
|
4
|
-
|
5
|
-
describe Sinatra::Bouncer::BasicBouncer do
|
6
|
-
let(:bouncer) { Sinatra::Bouncer::BasicBouncer.new }
|
7
|
-
|
8
|
-
describe '#can' do
|
9
|
-
it 'should raise an error if provided a block' do
|
10
|
-
msg = <<~ERR
|
11
|
-
You cannot provide a block to #can. If you wish to conditionally allow, use #can_sometimes instead.
|
12
|
-
ERR
|
13
|
-
|
14
|
-
expect do
|
15
|
-
bouncer.can(:post, 'some_path') do
|
16
|
-
# stub
|
17
|
-
end
|
18
|
-
end.to raise_error(Sinatra::Bouncer::BouncerError, msg.chomp)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should handle a list of paths' do
|
22
|
-
bouncer.can(:post, 'some_path', 'other_path')
|
23
|
-
|
24
|
-
expect(bouncer.can?(:post, 'some_path')).to be true
|
25
|
-
expect(bouncer.can?(:post, 'other_path')).to be true
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should accept a splat' do
|
29
|
-
bouncer.can(:post, 'directory/*')
|
30
|
-
|
31
|
-
expect(bouncer.can?(:post, 'directory/some_path')).to be true
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe '#can_sometimes' do
|
36
|
-
it 'should accept :any_method to mean all http methods' do
|
37
|
-
bouncer.can_sometimes(:any_method, 'some_path') do
|
38
|
-
true
|
39
|
-
end
|
40
|
-
|
41
|
-
expect(bouncer.can?(:get, 'some_path')).to be true
|
42
|
-
expect(bouncer.can?(:post, 'some_path')).to be true
|
43
|
-
expect(bouncer.can?(:put, 'some_path')).to be true
|
44
|
-
expect(bouncer.can?(:delete, 'some_path')).to be true
|
45
|
-
expect(bouncer.can?(:options, 'some_path')).to be true
|
46
|
-
expect(bouncer.can?(:link, 'some_path')).to be true
|
47
|
-
expect(bouncer.can?(:unlink, 'some_path')).to be true
|
48
|
-
expect(bouncer.can?(:head, 'some_path')).to be true
|
49
|
-
expect(bouncer.can?(:trace, 'some_path')).to be true
|
50
|
-
expect(bouncer.can?(:connect, 'some_path')).to be true
|
51
|
-
expect(bouncer.can?(:patch, 'some_path')).to be true
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should accept :all to mean all paths' do
|
55
|
-
bouncer.can_sometimes(:get, :all) do
|
56
|
-
true
|
57
|
-
end
|
58
|
-
|
59
|
-
expect(bouncer.can?(:get, 'some_path')).to be true
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should accept a list of paths' do
|
63
|
-
bouncer.can_sometimes(:post, 'some_path', 'other_path') do
|
64
|
-
true
|
65
|
-
end
|
66
|
-
|
67
|
-
expect(bouncer.can?(:post, 'some_path')).to be true
|
68
|
-
expect(bouncer.can?(:post, 'other_path')).to be true
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should accept a splat' do
|
72
|
-
bouncer.can_sometimes(:post, 'directory/*') do
|
73
|
-
true
|
74
|
-
end
|
75
|
-
|
76
|
-
expect(bouncer.can?(:post, 'directory/some_path')).to be true
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should not raise an error if provided a block' do
|
80
|
-
expect do
|
81
|
-
bouncer.can_sometimes(:any_method, 'some_path') do
|
82
|
-
true
|
83
|
-
end
|
84
|
-
end.to_not raise_error
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'should raise an error if not provided a block' do
|
88
|
-
msg = <<~ERR
|
89
|
-
You must provide a block to #can_sometimes. If you wish to always allow, use #can instead.
|
90
|
-
ERR
|
91
|
-
|
92
|
-
expect do
|
93
|
-
bouncer.can_sometimes(:any_method, 'some_path')
|
94
|
-
end.to raise_error(Sinatra::Bouncer::BouncerError, msg.chomp)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe '#can?' do
|
99
|
-
it 'should pass when declared allowed' do
|
100
|
-
bouncer.can(:any_method, 'some_path')
|
101
|
-
|
102
|
-
expect(bouncer.can?(:post, 'some_path')).to be true
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should fail when not declared allowed' do
|
106
|
-
expect(bouncer.can?(:post, 'some_path')).to be false
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'should pass if the rule block passes' do
|
110
|
-
bouncer.can_sometimes(:any_method, 'some_path') do
|
111
|
-
true
|
112
|
-
end
|
113
|
-
|
114
|
-
expect(bouncer.can?(:post, 'some_path')).to be true
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'should fail if the rule block fails' do
|
118
|
-
bouncer.can_sometimes(:any_method, 'some_path') do
|
119
|
-
false
|
120
|
-
end
|
121
|
-
|
122
|
-
expect(bouncer.can?(:post, 'some_path')).to be false
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe '#bounce' do
|
127
|
-
it 'should run the bounce_with block on sinatra instance' do
|
128
|
-
runner = nil
|
129
|
-
sinatra = double('sinatra')
|
130
|
-
|
131
|
-
bouncer.bounce_with = proc do
|
132
|
-
runner = self # self should be the sinatra double
|
133
|
-
end
|
134
|
-
|
135
|
-
bouncer.bounce(sinatra)
|
136
|
-
|
137
|
-
expect(runner).to be sinatra
|
138
|
-
end
|
139
|
-
|
140
|
-
it 'should halt 403 if no block provided' do
|
141
|
-
app = double('sinatra')
|
142
|
-
|
143
|
-
expect(app).to receive(:halt).with(403)
|
144
|
-
|
145
|
-
bouncer.bounce(app)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
data/tests/spec/rule_spec.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'spec_helper'
|
4
|
-
|
5
|
-
describe Sinatra::Bouncer::Rule do
|
6
|
-
describe '#match_path?' do
|
7
|
-
it 'should match simple paths' do
|
8
|
-
rule = Sinatra::Bouncer::Rule.new('/some_path') { true }
|
9
|
-
|
10
|
-
expect(rule.match_path?('/some_path')).to be true
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should append leading slashes to the given path' do
|
14
|
-
rule = Sinatra::Bouncer::Rule.new('some_path') { true }
|
15
|
-
|
16
|
-
expect(rule.match_path?('/some_path')).to be true
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should append leading slashes to the tested path' do
|
20
|
-
rule = Sinatra::Bouncer::Rule.new('/other_path') { true }
|
21
|
-
|
22
|
-
expect(rule.match_path?('other_path')).to be true
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should match splats' do
|
26
|
-
rule = Sinatra::Bouncer::Rule.new('/directory/*') { true }
|
27
|
-
|
28
|
-
%w[/directory/one /directory/two /directory/three].each do |path|
|
29
|
-
expect(rule.match_path?(path)).to be true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should NOT match empty string to a splat' do
|
34
|
-
rule = Sinatra::Bouncer::Rule.new('/directory/*') { true }
|
35
|
-
|
36
|
-
expect(rule.match_path?('/directory/')).to be false
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should require that both paths are same length' do
|
40
|
-
rule = Sinatra::Bouncer::Rule.new('/directory/*') { true }
|
41
|
-
|
42
|
-
%w[/directory /directory/extra/length].each do |path|
|
43
|
-
expect(rule.match_path?(path)).to be false
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe '#rule_passes?' do
|
49
|
-
it 'should raise an error if rule returns nonbool' do
|
50
|
-
rule = Sinatra::Bouncer::Rule.new('/something') { nil }
|
51
|
-
|
52
|
-
expect { rule.rule_passes? }.to raise_error Sinatra::Bouncer::BouncerError
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'should return true when the block is true' do
|
56
|
-
rule = Sinatra::Bouncer::Rule.new('/something') { true }
|
57
|
-
|
58
|
-
expect(rule.rule_passes?).to be true
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'should return true when the block is false' do
|
62
|
-
rule = Sinatra::Bouncer::Rule.new('/something') { false }
|
63
|
-
|
64
|
-
expect(rule.rule_passes?).to be false
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/tests/spec/spec_helper.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
src_dir = File.expand_path('../..', __dir__)
|
4
|
-
$LOAD_PATH.unshift(src_dir) unless $LOAD_PATH.include?(src_dir)
|
5
|
-
|
6
|
-
require 'simplecov'
|
7
|
-
|
8
|
-
SimpleCov.command_name 'spec'
|
9
|
-
|
10
|
-
require 'lib/sinatra/bouncer'
|
11
|
-
require 'rspec/matchers'
|