protector 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +26 -0
- data/Appraisals +2 -2
- data/README.md +7 -4
- data/lib/protector.rb +12 -11
- data/lib/protector/adapters/active_record.rb +5 -3
- data/lib/protector/adapters/active_record/association.rb +3 -3
- data/lib/protector/adapters/active_record/base.rb +10 -8
- data/lib/protector/adapters/active_record/preloader.rb +3 -3
- data/lib/protector/adapters/active_record/relation.rb +13 -9
- data/lib/protector/adapters/active_record/strong_parameters.rb +3 -3
- data/lib/protector/adapters/sequel.rb +2 -2
- data/lib/protector/adapters/sequel/dataset.rb +6 -2
- data/lib/protector/adapters/sequel/eager_graph_loader.rb +3 -3
- data/lib/protector/adapters/sequel/model.rb +11 -7
- data/lib/protector/dsl.rb +32 -17
- data/lib/protector/engine.rb +3 -3
- data/lib/protector/version.rb +1 -1
- data/perf/active_record_perf.rb +2 -2
- data/perf/sequel_perf.rb +2 -2
- data/spec/lib/protector/adapters/active_record_spec.rb +1 -1
- data/spec/lib/protector/adapters/sequel_spec.rb +1 -1
- data/spec/lib/protector/dsl_spec.rb +21 -3
- data/spec/spec_helpers/examples/model.rb +3 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b6f32b7d79bf2d7f9780574d4dbb40c561713ea
|
4
|
+
data.tar.gz: 9bbcc88df9a26dddaed4703eba2b07ae314cff05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bc5bcb7599dfaa7befa6340290d9aa329e98cb967cfbcfa6e122c6c7ca24ed944d3ca4fc42293d67ccb135be0210f0707f39c84463b2e37f4b54ccf5042d396
|
7
|
+
data.tar.gz: 3229c4cb23b9eaf637247d83297b1f6bddd515dd15ea2f30e3db9e747dac6e35d629eb40e69a188d9667d2f150710db8656d453ec16de36bfb4e0d4be928de13
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
AllCops:
|
2
|
+
Excludes:
|
3
|
+
- spec/**
|
4
|
+
- perf/**
|
5
|
+
- migrations/**
|
6
|
+
|
7
|
+
LineLength:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
SpaceAroundEqualsInParameterDefault:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
MethodLength:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
ClassLength:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
TrivialAccessors:
|
23
|
+
ExactNameMatch: true
|
24
|
+
|
25
|
+
ParameterLists:
|
26
|
+
Max: 6
|
data/Appraisals
CHANGED
@@ -9,14 +9,14 @@ appraise "AR_4" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
appraise "Rails_3.2" do
|
12
|
-
gem "combustion", github:
|
12
|
+
gem "combustion", github: "pat/combustion", ref: "50a946b5a7ab3d9249f0e5fcebbb73488a91b1e5"
|
13
13
|
gem "rails", "3.2.13"
|
14
14
|
gem "strong_parameters"
|
15
15
|
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby, github: "jruby/activerecord-jdbc-adapter"
|
16
16
|
end
|
17
17
|
|
18
18
|
appraise "Rails_4" do
|
19
|
-
gem "combustion", github:
|
19
|
+
gem "combustion", github: "pat/combustion", ref: "50a946b5a7ab3d9249f0e5fcebbb73488a91b1e5"
|
20
20
|
gem "rails", "4.0.0"
|
21
21
|
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby, github: "jruby/activerecord-jdbc-adapter"
|
22
22
|
end
|
data/README.md
CHANGED
@@ -21,6 +21,7 @@ We are working hard to extend the list with:
|
|
21
21
|
Protector is an extension and therefore hides deeply inside your ORM library making itself compatible to the most gems you use. Sometimes however, you might need additional integration to take the best from it:
|
22
22
|
|
23
23
|
* [Protector and Strong Parameters](https://github.com/inossidabile/protector/wiki/Protector-and-Strong-Parameters)
|
24
|
+
* [Protector and InheritedResources](https://github.com/inossidabile/protector/wiki/Protector-and-Inherited-Resources)
|
24
25
|
* [Protector and CanCan](https://github.com/inossidabile/protector/wiki/Protector-and-CanCan)
|
25
26
|
* [Protector and SimpleForm](https://github.com/inossidabile/protector/wiki/Protector-and-SimpleForm)
|
26
27
|
|
@@ -39,16 +40,16 @@ class Article < ActiveRecord::Base # Fields: title, text, user_id, hidd
|
|
39
40
|
if user.admin?
|
40
41
|
scope { all } # Admins can retrieve anything
|
41
42
|
|
42
|
-
can :
|
43
|
+
can :read # ... and view anything
|
43
44
|
can :create # ... and create anything
|
44
45
|
can :update # ... and update anything
|
45
46
|
can :destroy # ... and they can delete
|
46
47
|
else
|
47
48
|
scope { where(hidden: false) } # Non-admins can only read insecure data
|
48
49
|
|
49
|
-
can :
|
50
|
+
can :read # Allow to read any field
|
50
51
|
if user.nil? # User is unknown and therefore not authenticated
|
51
|
-
cannot :
|
52
|
+
cannot :read, :text # Guests can't read the text
|
52
53
|
end
|
53
54
|
|
54
55
|
can :create, %w(title text) # Non-admins can't set `hidden` flag
|
@@ -145,7 +146,7 @@ Each restricted model responds to the following methods:
|
|
145
146
|
* `updatable?` – determines if you pass validation on update with the fields you changed
|
146
147
|
* `destroyable?` – determines if you can destroy the model
|
147
148
|
|
148
|
-
In fact Protector does not limit you to `:
|
149
|
+
In fact Protector does not limit you to `:read`, `: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.
|
149
150
|
|
150
151
|
```ruby
|
151
152
|
protect do
|
@@ -230,3 +231,5 @@ Protector features basic Rails integration so you can assign options using `conf
|
|
230
231
|
## License
|
231
232
|
|
232
233
|
It is free software, and may be redistributed under the terms of MIT license.
|
234
|
+
|
235
|
+
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/inossidabile/protector/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
data/lib/protector.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'i18n'
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
4
|
+
require 'protector/version'
|
5
|
+
require 'protector/dsl'
|
6
|
+
require 'protector/adapters/active_record'
|
7
|
+
require 'protector/adapters/sequel'
|
8
8
|
|
9
|
-
require
|
9
|
+
require 'protector/engine' if defined?(Rails)
|
10
10
|
|
11
11
|
I18n.load_path += Dir[File.expand_path File.join('..', 'locales', '*.yml'), File.dirname(__FILE__)]
|
12
12
|
|
@@ -20,7 +20,7 @@ module Protector
|
|
20
20
|
attr_accessor :config
|
21
21
|
|
22
22
|
def paranoid=
|
23
|
-
|
23
|
+
'`Protector.paranoid = ...` is deprecated! Please change it to `Protector.config.paranoid = ...`'
|
24
24
|
end
|
25
25
|
|
26
26
|
# Allows executing any code having Protector globally disabled
|
@@ -39,21 +39,22 @@ module Protector
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def activate!
|
42
|
-
ADAPTERS.each{|adapter| adapter.activate!}
|
42
|
+
ADAPTERS.each { |adapter| adapter.activate! }
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# Internal protector config holder
|
46
47
|
class Config < ActiveSupport::OrderedOptions
|
47
48
|
def paranoid?
|
48
49
|
!!paranoid
|
49
50
|
end
|
50
51
|
|
51
52
|
def strong_parameters?
|
52
|
-
strong_parameters
|
53
|
+
strong_parameters.nil? || !!strong_parameters
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
56
57
|
self.config = Config.new
|
57
58
|
end
|
58
59
|
|
59
|
-
Protector.activate!
|
60
|
+
Protector.activate!
|
@@ -30,12 +30,14 @@ module Protector
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.null_proc
|
33
|
+
# rubocop:disable IndentationWidth, EndAlignment
|
33
34
|
@null_proc ||= if modern?
|
34
|
-
|
35
|
+
proc { none }
|
35
36
|
else
|
36
|
-
|
37
|
+
proc { where('1=0') }
|
37
38
|
end
|
39
|
+
# rubocop:enable IndentationWidth, EndAlignment
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
|
-
end
|
43
|
+
end
|
@@ -10,8 +10,8 @@ module Protector
|
|
10
10
|
if method_defined?(:scope)
|
11
11
|
alias_method_chain :scope, :protector
|
12
12
|
else
|
13
|
-
alias_method
|
14
|
-
alias_method
|
13
|
+
alias_method 'scope_without_protector', 'scoped'
|
14
|
+
alias_method 'scoped', 'scope_with_protector'
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -24,4 +24,4 @@ module Protector
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end
|
@@ -36,19 +36,20 @@ module Protector
|
|
36
36
|
super
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
if !Protector::Adapters::ActiveRecord.modern?
|
40
40
|
def self.restrict!(*args)
|
41
|
-
scoped.restrict!
|
41
|
+
scoped.restrict!(*args)
|
42
42
|
end
|
43
43
|
else
|
44
44
|
def self.restrict!(*args)
|
45
|
-
all.restrict!
|
45
|
+
all.restrict!(*args)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def [](name)
|
50
|
+
# rubocop:disable ParenthesesAroundCondition
|
50
51
|
if (
|
51
|
-
!protector_subject? ||
|
52
|
+
!protector_subject? ||
|
52
53
|
name == self.class.primary_key ||
|
53
54
|
(self.class.primary_key.is_a?(Array) && self.class.primary_key.include?(name)) ||
|
54
55
|
protector_meta.readable?(name)
|
@@ -57,6 +58,7 @@ module Protector
|
|
57
58
|
else
|
58
59
|
nil
|
59
60
|
end
|
61
|
+
# rubocop:enable ParenthesesAroundCondition
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
@@ -64,7 +66,7 @@ module Protector
|
|
64
66
|
# Storage of {Protector::DSL::Meta}
|
65
67
|
def protector_meta
|
66
68
|
@protector_meta ||= Protector::DSL::Meta.new(Protector::Adapters::ActiveRecord, self) do
|
67
|
-
|
69
|
+
column_names
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
@@ -73,7 +75,7 @@ module Protector
|
|
73
75
|
super
|
74
76
|
|
75
77
|
# Show some <3 to composite primary keys
|
76
|
-
unless
|
78
|
+
unless primary_key == name || Array(primary_key).include?(name)
|
77
79
|
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
78
80
|
alias_method #{"#{name}_unprotected".inspect}, #{name.inspect}
|
79
81
|
|
@@ -91,7 +93,7 @@ module Protector
|
|
91
93
|
|
92
94
|
# Gathers real changed values bypassing restrictions
|
93
95
|
def protector_changed
|
94
|
-
HashWithIndifferentAccess[changed.map{|field| [field, read_attribute(field)]}]
|
96
|
+
HashWithIndifferentAccess[changed.map { |field| [field, read_attribute(field)] }]
|
95
97
|
end
|
96
98
|
|
97
99
|
# Storage for {Protector::DSL::Meta::Box}
|
@@ -129,4 +131,4 @@ module Protector
|
|
129
131
|
end
|
130
132
|
end
|
131
133
|
end
|
132
|
-
end
|
134
|
+
end
|
@@ -11,8 +11,8 @@ module Protector
|
|
11
11
|
if method_defined?(:scope)
|
12
12
|
alias_method_chain :scope, :protector
|
13
13
|
else
|
14
|
-
alias_method
|
15
|
-
alias_method
|
14
|
+
alias_method 'scope_without_protector', 'scoped'
|
15
|
+
alias_method 'scoped', 'scope_with_protector'
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -39,4 +39,4 @@ module Protector
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
-
end
|
42
|
+
end
|
@@ -32,6 +32,10 @@ module Protector
|
|
32
32
|
new.creatable?
|
33
33
|
end
|
34
34
|
|
35
|
+
def can?(action, field=false)
|
36
|
+
protector_meta.can?(action, field)
|
37
|
+
end
|
38
|
+
|
35
39
|
# Gets {Protector::DSL::Meta::Box} of this relation
|
36
40
|
def protector_meta(subject=protector_subject)
|
37
41
|
@klass.protector_meta.evaluate(subject)
|
@@ -70,13 +74,13 @@ module Protector
|
|
70
74
|
# Merges current relation with restriction and calls real `calculate`
|
71
75
|
def calculate(*args)
|
72
76
|
return super unless protector_subject?
|
73
|
-
protector_relation.unrestrict!.calculate
|
77
|
+
protector_relation.unrestrict!.calculate(*args)
|
74
78
|
end
|
75
79
|
|
76
80
|
# Merges current relation with restriction and calls real `exists?`
|
77
81
|
def exists?(*args)
|
78
82
|
return super unless protector_subject?
|
79
|
-
protector_relation.unrestrict!.exists?
|
83
|
+
protector_relation.unrestrict!.exists?(*args)
|
80
84
|
end
|
81
85
|
|
82
86
|
# Forwards protection subject to the new instance
|
@@ -85,7 +89,7 @@ module Protector
|
|
85
89
|
|
86
90
|
# strong_parameters integration
|
87
91
|
if Protector.config.strong_parameters? && args.first.respond_to?(:permit)
|
88
|
-
Protector::ActiveRecord::StrongParameters
|
92
|
+
Protector::ActiveRecord::StrongParameters.sanitize! args, true, protector_meta
|
89
93
|
end
|
90
94
|
|
91
95
|
new_without_protector(*args, &block).restrict!(protector_subject)
|
@@ -128,7 +132,7 @@ module Protector
|
|
128
132
|
# ourselves respecting security scopes FTW!
|
129
133
|
associations, relation.preload_values = relation.preload_values, []
|
130
134
|
|
131
|
-
@records = relation.send(:exec_queries).each{|record| record.restrict!(subject)}
|
135
|
+
@records = relation.send(:exec_queries).each { |record| record.restrict!(subject) }
|
132
136
|
|
133
137
|
# Now we have @records restricted properly so let's preload associations!
|
134
138
|
associations.each do |association|
|
@@ -210,13 +214,13 @@ module Protector
|
|
210
214
|
results
|
211
215
|
end
|
212
216
|
|
213
|
-
|
217
|
+
private
|
214
218
|
|
215
219
|
def protector_expand_inclusion_hash(inclusion, results=[], base=[], klass=@klass)
|
216
220
|
inclusion.each do |key, value|
|
217
221
|
model = klass.reflect_on_association(key.to_sym).klass
|
218
222
|
value = [value] unless value.is_a?(Array)
|
219
|
-
nest = [key]+base
|
223
|
+
nest = [key] + base
|
220
224
|
|
221
225
|
value.each do |v|
|
222
226
|
if v.is_a?(Hash)
|
@@ -224,15 +228,15 @@ module Protector
|
|
224
228
|
else
|
225
229
|
results << [
|
226
230
|
model.reflect_on_association(v.to_sym).klass,
|
227
|
-
nest.
|
231
|
+
nest.reduce(v) { |a, n| { n => a } }
|
228
232
|
]
|
229
233
|
end
|
230
234
|
end
|
231
235
|
|
232
|
-
results << [model, base.
|
236
|
+
results << [model, base.reduce(key) { |a, n| { n => a } }]
|
233
237
|
end
|
234
238
|
end
|
235
239
|
end
|
236
240
|
end
|
237
241
|
end
|
238
|
-
end
|
242
|
+
end
|
@@ -3,9 +3,9 @@ module Protector
|
|
3
3
|
module StrongParameters
|
4
4
|
def self.sanitize!(args, is_new, meta)
|
5
5
|
if is_new
|
6
|
-
args[0] = args[0].permit
|
6
|
+
args[0] = args[0].permit(*meta.access[:create].keys) if meta.access.include? :create
|
7
7
|
else
|
8
|
-
args[0] = args[0].permit
|
8
|
+
args[0] = args[0].permit(*meta.access[:update].keys) if meta.access.include? :update
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -16,7 +16,7 @@ module Protector
|
|
16
16
|
if Protector.config.strong_parameters? && args.first.respond_to?(:permit) \
|
17
17
|
&& !new_record? && protector_subject?
|
18
18
|
|
19
|
-
StrongParameters
|
19
|
+
StrongParameters.sanitize! args, false, protector_meta
|
20
20
|
end
|
21
21
|
|
22
22
|
super
|
@@ -19,7 +19,7 @@ module Protector
|
|
19
19
|
# @param entity [Object] Entity coming from Dataset
|
20
20
|
def call(entity)
|
21
21
|
entity = mutator.call(entity) if mutator
|
22
|
-
return entity
|
22
|
+
return entity unless entity.respond_to?(:restrict!)
|
23
23
|
entity.restrict!(@subject)
|
24
24
|
end
|
25
25
|
end
|
@@ -34,6 +34,10 @@ module Protector
|
|
34
34
|
model.new.restrict!(protector_subject).creatable?
|
35
35
|
end
|
36
36
|
|
37
|
+
def can?(action, field=false)
|
38
|
+
protector_meta.can?(action, field)
|
39
|
+
end
|
40
|
+
|
37
41
|
# Gets {Protector::DSL::Meta::Box} of this dataset
|
38
42
|
def protector_meta(subject=protector_subject)
|
39
43
|
model.protector_meta.evaluate(subject)
|
@@ -67,4 +71,4 @@ module Protector
|
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
70
|
-
end
|
74
|
+
end
|
@@ -12,13 +12,13 @@ module Protector
|
|
12
12
|
initialize_without_protector(dataset)
|
13
13
|
|
14
14
|
if dataset.protector_subject?
|
15
|
-
@row_procs.each do |k,v|
|
15
|
+
@row_procs.each do |k, v|
|
16
16
|
@row_procs[k] = Dataset::Restrictor.new(dataset.protector_subject, v)
|
17
|
-
@ta_map[k][1] = @row_procs[k] if @ta_map.
|
17
|
+
@ta_map[k][1] = @row_procs[k] if @ta_map.key?(k)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
end
|
24
|
+
end
|
@@ -19,19 +19,19 @@ module Protector
|
|
19
19
|
# Storage of {Protector::DSL::Meta}
|
20
20
|
def protector_meta
|
21
21
|
@protector_meta ||= Protector::DSL::Meta.new(Protector::Adapters::Sequel, self) do
|
22
|
-
|
22
|
+
columns
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
# Gets default restricted `Dataset`
|
27
27
|
def restrict!(*args)
|
28
|
-
dataset.clone.restrict!
|
28
|
+
dataset.clone.restrict!(*args)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
# Gathers real values of given fields bypassing restrictions
|
33
33
|
def protector_changed(fields)
|
34
|
-
HashWithIndifferentAccess[fields.map{|x| [x.to_s, @values[x]]}]
|
34
|
+
HashWithIndifferentAccess[fields.map { |x| [x.to_s, @values[x]] }]
|
35
35
|
end
|
36
36
|
|
37
37
|
# Storage for {Protector::DSL::Meta::Box}
|
@@ -47,7 +47,6 @@ module Protector
|
|
47
47
|
|
48
48
|
# Checks if current model can be created in the context of current subject
|
49
49
|
def creatable?
|
50
|
-
fields = HashWithIndifferentAccess[keys.map{|x| [x.to_s, @values[x]]}]
|
51
50
|
protector_meta.creatable? protector_changed(keys)
|
52
51
|
end
|
53
52
|
|
@@ -67,13 +66,16 @@ module Protector
|
|
67
66
|
|
68
67
|
# Basic security validations
|
69
68
|
def validate
|
70
|
-
super
|
69
|
+
super
|
70
|
+
return unless protector_subject?
|
71
71
|
|
72
|
+
# rubocop:disable IndentationWidth, EndAlignment
|
72
73
|
field = if new?
|
73
74
|
protector_meta.first_uncreatable_field protector_changed(keys)
|
74
75
|
else
|
75
76
|
protector_meta.first_unupdatable_field protector_changed(changed_columns)
|
76
77
|
end
|
78
|
+
# rubocop:enable IndentationWidth, EndAlignment
|
77
79
|
|
78
80
|
errors.add :base, I18n.t('protector.invalid', field: field) if field
|
79
81
|
end
|
@@ -88,8 +90,9 @@ module Protector
|
|
88
90
|
#
|
89
91
|
# @param name [Symbol] Name of attribute to read
|
90
92
|
def [](name)
|
93
|
+
# rubocop:disable ParenthesesAroundCondition
|
91
94
|
if (
|
92
|
-
!protector_subject? ||
|
95
|
+
!protector_subject? ||
|
93
96
|
name == self.class.primary_key ||
|
94
97
|
(self.class.primary_key.is_a?(Array) && self.class.primary_key.include?(name)) ||
|
95
98
|
protector_meta.readable?(name.to_s)
|
@@ -98,6 +101,7 @@ module Protector
|
|
98
101
|
else
|
99
102
|
nil
|
100
103
|
end
|
104
|
+
# rubocop:enable ParenthesesAroundCondition
|
101
105
|
end
|
102
106
|
|
103
107
|
# This is used whenever we fetch data
|
@@ -114,4 +118,4 @@ module Protector
|
|
114
118
|
end
|
115
119
|
end
|
116
120
|
end
|
117
|
-
end
|
121
|
+
end
|
data/lib/protector/dsl.rb
CHANGED
@@ -24,11 +24,11 @@ module Protector
|
|
24
24
|
blocks.each do |b|
|
25
25
|
case b.arity
|
26
26
|
when 2
|
27
|
-
instance_exec
|
27
|
+
instance_exec(subject, entry, &b)
|
28
28
|
when 1
|
29
|
-
instance_exec
|
29
|
+
instance_exec(subject, &b)
|
30
30
|
else
|
31
|
-
instance_exec
|
31
|
+
instance_exec(&b)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -69,14 +69,14 @@ module Protector
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def eval_scope_procs(instance)
|
72
|
-
|
72
|
+
scope_procs.reduce(instance) do |relation, scope_proc|
|
73
73
|
relation.instance_eval(&scope_proc)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
# Enables action for given fields.
|
78
78
|
#
|
79
|
-
# Built-in possible actions are: `:
|
79
|
+
# Built-in possible actions are: `:read`, `:update`, `:create`.
|
80
80
|
# You can pass any other actions you want to use with {#can?} afterwards.
|
81
81
|
#
|
82
82
|
# **The method enables action for every field if `fields` splat is empty.**
|
@@ -94,25 +94,27 @@ module Protector
|
|
94
94
|
#
|
95
95
|
# @example
|
96
96
|
# protect do
|
97
|
-
# can :
|
98
|
-
# can :
|
99
|
-
# can :
|
97
|
+
# can :read # Can read any field
|
98
|
+
# can :read, 'f1' # Can read `f1` field
|
99
|
+
# can :read, %w(f2 f3) # Can read `f2`, `f3` fields
|
100
100
|
# can :update, f1: 1..2 # Can update f1 field with values between 1 and 2
|
101
101
|
#
|
102
102
|
# # Can create f1 field with value equal to 'olo'
|
103
103
|
# can :create, f1: lambda{|x| x == 'olo'}
|
104
104
|
# end
|
105
105
|
def can(action, *fields)
|
106
|
+
action = deprecate_actions(action)
|
107
|
+
|
106
108
|
return @destroyable = true if action == :destroy
|
107
109
|
|
108
110
|
@access[action] = {} unless @access[action]
|
109
111
|
|
110
112
|
if fields.length == 0
|
111
|
-
@fields.each{|f| @access[action][f.to_s] = nil}
|
113
|
+
@fields.each { |f| @access[action][f.to_s] = nil }
|
112
114
|
else
|
113
115
|
fields.each do |a|
|
114
116
|
if a.is_a?(Array)
|
115
|
-
a.each{|f| @access[action][f.to_s] = nil}
|
117
|
+
a.each { |f| @access[action][f.to_s] = nil }
|
116
118
|
elsif a.is_a?(Hash)
|
117
119
|
@access[action].merge!(a.stringify_keys)
|
118
120
|
else
|
@@ -132,6 +134,8 @@ module Protector
|
|
132
134
|
# @see #can
|
133
135
|
# @see #can?
|
134
136
|
def cannot(action, *fields)
|
137
|
+
action = deprecate_actions(action)
|
138
|
+
|
135
139
|
return @destroyable = false if action == :destroy
|
136
140
|
|
137
141
|
return unless @access[action]
|
@@ -141,7 +145,7 @@ module Protector
|
|
141
145
|
else
|
142
146
|
fields.each do |a|
|
143
147
|
if a.is_a?(Array)
|
144
|
-
a.each{|f| @access[action].delete(f.to_s)}
|
148
|
+
a.each { |f| @access[action].delete(f.to_s) }
|
145
149
|
else
|
146
150
|
@access[action].delete(a.to_s)
|
147
151
|
end
|
@@ -155,7 +159,7 @@ module Protector
|
|
155
159
|
|
156
160
|
# Checks whether given field of a model is readable in context of current subject
|
157
161
|
def readable?(field)
|
158
|
-
@access[:
|
162
|
+
@access[:read] && @access[:read].key?(field)
|
159
163
|
end
|
160
164
|
|
161
165
|
# Checks whether you can create a model with given field in context of current subject
|
@@ -191,7 +195,7 @@ module Protector
|
|
191
195
|
return false unless @access[action]
|
192
196
|
return !@access[action].empty? unless field
|
193
197
|
|
194
|
-
@access[action].
|
198
|
+
@access[action].key?(field.to_s)
|
195
199
|
end
|
196
200
|
|
197
201
|
def cannot?(*args)
|
@@ -206,14 +210,14 @@ module Protector
|
|
206
210
|
diff = fields.keys - @access[part].keys
|
207
211
|
return diff.first if diff.length > 0
|
208
212
|
|
209
|
-
fields.each do |k,v|
|
213
|
+
fields.each do |k, v|
|
210
214
|
case x = @access[part][k]
|
211
215
|
when Range
|
212
216
|
return k unless x.include?(v)
|
213
217
|
when Proc
|
214
218
|
return k unless x.call(v)
|
215
219
|
else
|
216
|
-
return k if x
|
220
|
+
return k if !x.nil? && x != v
|
217
221
|
end
|
218
222
|
end
|
219
223
|
|
@@ -225,6 +229,17 @@ module Protector
|
|
225
229
|
return false if fields && first_unmodifiable_field(part, fields)
|
226
230
|
true
|
227
231
|
end
|
232
|
+
|
233
|
+
def deprecate_actions(action)
|
234
|
+
if action == :view
|
235
|
+
ActiveSupport::Deprecation.warn ":view rule has been deprecated and replaced with :read! "+
|
236
|
+
"Starting from version 1.0 :view will be treated as a custom rule."
|
237
|
+
|
238
|
+
:read
|
239
|
+
else
|
240
|
+
action
|
241
|
+
end
|
242
|
+
end
|
228
243
|
end
|
229
244
|
|
230
245
|
def initialize(adapter, model, &fields_proc)
|
@@ -263,7 +278,7 @@ module Protector
|
|
263
278
|
# subject on a non-protected model
|
264
279
|
def protector_subject
|
265
280
|
unless protector_subject?
|
266
|
-
|
281
|
+
fail "Unprotected entity detected for '#{self.class}': use `restrict` method to protect it."
|
267
282
|
end
|
268
283
|
|
269
284
|
@protector_subject
|
@@ -305,4 +320,4 @@ module Protector
|
|
305
320
|
end
|
306
321
|
end
|
307
322
|
end
|
308
|
-
end
|
323
|
+
end
|
data/lib/protector/engine.rb
CHANGED
@@ -2,12 +2,12 @@ module Protector
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
config.protector = ActiveSupport::OrderedOptions.new
|
4
4
|
|
5
|
-
initializer
|
6
|
-
app.config.protector.each{|k,v| Protector.config[k] = v}
|
5
|
+
initializer 'protector.configuration' do |app|
|
6
|
+
app.config.protector.each { |k, v| Protector.config[k] = v }
|
7
7
|
|
8
8
|
if Protector::Adapters::ActiveRecord.modern?
|
9
9
|
::ActiveRecord::Base.send(:include, Protector::ActiveRecord::StrongParameters)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
end
|
13
|
+
end
|
data/lib/protector/version.rb
CHANGED
data/perf/active_record_perf.rb
CHANGED
data/perf/sequel_perf.rb
CHANGED
@@ -85,7 +85,7 @@ describe Protector::DSL do
|
|
85
85
|
before :each do
|
86
86
|
@meta = Protector::DSL::Meta.new(nil, nil){%w(field1 field2 field3 field4 field5)}
|
87
87
|
@meta << lambda {
|
88
|
-
can :
|
88
|
+
can :read
|
89
89
|
}
|
90
90
|
|
91
91
|
@meta << lambda {|user|
|
@@ -95,7 +95,7 @@ describe Protector::DSL do
|
|
95
95
|
@meta << lambda {|user|
|
96
96
|
user.should == 'user' if user
|
97
97
|
|
98
|
-
cannot :
|
98
|
+
cannot :read, %w(field5), :field4
|
99
99
|
}
|
100
100
|
|
101
101
|
@meta << lambda {|user, entry|
|
@@ -144,7 +144,7 @@ describe Protector::DSL do
|
|
144
144
|
"field4" => 0..5,
|
145
145
|
"field5" => l
|
146
146
|
},
|
147
|
-
|
147
|
+
read: {
|
148
148
|
"field1" => nil,
|
149
149
|
"field2" => nil,
|
150
150
|
"field3" => nil
|
@@ -181,6 +181,24 @@ describe Protector::DSL do
|
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
184
|
+
context "deprecated methods" do
|
185
|
+
before :each do
|
186
|
+
@meta = Protector::DSL::Meta.new(nil, nil){%w(field1 field2 field3)}
|
187
|
+
|
188
|
+
@meta << lambda {
|
189
|
+
can :view
|
190
|
+
cannot :view, :field2
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
it "evaluates" do
|
195
|
+
data = ActiveSupport::Deprecation.silence { @meta.evaluate('user', 'entry') }
|
196
|
+
data.can?(:read).should == true
|
197
|
+
data.can?(:read, :field1).should == true
|
198
|
+
data.can?(:read, :field2).should == false
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
184
202
|
context "custom methods" do
|
185
203
|
before :each do
|
186
204
|
@meta = Protector::DSL::Meta.new(nil, nil){%w(field1 field2)}
|
@@ -7,7 +7,7 @@ shared_examples_for "a model" do
|
|
7
7
|
|
8
8
|
scope { limit(5) }
|
9
9
|
|
10
|
-
can :
|
10
|
+
can :read
|
11
11
|
can :create
|
12
12
|
can :update
|
13
13
|
end
|
@@ -16,7 +16,7 @@ shared_examples_for "a model" do
|
|
16
16
|
fields = Hash[*%w(id string number text dummy_id).map{|x| [x, nil]}.flatten]
|
17
17
|
meta = dummy.new.restrict!('!').protector_meta
|
18
18
|
|
19
|
-
meta.access[:
|
19
|
+
meta.access[:read].should == fields
|
20
20
|
meta.access[:create].should == fields
|
21
21
|
meta.access[:update].should == fields
|
22
22
|
end
|
@@ -64,7 +64,7 @@ shared_examples_for "a model" do
|
|
64
64
|
it "hides fields" do
|
65
65
|
dummy.instance_eval do
|
66
66
|
protect do
|
67
|
-
can :
|
67
|
+
can :read, :string
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
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.
|
4
|
+
version: 0.7.0
|
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-
|
11
|
+
date: 2013-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -48,6 +48,7 @@ extra_rdoc_files: []
|
|
48
48
|
files:
|
49
49
|
- .gitignore
|
50
50
|
- .rspec
|
51
|
+
- .rubocop.yml
|
51
52
|
- .travis.yml
|
52
53
|
- .yardopts
|
53
54
|
- Appraisals
|