param_protected 1.2.0 → 1.3.0

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.
data/README.rdoc CHANGED
@@ -46,6 +46,7 @@ If you call <tt>param_protected</tt> or <tt>param_accessible</tt> multiple times
46
46
  param_protected [{ :user => [:first, :last] }, :password], :only => :some_action
47
47
  Is equivalent to saying...
48
48
  param_protected [:id, { :user => [:first, :last] }, :password], :only => :some_action
49
+
49
50
  Credit: Moritz Heidkamp
50
51
 
51
52
  === Inheritance
@@ -53,6 +54,20 @@ Param protections will be inherited to derived controllers.
53
54
 
54
55
  Credit: Moritz Heidkamp
55
56
 
57
+ === Conditions
58
+ You can conditionally protect params...
59
+ param_protected :admin, :unless => "user_is_admin?"
60
+ param_accessible :admin, :if => :user_is_admin?
61
+ param_protected :admin, :unless => Proc.new{ |controller| controller.user_is_admin? }
62
+
63
+ Credit: Mortiz Heidkamp
64
+
65
+ == Regular Expressions
66
+ You can use regular expressions when specifying which params to make protected or accessible.
67
+ param_accessible /item\d/
68
+
69
+ Credit: Mortiz Heidkamp
70
+
56
71
  === How does it work?
57
72
  It does an <tt>alias_method_chain</tt> on <tt>ActionController::Base#params</tt> that filters (and caches) the params. You can get the unfiltered, pristine params by calling <tt>ActionController::Base#params_without_protection</tt>.
58
73
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.3.0
@@ -46,7 +46,7 @@ module ParamProtected
46
46
  elsif @params_protected
47
47
  @params_protected
48
48
  else
49
- @params_protected = Protector.instance(self.class).protect(params_without_protection, action_name)
49
+ @params_protected = Protector.instance(self.class).protect(self, params_without_protection, action_name)
50
50
  end
51
51
 
52
52
  end
@@ -17,15 +17,15 @@ module ParamProtected
17
17
  copy.instance_variable_set(:@protections, deep_copy(@protections))
18
18
  end
19
19
 
20
- def declare_protection(params, actions, exclusivity)
20
+ def declare_protection(params, options, exclusivity)
21
21
  params = normalize_params(params)
22
- actions = normalize_actions(actions)
23
- @protections << [params, actions, exclusivity]
22
+ actions, condition = normalize_options(options)
23
+ @protections << [params, actions, condition, exclusivity]
24
24
  end
25
25
 
26
- def protect(controller_params, action_name)
26
+ def protect(controller, controller_params, action_name)
27
27
  returning(deep_copy(controller_params)) do |params|
28
- protections_for_action(action_name).each do |exclusivity, protected_params|
28
+ protections_for_action(controller, action_name).each do |exclusivity, protected_params|
29
29
  filter_params(protected_params, params, exclusivity) unless protected_params.empty?
30
30
  end
31
31
  end
@@ -33,12 +33,10 @@ module ParamProtected
33
33
 
34
34
  private
35
35
 
36
- def protections_for_action(action_name)
37
- @protections_for_action ||= { }
38
-
39
- @protections_for_action[action_name] ||= @protections.select do |protected_params, actions, exclusivity|
40
- action_matches?(actions[0], actions[1..-1], action_name)
41
- end.inject({ WHITELIST => { }, BLACKLIST => { } }) do |result, (protected_params, action_name, exclusivity)|
36
+ def protections_for_action(controller, action_name)
37
+ @protections.select do |protected_params, actions, condition, exclusivity|
38
+ action_matches?(actions[0], actions[1..-1], action_name) && condition_applies?(controller, condition)
39
+ end.inject({ WHITELIST => { }, BLACKLIST => { } }) do |result, (protected_params, actions, condition, exclusivity)|
42
40
  merge_protections(result[exclusivity], protected_params)
43
41
  result
44
42
  end
@@ -80,36 +78,59 @@ module ParamProtected
80
78
  params.each{ |param| normalize_params(param, params_out) }
81
79
  elsif params.instance_of?(Hash)
82
80
  params.each do |k, v|
83
- k = k.to_s
81
+ k = normalize_key(k)
84
82
  params_out[k] = {}
85
83
  normalize_params(v, params_out[k])
86
84
  end
87
85
  else
88
- params_out[params.to_s] = nil
86
+ params_out[normalize_key(params)] = nil
89
87
  end
90
88
  params_out
91
89
  end
90
+
91
+ def normalize_key(k)
92
+ if k.is_a?(Regexp)
93
+ k
94
+ else
95
+ k.to_s
96
+ end
97
+ end
92
98
 
93
99
  # When specifying which actions param protection apply to, we allow a format like this...
94
100
  # :only => [:action1, :action2]
95
101
  # This method normalizes that to...
96
102
  # [:only, "action1", "action2"]
97
- def normalize_actions(actions)
98
- error_message = "invalid actions, use :only => ..., :except => ..., or nil"
99
- return [:except, nil] if actions.blank?
100
- raise ArgumentError, error_message unless actions.instance_of?(Hash)
101
- raise ArgumentError, error_message unless actions.length == 1
102
- raise ArgumentError, error_message unless [:only, :except].include?(actions.keys.first)
103
-
104
- scope, actions = actions.keys.first, actions.values.first
103
+ def normalize_options(options)
104
+ error_message = "invalid options, use :only or :except, :if or :unless"
105
+ return [[:except, nil], [:if, true]] if options.blank?
106
+
107
+ raise ArgumentError, error_message unless options.instance_of?(Hash)
108
+
109
+ scope = [:only, :except] & options.keys
110
+ condition = [:if, :unless] & options.keys
111
+
112
+ raise ArgumentError, error_message unless (options.keys - [:only, :except, :if, :unless]).empty?
113
+ raise ArgumentError, error_message if scope.size > 1 || condition.size > 1
114
+
115
+ scope = scope.first || :except
116
+ actions = options[scope]
105
117
  actions = [actions] unless actions.instance_of?(Array)
106
- actions = actions.collect{ |action| action.to_s }
107
- [scope, *actions]
118
+ actions = actions.collect{ |action| action.try(:to_s) }
119
+
120
+ condition = condition.first || :if
121
+
122
+ if options.has_key?(condition)
123
+ condition_value = options[condition]
124
+ else
125
+ condition_value = true
126
+ end
127
+
128
+ [[scope, *actions], [condition, condition_value]]
108
129
  end
109
130
 
110
131
  # When #dup just isn't enough... :P
111
132
  def deep_copy(object)
112
- returning(try_to_dup(object)) do |new_object|
133
+ returning(try_to_clone(object)) do |new_object|
113
134
  case new_object
114
135
  when Hash
115
136
  new_object.each{ |k, v| new_object[k] = deep_copy(v) }
@@ -120,11 +141,28 @@ module ParamProtected
120
141
  end
121
142
 
122
143
  # Some objects are not dupable... like TrueClass, FalseClass and NilClass.
123
- def try_to_dup(object)
124
- object.dup
144
+ def try_to_clone(object)
145
+ object.clone
125
146
  rescue TypeError
126
147
  object
127
148
  end
149
+
150
+ def condition_applies?(controller, condition)
151
+ result = case condition[1]
152
+ when Proc
153
+ condition[1].call(controller)
154
+ when Symbol, String
155
+ controller.send(condition[1])
156
+ else
157
+ condition[1]
158
+ end
159
+
160
+ if condition[0] == :unless
161
+ not result
162
+ else
163
+ result
164
+ end
165
+ end
128
166
 
129
167
  def action_matches?(scope, actions, action_name)
130
168
  if action_name.blank?
@@ -142,15 +180,35 @@ module ParamProtected
142
180
  return unless params.kind_of?(Hash)
143
181
  return if protected_params.nil?
144
182
  if exclusivity == BLACKLIST
145
- params.delete_if{ |k, v| protected_params.has_key?(k) and protected_params[k].nil? }
183
+ params.delete_if{ |k, v| key_exists?(protected_params, k) and find_by_key(protected_params, k).nil? }
146
184
  elsif exclusivity == WHITELIST
147
- params.delete_if{ |k, v| !protected_params.has_key?(k) }
185
+ params.delete_if{ |k, v| !key_exists?(protected_params, k) }
148
186
  else
149
187
  raise ArgumentError, "unexpected exclusivity: #{exclusivity}"
150
188
  end
151
189
  params.each{ |k, v| filter_params(protected_params[k], v, exclusivity) }
152
190
  params
153
191
  end
192
+
193
+ def find_by_key(protected_params, key)
194
+ protected_params.detect do |k,v|
195
+ key_matches?(k, key)
196
+ end.try(:last)
197
+ end
154
198
 
199
+ def key_exists?(protected_params, key)
200
+ protected_params.any? do |k,v|
201
+ key_matches?(k, key)
202
+ end
203
+ end
204
+
205
+ def key_matches?(k, key)
206
+ if k.is_a? Regexp
207
+ key.to_s =~ k
208
+ else
209
+ key.to_s == k.to_s
210
+ end
211
+ end
212
+
155
213
  end
156
- end
214
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{param_protected}
8
- s.version = "1.2.0"
8
+ s.version = "1.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Christopher J. Bottaro"]
12
- s.date = %q{2010-02-18}
12
+ s.date = %q{2010-05-25}
13
13
  s.description = %q{Provides two class methods on ActiveController::Base that filter the params hash for that controller's actions. You can think of them as the controller analog of attr_protected and attr_accessible.}
14
14
  s.email = %q{cjbottaro@alumni.cs.utexas.edu}
15
15
  s.extra_rdoc_files = [
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "test/app_root/app/controllers/accessible_except_controller.rb",
35
35
  "test/app_root/app/controllers/accessible_only_controller.rb",
36
36
  "test/app_root/app/controllers/application_controller.rb",
37
+ "test/app_root/app/controllers/conditions_controller.rb",
37
38
  "test/app_root/app/controllers/inherited_users_controller.rb",
38
39
  "test/app_root/app/controllers/merge_controller.rb",
39
40
  "test/app_root/app/controllers/protected_controller.rb",
@@ -48,6 +49,7 @@ Gem::Specification.new do |s|
48
49
  "test/app_root/config/environments/sqlite3.rb",
49
50
  "test/app_root/config/routes.rb",
50
51
  "test/app_root/lib/console_with_fixtures.rb",
52
+ "test/conditions_controller_test.rb",
51
53
  "test/inherited_users_controller_test.rb",
52
54
  "test/merge_controller_test.rb",
53
55
  "test/protected_controller_test.rb",
@@ -59,7 +61,7 @@ Gem::Specification.new do |s|
59
61
  s.homepage = %q{http://github.com/cjbottaro/param_protected}
60
62
  s.rdoc_options = ["--charset=UTF-8"]
61
63
  s.require_paths = ["lib"]
62
- s.rubygems_version = %q{1.3.5}
64
+ s.rubygems_version = %q{1.3.6}
63
65
  s.summary = %q{Filter unwanted parameters in your controllers and actions.}
64
66
  s.test_files = [
65
67
  "test/accessible_except_test.rb",
@@ -67,6 +69,7 @@ Gem::Specification.new do |s|
67
69
  "test/app_root/app/controllers/accessible_except_controller.rb",
68
70
  "test/app_root/app/controllers/accessible_only_controller.rb",
69
71
  "test/app_root/app/controllers/application_controller.rb",
72
+ "test/app_root/app/controllers/conditions_controller.rb",
70
73
  "test/app_root/app/controllers/inherited_users_controller.rb",
71
74
  "test/app_root/app/controllers/merge_controller.rb",
72
75
  "test/app_root/app/controllers/protected_controller.rb",
@@ -80,6 +83,7 @@ Gem::Specification.new do |s|
80
83
  "test/app_root/config/environments/sqlite3.rb",
81
84
  "test/app_root/config/routes.rb",
82
85
  "test/app_root/lib/console_with_fixtures.rb",
86
+ "test/conditions_controller_test.rb",
83
87
  "test/inherited_users_controller_test.rb",
84
88
  "test/merge_controller_test.rb",
85
89
  "test/protected_controller_test.rb",
@@ -0,0 +1,21 @@
1
+ class ConditionsController < ApplicationController
2
+ param_accessible :a, :if => :something?
3
+ param_accessible :b, :unless => false
4
+ param_protected :b, :if => :first_action?
5
+ param_accessible :c, :if => lambda { |controller| controller.instance_eval { first_action? } }
6
+
7
+ def first; end
8
+
9
+ def second; end
10
+
11
+ protected
12
+
13
+ def something?
14
+ true
15
+ end
16
+
17
+ def first_action?
18
+ action_name == 'first'
19
+ end
20
+
21
+ end
@@ -1,5 +1,5 @@
1
1
  class UsersController < ApplicationController
2
- param_accessible( {:user => [ {:name => [:first, :last]}, :email ]} )
2
+ param_accessible( {:user => [ {:name => [:first, :last], /\A\d+\z/ => :ok}, :email ]} )
3
3
 
4
4
  def create; end
5
5
  def update; end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ class ConditionsControllerTest < ActionController::TestCase
4
+
5
+ test_action :first do
6
+ assert_params %w[a c]
7
+ end
8
+
9
+ test_action :second do
10
+ assert_params %w[a b]
11
+ end
12
+
13
+ end
@@ -20,25 +20,29 @@ class HelpersTest < Test::Unit::TestCase
20
20
  assert_equal({"something" => {"stuff" => nil, "blah" => {"bleck" => nil}}}, params)
21
21
  end
22
22
 
23
- def test_normalize_actions
24
- actions = @protector.send(:normalize_actions, nil)
25
- assert_equal [:except, nil], actions
23
+ def test_normalize_options
24
+ options = @protector.send(:normalize_options, nil)
25
+ assert_equal [[:except, nil], [:if, true]], options
26
26
 
27
- actions = @protector.send(:normalize_actions, :only => :blah)
28
- assert_equal [:only, "blah"], actions
27
+ options = @protector.send(:normalize_options, :only => :blah)
28
+ assert_equal [[:only, "blah"], [:if, true]], options
29
29
 
30
- actions = @protector.send(:normalize_actions, :only => [:blah, :bleck])
31
- assert_equal [:only, "blah", "bleck"], actions
30
+ options = @protector.send(:normalize_options, :only => [:blah, :bleck])
31
+ assert_equal [[:only, "blah", "bleck"], [:if, true]], options
32
32
 
33
- actions = @protector.send(:normalize_actions, :except => :blah)
34
- assert_equal [:except, "blah"], actions
33
+ options = @protector.send(:normalize_options, :except => :blah)
34
+ assert_equal [[:except, "blah"], [:if, true]], options
35
35
 
36
- actions = @protector.send(:normalize_actions, :except => [:blah, :bleck])
37
- assert_equal [:except, "blah", "bleck"], actions
36
+ options = @protector.send(:normalize_options, :except => [:blah, :bleck])
37
+ assert_equal [[:except, "blah", "bleck"], [:if, true]], options
38
+
39
+ options = @protector.send(:normalize_options, :unless => :foo?)
40
+ assert_equal [[:except, nil], [:unless, :foo?]], options
38
41
 
39
- assert_raises(ArgumentError){ @protector.send(:normalize_actions, :onlyy => :blah) }
40
- assert_raises(ArgumentError){ @protector.send(:normalize_actions, :blah) }
41
- assert_raises(ArgumentError){ @protector.send(:normalize_actions, :only => :something, :except => :something) }
42
+ assert_raises(ArgumentError){ @protector.send(:normalize_options, :onlyy => :blah) }
43
+ assert_raises(ArgumentError){ @protector.send(:normalize_options, :blah) }
44
+ assert_raises(ArgumentError){ @protector.send(:normalize_options, :only => :something, :except => :something) }
45
+ assert_raises(ArgumentError){ @protector.send(:normalize_options, :if => :something, :unless => :something) }
42
46
  end
43
47
 
44
48
  def test_deep_copy
@@ -2,11 +2,15 @@ require "test_helper"
2
2
 
3
3
  class UsersControllerTest < ActionController::TestCase
4
4
  PARAMS = { :user => { :id => 123,
5
- :name => { :first => "chris", :middle => "james", :last => "bottaro"},
6
- :email => "cjbottaro@blah.com" },
5
+ '33' => 'ok',
6
+ '123' => 'ok',
7
+ :x21 => 'ok',
8
+ :name => { :first => "chris", :middle => "james", :last => "bottaro"},
9
+ :email => "cjbottaro@blah.com" },
7
10
  :something => "something" }
8
11
 
9
12
  EXPECTED_PARAMS = { "user" => { "name" => {"first" => "chris", "last" => "bottaro"},
13
+ '33' => 'ok', '123' => 'ok',
10
14
  "email" => "cjbottaro@blah.com" } }
11
15
 
12
16
  def test_create
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: param_protected
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 3
8
+ - 0
9
+ version: 1.3.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Christopher J. Bottaro
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-18 00:00:00 -06:00
17
+ date: 2010-05-25 00:00:00 -05:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -40,6 +45,7 @@ files:
40
45
  - test/app_root/app/controllers/accessible_except_controller.rb
41
46
  - test/app_root/app/controllers/accessible_only_controller.rb
42
47
  - test/app_root/app/controllers/application_controller.rb
48
+ - test/app_root/app/controllers/conditions_controller.rb
43
49
  - test/app_root/app/controllers/inherited_users_controller.rb
44
50
  - test/app_root/app/controllers/merge_controller.rb
45
51
  - test/app_root/app/controllers/protected_controller.rb
@@ -54,6 +60,7 @@ files:
54
60
  - test/app_root/config/environments/sqlite3.rb
55
61
  - test/app_root/config/routes.rb
56
62
  - test/app_root/lib/console_with_fixtures.rb
63
+ - test/conditions_controller_test.rb
57
64
  - test/inherited_users_controller_test.rb
58
65
  - test/merge_controller_test.rb
59
66
  - test/protected_controller_test.rb
@@ -74,18 +81,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
81
  requirements:
75
82
  - - ">="
76
83
  - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
77
86
  version: "0"
78
- version:
79
87
  required_rubygems_version: !ruby/object:Gem::Requirement
80
88
  requirements:
81
89
  - - ">="
82
90
  - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
83
93
  version: "0"
84
- version:
85
94
  requirements: []
86
95
 
87
96
  rubyforge_project:
88
- rubygems_version: 1.3.5
97
+ rubygems_version: 1.3.6
89
98
  signing_key:
90
99
  specification_version: 3
91
100
  summary: Filter unwanted parameters in your controllers and actions.
@@ -95,6 +104,7 @@ test_files:
95
104
  - test/app_root/app/controllers/accessible_except_controller.rb
96
105
  - test/app_root/app/controllers/accessible_only_controller.rb
97
106
  - test/app_root/app/controllers/application_controller.rb
107
+ - test/app_root/app/controllers/conditions_controller.rb
98
108
  - test/app_root/app/controllers/inherited_users_controller.rb
99
109
  - test/app_root/app/controllers/merge_controller.rb
100
110
  - test/app_root/app/controllers/protected_controller.rb
@@ -108,6 +118,7 @@ test_files:
108
118
  - test/app_root/config/environments/sqlite3.rb
109
119
  - test/app_root/config/routes.rb
110
120
  - test/app_root/lib/console_with_fixtures.rb
121
+ - test/conditions_controller_test.rb
111
122
  - test/inherited_users_controller_test.rb
112
123
  - test/merge_controller_test.rb
113
124
  - test/protected_controller_test.rb