protector 0.2.1 → 0.2.2
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/README.md +29 -0
- data/gemfiles/AR_3.2.gemfile.lock +1 -1
- data/gemfiles/AR_4.gemfile.lock +1 -1
- data/gemfiles/Sequel.gemfile.lock +1 -1
- data/lib/protector/adapters/active_record/base.rb +4 -0
- data/lib/protector/adapters/sequel/model.rb +5 -0
- data/lib/protector/dsl.rb +1 -1
- data/lib/protector/version.rb +1 -1
- data/spec/lib/dsl_spec.rb +81 -55
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03db84c2cab1a1f3ea79576688e6102d14976aa1
|
4
|
+
data.tar.gz: e89e5f3d0be3758a229e399a7a5696ee71572075
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1606ca8a4e1eb3683912625aec8a7366177fe377029cd05eb1f2ba4a95eaf123edd75b3ac1763101a8b60778d1c15b8fdac8a0e02c2460d084110dcdad0ca07e
|
7
|
+
data.tar.gz: 0a093f6600af980f34673ea75217897e29e75b5b1eef34814feea309440bb8f8f142948b8b8f1f53d75054a15fac75418eb80e0397092d79468a646601319733
|
data/README.md
CHANGED
@@ -62,6 +62,8 @@ Now that we have ACL described we can enable it as easy as:
|
|
62
62
|
article.restrict!(current_user) # Assuming article is an instance of Article
|
63
63
|
```
|
64
64
|
|
65
|
+
Now if `current_user` is a guest we will get `nil` from `article.text`. At the same time we will get validation error if we pass any fields but title, text and user_id (equal to our own id) on creation.
|
66
|
+
|
65
67
|
To make model unsafe again call:
|
66
68
|
|
67
69
|
```ruby
|
@@ -143,6 +145,33 @@ Foo.restrict!(current_user).preload(:bars).join(:bars).where(bars: {absolute: tr
|
|
143
145
|
|
144
146
|
Such chain will force the usage of an additional request so the first query will not be scoped with `Bar` restriction.
|
145
147
|
|
148
|
+
## Manual checks and custom actions
|
149
|
+
|
150
|
+
Each restricted model responds to the following methods:
|
151
|
+
|
152
|
+
* `visible?` – determines if the model is visible through restriction scope
|
153
|
+
* `creatable?` – determines if you pass validation on creation with the fields you set
|
154
|
+
* `updateable?` – determines if you pass validation on update with the fields you changed
|
155
|
+
* `destroyable?` – determines if you can destroy the model
|
156
|
+
|
157
|
+
In fact Protector does not limit you to `:view`, `:update` and `:create` actions. They are just used internally. You however can define any other to make custom roles and restrictions. All of them are able to work on a field level.
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
protect do
|
161
|
+
can :drink, :field1 # Allows `drink` action with field1
|
162
|
+
can :eat # Allows `eat` action with any field
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
To check against custom actions use `can?` method:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
model.can?(:drink, :field2) # Checks if model can drink field2
|
170
|
+
model.can?(:drink) # Checks if model can drink any field
|
171
|
+
```
|
172
|
+
|
173
|
+
As you can see you don't have to use fields. You can use `can :foo` and `can? :foo`. While they will bound to fields internally it will work like you expect for empty sets.
|
174
|
+
|
146
175
|
## Ideology
|
147
176
|
|
148
177
|
Protector is a successor to [Heimdallr](https://github.com/inossidabile/heimdallr). The latter being a proof-of-concept appeared to be way too paranoid and incompatible with the rest of the world. Protector re-implements same idea keeping the Ruby way:
|
data/gemfiles/AR_4.gemfile.lock
CHANGED
@@ -34,6 +34,7 @@ module Protector
|
|
34
34
|
|
35
35
|
# Checks if current model can be selected in the context of current subject
|
36
36
|
def visible?
|
37
|
+
return true unless protector_meta.scoped?
|
37
38
|
protector_meta.relation.where(pk_hash).any?
|
38
39
|
end
|
39
40
|
|
@@ -54,6 +55,10 @@ module Protector
|
|
54
55
|
protector_meta.destroyable?
|
55
56
|
end
|
56
57
|
|
58
|
+
def can?(action, field)
|
59
|
+
protector_meta.can?(action, field)
|
60
|
+
end
|
61
|
+
|
57
62
|
# Basic security validations
|
58
63
|
def validate
|
59
64
|
super
|
data/lib/protector/dsl.rb
CHANGED
data/lib/protector/version.rb
CHANGED
data/spec/lib/dsl_spec.rb
CHANGED
@@ -41,75 +41,101 @@ describe Protector::DSL do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
describe Protector::DSL::Meta do
|
44
|
-
|
44
|
+
context "basic methods" do
|
45
|
+
l = lambda {|x| x > 4 }
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
before :each do
|
48
|
+
@meta = Protector::DSL::Meta.new
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
@meta << lambda {
|
51
|
+
scope { 'relation' }
|
52
|
+
}
|
52
53
|
|
53
|
-
|
54
|
-
|
54
|
+
@meta << lambda {|user|
|
55
|
+
user.should == 'user'
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
can :view
|
58
|
+
cannot :view, %w(field5), :field4
|
59
|
+
}
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
@meta << lambda {|user, entry|
|
62
|
+
user.should == 'user'
|
63
|
+
entry.should == 'entry'
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
can :update, %w(field1 field2 field3),
|
66
|
+
field4: 0..5,
|
67
|
+
field5: l
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
can :destroy
|
70
|
+
}
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
73
|
+
it "evaluates" do
|
74
|
+
@meta.evaluate(nil, 'user', [], 'entry')
|
75
|
+
end
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
it "sets relation" do
|
78
|
+
data = @meta.evaluate(nil, 'user', [], 'entry')
|
79
|
+
data.relation.should == 'relation'
|
80
|
+
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
82
|
+
it "sets access" do
|
83
|
+
data = @meta.evaluate(nil, 'user', %w(field1 field2 field3 field4 field5), 'entry')
|
84
|
+
data.access.should == {
|
85
|
+
update: {
|
86
|
+
"field1" => nil,
|
87
|
+
"field2" => nil,
|
88
|
+
"field3" => nil,
|
89
|
+
"field4" => 0..5,
|
90
|
+
"field5" => l
|
91
|
+
},
|
92
|
+
view: {
|
93
|
+
"field1" => nil,
|
94
|
+
"field2" => nil,
|
95
|
+
"field3" => nil
|
96
|
+
},
|
97
|
+
create: {}
|
98
|
+
}
|
99
|
+
end
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
it "marks destroyable" do
|
102
|
+
data = @meta.evaluate(nil, 'user', [], 'entry')
|
103
|
+
data.destroyable?.should == true
|
104
|
+
end
|
105
|
+
|
106
|
+
it "marks updatable" do
|
107
|
+
data = @meta.evaluate(nil, 'user', [], 'entry')
|
108
|
+
data.updatable?.should == true
|
109
|
+
end
|
104
110
|
|
105
|
-
|
106
|
-
|
107
|
-
|
111
|
+
it "marks creatable" do
|
112
|
+
data = @meta.evaluate(nil, 'user', [], 'entry')
|
113
|
+
data.creatable?.should == false
|
114
|
+
end
|
108
115
|
end
|
109
116
|
|
110
|
-
|
111
|
-
|
112
|
-
|
117
|
+
context "custom methods" do
|
118
|
+
before :each do
|
119
|
+
@meta = Protector::DSL::Meta.new
|
120
|
+
|
121
|
+
@meta << lambda {
|
122
|
+
can :drink, :field1
|
123
|
+
can :eat
|
124
|
+
cannot :eat, :field1
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
it "sets field-level restriction" do
|
129
|
+
box = @meta.evaluate(nil, 'user', %w(field1 field2), 'entry')
|
130
|
+
box.can?(:drink, :field1).should == true
|
131
|
+
box.can?(:drink).should == true
|
132
|
+
end
|
133
|
+
|
134
|
+
it "sets field-level protection" do
|
135
|
+
box = @meta.evaluate(nil, 'user', %w(field1 field2), 'entry')
|
136
|
+
box.can?(:eat, :field1).should == false
|
137
|
+
box.can?(:eat).should == true
|
138
|
+
end
|
113
139
|
end
|
114
140
|
end
|
115
141
|
end
|