protector 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/protector/adapters/active_record.rb +55 -3
- data/lib/protector/dsl.rb +9 -2
- data/lib/protector/version.rb +1 -1
- data/spec/lib/adapters/active_record_spec.rb +30 -8
- data/spec/spec_helpers/model.rb +50 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 098c77da509ed0a347c0a22df9dd6c6a8d34289a
|
4
|
+
data.tar.gz: b9ae1d35809445399fda713c3f0276ac91114659
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0cc601d414b036f8eb6db9381c9f30a93bc1bdb5bd92a946165f32ea97f9229be9fa76210a7b98ec878da9b0476f6dacffb6bf7e24200c496bf8e6106a6b4bf
|
7
|
+
data.tar.gz: 9994bc1d0e0a3a93f81f4ee07fabf7cf1faf7c02c958952ec8cd80a6452349c20cd8fc7a79bf51665da2cbccdef179ce85963cc4ab0528b039b6b21a735b85bc
|
@@ -4,6 +4,8 @@ module Protector
|
|
4
4
|
def self.activate!
|
5
5
|
::ActiveRecord::Base.send :include, Protector::Adapters::ActiveRecord::Base
|
6
6
|
::ActiveRecord::Relation.send :include, Protector::Adapters::ActiveRecord::Relation
|
7
|
+
::ActiveRecord::Associations::SingularAssociation.send :include, Protector::Adapters::ActiveRecord::Association
|
8
|
+
::ActiveRecord::Associations::CollectionAssociation.send :include, Protector::Adapters::ActiveRecord::Association
|
7
9
|
end
|
8
10
|
|
9
11
|
module Base
|
@@ -33,6 +35,28 @@ module Protector
|
|
33
35
|
def restrict(subject)
|
34
36
|
all.restrict(subject)
|
35
37
|
end
|
38
|
+
|
39
|
+
def define_method_attribute(name)
|
40
|
+
safe_name = name.unpack('h*').first
|
41
|
+
|
42
|
+
if primary_key == name || (primary_key.is_a?(Array) && primary_key.include?(name))
|
43
|
+
condition = "true"
|
44
|
+
else
|
45
|
+
condition = "!@protector_subject || protector_meta.readable?(#{name.inspect})"
|
46
|
+
end
|
47
|
+
|
48
|
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
49
|
+
def __temp__#{safe_name}
|
50
|
+
if #{condition}
|
51
|
+
read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) }
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
alias_method #{name.inspect}, :__temp__#{safe_name}
|
57
|
+
undef_method :__temp__#{safe_name}
|
58
|
+
STR
|
59
|
+
end
|
36
60
|
end
|
37
61
|
|
38
62
|
def protector_meta
|
@@ -50,23 +74,37 @@ module Protector
|
|
50
74
|
|
51
75
|
def visible?
|
52
76
|
protector_meta.relation.where(
|
53
|
-
self.class.primary_key =>
|
77
|
+
self.class.primary_key => id
|
54
78
|
).any?
|
55
79
|
end
|
56
80
|
|
57
81
|
def creatable?
|
58
|
-
fields = HashWithIndifferentAccess[changed.map{|x| [x,
|
82
|
+
fields = HashWithIndifferentAccess[changed.map{|x| [x, read_attribute(x)]}]
|
59
83
|
protector_meta.creatable?(fields)
|
60
84
|
end
|
61
85
|
|
62
86
|
def updatable?
|
63
|
-
fields = HashWithIndifferentAccess[changed.map{|x| [x,
|
87
|
+
fields = HashWithIndifferentAccess[changed.map{|x| [x, read_attribute(x)]}]
|
64
88
|
protector_meta.updatable?(fields)
|
65
89
|
end
|
66
90
|
|
67
91
|
def destroyable?
|
68
92
|
protector_meta.destroyable?
|
69
93
|
end
|
94
|
+
|
95
|
+
def [](name)
|
96
|
+
if !@protector_subject || protector_meta.readable?(name)
|
97
|
+
super
|
98
|
+
else
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def association(*args)
|
104
|
+
association = super
|
105
|
+
association.restrict @protector_subject
|
106
|
+
association
|
107
|
+
end
|
70
108
|
end
|
71
109
|
|
72
110
|
module Relation
|
@@ -100,6 +138,20 @@ module Protector
|
|
100
138
|
@records = merge(protector_meta.relation).unrestrict.send :exec_queries
|
101
139
|
end
|
102
140
|
end
|
141
|
+
|
142
|
+
module Association
|
143
|
+
extend ActiveSupport::Concern
|
144
|
+
|
145
|
+
included do
|
146
|
+
include Protector::DSL::Base
|
147
|
+
|
148
|
+
alias_method_chain :reader, :protector
|
149
|
+
end
|
150
|
+
|
151
|
+
def reader_with_protector
|
152
|
+
reader_without_protector.restrict(@protector_subject)
|
153
|
+
end
|
154
|
+
end
|
103
155
|
end
|
104
156
|
end
|
105
157
|
end
|
data/lib/protector/dsl.rb
CHANGED
@@ -9,6 +9,7 @@ module Protector
|
|
9
9
|
@model = model
|
10
10
|
@fields = fields
|
11
11
|
@access = {update: {}, view: {}, create: {}}.with_indifferent_access
|
12
|
+
@access_keys = {}.with_indifferent_access
|
12
13
|
@relation = false
|
13
14
|
@destroyable = false
|
14
15
|
|
@@ -21,6 +22,8 @@ module Protector
|
|
21
22
|
instance_exec &b
|
22
23
|
end
|
23
24
|
end
|
25
|
+
|
26
|
+
@access.each{|k,v| @access_keys[k] = v.keys}
|
24
27
|
end
|
25
28
|
|
26
29
|
def scope(&block)
|
@@ -63,6 +66,10 @@ module Protector
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
69
|
+
def readable?(field)
|
70
|
+
@access_keys[:view].include?(field.to_s)
|
71
|
+
end
|
72
|
+
|
66
73
|
def creatable?(fields=false)
|
67
74
|
modifiable? :create, fields
|
68
75
|
end
|
@@ -78,10 +85,10 @@ module Protector
|
|
78
85
|
private
|
79
86
|
|
80
87
|
def modifiable?(part, fields)
|
81
|
-
return false unless @
|
88
|
+
return false unless @access_keys[part].length > 0
|
82
89
|
|
83
90
|
if fields
|
84
|
-
return false if (fields.keys - @
|
91
|
+
return false if (fields.keys - @access_keys[part]).length > 0
|
85
92
|
|
86
93
|
fields.each do |k,v|
|
87
94
|
case x = @access[part][k]
|
data/lib/protector/version.rb
CHANGED
@@ -4,18 +4,36 @@ describe Protector::Adapters::ActiveRecord do
|
|
4
4
|
before(:all) do
|
5
5
|
ActiveRecord::Schema.verbose = false
|
6
6
|
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
7
|
+
|
7
8
|
ActiveRecord::Migration.create_table :dummies do |t|
|
8
|
-
t.string
|
9
|
-
t.integer
|
10
|
-
t.text
|
9
|
+
t.string :string
|
10
|
+
t.integer :number
|
11
|
+
t.text :text
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Migration.create_table :fluffies do |t|
|
16
|
+
t.string :string
|
17
|
+
t.belongs_to :dummy
|
11
18
|
t.timestamps
|
12
19
|
end
|
13
20
|
|
14
|
-
|
21
|
+
Protector::Adapters::ActiveRecord.activate!
|
22
|
+
|
23
|
+
class Dummy < ActiveRecord::Base
|
24
|
+
protect do; end
|
25
|
+
has_many :fluffies
|
26
|
+
end
|
15
27
|
Dummy.create! string: 'zomgstring', number: 999, text: 'zomgtext'
|
16
28
|
Dummy.create! string: 'zomgstring', number: 777, text: 'zomgtext'
|
17
29
|
|
18
|
-
|
30
|
+
class Fluffy < ActiveRecord::Base
|
31
|
+
protect do
|
32
|
+
can :view, :dummy_id
|
33
|
+
end
|
34
|
+
belongs_to :dummy
|
35
|
+
end
|
36
|
+
Fluffy.create! string: 'zomgstring', dummy_id: 1
|
19
37
|
end
|
20
38
|
|
21
39
|
describe Protector::Adapters::ActiveRecord::Base do
|
@@ -30,8 +48,12 @@ describe Protector::Adapters::ActiveRecord do
|
|
30
48
|
end
|
31
49
|
|
32
50
|
it "scopes" do
|
51
|
+
@dummy.instance_eval do
|
52
|
+
protect do; scope{ all }; end
|
53
|
+
end
|
54
|
+
|
33
55
|
scope = @dummy.restrict('!')
|
34
|
-
scope.should
|
56
|
+
scope.should be_a_kind_of ActiveRecord::Relation
|
35
57
|
scope.protector_subject.should == '!'
|
36
58
|
end
|
37
59
|
|
@@ -56,7 +78,7 @@ describe Protector::Adapters::ActiveRecord do
|
|
56
78
|
context "with null relation" do
|
57
79
|
before(:each) do
|
58
80
|
@dummy.instance_eval do
|
59
|
-
protect
|
81
|
+
protect do; scope{ none }; end
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
@@ -76,7 +98,7 @@ describe Protector::Adapters::ActiveRecord do
|
|
76
98
|
context "with active relation" do
|
77
99
|
before(:each) do
|
78
100
|
@dummy.instance_eval do
|
79
|
-
protect
|
101
|
+
protect do; scope{ where(number: 999) }; end
|
80
102
|
end
|
81
103
|
end
|
82
104
|
|
data/spec/spec_helpers/model.rb
CHANGED
@@ -39,25 +39,51 @@ shared_examples_for "a model" do
|
|
39
39
|
meta.access[:update].should == fields
|
40
40
|
end
|
41
41
|
|
42
|
+
describe "association" do
|
43
|
+
context "(has_many)" do
|
44
|
+
it "passes subject" do
|
45
|
+
Dummy.first.restrict('!').fluffies.protector_subject.should == '!'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "(belongs_to)" do
|
50
|
+
it "passes subject" do
|
51
|
+
Fluffy.first.restrict('!').dummy.protector_subject.should == '!'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
42
56
|
describe "visibility" do
|
43
57
|
it "marks blocked" do
|
44
58
|
@dummy.instance_eval do
|
45
|
-
protect do
|
46
|
-
scope { none }
|
47
|
-
end
|
59
|
+
protect do; scope { none }; end
|
48
60
|
end
|
49
61
|
|
50
62
|
@dummy.first.restrict('!').visible?.should == false
|
51
63
|
end
|
52
64
|
|
53
65
|
it "marks allowed" do
|
66
|
+
@dummy.instance_eval do
|
67
|
+
protect do; scope { limit(5) }; end
|
68
|
+
end
|
69
|
+
|
70
|
+
@dummy.first.restrict('!').visible?.should == true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "readability" do
|
75
|
+
it "hides fields" do
|
54
76
|
@dummy.instance_eval do
|
55
77
|
protect do
|
56
|
-
|
78
|
+
can :view, :string
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
60
|
-
@dummy.first.restrict('!')
|
82
|
+
dummy = @dummy.first.restrict('!')
|
83
|
+
dummy.number.should == nil
|
84
|
+
dummy[:number].should == nil
|
85
|
+
dummy.read_attribute(:number).should_not == nil
|
86
|
+
dummy.string.should == 'zomgstring'
|
61
87
|
end
|
62
88
|
end
|
63
89
|
|
@@ -74,10 +100,10 @@ shared_examples_for "a model" do
|
|
74
100
|
dummy.restrict('!').creatable?.should == false
|
75
101
|
end
|
76
102
|
|
77
|
-
it "invalidates" do
|
78
|
-
|
79
|
-
|
80
|
-
end
|
103
|
+
# it "invalidates" do
|
104
|
+
# dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
|
105
|
+
# dummy.should invalidate
|
106
|
+
# end
|
81
107
|
end
|
82
108
|
|
83
109
|
context "by list of fields" do
|
@@ -99,10 +125,10 @@ shared_examples_for "a model" do
|
|
99
125
|
dummy.restrict('!').creatable?.should == true
|
100
126
|
end
|
101
127
|
|
102
|
-
it "invalidates" do
|
103
|
-
|
104
|
-
|
105
|
-
end
|
128
|
+
# it "invalidates" do
|
129
|
+
# dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
|
130
|
+
# dummy.should invalidate
|
131
|
+
# end
|
106
132
|
|
107
133
|
it "validates" do
|
108
134
|
dummy = @dummy.new(string: 'bam').restrict('!')
|
@@ -114,7 +140,7 @@ shared_examples_for "a model" do
|
|
114
140
|
before(:each) do
|
115
141
|
@dummy.instance_eval do
|
116
142
|
protect do
|
117
|
-
can :create, string: -> (x) { x.length == 5 }
|
143
|
+
can :create, string: -> (x) { x.try(:length) == 5 }
|
118
144
|
end
|
119
145
|
end
|
120
146
|
end
|
@@ -129,10 +155,10 @@ shared_examples_for "a model" do
|
|
129
155
|
dummy.restrict('!').creatable?.should == true
|
130
156
|
end
|
131
157
|
|
132
|
-
it "invalidates" do
|
133
|
-
|
134
|
-
|
135
|
-
end
|
158
|
+
# it "invalidates" do
|
159
|
+
# dummy = @dummy.new(string: 'bam').restrict('!')
|
160
|
+
# dummy.should invalidate
|
161
|
+
# end
|
136
162
|
|
137
163
|
it "validates" do
|
138
164
|
dummy = @dummy.new(string: '12345').restrict('!')
|
@@ -159,10 +185,10 @@ shared_examples_for "a model" do
|
|
159
185
|
dummy.restrict('!').creatable?.should == true
|
160
186
|
end
|
161
187
|
|
162
|
-
it "invalidates" do
|
163
|
-
|
164
|
-
|
165
|
-
end
|
188
|
+
# it "invalidates" do
|
189
|
+
# dummy = @dummy.new(number: 500).restrict('!')
|
190
|
+
# dummy.should invalidate
|
191
|
+
# end
|
166
192
|
|
167
193
|
it "validates" do
|
168
194
|
dummy = @dummy.new(number: 2).restrict('!')
|
@@ -230,7 +256,7 @@ shared_examples_for "a model" do
|
|
230
256
|
before(:each) do
|
231
257
|
@dummy.instance_eval do
|
232
258
|
protect do
|
233
|
-
can :update, string: -> (x) { x.length == 5 }
|
259
|
+
can :update, string: -> (x) { x.try(:length) == 5 }
|
234
260
|
end
|
235
261
|
end
|
236
262
|
end
|
@@ -326,7 +352,7 @@ shared_examples_for "a model" do
|
|
326
352
|
end
|
327
353
|
|
328
354
|
dummy = @dummy.create!.restrict('!')
|
329
|
-
dummy.destroy
|
355
|
+
dummy.destroy!.should == dummy
|
330
356
|
dummy.destroyed?.should == true
|
331
357
|
end
|
332
358
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boris Staal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|