vinyl 0.0.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.
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/README.md +144 -0
- data/UNLICENSE +24 -0
- data/examples/.gitkeep +0 -0
- data/examples/usage_example.rb +30 -0
- data/lib/vinyl.rb +4 -0
- data/lib/vinyl/.gitkeep +0 -0
- data/lib/vinyl/base.rb +68 -0
- data/lib/vinyl/rule.rb +88 -0
- data/lib/vinyl/validator.rb +72 -0
- data/lib/vinyl/variables.rb +41 -0
- data/lib/vinyl/version.rb +4 -0
- data/tests/.gitkeep +0 -0
- data/tests/gem_spec.rb +5 -0
- data/tests/rules_spec.rb +32 -0
- data/tests/spec_helper.rb +15 -0
- data/tests/validators_spec.rb +19 -0
- data/tests/variables_spec.rb +35 -0
- data/tests/vinyl_spec.rb +65 -0
- data/vinyl.gemspec +19 -0
- metadata +84 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# Vinyl
|
2
|
+
**_Access Level for him and her_**
|
3
|
+
|
4
|
+
_by: Federico Saravia Barrantes [@fsaravia](https://github.com/fsaravia) and Lautaro Orazi [@tarolandia](https://github.com/tarolandia)_
|
5
|
+
|
6
|
+
## Introduction
|
7
|
+
|
8
|
+
"Vinyl" is a simple gem that allows developer to define different access levels for a resource and a serie of local and global validators to gain access to those levels.
|
9
|
+
It works by analizing a series of validators defined by you and returning a number representing the access level a particular request is able to reach.
|
10
|
+
|
11
|
+
## What is it useful for?
|
12
|
+
|
13
|
+
This gem is useful when you need to control the output depending on who wants to access to a resource.
|
14
|
+
|
15
|
+
For example: user A wants to get user B's profile.
|
16
|
+
|
17
|
+
1. If A == B, A have full access to data
|
18
|
+
2. If A is friend of B, A can see private data but not config data
|
19
|
+
3. If A is not friend of B, A only can see public data
|
20
|
+
|
21
|
+
In the example we have 3 different levels of access to B information.
|
22
|
+
|
23
|
+
## Basic Config
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Vinyl::configure do |config|
|
27
|
+
config.api_acl_mode = Vinyl::Configuration::STRATEGY_DESCENDING
|
28
|
+
config.force_access_control = true
|
29
|
+
config.warn_on_missing_validators = true
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
__:api_acl_mode can take two values:__
|
34
|
+
|
35
|
+
1. Vinyl::Configuration::STRATEGY_DESCENDING, Check for validators starting on the highest access level
|
36
|
+
2. Vinyl::Configuration::STRATEGY_ASCENDING, Check for validators starting on the lowest access level
|
37
|
+
|
38
|
+
__:force_access_control true/false__
|
39
|
+
|
40
|
+
Deny access if no validators are given for a route/method combination and no global validators exist
|
41
|
+
|
42
|
+
__:warn_on_missing_validators true/false__
|
43
|
+
|
44
|
+
Display a warning on STDOUT when calling a missing validator
|
45
|
+
|
46
|
+
|
47
|
+
## Defining Rules
|
48
|
+
|
49
|
+
A rule defines the access level and the validators for a route/method combination:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
Vinyl.when_route
|
53
|
+
'/api/route',
|
54
|
+
:with_method => 'POST|GET|PUT|DELETE',
|
55
|
+
:get_access_level => 1...n,
|
56
|
+
:if_pass => ['validator1', 'validator2', …, 'validatorn']
|
57
|
+
```
|
58
|
+
|
59
|
+
__Example:__
|
60
|
+
```ruby
|
61
|
+
Vinyl.when_route '/profiles.json',
|
62
|
+
:with_method => 'GET',
|
63
|
+
:get_access_level => 1,
|
64
|
+
:if_pass => ['is_user']
|
65
|
+
|
66
|
+
Vinyl.when_route '/profiles.json',
|
67
|
+
:with_method => 'GET',
|
68
|
+
:get_access_level => 2,
|
69
|
+
:if_pass => ['is_admin']
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
## Defining validators
|
74
|
+
|
75
|
+
There are two kind of validators: global and normal validators. All validators you define must return true or false.
|
76
|
+
|
77
|
+
Global validators will be applied to all rules defined. You can add a global validator using add_global_validator method:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
Vinyl.add_global_validator("name_of_global_validator", lambda {
|
81
|
+
# your code here
|
82
|
+
return true/false
|
83
|
+
})
|
84
|
+
```
|
85
|
+
|
86
|
+
Normal validators will be applied when a rule includes it into its validators list. Validators can be added using add_validator method:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
Vinyl.add_validator("name_of_validator", lambda {
|
90
|
+
# your code here
|
91
|
+
return true/false
|
92
|
+
})
|
93
|
+
```
|
94
|
+
|
95
|
+
|
96
|
+
## Defining Variables
|
97
|
+
|
98
|
+
Inside validators you can use your models, classes and whatever. If you want a custom variable to be available in the scope of the validators, add it this way:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Vinyl.my_variable = variable_value
|
102
|
+
```
|
103
|
+
|
104
|
+
Inside your validator:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
Vinyl.add_validator("my_validator", lambda {
|
108
|
+
puts my_variable # will output variable_value
|
109
|
+
return true/false
|
110
|
+
})
|
111
|
+
```
|
112
|
+
|
113
|
+
__Clearing Variables__
|
114
|
+
|
115
|
+
If you need to reset previously defined variables to avoid validation errors just call:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
Vinyl.reset_variables
|
119
|
+
```
|
120
|
+
## Getting Access Level
|
121
|
+
|
122
|
+
At this point you had defined your rules, validators and variables. Now you are ready to get call access level.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
access_level = Vinyl.check_level('/call/route','call_method')
|
126
|
+
```
|
127
|
+
|
128
|
+
If you need to avoid a global validator you can use bypass method:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
access_level = Vinyl.bypass("global_validator_name").check_level('/call/route','call_method')
|
132
|
+
```
|
133
|
+
|
134
|
+
or a list of them
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
access_level = Vinyl.bypass(["global_1","global_2"]).check_level('/call/route','call_method')
|
138
|
+
```
|
139
|
+
|
140
|
+
Using bypass means exclude the validators only for the current check.
|
141
|
+
|
142
|
+
## License
|
143
|
+
|
144
|
+
See the `UNLICENSE` file included with this gem distribution.
|
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/examples/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'vinyl'
|
2
|
+
#Configuration:
|
3
|
+
Vinyl::configure do |config|
|
4
|
+
config.api_acl_mode = Vinyl::Configuration::STRATEGY_DESCENDING
|
5
|
+
config.force_access_control = true #Deny access if no validators are given for a route/method combination and no global validators exist
|
6
|
+
config.warn_on_missing_validators = true #Display a warning on STDOUT when calling a missing validator
|
7
|
+
end
|
8
|
+
|
9
|
+
#Clear previous registered variables
|
10
|
+
Vinyl::reset_variables
|
11
|
+
#Define variables
|
12
|
+
Vinyl::some_arbitrary_value = true
|
13
|
+
|
14
|
+
#Define some validators:
|
15
|
+
#Global
|
16
|
+
Vinyl.add_global_validator("global_validator",lambda{return true}) #Global validators are executed for every route
|
17
|
+
#
|
18
|
+
Vinyl::add_validator("validator",lambda{return some_arbitrary_value})
|
19
|
+
Vinyl::add_validator("another_validator",lambda{return false})
|
20
|
+
|
21
|
+
#Define routes
|
22
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 1, :if_pass => ['validator']
|
23
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 2, :if_pass => ['validator', 'another_validator']
|
24
|
+
Vinyl::when_route 'test', :with_method => 'GET', :get_access_level => 1, :if_pass => ['another_validator']
|
25
|
+
Vinyl::when_route 'test', :with_method => 'GET', :get_access_level => 2, :if_pass => []
|
26
|
+
|
27
|
+
access_level = Vinyl::check_level('test','POST')
|
28
|
+
puts access_level
|
29
|
+
access_level = Vinyl::check_level('test','GET')
|
30
|
+
puts access_level
|
data/lib/vinyl.rb
ADDED
data/lib/vinyl/.gitkeep
ADDED
File without changes
|
data/lib/vinyl/base.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Vinyl
|
2
|
+
|
3
|
+
def self.configure
|
4
|
+
yield config
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.config=(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.config
|
12
|
+
@config ||=Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.check_level(route,method)
|
16
|
+
required_route = Vinyl::acl_routes_collection[route]
|
17
|
+
required_route = Hash.new if required_route.nil?
|
18
|
+
validators_to_call = required_route[method]
|
19
|
+
if (validators_to_call.nil? || validators_to_call.empty?) then
|
20
|
+
if (global_validators.empty?) then
|
21
|
+
return Vinyl.config.force_access_control ? 0 : 1
|
22
|
+
else
|
23
|
+
validators_to_call = {1 => []} #No access level defined but global validators must be called
|
24
|
+
end
|
25
|
+
end
|
26
|
+
keys = validators_to_call.keys.sort
|
27
|
+
highest_level = 0
|
28
|
+
keys.send("#{Vinyl::config.validators_iterate_strategy}") do |access_level|
|
29
|
+
pass = Vinyl::Validators.run_validators(validators_to_call[access_level])
|
30
|
+
if (pass==true) then
|
31
|
+
highest_level = access_level
|
32
|
+
break if Vinyl::config.api_acl_mode == Vinyl::Configuration::STRATEGY_DESCENDING #Already on the highest level
|
33
|
+
elsif (pass==false)
|
34
|
+
break if Vinyl::config.api_acl_mode == Vinyl::Configuration::STRATEGY_ASCENDING #Do not check for higher levels
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return highest_level
|
38
|
+
end
|
39
|
+
|
40
|
+
class Configuration
|
41
|
+
|
42
|
+
attr_accessor :api_acl_mode, :force_access_control, :warn_on_missing_validators
|
43
|
+
STRATEGY_DESCENDING = 1 #Check for validators starting on the highest access level
|
44
|
+
STRATEGY_ASCENDING = 2 #Check for validators starting on the lowest access level
|
45
|
+
|
46
|
+
@@defaults = {
|
47
|
+
:api_acl_mode => STRATEGY_DESCENDING,
|
48
|
+
:force_access_control => false,
|
49
|
+
:warn_on_missing_validators => true
|
50
|
+
}
|
51
|
+
|
52
|
+
def validators_iterate_strategy
|
53
|
+
if(@api_acl_mode == STRATEGY_DESCENDING) then
|
54
|
+
return 'reverse_each'
|
55
|
+
else
|
56
|
+
return 'each'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.defaults
|
61
|
+
@@defaults
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
@@defaults.each_pair{|k,v| self.send("#{k}=",v)}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/vinyl/rule.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Vinyl
|
2
|
+
|
3
|
+
def self.when_route(route, *args)
|
4
|
+
Rule.add(route, args[0])
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.acl_routes_collection
|
8
|
+
Rule.acl_routes_collection
|
9
|
+
end
|
10
|
+
|
11
|
+
class Rule
|
12
|
+
|
13
|
+
class RegExpHash < Hash
|
14
|
+
def [](a)
|
15
|
+
return super a if a.class == Regexp
|
16
|
+
self.keys.each do |pattern|
|
17
|
+
return super pattern if a.respond_to?(:match) && a.match(pattern)
|
18
|
+
end
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
@@acl_routes_collection = RegExpHash.new
|
24
|
+
|
25
|
+
def self.add(route, *args)
|
26
|
+
begin
|
27
|
+
method = args[0][:with_method]
|
28
|
+
access_level = args[0][:get_access_level]
|
29
|
+
validators = args[0][:if_pass]
|
30
|
+
if(route.empty? || method.empty? || access_level.to_s.empty?) then
|
31
|
+
raise InvalidAclRule, "Vinyl.rule is invalid"
|
32
|
+
end
|
33
|
+
rescue NoMethodError => e
|
34
|
+
raise InvalidAclRule, "Vinyl.rule is invalid"
|
35
|
+
rescue InvalidAclRule => e
|
36
|
+
puts e.message
|
37
|
+
puts e.backtrace
|
38
|
+
end
|
39
|
+
pattern = generate_pattern(route)
|
40
|
+
@@acl_routes_collection[pattern] ||= Hash.new
|
41
|
+
@@acl_routes_collection[pattern][method] ||= Hash.new
|
42
|
+
@@acl_routes_collection[pattern][method][access_level] = validators
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.generate_pattern(path)
|
46
|
+
if path.respond_to? :to_str
|
47
|
+
ignore = ""
|
48
|
+
pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) do |c|
|
49
|
+
ignore << escaped(c).join if c.match(/[\.@]/)
|
50
|
+
encoded(c)
|
51
|
+
end
|
52
|
+
pattern.gsub!(/((:\w+)|\*)/) do |match|
|
53
|
+
if match == "*"
|
54
|
+
"(.*?)"
|
55
|
+
else
|
56
|
+
"([^#{ignore}/?#]+)"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
/\A#{pattern}\z/
|
60
|
+
elsif path.respond_to?(:keys) && path.respond_to?(:match)
|
61
|
+
path
|
62
|
+
elsif path.respond_to?(:names) && path.respond_to?(:match)
|
63
|
+
path
|
64
|
+
elsif path.respond_to? :match
|
65
|
+
path
|
66
|
+
else
|
67
|
+
raise TypeError, path
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.escaped(char, enc = URI.escape(char))
|
72
|
+
[Regexp.escape(enc), URI.escape(char, /./)]
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.encoded(char)
|
76
|
+
enc = URI.escape(char)
|
77
|
+
enc = "(?:#{escaped(char, enc).join('|')})" if enc == char
|
78
|
+
enc = "(?:#{enc}|#{encoded('+')})" if char == " "
|
79
|
+
enc
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.acl_routes_collection
|
83
|
+
@@acl_routes_collection
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class InvalidAclRule < StandardError; end
|
88
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Vinyl
|
2
|
+
|
3
|
+
def self.add_validator(name,block)
|
4
|
+
Validators.module_eval{define_singleton_method(Validators.prefix + name,block)}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.add_global_validator(name,block)
|
8
|
+
Validators.module_eval{define_singleton_method(Validators.prefix + name,block)}
|
9
|
+
global_validators << name
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.execute(name)
|
13
|
+
Validators.send(Validators.prefix + name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.bypass(names)
|
17
|
+
Validators.exclude_global_validator(names)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.global_validators
|
22
|
+
Validators.global_validators
|
23
|
+
end
|
24
|
+
|
25
|
+
module Validators
|
26
|
+
|
27
|
+
@@prefix = "validator_"#use prefixs to avoid collisions betweeen variables and methods names
|
28
|
+
@@exclusion_list = []
|
29
|
+
|
30
|
+
def self.prefix
|
31
|
+
@@prefix
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.global_validators
|
35
|
+
@@global_validators ||= Array.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.exclude_global_validator(name)
|
39
|
+
name = ["#{name}"] if name.instance_of? String
|
40
|
+
@@exclusion_list |= name
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def self.clean_exclusion_list
|
45
|
+
@@exclusion_list = Array.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.run_validators(validators)
|
49
|
+
validators = validators + (Vinyl.global_validators - @@exclusion_list)
|
50
|
+
clean_exclusion_list
|
51
|
+
if validators.nil? || validators.empty? then
|
52
|
+
return !Vinyl.config.force_access_control
|
53
|
+
end
|
54
|
+
validators.each do |method_name|
|
55
|
+
pass = Vinyl::Validators.send(prefix + method_name)
|
56
|
+
if(pass == false) then
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.method_missing(*args) #Return false if no validator exists
|
64
|
+
if (Vinyl::controller.variables.include?(args[0])) then
|
65
|
+
return Vinyl::get(args[0])
|
66
|
+
else
|
67
|
+
STDOUT.puts "Warning: missing method #{args[0]}, Validator defaults to false" if Vinyl.config.warn_on_missing_validators
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Vinyl
|
2
|
+
|
3
|
+
def self.put(variable)
|
4
|
+
controller.put(variable)
|
5
|
+
return self
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.get(value)
|
9
|
+
controller.variables[value]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.reset_variables
|
13
|
+
controller.variables.clear
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.controller
|
17
|
+
@@user_variables ||=UserVariables.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.method_missing(*args)
|
21
|
+
if args.length == 2 then #set value
|
22
|
+
Vinyl::put ({args[0].to_s.chomp('=').to_sym => args[1]})
|
23
|
+
elsif args.length == 1 #return value
|
24
|
+
return Vinyl::get(args.first)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class UserVariables
|
31
|
+
attr_reader :variables
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@variables = Hash.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def put(variable)
|
38
|
+
@variables.merge!(variable)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/tests/.gitkeep
ADDED
File without changes
|
data/tests/gem_spec.rb
ADDED
data/tests/rules_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Vinyl::Rule do
|
2
|
+
|
3
|
+
it "should add route to Vinyl" do
|
4
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 1,
|
5
|
+
:if_pass => ['validator']
|
6
|
+
|
7
|
+
Vinyl.acl_routes_collection.should_not be_empty
|
8
|
+
Vinyl.acl_routes_collection.length.should == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should add multiple access level to route" do
|
12
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 1,
|
13
|
+
:if_pass => ['validator','bad_guy']
|
14
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 2,
|
15
|
+
:if_pass => ['validator']
|
16
|
+
Vinyl::when_route 'test', :with_method => 'POST', :get_access_level => 3,
|
17
|
+
:if_pass => []
|
18
|
+
|
19
|
+
Vinyl.acl_routes_collection['test'].should_not be_empty
|
20
|
+
Vinyl.acl_routes_collection.length.should == 1
|
21
|
+
Vinyl.acl_routes_collection['test'].should include("POST")
|
22
|
+
Vinyl.acl_routes_collection['test']['POST'].length.should == 3
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should add a route with a non-existent validator" do
|
26
|
+
Vinyl::when_route 'test', :with_method => 'GET', :get_access_level => 1,
|
27
|
+
:if_pass => ['fake_validator']
|
28
|
+
Vinyl.acl_routes_collection['test'].should include("GET")
|
29
|
+
Vinyl.acl_routes_collection['test']['GET'].length.should == 1
|
30
|
+
Vinyl.execute('fake_validator').should be_false
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
ENV['RACK_ENV'] = "test"
|
2
|
+
require 'bundler/setup'
|
3
|
+
#require 'rack/test'
|
4
|
+
|
5
|
+
require 'vinyl'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
#config.include Rack::Test::Methods
|
9
|
+
end
|
10
|
+
|
11
|
+
Vinyl::configure do |config|
|
12
|
+
config.api_acl_mode = Vinyl::Configuration::STRATEGY_DESCENDING
|
13
|
+
config.force_access_control = true #Deny access if no validators are given for a route/method combination and no global validators exist
|
14
|
+
config.warn_on_missing_validators = false
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe "Validators" do
|
2
|
+
|
3
|
+
it "should add some validators to Vinyl" do
|
4
|
+
Vinyl.add_validator('validator', lambda{
|
5
|
+
return some_arbitrary_value && hash_value == Hash.new
|
6
|
+
})
|
7
|
+
Vinyl.execute('validator').should be_true
|
8
|
+
Vinyl.add_validator('bad_guy', lambda{
|
9
|
+
return false
|
10
|
+
})
|
11
|
+
Vinyl.execute('bad_guy').should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return nil if there has been defined a variable with nil value" do
|
15
|
+
Vinyl.some_nil_variable = nil
|
16
|
+
Vinyl::Validators.some_nil_variable.should be_nil
|
17
|
+
Vinyl::Validators.non_set_value.should be_false
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
describe Vinyl::UserVariables do
|
2
|
+
|
3
|
+
before do
|
4
|
+
$string_variable = "Test string"
|
5
|
+
$hash_variable = Hash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should define some variables and reset them all" do
|
9
|
+
Vinyl.here_is_one_variable = "Some value"
|
10
|
+
Vinyl.some_arbitrary_value = true
|
11
|
+
Vinyl.string_value = $string_variable
|
12
|
+
Vinyl.hash_value = $hash_variable
|
13
|
+
Vinyl.controller.variables.length.should == 4
|
14
|
+
Vinyl.reset_variables
|
15
|
+
Vinyl.controller.variables.length.should == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should add some variables to be used by validators" do
|
19
|
+
Vinyl.some_arbitrary_value = true
|
20
|
+
Vinyl.string_value = $string_variable
|
21
|
+
Vinyl.hash_value = $hash_variable
|
22
|
+
Vinyl.controller.variables.length.should == 3
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be able to access to previous defined variables" do
|
26
|
+
Vinyl.some_arbitrary_value.should be_true
|
27
|
+
Vinyl.string_value.should eq $string_variable
|
28
|
+
Vinyl.hash_value.should == $hash_variable
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be able to assign and retrieve null values" do
|
32
|
+
Vinyl.variable_im_setting_nil = nil
|
33
|
+
Vinyl.variable_im_setting_nil.should be_nil
|
34
|
+
end
|
35
|
+
end
|
data/tests/vinyl_spec.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
describe "Vinyl.Access control" do
|
2
|
+
|
3
|
+
it "should deny access to non configured routes if force_access_control is enabled" do
|
4
|
+
Vinyl::configure do |config|
|
5
|
+
config.force_access_control = false
|
6
|
+
end
|
7
|
+
access_level = Vinyl.check_level('fake_route','GET')
|
8
|
+
access_level.should == 1
|
9
|
+
Vinyl::configure do |config|
|
10
|
+
config.force_access_control = true
|
11
|
+
end
|
12
|
+
access_level = Vinyl.check_level('fake_route','GET')
|
13
|
+
access_level.should == 0
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should force access control in abscence of validators" do
|
17
|
+
access_level = Vinyl.check_level('test','POST')
|
18
|
+
access_level.should == 2
|
19
|
+
Vinyl::configure do |config|
|
20
|
+
config.force_access_control = false
|
21
|
+
end
|
22
|
+
access_level = Vinyl.check_level('test','POST')
|
23
|
+
access_level.should == 3
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should add a global validator to Vinyl" do
|
27
|
+
global_validator_name = "global_validator"
|
28
|
+
Vinyl.add_global_validator(global_validator_name,lambda{return true})
|
29
|
+
result = Vinyl.execute(global_validator_name)
|
30
|
+
result.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should fail with global validator" do
|
34
|
+
Vinyl::global_validator_return = false
|
35
|
+
Vinyl.add_global_validator("global_validator_name2",lambda{return global_validator_return})
|
36
|
+
access_level = Vinyl.check_level('test','POST')
|
37
|
+
access_level.should == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should bypass global validator" do
|
41
|
+
access_level = Vinyl.bypass("global_validator_name2").check_level('test','POST')
|
42
|
+
access_level.should == 3
|
43
|
+
access_level = Vinyl.check_level('test','POST')
|
44
|
+
access_level.should == 0
|
45
|
+
Vinyl::global_validator_return = true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return grant access levels according to validators" do
|
49
|
+
access_level = Vinyl.check_level('test','POST')
|
50
|
+
access_level.should == 3
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should deny access to routes with non-existent validators" do
|
54
|
+
access_level = Vinyl.check_level('test','GET')
|
55
|
+
access_level.should == 0
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should deny access after changing strategy" do
|
59
|
+
Vinyl::configure do |config|
|
60
|
+
config.api_acl_mode = Vinyl::Configuration::STRATEGY_ASCENDING
|
61
|
+
end
|
62
|
+
access_level = Vinyl.check_level('test','POST')
|
63
|
+
access_level.should == 0
|
64
|
+
end
|
65
|
+
end
|
data/vinyl.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "vinyl/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "vinyl"
|
6
|
+
gem.authors = ["Federico Saravia Barrantes", "Lautaro Orazi"]
|
7
|
+
gem.email = ["vinyl.dev@gmail.com"]
|
8
|
+
gem.description = %q{Custom access level for resources}
|
9
|
+
gem.summary = %q{Custom access level for resources}
|
10
|
+
gem.homepage = "http://tarolandia.github.com/vinyl/"
|
11
|
+
gem.version = Vinyl::VERSION
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rspec', '~> 2.7'
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vinyl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Federico Saravia Barrantes
|
9
|
+
- Lautaro Orazi
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-10-23 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.7'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '2.7'
|
31
|
+
description: Custom access level for resources
|
32
|
+
email:
|
33
|
+
- vinyl.dev@gmail.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- README.md
|
41
|
+
- UNLICENSE
|
42
|
+
- examples/.gitkeep
|
43
|
+
- examples/usage_example.rb
|
44
|
+
- lib/vinyl.rb
|
45
|
+
- lib/vinyl/.gitkeep
|
46
|
+
- lib/vinyl/base.rb
|
47
|
+
- lib/vinyl/rule.rb
|
48
|
+
- lib/vinyl/validator.rb
|
49
|
+
- lib/vinyl/variables.rb
|
50
|
+
- lib/vinyl/version.rb
|
51
|
+
- tests/.gitkeep
|
52
|
+
- tests/gem_spec.rb
|
53
|
+
- tests/rules_spec.rb
|
54
|
+
- tests/spec_helper.rb
|
55
|
+
- tests/validators_spec.rb
|
56
|
+
- tests/variables_spec.rb
|
57
|
+
- tests/vinyl_spec.rb
|
58
|
+
- vinyl.gemspec
|
59
|
+
homepage: http://tarolandia.github.com/vinyl/
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.24
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Custom access level for resources
|
83
|
+
test_files: []
|
84
|
+
has_rdoc:
|