protector 0.0.1 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ffb03e438ddf160d6def55eedad02d8666ed2c4a
4
- data.tar.gz: 8c1cf283df6c5ddd6e0cb96dd8439331406911b4
3
+ metadata.gz: 098c77da509ed0a347c0a22df9dd6c6a8d34289a
4
+ data.tar.gz: b9ae1d35809445399fda713c3f0276ac91114659
5
5
  SHA512:
6
- metadata.gz: 83ac0169c982cfa2a839eefb4dda73c10c8432516cb2eea9919e1a337233f1c86be2fbbd53164a3da01b65e19bc929afcef50e48e3918c11348f095fe2376d1c
7
- data.tar.gz: 5eaa624122f8c6272b0e7b2f139f83e7f12961f487a3019119f8e05bdd82b68fa2eee5d0d4ebb1888cc122aac58b080c27abf9f4a0a05eec7f34818e72e5063b
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 => send(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, __send__(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, __send__(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
@@ -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 @access[part].length > 0
88
+ return false unless @access_keys[part].length > 0
82
89
 
83
90
  if fields
84
- return false if (fields.keys - @access[part].keys).length > 0
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]
@@ -1,3 +1,3 @@
1
1
  module Protector
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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 :string
9
- t.integer :number
10
- t.text :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
- class Dummy < ActiveRecord::Base; end
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
- Protector::Adapters::ActiveRecord.activate!
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 be_an_instance_of ActiveRecord::Relation
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{ scope{ none } }
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{ scope{ where(number: 999) } }
101
+ protect do; scope{ where(number: 999) }; end
80
102
  end
81
103
  end
82
104
 
@@ -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
- scope { limit(5) }
78
+ can :view, :string
57
79
  end
58
80
  end
59
81
 
60
- @dummy.first.restrict('!').visible?.should == true
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
- dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
79
- dummy.should invalidate
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
- dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
104
- dummy.should invalidate
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
- dummy = @dummy.new(string: 'bam').restrict('!')
134
- dummy.should invalidate
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
- dummy = @dummy.new(number: 500).restrict('!')
164
- dummy.should invalidate
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.should == dummy
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.1
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-22 00:00:00.000000000 Z
11
+ date: 2013-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport