param_accessible 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.
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.gem
2
2
  *.rbc
3
3
  .bundle
4
+ .rvmrc
4
5
  .config
5
6
  .yardoc
6
7
  .rspec
data/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ # Important Note
2
+
3
+ Soon after I created this project, @dhh (creator of Rails) made his own parameter protection gem public: https://github.com/rails/strong_parameters
4
+
5
+ DHH's strong_parameters gem will be integrated into rails4, so I suggest you use it instead.
6
+
1
7
  # ParamAccessible
2
8
 
3
9
  [![Build Status](https://secure.travis-ci.org/topdan/param_accessible.png)](https://secure.travis-ci.org/topdan/param_accessible.png)
@@ -24,33 +30,61 @@ Or install it yourself as:
24
30
 
25
31
  ## Usage
26
32
 
33
+ This gem does not add any functionality by default. To activate it create a before_filter in any ActionController::Base subclass. We only use the filter for create and update actions because those are the normally only the only harmful ones:
34
+
35
+ before_filter :ensure_params_are_accessible, :only => [:create, :update]
36
+
37
+ Now let's expose the parameters that are common across our application:
38
+
39
+ param_accessible :page, :sort
40
+
41
+ You may want to allow all base-level parameters since most Rails controllers only send nested parameters to models (i.e. params[:user]):
42
+
43
+ # allow all base parameters (// is a regex that matches all strings)
44
+ param_accessible //
45
+
46
+ # allow any base parameter starting with "my_"
47
+ param_accessible /^my_/
48
+
49
+ We also want to make sure only admins can change a user's "is_admin" and "is_active" attributes:
50
+
51
+ param_accessible :user => [:is_admin, :is_active], :if => :is_admin?
52
+
53
+ Rinse and repeat for all your controllers and you're Rails Application will be much safer.
54
+
55
+ ## Example
56
+
57
+ Placing the before_filter in our ApplicationController makes all our create and update actions secure by default. We also expose application-wide parameters and provide a friendly error message when an invalid parameter is provided.
58
+
27
59
  class ApplicationController < ActionController::Base
28
60
 
29
61
  # make all your controllers secure by default
30
62
  before_filter :ensure_params_are_accessible, :only => [:create, :update]
31
63
 
32
- # expose the common rails parameters
33
- param_accessible :controller, :action, :format, :id
64
+ # expose the your common application parameters
65
+ param_accessible :page, :sort
34
66
 
35
- # this error is thrown when the user tries to access an inaccessible param
67
+ # this error is thrown when the user submits an inaccessible param
36
68
  rescue_from ParamAccessible::Error, :with => :handle_param_not_accessible
37
69
 
38
70
  protected
39
71
 
40
72
  def handle_param_not_accessible e
41
- flash[:error] = "You gave me some invalid parameters: #{e.inaccessible_params.join(', )}"
73
+ flash[:error] = "You gave me some invalid parameters: #{e.inaccessible_params.join(', ')}"
42
74
  redirect_to :back
43
75
  end
44
76
 
45
77
  end
46
-
47
- class UserController < ApplicationController
78
+
79
+ Inheriting from the class above, we now need to specify our accessible parameters for the create and update actions.
80
+
81
+ class UsersController < ApplicationController
48
82
 
49
83
  # these attributes are available for everyone
50
- param_accessible :user => {:name, :email, :password, :password_confirmation}
84
+ param_accessible :user => [:name, :email, :password, :password_confirmation]
51
85
 
52
86
  # these attributes are only available if the controller instance method is_admin? is true
53
- param_accessible :user => {:is_admin, :is_locked_out}, :if => :is_admin?
87
+ param_accessible :user => [:is_admin, :is_locked_out], :if => :is_admin?
54
88
 
55
89
  def update
56
90
  @user = User.find(params[:id])
@@ -63,7 +97,9 @@ Or install it yourself as:
63
97
  end
64
98
  end
65
99
  end
66
-
100
+
101
+ Showcase a helper module for handling errors and some more options.
102
+
67
103
  class DemoController < ApplicationController
68
104
 
69
105
  # rescue_from ParamAccessible::Error and respond with a 406 Not Acceptable status
@@ -76,14 +112,25 @@ Or install it yourself as:
76
112
  param_accessible :nut, :except => :index
77
113
 
78
114
  end
79
-
115
+
116
+ Using Rails' skip_before_filter to make a controller insecure again
117
+
80
118
  class InsecureController < ApplicationController
81
119
 
82
120
  # skip the filter ApplicationController set up to avoid the accessible parameter checks
83
121
  skip_before_filter :ensure_params_are_accessible
84
122
 
85
123
  end
86
-
124
+
125
+ ## Nested attributes
126
+
127
+ Arrays of attributes like the ones used with Rails' nested forms feature can be specified using
128
+ the following syntax:
129
+
130
+ class DemoController < ApplicationController
131
+ param_accessible :"foo[]" => [:bar, :baz]
132
+ end
133
+
87
134
  ## Contributing
88
135
 
89
136
  1. Fork it
@@ -30,7 +30,8 @@ module ParamAccessible
30
30
  if superclass.respond_to?(:param_accessible_rules)
31
31
  @param_accessible_rules = Rules.new superclass.param_accessible_rules
32
32
  else
33
- @param_accessible_rules = Rules.new
33
+ common_rails_parameters_rule = Rule.new :controller, :action, :id, :format, :authenticity_token, :commit, :utf8
34
+ @param_accessible_rules = Rules.new [common_rails_parameters_rule]
34
35
  end
35
36
  end
36
37
 
@@ -40,27 +40,67 @@ module ParamAccessible
40
40
  return if @only_options != nil && !@only_options.include?(controller.action_name)
41
41
  return if @except_options != nil && @except_options.include?(controller.action_name)
42
42
 
43
- accessible_hash_for controller, @attributes, dest
43
+ accessible_hash_for controller.params, @attributes, dest
44
44
  end
45
45
 
46
46
  protected
47
47
 
48
- def accessible_hash_for controller, attributes, dest
48
+ def accessible_hash_for params, attributes, dest
49
49
  attributes.each do |key, value|
50
- if value.is_a?(Hash)
50
+ if key.to_s =~ /\[\]$/
51
+ accessible_array_for key, params, value, dest
52
+ elsif value.is_a?(Hash)
51
53
  attrs = dest[key]
52
54
  if attrs.nil?
53
55
  attrs = {}
54
56
  dest[key] = attrs
55
57
  end
56
58
 
57
- accessible_hash_for controller, value, attrs
58
- else
59
+ nested_params = params[key] if params.is_a?(Hash)
60
+ accessible_hash_for nested_params, value, attrs
61
+
62
+ elsif key.is_a?(String)
59
63
  dest[key] = value
64
+
65
+ elsif key.is_a?(Regexp) && params
66
+ accessible_params_for_regex key, params, dest
60
67
  end
61
68
  end
62
69
  end
63
70
 
71
+ def accessible_params_for_regex regex, params, dest
72
+ params.keys.each do |key|
73
+ if key.to_s =~ regex
74
+ dest[key] = nil
75
+ end
76
+ end
77
+
78
+ dest
79
+ end
80
+
81
+ def accessible_array_for key, params, value, dest
82
+ key = key.to_s.chomp('[]')
83
+
84
+ if params and params[key].is_a? Hash
85
+ params[key].each do |index, nested_params|
86
+ dest[key] ||= {}
87
+ attrs = dest[key][index] = {}
88
+ accessible_hash_for nested_params, value, attrs if value
89
+ end
90
+ elsif params and params[key].is_a? Array
91
+ params[key].each do |nested_params|
92
+ if nested_params.is_a? Hash
93
+ dest[key] ||= []
94
+ attrs = {}
95
+ accessible_hash_for nested_params, value, attrs if value
96
+ dest[key].push(attrs)
97
+ else
98
+ dest[key] = nil
99
+ end
100
+ end
101
+ end
102
+ end
103
+
64
104
  # When specifying params to protect, we allow a combination of arrays and hashes much like how
65
105
  # ActiveRecord::Base#find's :include options works. This method normalizes that into just nested hashes,
66
106
  # stringifying the keys and setting all values to nil. This format is easier/faster to work with when
@@ -85,7 +125,11 @@ module ParamAccessible
85
125
  end
86
126
 
87
127
  def normalize_key(k)
88
- k.to_s
128
+ if k.is_a?(Regexp)
129
+ k
130
+ else
131
+ k.to_s
132
+ end
89
133
  end
90
134
 
91
135
  end
@@ -33,10 +33,9 @@ module ParamAccessible
33
33
  detect_inaccessible_hash value, nested, errors, prefix_for(prefix, key)
34
34
 
35
35
  elsif value.is_a?(Array)
36
- nested = accessible[key] || {}
37
- value.each do |v|
36
+ value.each_with_index do |v, i|
38
37
  if v.is_a?(Hash)
39
- detect_inaccessible_hash v, nested, errors, prefix_for(prefix, key)
38
+ detect_inaccessible_hash v, accessible[key][i], errors, prefix_for(prefix_for(prefix, key), "")
40
39
  end
41
40
  end
42
41
  end
@@ -1,3 +1,3 @@
1
1
  module ParamAccessible
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -2,8 +2,6 @@ class ApplicationController < ActionController::Base
2
2
  before_filter :ensure_params_are_accessible, :only => [:create, :update]
3
3
  before_filter :render_nothing
4
4
 
5
- param_accessible :action, :controller, :format
6
-
7
5
  def index
8
6
  end
9
7
 
@@ -0,0 +1,4 @@
1
+ class NestedController < ApplicationController
2
+ param_accessible :a => [{:"b[]" => [:d, :e, :q]}, :c]
3
+ param_accessible :"o[]", :p
4
+ end
@@ -0,0 +1,6 @@
1
+ class RegexController < ApplicationController
2
+
3
+ param_accessible /^foo/
4
+ param_accessible :user => [/^bar/]
5
+
6
+ end
@@ -0,0 +1,88 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe NestedController do
4
+ include RSpec::Rails::ControllerExampleGroup
5
+
6
+ it "should allow arrays given as rails style pseudo hashes" do
7
+ post :create, :a => { :b => {"0" => {"d"=>"foo", "e"=>"bar"}, "1" => {"d"=>"foo", "e"=>"bar"}}}
8
+ response.code.should == "200"
9
+ end
10
+
11
+ it "should allow arrays given as arrays hashes" do
12
+ post :create, :a => { :b => [{"d"=>"foo", "e"=>"bar"}, {"d"=>"foo", "e"=>"bar"}]}
13
+ response.code.should == "200"
14
+ end
15
+
16
+ it "should allow arrays given as arrays hashes" do
17
+ post :create, :o => ["foo", "bar"]
18
+ response.code.should == "200"
19
+ end
20
+
21
+ it "should allow arrays given as rails style hash arrays when only arrays of strings are allowed" do
22
+ post :create, :o => { "0" => "foo", "1" => "bar" }
23
+ response.code.should == "200"
24
+ end
25
+
26
+ it "should not allow options which are not in the list" do
27
+ begin
28
+ post :create, :a => { :b => {"0" => {"x"=>"foo" }}}
29
+ raise "should fail"
30
+ rescue ParamAccessible::Error => e
31
+ e.inaccessible_params.should == %w(a[b][0][x])
32
+ end
33
+ end
34
+
35
+ it "should not allow strings for an array" do
36
+ begin
37
+ post :create, :a => { :b => "foo" }
38
+ raise "should fail"
39
+ rescue ParamAccessible::Error => e
40
+ e.inaccessible_params.should == %w(a[b])
41
+ end
42
+ end
43
+
44
+ it "should not allow arrays with invalid values" do
45
+ begin
46
+ post :create, :a => { :b => [{"x"=>"foo"}]}
47
+ raise "should fail"
48
+ rescue ParamAccessible::Error => e
49
+ e.inaccessible_params.should == %w(a[b][][x])
50
+ end
51
+ end
52
+
53
+ it "should not allow arrays with invalid values at other index" do
54
+ begin
55
+ post :create, :a => { :b => [{"d" => "foo"}, {"x"=>"foo"}]}
56
+ raise "should fail"
57
+ rescue ParamAccessible::Error => e
58
+ e.inaccessible_params.should == %w(a[b][][x])
59
+ end
60
+ end
61
+
62
+ it "should not allow hashes when only arrays of strings are allowed" do
63
+ begin
64
+ post :create, :o => [{ :foo => "bar" }]
65
+ raise "should fail"
66
+ rescue ParamAccessible::Error => e
67
+ e.inaccessible_params.should == %w(o[][foo])
68
+ end
69
+ end
70
+
71
+ it "should not allow string when only arrays are allowed" do
72
+ begin
73
+ post :create, :o => "foo"
74
+ raise "should fail"
75
+ rescue ParamAccessible::Error => e
76
+ e.inaccessible_params.should == %w(o)
77
+ end
78
+ end
79
+
80
+ it "should not allow arrays given as rails style hash arrays containing hashes when only arrays of strings are allowed" do
81
+ begin
82
+ post :create, :o => { "0" => { "x" => "foo" } }
83
+ raise "should fail"
84
+ rescue ParamAccessible::Error => e
85
+ e.inaccessible_params.should == %w(o[0][x])
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe RegexController do
4
+ include RSpec::Rails::ControllerExampleGroup
5
+
6
+ it "should allow base parameters matching a regex" do
7
+ post :create, :foo => 'hi', :foobar => 'hey'
8
+ response.code.should == '200'
9
+ end
10
+
11
+ it "should not allow base parameters not matching a regex" do
12
+ begin
13
+ post :create, :nuts => "hi"
14
+ raise "should fail"
15
+ rescue ParamAccessible::Error => e
16
+ e.inaccessible_params.should == %w(nuts)
17
+ end
18
+ end
19
+
20
+ it "should allow nested parameters matching the regex" do
21
+ post :create, :user => {:bar => 'hi', :bar_me => 'hey'}
22
+ response.code.should == '200'
23
+ end
24
+
25
+ it "should not allow nested parameters not matching a regex" do
26
+ begin
27
+ post :create, :user => {:nuts => "hi"}
28
+ raise "should fail"
29
+ rescue ParamAccessible::Error => e
30
+ e.inaccessible_params.should == %w(user[nuts])
31
+ end
32
+ end
33
+
34
+ end
@@ -8,6 +8,11 @@ describe SimpleController do
8
8
  response.code.should == "200"
9
9
  end
10
10
 
11
+ it "should not complain about common rails parameters" do
12
+ post :update, :format => "json", :id => "foo"
13
+ response.code.should == "200"
14
+ end
15
+
11
16
  it "should not complain if a subset of those attributes are given" do
12
17
  post :create, :foo => 'hi'
13
18
  response.code.should == "200"
@@ -40,12 +45,7 @@ describe SimpleController do
40
45
  e.inaccessible_params.should == %w(bar[unknown])
41
46
  end
42
47
  end
43
-
44
- it "should handle nested arrays" do
45
- post :create, :bar => [:baz => 'hi']
46
- response.code.should == '200'
47
- end
48
-
48
+
49
49
  it "should be fine when the ONLY value is a value but not an options hash" do
50
50
  SimpleController.param_accessible :bar => []
51
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: param_accessible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-15 00:00:00.000000000 Z
12
+ date: 2012-06-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &177970 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *177970
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: actionpack
27
- requirement: &177640 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: 3.0.0
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *177640
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rails
38
- requirement: &177410 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: 3.0.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *177410
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: rspec-rails
49
- requirement: &177110 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: '0'
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *177110
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: simplecov
60
- requirement: &176790 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,7 +85,12 @@ dependencies:
65
85
  version: '0'
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *176790
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
69
94
  description: Help secure your controllers from malicious parameters
70
95
  email:
71
96
  - dan@topdan.com
@@ -92,8 +117,10 @@ files:
92
117
  - spec/app_root/app/controllers/if_false_controller.rb
93
118
  - spec/app_root/app/controllers/if_true_controller.rb
94
119
  - spec/app_root/app/controllers/merge_controller.rb
120
+ - spec/app_root/app/controllers/nested_controller.rb
95
121
  - spec/app_root/app/controllers/not_acceptable_controller.rb
96
122
  - spec/app_root/app/controllers/only_controller.rb
123
+ - spec/app_root/app/controllers/regex_controller.rb
97
124
  - spec/app_root/app/controllers/simple_controller.rb
98
125
  - spec/app_root/app/controllers/unless_false_controller.rb
99
126
  - spec/app_root/app/controllers/unless_true_controller.rb
@@ -104,8 +131,10 @@ files:
104
131
  - spec/lib/if_false_spec.rb
105
132
  - spec/lib/if_true_spec.rb
106
133
  - spec/lib/merge_spec.rb
134
+ - spec/lib/nested_spec.rb
107
135
  - spec/lib/not_acceptable_helper_spec.rb
108
136
  - spec/lib/only_spec.rb
137
+ - spec/lib/regex_spec.rb
109
138
  - spec/lib/simple_spec.rb
110
139
  - spec/lib/unless_false_spec.rb
111
140
  - spec/lib/unless_true_spec.rb
@@ -122,15 +151,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
151
  - - ! '>='
123
152
  - !ruby/object:Gem::Version
124
153
  version: '0'
154
+ segments:
155
+ - 0
156
+ hash: -3120574609072739979
125
157
  required_rubygems_version: !ruby/object:Gem::Requirement
126
158
  none: false
127
159
  requirements:
128
160
  - - ! '>='
129
161
  - !ruby/object:Gem::Version
130
162
  version: '0'
163
+ segments:
164
+ - 0
165
+ hash: -3120574609072739979
131
166
  requirements: []
132
167
  rubyforge_project:
133
- rubygems_version: 1.8.10
168
+ rubygems_version: 1.8.24
134
169
  signing_key:
135
170
  specification_version: 3
136
171
  summary: Help secure your controllers from malicious parameters
@@ -140,8 +175,10 @@ test_files:
140
175
  - spec/app_root/app/controllers/if_false_controller.rb
141
176
  - spec/app_root/app/controllers/if_true_controller.rb
142
177
  - spec/app_root/app/controllers/merge_controller.rb
178
+ - spec/app_root/app/controllers/nested_controller.rb
143
179
  - spec/app_root/app/controllers/not_acceptable_controller.rb
144
180
  - spec/app_root/app/controllers/only_controller.rb
181
+ - spec/app_root/app/controllers/regex_controller.rb
145
182
  - spec/app_root/app/controllers/simple_controller.rb
146
183
  - spec/app_root/app/controllers/unless_false_controller.rb
147
184
  - spec/app_root/app/controllers/unless_true_controller.rb
@@ -152,8 +189,10 @@ test_files:
152
189
  - spec/lib/if_false_spec.rb
153
190
  - spec/lib/if_true_spec.rb
154
191
  - spec/lib/merge_spec.rb
192
+ - spec/lib/nested_spec.rb
155
193
  - spec/lib/not_acceptable_helper_spec.rb
156
194
  - spec/lib/only_spec.rb
195
+ - spec/lib/regex_spec.rb
157
196
  - spec/lib/simple_spec.rb
158
197
  - spec/lib/unless_false_spec.rb
159
198
  - spec/lib/unless_true_spec.rb