param_protected 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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