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 +15 -0
- data/VERSION +1 -1
- data/lib/param_protected/controller_modifications.rb +1 -1
- data/lib/param_protected/protector.rb +87 -29
- data/param_protected.gemspec +7 -3
- data/test/app_root/app/controllers/conditions_controller.rb +21 -0
- data/test/app_root/app/controllers/users_controller.rb +1 -1
- data/test/conditions_controller_test.rb +13 -0
- data/test/protector_test.rb +18 -14
- data/test/users_controller_test.rb +6 -2
- metadata +16 -5
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.
|
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,
|
20
|
+
def declare_protection(params, options, exclusivity)
|
21
21
|
params = normalize_params(params)
|
22
|
-
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
|
-
@
|
38
|
-
|
39
|
-
|
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
|
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
|
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
|
98
|
-
error_message = "invalid
|
99
|
-
return [:except, nil] if
|
100
|
-
|
101
|
-
raise ArgumentError, error_message unless
|
102
|
-
|
103
|
-
|
104
|
-
|
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
|
-
|
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(
|
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
|
124
|
-
object.
|
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|
|
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| !
|
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
|
data/param_protected.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{param_protected}
|
8
|
-
s.version = "1.
|
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-
|
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.
|
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
|
data/test/protector_test.rb
CHANGED
@@ -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
|
24
|
-
|
25
|
-
assert_equal [:except, nil],
|
23
|
+
def test_normalize_options
|
24
|
+
options = @protector.send(:normalize_options, nil)
|
25
|
+
assert_equal [[:except, nil], [:if, true]], options
|
26
26
|
|
27
|
-
|
28
|
-
assert_equal [:only, "blah"],
|
27
|
+
options = @protector.send(:normalize_options, :only => :blah)
|
28
|
+
assert_equal [[:only, "blah"], [:if, true]], options
|
29
29
|
|
30
|
-
|
31
|
-
assert_equal [:only, "blah", "bleck"],
|
30
|
+
options = @protector.send(:normalize_options, :only => [:blah, :bleck])
|
31
|
+
assert_equal [[:only, "blah", "bleck"], [:if, true]], options
|
32
32
|
|
33
|
-
|
34
|
-
assert_equal [:except, "blah"],
|
33
|
+
options = @protector.send(:normalize_options, :except => :blah)
|
34
|
+
assert_equal [[:except, "blah"], [:if, true]], options
|
35
35
|
|
36
|
-
|
37
|
-
assert_equal [:except, "blah", "bleck"],
|
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(:
|
40
|
-
assert_raises(ArgumentError){ @protector.send(:
|
41
|
-
assert_raises(ArgumentError){ @protector.send(:
|
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
|
-
|
6
|
-
|
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
|
-
|
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-
|
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.
|
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
|