protector 0.2.4 → 0.3.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/gemfiles/AR_3.2.gemfile.lock +1 -1
- data/gemfiles/AR_4.gemfile.lock +1 -1
- data/gemfiles/Sequel.gemfile.lock +12 -4
- data/lib/protector/adapters/active_record/association.rb +3 -1
- data/lib/protector/adapters/active_record/base.rb +5 -5
- data/lib/protector/adapters/active_record/preloader.rb +5 -1
- data/lib/protector/adapters/active_record/relation.rb +9 -11
- data/lib/protector/adapters/sequel/dataset.rb +4 -4
- data/lib/protector/adapters/sequel/eager_graph_loader.rb +1 -1
- data/lib/protector/adapters/sequel/model.rb +6 -6
- data/lib/protector/dsl.rb +15 -4
- data/lib/protector/version.rb +1 -1
- data/spec/lib/dsl_spec.rb +11 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b37c2f2aabf355a3953ac75518bdb389317c460
|
4
|
+
data.tar.gz: 2a4e9e21d922f263c4518aafd19ea95f043239bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce3cf9b5c16c4a1ac0c6126049eb645cc4fea48e8b264a6d833b97a9100e63d2f0dff4924073e4482e6819d695edd90a36ae864ae94b6874489c3c0bba2219e4
|
7
|
+
data.tar.gz: 9a97ac4a1ecee65b4b796ef2ca3ec9d58df8c1b9d92b9eaffb1211f3cec3c59476012361eefa2d43de996f67bc26c54f99c044ee8d51adee524b7a4022b942aa
|
data/gemfiles/AR_4.gemfile.lock
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: /Users/inossidabile/Repos/protector
|
3
3
|
specs:
|
4
|
-
protector (0.
|
4
|
+
protector (0.3.0.beta.1)
|
5
5
|
activesupport
|
6
6
|
i18n
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activesupport (
|
12
|
-
i18n (~> 0.6)
|
13
|
-
|
11
|
+
activesupport (4.0.0)
|
12
|
+
i18n (~> 0.6, >= 0.6.4)
|
13
|
+
minitest (~> 4.2)
|
14
|
+
multi_json (~> 1.3)
|
15
|
+
thread_safe (~> 0.1)
|
16
|
+
tzinfo (~> 0.3.37)
|
14
17
|
appraisal (0.5.2)
|
15
18
|
bundler
|
16
19
|
rake
|
20
|
+
atomic (1.1.10)
|
17
21
|
coderay (1.0.9)
|
18
22
|
colored (1.2)
|
19
23
|
colorize (0.5.8)
|
@@ -45,6 +49,7 @@ GEM
|
|
45
49
|
lumberjack (1.0.3)
|
46
50
|
method_source (0.8.1)
|
47
51
|
mime-types (1.23)
|
52
|
+
minitest (4.7.5)
|
48
53
|
multi_json (1.7.5)
|
49
54
|
pry (0.9.12.2)
|
50
55
|
coderay (~> 1.0.5)
|
@@ -82,6 +87,9 @@ GEM
|
|
82
87
|
ffi
|
83
88
|
sqlite3 (1.3.7)
|
84
89
|
thor (0.18.1)
|
90
|
+
thread_safe (0.1.0)
|
91
|
+
atomic
|
92
|
+
tzinfo (0.3.37)
|
85
93
|
|
86
94
|
PLATFORMS
|
87
95
|
java
|
@@ -17,7 +17,9 @@ module Protector
|
|
17
17
|
|
18
18
|
# Wraps every association with current subject
|
19
19
|
def scope_with_protector(*args)
|
20
|
-
scope_without_protector(*args)
|
20
|
+
scope = scope_without_protector(*args)
|
21
|
+
scope = scope.restrict!(owner.protector_subject) if owner.protector_subject?
|
22
|
+
scope
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -14,14 +14,14 @@ module Protector
|
|
14
14
|
end
|
15
15
|
|
16
16
|
validate do
|
17
|
-
return unless
|
17
|
+
return unless protector_subject?
|
18
18
|
if (new_record? && !creatable?) || (!new_record? && !updatable?)
|
19
19
|
errors[:base] << I18n.t('protector.invalid')
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
before_destroy do
|
24
|
-
return true unless
|
24
|
+
return true unless protector_subject?
|
25
25
|
destroyable?
|
26
26
|
end
|
27
27
|
|
@@ -43,7 +43,7 @@ module Protector
|
|
43
43
|
|
44
44
|
def [](name)
|
45
45
|
if (
|
46
|
-
|
46
|
+
!protector_subject? ||
|
47
47
|
name == self.class.primary_key ||
|
48
48
|
(self.class.primary_key.is_a?(Array) && self.class.primary_key.include?(name)) ||
|
49
49
|
protector_meta.readable?(name)
|
@@ -66,7 +66,7 @@ module Protector
|
|
66
66
|
alias_method #{"#{name}_unprotected".inspect}, #{name.inspect}
|
67
67
|
|
68
68
|
def #{name}
|
69
|
-
if
|
69
|
+
if !protector_subject? || protector_meta.readable?(#{name.inspect})
|
70
70
|
#{name}_unprotected
|
71
71
|
else
|
72
72
|
nil
|
@@ -81,7 +81,7 @@ module Protector
|
|
81
81
|
def protector_meta
|
82
82
|
@protector_meta ||= self.class.protector_meta.evaluate(
|
83
83
|
self.class,
|
84
|
-
|
84
|
+
protector_subject,
|
85
85
|
self.class.column_names,
|
86
86
|
self
|
87
87
|
)
|
@@ -23,9 +23,13 @@ module Protector
|
|
23
23
|
owners.first.protector_subject
|
24
24
|
end
|
25
25
|
|
26
|
+
def protector_subject?
|
27
|
+
owners.first.protector_subject?
|
28
|
+
end
|
29
|
+
|
26
30
|
# Restricts preloading association scope with subject of the owner
|
27
31
|
def scope_with_protector(*args)
|
28
|
-
return scope_without_protector unless protector_subject
|
32
|
+
return scope_without_protector unless protector_subject?
|
29
33
|
|
30
34
|
@meta ||= klass.protector_meta.evaluate(klass, protector_subject)
|
31
35
|
scope_without_protector.merge(@meta.relation)
|
@@ -28,13 +28,13 @@ module Protector
|
|
28
28
|
# Gets {Protector::DSL::Meta::Box} of this relation
|
29
29
|
def protector_meta
|
30
30
|
# We don't seem to require columns here as well
|
31
|
-
|
32
|
-
@klass.protector_meta.evaluate(@klass, @protector_subject)
|
31
|
+
@klass.protector_meta.evaluate(@klass, protector_subject)
|
33
32
|
end
|
34
33
|
|
35
34
|
# @note Unscoped relation drops properties and therefore should be re-restricted
|
36
35
|
def unscoped
|
37
|
-
super
|
36
|
+
return super unless protector_subject?
|
37
|
+
super.restrict!(protector_subject)
|
38
38
|
end
|
39
39
|
|
40
40
|
# @note This is here cause `NullRelation` can return `nil` from `count`
|
@@ -49,13 +49,13 @@ module Protector
|
|
49
49
|
|
50
50
|
# Merges current relation with restriction and calls real `calculate`
|
51
51
|
def calculate(*args)
|
52
|
-
return super unless
|
52
|
+
return super unless protector_subject?
|
53
53
|
merge(protector_meta.relation).unrestrict!.calculate *args
|
54
54
|
end
|
55
55
|
|
56
56
|
# Merges current relation with restriction and calls real `exists?`
|
57
57
|
def exists?(*args)
|
58
|
-
return super unless
|
58
|
+
return super unless protector_subject?
|
59
59
|
merge(protector_meta.relation).unrestrict!.exists? *args
|
60
60
|
end
|
61
61
|
|
@@ -68,11 +68,11 @@ module Protector
|
|
68
68
|
# * merging current relation with restriction (of self and every eager association)
|
69
69
|
def exec_queries_with_protector(*args)
|
70
70
|
return @records if loaded?
|
71
|
-
return exec_queries_without_protector unless
|
71
|
+
return exec_queries_without_protector unless protector_subject?
|
72
72
|
|
73
|
-
subject =
|
73
|
+
subject = protector_subject
|
74
74
|
relation = merge(protector_meta.relation).unrestrict!
|
75
|
-
relation = protector_substitute_includes(relation)
|
75
|
+
relation = protector_substitute_includes(subject, relation)
|
76
76
|
|
77
77
|
# Preserve associations from internal loading. We are going to handle that
|
78
78
|
# ourselves respecting security scopes FTW!
|
@@ -91,9 +91,7 @@ module Protector
|
|
91
91
|
|
92
92
|
# Swaps `includes` with `preload` whether it's not referenced or merges
|
93
93
|
# security scope of proper class otherwise
|
94
|
-
def protector_substitute_includes(relation)
|
95
|
-
subject = @protector_subject
|
96
|
-
|
94
|
+
def protector_substitute_includes(subject, relation)
|
97
95
|
if eager_loading?
|
98
96
|
protector_expand_inclusion(includes_values + eager_load_values).each do |klass, path|
|
99
97
|
# AR drops default_scope for eagerly loadable associations
|
@@ -32,17 +32,17 @@ module Protector
|
|
32
32
|
|
33
33
|
# Gets {Protector::DSL::Meta::Box} of this dataset
|
34
34
|
def protector_meta
|
35
|
-
model.protector_meta.evaluate(model,
|
35
|
+
model.protector_meta.evaluate(model, protector_subject)
|
36
36
|
end
|
37
37
|
|
38
38
|
# Substitutes `row_proc` with {Protector} and injects protection scope
|
39
39
|
def each_with_protector(*args, &block)
|
40
|
-
return each_without_protector(*args, &block)
|
40
|
+
return each_without_protector(*args, &block) unless protector_subject?
|
41
41
|
|
42
|
-
relation = protector_defend_graph(clone,
|
42
|
+
relation = protector_defend_graph(clone, protector_subject)
|
43
43
|
relation = relation.instance_eval(&protector_meta.scope_proc) if protector_meta.scoped?
|
44
44
|
|
45
|
-
relation.row_proc = Restrictor.new(
|
45
|
+
relation.row_proc = Restrictor.new(protector_subject, relation.row_proc)
|
46
46
|
relation.each_without_protector(*args, &block)
|
47
47
|
end
|
48
48
|
|
@@ -11,7 +11,7 @@ module Protector
|
|
11
11
|
def initialize_with_protector(dataset)
|
12
12
|
initialize_without_protector(dataset)
|
13
13
|
|
14
|
-
if dataset.protector_subject
|
14
|
+
if dataset.protector_subject?
|
15
15
|
@row_procs.each do |k,v|
|
16
16
|
@row_procs[k] = Dataset::Restrictor.new(dataset.protector_subject, v)
|
17
17
|
@ta_map[k][1] = @row_procs[k] if @ta_map.has_key?(k)
|
@@ -26,7 +26,7 @@ module Protector
|
|
26
26
|
def protector_meta
|
27
27
|
@protector_meta ||= self.class.protector_meta.evaluate(
|
28
28
|
self.class,
|
29
|
-
|
29
|
+
protector_subject,
|
30
30
|
self.class.columns,
|
31
31
|
self
|
32
32
|
)
|
@@ -62,14 +62,14 @@ module Protector
|
|
62
62
|
# Basic security validations
|
63
63
|
def validate
|
64
64
|
super
|
65
|
-
return unless
|
65
|
+
return unless protector_subject?
|
66
66
|
method = new? ? :creatable? : :updatable?
|
67
67
|
errors.add(:base, I18n.t('protector.invalid')) unless __send__(method)
|
68
68
|
end
|
69
69
|
|
70
70
|
# Destroy availability check
|
71
71
|
def before_destroy
|
72
|
-
return false if
|
72
|
+
return false if protector_subject? && !destroyable?
|
73
73
|
super
|
74
74
|
end
|
75
75
|
|
@@ -78,7 +78,7 @@ module Protector
|
|
78
78
|
# @param name [Symbol] Name of attribute to read
|
79
79
|
def [](name)
|
80
80
|
if (
|
81
|
-
|
81
|
+
!protector_subject? ||
|
82
82
|
name == self.class.primary_key ||
|
83
83
|
(self.class.primary_key.is_a?(Array) && self.class.primary_key.include?(name)) ||
|
84
84
|
protector_meta.readable?(name.to_s)
|
@@ -91,12 +91,12 @@ module Protector
|
|
91
91
|
|
92
92
|
# This is used whenever we fetch data
|
93
93
|
def _associated_dataset(*args)
|
94
|
-
super.restrict!(
|
94
|
+
super.restrict!(protector_subject)
|
95
95
|
end
|
96
96
|
|
97
97
|
# This is used whenever we call counters and existance checkers
|
98
98
|
def _dataset(*args)
|
99
|
-
super.restrict!(
|
99
|
+
super.restrict!(protector_subject)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
data/lib/protector/dsl.rb
CHANGED
@@ -207,8 +207,6 @@ module Protector
|
|
207
207
|
# @param fields [Array<String>] All the fields the model has
|
208
208
|
# @param entry [Object] An instance of the model
|
209
209
|
def evaluate(model, subject, fields=[], entry=nil)
|
210
|
-
raise "Unprotected entity detected: use `restrict` method to protect it." unless subject
|
211
|
-
|
212
210
|
Box.new(model, fields, subject, entry, blocks)
|
213
211
|
end
|
214
212
|
end
|
@@ -216,8 +214,14 @@ module Protector
|
|
216
214
|
module Base
|
217
215
|
extend ActiveSupport::Concern
|
218
216
|
|
219
|
-
|
220
|
-
|
217
|
+
# Property accessor that makes sure you don't use
|
218
|
+
# subject on a non-protected model
|
219
|
+
def protector_subject
|
220
|
+
unless protector_subject?
|
221
|
+
raise "Unprotected entity detected: use `restrict` method to protect it."
|
222
|
+
end
|
223
|
+
|
224
|
+
@protector_subject
|
221
225
|
end
|
222
226
|
|
223
227
|
# Assigns restriction subject
|
@@ -225,14 +229,21 @@ module Protector
|
|
225
229
|
# @param [Object] subject Subject to restrict against
|
226
230
|
def restrict!(subject)
|
227
231
|
@protector_subject = subject
|
232
|
+
@protector_subject_set = true
|
228
233
|
self
|
229
234
|
end
|
230
235
|
|
231
236
|
# Clears restriction subject
|
232
237
|
def unrestrict!
|
233
238
|
@protector_subject = nil
|
239
|
+
@protector_subject_set = false
|
234
240
|
self
|
235
241
|
end
|
242
|
+
|
243
|
+
# Checks if model was restricted
|
244
|
+
def protector_subject?
|
245
|
+
@protector_subject_set == true
|
246
|
+
end
|
236
247
|
end
|
237
248
|
|
238
249
|
module Entry
|
data/lib/protector/version.rb
CHANGED
data/spec/lib/dsl_spec.rb
CHANGED
@@ -11,6 +11,16 @@ describe Protector::DSL do
|
|
11
11
|
@base.instance_methods.should include(:protector_subject)
|
12
12
|
end
|
13
13
|
|
14
|
+
it "throws error for empty subect" do
|
15
|
+
base = @base.new
|
16
|
+
expect { base.protector_subject }.to raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it "accepts nil as a subject" do
|
20
|
+
base = @base.new.restrict!(nil)
|
21
|
+
expect { base.protector_subject }.to_not raise_error
|
22
|
+
end
|
23
|
+
|
14
24
|
it "remembers protection subject" do
|
15
25
|
base = @base.new
|
16
26
|
base.restrict!("universe")
|
@@ -22,7 +32,7 @@ describe Protector::DSL do
|
|
22
32
|
base.restrict!("universe")
|
23
33
|
base.protector_subject.should == "universe"
|
24
34
|
base.unrestrict!
|
25
|
-
base.protector_subject.
|
35
|
+
expect { base.protector_subject }.to raise_error
|
26
36
|
end
|
27
37
|
end
|
28
38
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2
|
4
|
+
version: 0.3.0.beta.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boris Staal
|
@@ -104,9 +104,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
|
-
- - '
|
107
|
+
- - '>'
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 1.3.1
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
112
|
rubygems_version: 2.0.2
|