protector 0.2.4 → 0.3.0.beta.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/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
|