protector 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0adb740ad6dcc0053fd159bf424ce0dac2092cf
4
- data.tar.gz: 07969057659e1baa91b16806d25efc324389e7c8
3
+ metadata.gz: d22e142c0d5654a1287d706ad235b1d921fbf641
4
+ data.tar.gz: befe5711c88baea2c46f9004aaccfef20541db74
5
5
  SHA512:
6
- metadata.gz: 5d40755015122eef231bbe2b755db8440e6e6a38fdf51c82fc1a5d81e629012ff876c3e921b90d4c4a13b6667ad95050b63d3b79cf5207bb1e6767f24f4ef87c
7
- data.tar.gz: abef904c2b38cbc1a40b5de0c6bb28e56c14db83cd3fd8e631b9a94d0ececa78356abd93f3e1e4b2651cb019a6f8bac1257e5415324a118d97dd8c323a122b2e
6
+ metadata.gz: 85757bb7c0f7e485d4912877572d0a9bfa7d890988c3c6df50bc40fb208e699f5394b3f014a675c7b24671aaad336b378c2d60197124efa4f0acc15024853fbe
7
+ data.tar.gz: 2c0c4d49b32b6d958804f1693bc10d018dba0b0566d0c7514fdc9ca974eec3351b89525986eb160f9562e95b1c5bd0bc8984334dde6a30548f05c3fda8d9cefc
data/README.md CHANGED
@@ -175,6 +175,8 @@ end
175
175
 
176
176
  No matter what happens inside, all your entities will act unprotected. So use with **EXTREME** caution.
177
177
 
178
+ Please note also that we are talking about "unprotected" and "disabled". It does not make `can?` to always return `true`. Instead `can?` would thrown an exception just like it does for any unprotected model. Any other approach makes logic incostitent, unpredictable and just dangerous. There are different possible strategies to isolate business logic from security domain in tests like direct `can?` mocking or forcing admin role to a test user. Use them whenever you want to abstract from security in a whole and `insecurely` when you want to mock a model to the basic security state.
179
+
178
180
  ## Ideology
179
181
 
180
182
  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:
@@ -216,6 +218,11 @@ Use `Protector.config.option = value` to assign an option. Available options are
216
218
 
217
219
  Protector features basic Rails integration so you can assign options using `config.protector.option = value` at your `config/*.rb`.
218
220
 
221
+ ## Need help?
222
+
223
+ * Use [StackOverflow](http://stackoverflow.com/questions/tagged/protector) Luke! Make sure to use tag `protector`.
224
+ * You can get help at [irc.freenode.net](http://freenode.net) #protector.rb.
225
+
219
226
  ## Maintainers
220
227
 
221
228
  * Boris Staal, [@inossidabile](http://staal.io)
@@ -28,6 +28,10 @@ module Protector
28
28
  end
29
29
  end
30
30
 
31
+ def creatable?
32
+ new.creatable?
33
+ end
34
+
31
35
  # Gets {Protector::DSL::Meta::Box} of this relation
32
36
  def protector_meta(subject=protector_subject)
33
37
  @klass.protector_meta.evaluate(subject)
@@ -30,6 +30,10 @@ module Protector
30
30
  alias_method_chain :each, :protector
31
31
  end
32
32
 
33
+ def creatable?
34
+ model.new.restrict!(protector_subject).creatable?
35
+ end
36
+
33
37
  # Gets {Protector::DSL::Meta::Box} of this dataset
34
38
  def protector_meta(subject=protector_subject)
35
39
  model.protector_meta.evaluate(subject)
data/lib/protector/dsl.rb CHANGED
@@ -16,7 +16,7 @@ module Protector
16
16
  @adapter = adapter
17
17
  @model = model
18
18
  @fields = fields
19
- @access = {update: {}, view: {}, create: {}}
19
+ @access = {}
20
20
  @scope_procs = []
21
21
  @destroyable = false
22
22
 
@@ -104,9 +104,10 @@ module Protector
104
104
  # end
105
105
  def can(action, *fields)
106
106
  return @destroyable = true if action == :destroy
107
+
107
108
  @access[action] = {} unless @access[action]
108
109
 
109
- if fields.size == 0
110
+ if fields.length == 0
110
111
  @fields.each{|f| @access[action][f.to_s] = nil}
111
112
  else
112
113
  fields.each do |a|
@@ -132,10 +133,11 @@ module Protector
132
133
  # @see #can?
133
134
  def cannot(action, *fields)
134
135
  return @destroyable = false if action == :destroy
136
+
135
137
  return unless @access[action]
136
138
 
137
- if fields.size == 0
138
- @access[action].clear
139
+ if fields.length == 0
140
+ @access.delete(action)
139
141
  else
140
142
  fields.each do |a|
141
143
  if a.is_a?(Array)
@@ -144,6 +146,8 @@ module Protector
144
146
  @access[action].delete(a.to_s)
145
147
  end
146
148
  end
149
+
150
+ @access.delete(action) if @access[action].empty?
147
151
  end
148
152
  end
149
153
 
@@ -151,7 +155,7 @@ module Protector
151
155
 
152
156
  # Checks whether given field of a model is readable in context of current subject
153
157
  def readable?(field)
154
- @access[:view].has_key?(field)
158
+ @access[:view] && @access[:view].has_key?(field)
155
159
  end
156
160
 
157
161
  # Checks whether you can create a model with given field in context of current subject
@@ -182,14 +186,23 @@ module Protector
182
186
  # @param [Symbol] action Action to check against
183
187
  # @param [String] field Field to check against
184
188
  def can?(action, field=false)
189
+ return destroyable? if action == :destroy
190
+
185
191
  return false unless @access[action]
186
- return !@access[action].empty? if field === false
192
+ return !@access[action].empty? unless field
193
+
187
194
  @access[action].has_key?(field.to_s)
188
195
  end
189
196
 
197
+ def cannot?(*args)
198
+ !can?(*args)
199
+ end
200
+
190
201
  private
191
202
 
192
203
  def first_unmodifiable_field(part, fields)
204
+ return (fields.keys.first || '-') unless @access[part]
205
+
193
206
  diff = fields.keys - @access[part].keys
194
207
  return diff.first if diff.length > 0
195
208
 
@@ -207,8 +220,8 @@ module Protector
207
220
  false
208
221
  end
209
222
 
210
- def modifiable?(part, fields)
211
- return false unless @access[part].keys.length > 0
223
+ def modifiable?(part, fields=false)
224
+ return false unless @access[part]
212
225
  return false if fields && first_unmodifiable_field(part, fields)
213
226
  true
214
227
  end
@@ -250,7 +263,7 @@ module Protector
250
263
  # subject on a non-protected model
251
264
  def protector_subject
252
265
  unless protector_subject?
253
- raise "Unprotected entity detected: use `restrict` method to protect it."
266
+ raise "Unprotected entity detected for '#{self.class}': use `restrict` method to protect it."
254
267
  end
255
268
 
256
269
  @protector_subject
@@ -1,4 +1,4 @@
1
1
  module Protector
2
2
  # Gem version
3
- VERSION = "0.6.1"
3
+ VERSION = "0.6.2"
4
4
  end
data/lib/protector.rb CHANGED
@@ -25,10 +25,17 @@ module Protector
25
25
 
26
26
  # Allows executing any code having Protector globally disabled
27
27
  def insecurely(&block)
28
+ Thread.current[:protector_disabled_nesting] ||= 0
29
+ Thread.current[:protector_disabled_nesting] += 1
30
+
28
31
  Thread.current[:protector_disabled] = true
29
32
  yield
30
33
  ensure
31
- Thread.current[:protector_disabled] = false
34
+ Thread.current[:protector_disabled_nesting] -= 1
35
+
36
+ if Thread.current[:protector_disabled_nesting] == 0
37
+ Thread.current[:protector_disabled] = false
38
+ end
32
39
  end
33
40
 
34
41
  def activate!
@@ -116,6 +116,11 @@ if defined?(ActiveRecord)
116
116
  Dummy.restrict!('!').new.protector_subject.should == '!'
117
117
  end
118
118
 
119
+ it "checks creatability" do
120
+ Dummy.restrict!('!').creatable?.should == false
121
+ Dummy.restrict!('!').where(number: 999).creatable?.should == false
122
+ end
123
+
119
124
  context "with open relation" do
120
125
  context "adequate", paranoid: false do
121
126
  it "checks existence" do
@@ -88,6 +88,11 @@ if defined?(Sequel)
88
88
  Dummy.restrict!('!').eager_graph(fluffies: :loony).all.first.fluffies.first.loony.protector_subject.should == '!'
89
89
  end
90
90
 
91
+ it "checks creatability" do
92
+ Dummy.restrict!('!').creatable?.should == false
93
+ Dummy.restrict!('!').where(number: 999).creatable?.should == false
94
+ end
95
+
91
96
  context "with open relation" do
92
97
  context "adequate", paranoid: false do
93
98
  it "checks existence" do
@@ -34,6 +34,28 @@ describe Protector::DSL do
34
34
  base.unrestrict!
35
35
  expect { base.protector_subject }.to raise_error
36
36
  end
37
+
38
+ it "respects `insecurely`" do
39
+ base = @base.new
40
+ base.restrict!("universe")
41
+
42
+ base.protector_subject?.should == true
43
+ Protector.insecurely do
44
+ base.protector_subject?.should == false
45
+ end
46
+ end
47
+
48
+ it "allows nesting of `insecurely`" do
49
+ base = @base.new
50
+ base.restrict!("universe")
51
+
52
+ base.protector_subject?.should == true
53
+ Protector.insecurely do
54
+ Protector.insecurely do
55
+ base.protector_subject?.should == false
56
+ end
57
+ end
58
+ end
37
59
  end
38
60
 
39
61
  describe Protector::DSL::Entry do
@@ -126,19 +148,20 @@ describe Protector::DSL do
126
148
  "field1" => nil,
127
149
  "field2" => nil,
128
150
  "field3" => nil
129
- },
130
- create: {}
151
+ }
131
152
  }
132
153
  end
133
154
 
134
155
  it "marks destroyable" do
135
156
  data = @meta.evaluate('user', 'entry')
136
157
  data.destroyable?.should == true
158
+ data.can?(:destroy).should == true
137
159
  end
138
160
 
139
161
  it "marks updatable" do
140
162
  data = @meta.evaluate('user', 'entry')
141
163
  data.updatable?.should == true
164
+ data.can?(:update).should == true
142
165
  end
143
166
 
144
167
  it "gets first unupdatable field" do
@@ -149,6 +172,7 @@ describe Protector::DSL do
149
172
  it "marks creatable" do
150
173
  data = @meta.evaluate('user', 'entry')
151
174
  data.creatable?.should == false
175
+ data.can?(:create).should == false
152
176
  end
153
177
 
154
178
  it "gets first uncreatable field" do
@@ -28,8 +28,13 @@ if defined?(Rails)
28
28
  describe "strong_parameters" do
29
29
  before(:all) do
30
30
  load 'migrations/active_record.rb'
31
+ end
32
+
33
+ let(:dummy) do
34
+ Class.new(ActiveRecord::Base) do
35
+ def self.model_name; ActiveModel::Name.new(self, nil, "dummy"); end
36
+ self.table_name = "dummies"
31
37
 
32
- Dummy.instance_eval do
33
38
  protect do
34
39
  can :create, :string
35
40
  can :update, :number
@@ -42,15 +47,15 @@ if defined?(Rails)
42
47
  end
43
48
 
44
49
  it "creates" do
45
- expect{ Dummy.restrict!.new params(string: 'test') }.to_not raise_error
46
- expect{ Dummy.restrict!.new params(number: 1) }.to raise_error
50
+ expect{ dummy.restrict!.new params(string: 'test') }.to_not raise_error
51
+ expect{ dummy.restrict!.new params(number: 1) }.to raise_error
47
52
  end
48
53
 
49
54
  it "updates" do
50
- dummy = Dummy.create!
55
+ instance = dummy.create!
51
56
 
52
- expect{ dummy.restrict!.assign_attributes params(string: 'test') }.to raise_error
53
- expect{ dummy.restrict!.assign_attributes params(number: 1) }.to_not raise_error
57
+ expect{ instance.restrict!.assign_attributes params(string: 'test') }.to raise_error
58
+ expect{ instance.restrict!.assign_attributes params(number: 1) }.to_not raise_error
54
59
  end
55
60
  end
56
61
  end
@@ -33,7 +33,6 @@ shared_examples_for "a model" do
33
33
  it "doesn't get stuck with non-existing tables" do
34
34
  Rumba.class_eval do
35
35
  protect do
36
- can
37
36
  end
38
37
  end
39
38
  end
@@ -88,6 +87,13 @@ shared_examples_for "a model" do
88
87
  end
89
88
  end
90
89
 
90
+ it "handles empty creations" do
91
+ d = dummy.new.restrict!('!')
92
+ d.can?(:create).should == false
93
+ d.creatable?.should == false
94
+ d.should invalidate
95
+ end
96
+
91
97
  it "marks blocked" do
92
98
  d = dummy.new(string: 'bam', number: 1)
93
99
  d.restrict!('!').creatable?.should == false
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.6.1
4
+ version: 0.6.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-08-31 00:00:00.000000000 Z
11
+ date: 2013-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -78,10 +78,10 @@ files:
78
78
  - protector.gemspec
79
79
  - spec/internal/config/database.yml
80
80
  - spec/internal/db/schema.rb
81
- - spec/lib/adapters/active_record_spec.rb
82
- - spec/lib/adapters/sequel_spec.rb
83
- - spec/lib/dsl_spec.rb
84
- - spec/lib/engine_spec.rb
81
+ - spec/lib/protector/adapters/active_record_spec.rb
82
+ - spec/lib/protector/adapters/sequel_spec.rb
83
+ - spec/lib/protector/dsl_spec.rb
84
+ - spec/lib/protector/engine_spec.rb
85
85
  - spec/spec_helpers/adapters/active_record.rb
86
86
  - spec/spec_helpers/adapters/sequel.rb
87
87
  - spec/spec_helpers/boot.rb
@@ -107,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
107
  version: '0'
108
108
  requirements: []
109
109
  rubyforge_project:
110
- rubygems_version: 2.0.6
110
+ rubygems_version: 2.0.3
111
111
  signing_key:
112
112
  specification_version: 4
113
113
  summary: 'Protector is a successor to the Heimdallr gem: it hits the same goals keeping
@@ -115,10 +115,10 @@ summary: 'Protector is a successor to the Heimdallr gem: it hits the same goals
115
115
  test_files:
116
116
  - spec/internal/config/database.yml
117
117
  - spec/internal/db/schema.rb
118
- - spec/lib/adapters/active_record_spec.rb
119
- - spec/lib/adapters/sequel_spec.rb
120
- - spec/lib/dsl_spec.rb
121
- - spec/lib/engine_spec.rb
118
+ - spec/lib/protector/adapters/active_record_spec.rb
119
+ - spec/lib/protector/adapters/sequel_spec.rb
120
+ - spec/lib/protector/dsl_spec.rb
121
+ - spec/lib/protector/engine_spec.rb
122
122
  - spec/spec_helpers/adapters/active_record.rb
123
123
  - spec/spec_helpers/adapters/sequel.rb
124
124
  - spec/spec_helpers/boot.rb