protected_attributes 1.0.9 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07a8c210afe27e08b760e2f61b86a60c6980ec1a
4
- data.tar.gz: cb8ef9666fc6b0a73161f1d06a0cfd097edfc7cd
3
+ metadata.gz: 395ab272536df136e316a89087b094b773f6be7b
4
+ data.tar.gz: 279387fed8cec2a444b8a279c64d78aa6c3d876e
5
5
  SHA512:
6
- metadata.gz: c6c29a159034c283fd0e77c2b5ddf1469655bce17916e801668d01e8e104c6e4142621c01c75966f0333413c0d7e7179b8c22aa4bf8a03966f0a71334850316b
7
- data.tar.gz: d9e314e1e6b925ba6a34fb68b813999c1ffa00d29e4b32ca59eb8f523e35102d5c3098606410ae5cd702756737a1f0bacfa3d3e6b2d6ac01c1388c1bd42df771
6
+ metadata.gz: a034a1aae746c4d3c942e96d8201010fc5654ae4487547b64a67fee0f2e907321978d6af68050b34fc033e01598d2e579b661e03ae4f5d19d20253f7d3316db8
7
+ data.tar.gz: d114248044437b7da5d9760d07468b9d4670aeaff2654c0042d3f76e1c16fa1305016d8d5680402351a72dd17b6e067ede82e3696614f22021d54fcc532d792f
data/README.md CHANGED
@@ -75,13 +75,13 @@ In a similar way, `new`, `create`, `create!`, `update_attributes` and `update_at
75
75
  @user.name # => Sebastian
76
76
  @user.is_admin # => true
77
77
  ```
78
- A more paranoid technique to protect your whole project would be to enforce that all models define their accessible attributes.
79
- This can be easily achieved with a very simple application config option of:
78
+ By default the gem will create an empty whitelist of attributes available for mass-assignment for all models in your app.
79
+ As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an `attr_accessible` or `attr_protected` declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via `attr_accessible` or `attr_protected`), as dictated by your failing test.
80
+
81
+ This option can be turned off using a configuration option:
80
82
  ```ruby
81
- config.active_record.whitelist_attributes = true
83
+ config.active_record.whitelist_attributes = false
82
84
  ```
83
- This will create an empty whitelist of attributes available for mass-assignment for all models in your app.
84
- As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an `attr_accessible` or `attr_protected` declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via `attr_accessible` or `attr_protected`), as dictated by your failing test.
85
85
 
86
86
  For more complex permissions, mass-assignment security may be handled outside the model by extending a non-ActiveRecord class, such as a controller, with this behavior.
87
87
 
@@ -50,11 +50,14 @@ module ActiveModel
50
50
  # example implementation.
51
51
  module MassAssignmentSecurity
52
52
  extend ActiveSupport::Concern
53
+ include ActiveModel::ForbiddenAttributesProtection
53
54
 
54
55
  included do
55
56
  class_attribute :_accessible_attributes, instance_writer: false
56
57
  class_attribute :_protected_attributes, instance_writer: false
57
58
  class_attribute :_active_authorizer, instance_writer: false
59
+ class_attribute :_uses_mass_assignment_security, instance_writer: false
60
+ self._uses_mass_assignment_security = false
58
61
 
59
62
  class_attribute :_mass_assignment_sanitizer, instance_writer: false
60
63
  self.mass_assignment_sanitizer = :logger
@@ -123,6 +126,7 @@ module ActiveModel
123
126
  self._protected_attributes[name] = self.protected_attributes(name) + args
124
127
  end
125
128
 
129
+ self._uses_mass_assignment_security = true
126
130
  self._active_authorizer = self._protected_attributes
127
131
  end
128
132
 
@@ -189,6 +193,7 @@ module ActiveModel
189
193
  self._accessible_attributes[name] = self.accessible_attributes(name) + args
190
194
  end
191
195
 
196
+ self._uses_mass_assignment_security = true
192
197
  self._active_authorizer = self._accessible_attributes
193
198
  end
194
199
 
@@ -343,6 +348,10 @@ module ActiveModel
343
348
  protected
344
349
 
345
350
  def sanitize_for_mass_assignment(attributes, role = nil) #:nodoc:
351
+ unless _uses_mass_assignment_security
352
+ sanitize_forbidden_attributes(attributes)
353
+ end
354
+
346
355
  _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
347
356
  end
348
357
 
@@ -1,3 +1,3 @@
1
1
  module ProtectedAttributes
2
- VERSION = "1.0.9"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protected_attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-16 00:00:00.000000000 Z
11
+ date: 2015-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -144,29 +144,6 @@ files:
144
144
  - lib/protected_attributes.rb
145
145
  - lib/protected_attributes/railtie.rb
146
146
  - lib/protected_attributes/version.rb
147
- - test/abstract_unit.rb
148
- - test/accessible_params_wrapper_test.rb
149
- - test/ar_helper.rb
150
- - test/attribute_sanitization_test.rb
151
- - test/mass_assignment_security/black_list_test.rb
152
- - test/mass_assignment_security/permission_set_test.rb
153
- - test/mass_assignment_security/sanitizer_test.rb
154
- - test/mass_assignment_security/white_list_test.rb
155
- - test/mass_assignment_security_test.rb
156
- - test/models/battle.rb
157
- - test/models/company.rb
158
- - test/models/group.rb
159
- - test/models/keyboard.rb
160
- - test/models/mass_assignment_specific.rb
161
- - test/models/membership.rb
162
- - test/models/person.rb
163
- - test/models/pirate.rb
164
- - test/models/subscriber.rb
165
- - test/models/task.rb
166
- - test/models/team.rb
167
- - test/models/vampire.rb
168
- - test/models/wolf.rb
169
- - test/test_helper.rb
170
147
  homepage: https://github.com/rails/protected_attributes
171
148
  licenses:
172
149
  - MIT
@@ -191,27 +168,4 @@ rubygems_version: 2.4.5
191
168
  signing_key:
192
169
  specification_version: 4
193
170
  summary: Protect attributes from mass assignment in Active Record models
194
- test_files:
195
- - test/abstract_unit.rb
196
- - test/accessible_params_wrapper_test.rb
197
- - test/ar_helper.rb
198
- - test/attribute_sanitization_test.rb
199
- - test/mass_assignment_security/black_list_test.rb
200
- - test/mass_assignment_security/permission_set_test.rb
201
- - test/mass_assignment_security/sanitizer_test.rb
202
- - test/mass_assignment_security/white_list_test.rb
203
- - test/mass_assignment_security_test.rb
204
- - test/models/battle.rb
205
- - test/models/company.rb
206
- - test/models/group.rb
207
- - test/models/keyboard.rb
208
- - test/models/mass_assignment_specific.rb
209
- - test/models/membership.rb
210
- - test/models/person.rb
211
- - test/models/pirate.rb
212
- - test/models/subscriber.rb
213
- - test/models/task.rb
214
- - test/models/team.rb
215
- - test/models/vampire.rb
216
- - test/models/wolf.rb
217
- - test/test_helper.rb
171
+ test_files: []
@@ -1,165 +0,0 @@
1
- require 'action_dispatch'
2
- require 'action_controller'
3
- require 'active_support/dependencies'
4
-
5
- def active_support_4_0?
6
- ActiveSupport::VERSION::MAJOR == 4 && ActiveSupport::VERSION::MINOR == 0
7
- end
8
-
9
- if active_support_4_0?
10
- require 'active_support/core_ext/class/attribute_accessors'
11
- else
12
- require 'active_support/core_ext/module/attribute_accessors'
13
- end
14
-
15
- module SetupOnce
16
- extend ActiveSupport::Concern
17
-
18
- included do
19
- cattr_accessor :setup_once_block
20
- self.setup_once_block = nil
21
-
22
- setup :run_setup_once
23
- end
24
-
25
- module ClassMethods
26
- def setup_once(&block)
27
- self.setup_once_block = block
28
- end
29
- end
30
-
31
- private
32
- def run_setup_once
33
- if self.setup_once_block
34
- self.setup_once_block.call
35
- self.setup_once_block = nil
36
- end
37
- end
38
- end
39
-
40
- SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
41
-
42
- module ActiveSupport
43
- class TestCase
44
- include SetupOnce
45
- # Hold off drawing routes until all the possible controller classes
46
- # have been loaded.
47
- setup_once do
48
- SharedTestRoutes.draw do
49
- get ':controller(/:action)'
50
- end
51
-
52
- ActionDispatch::IntegrationTest.app.routes.draw do
53
- get ':controller(/:action)'
54
- end
55
- end
56
- end
57
- end
58
-
59
- class RoutedRackApp
60
- attr_reader :routes
61
-
62
- def initialize(routes, &blk)
63
- @routes = routes
64
- @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
65
- end
66
-
67
- def call(env)
68
- @stack.call(env)
69
- end
70
- end
71
-
72
- class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
73
- setup do
74
- @routes = SharedTestRoutes
75
- end
76
-
77
- def self.build_app(routes = nil)
78
- RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
79
- middleware.use "ActionDispatch::DebugExceptions"
80
- middleware.use "ActionDispatch::Callbacks"
81
- middleware.use "ActionDispatch::ParamsParser"
82
- middleware.use "ActionDispatch::Cookies"
83
- middleware.use "ActionDispatch::Flash"
84
- middleware.use "Rack::Head"
85
- yield(middleware) if block_given?
86
- end
87
- end
88
-
89
- self.app = build_app
90
-
91
- # Stub Rails dispatcher so it does not get controller references and
92
- # simply return the controller#action as Rack::Body.
93
- class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
94
- protected
95
- def controller_reference(controller_param)
96
- controller_param
97
- end
98
-
99
- def dispatch(controller, action, env)
100
- [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
101
- end
102
- end
103
-
104
- def self.stub_controllers
105
- old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
106
- ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
107
- ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
108
- yield ActionDispatch::Routing::RouteSet.new
109
- ensure
110
- ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
111
- ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
112
- end
113
-
114
- def with_routing(&block)
115
- temporary_routes = ActionDispatch::Routing::RouteSet.new
116
- old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
117
- old_routes = SharedTestRoutes
118
- silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
119
-
120
- yield temporary_routes
121
- ensure
122
- self.class.app = old_app
123
- silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
124
- end
125
-
126
- def with_autoload_path(path)
127
- path = File.join(File.dirname(__FILE__), "fixtures", path)
128
- if ActiveSupport::Dependencies.autoload_paths.include?(path)
129
- yield
130
- else
131
- begin
132
- ActiveSupport::Dependencies.autoload_paths << path
133
- yield
134
- ensure
135
- ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
136
- ActiveSupport::Dependencies.clear
137
- end
138
- end
139
- end
140
- end
141
-
142
- module ActionController
143
- class Base
144
- include ActionController::Testing
145
- # This stub emulates the Railtie including the URL helpers from a Rails application
146
- include SharedTestRoutes.url_helpers
147
- include SharedTestRoutes.mounted_helpers
148
-
149
- #self.view_paths = FIXTURE_LOAD_PATH
150
-
151
- def self.test_routes(&block)
152
- routes = ActionDispatch::Routing::RouteSet.new
153
- routes.draw(&block)
154
- include routes.url_helpers
155
- end
156
- end
157
-
158
- class TestCase
159
- include ActionDispatch::TestProcess
160
-
161
- setup do
162
- @routes = SharedTestRoutes
163
- end
164
- end
165
- end
@@ -1,76 +0,0 @@
1
- require 'test_helper'
2
- require 'abstract_unit'
3
- require 'action_controller/accessible_params_wrapper'
4
-
5
- module ParamsWrapperTestHelp
6
- def with_default_wrapper_options(&block)
7
- @controller.class._set_wrapper_options({:format => [:json]})
8
- @controller.class.inherited(@controller.class)
9
- yield
10
- end
11
-
12
- def assert_parameters(expected)
13
- assert_equal expected, self.class.controller_class.last_parameters
14
- end
15
- end
16
-
17
- class AccessibleParamsWrapperTest < ActionController::TestCase
18
- include ParamsWrapperTestHelp
19
-
20
- class UsersController < ActionController::Base
21
- class << self
22
- attr_accessor :last_parameters
23
- end
24
-
25
- def parse
26
- self.class.last_parameters = request.params.except(:controller, :action)
27
- head :ok
28
- end
29
- end
30
-
31
- class User; end
32
- class Person; end
33
-
34
- tests UsersController
35
-
36
- def teardown
37
- UsersController.last_parameters = nil
38
- end
39
-
40
- def test_derived_wrapped_keys_from_matching_model
41
- User.expects(:respond_to?).with(:accessible_attributes).returns(false)
42
- User.expects(:respond_to?).with(:attribute_names).returns(true)
43
- User.expects(:attribute_names).twice.returns(["username"])
44
-
45
- with_default_wrapper_options do
46
- @request.env['CONTENT_TYPE'] = 'application/json'
47
- post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
48
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
49
- end
50
- end
51
-
52
- def test_derived_wrapped_keys_from_specified_model
53
- with_default_wrapper_options do
54
- Person.expects(:respond_to?).with(:accessible_attributes).returns(false)
55
- Person.expects(:respond_to?).with(:attribute_names).returns(true)
56
- Person.expects(:attribute_names).twice.returns(["username"])
57
-
58
- UsersController.wrap_parameters Person
59
-
60
- @request.env['CONTENT_TYPE'] = 'application/json'
61
- post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
62
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }})
63
- end
64
- end
65
-
66
- def test_accessible_wrapped_keys_from_matching_model
67
- User.expects(:respond_to?).with(:accessible_attributes).returns(true)
68
- User.expects(:accessible_attributes).with(:default).twice.returns(["username"])
69
-
70
- with_default_wrapper_options do
71
- @request.env['CONTENT_TYPE'] = 'application/json'
72
- post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
73
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
74
- end
75
- end
76
- end
@@ -1,74 +0,0 @@
1
- require 'active_record'
2
-
3
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
4
-
5
- ActiveRecord::Schema.verbose = false
6
- ActiveRecord::Schema.define do
7
- create_table :accounts, :force => true do |t|
8
- t.integer :firm_id
9
- t.string :firm_name
10
- t.integer :credit_limit
11
- end
12
-
13
- create_table :companies, :force => true do |t|
14
- t.string :type
15
- t.integer :firm_id
16
- t.string :firm_name
17
- t.string :name
18
- t.integer :client_of
19
- t.integer :rating, :default => 1
20
- t.integer :account_id
21
- t.string :description, :default => ""
22
- end
23
-
24
- add_index :companies, [:firm_id, :type, :rating], :name => "company_index"
25
- add_index :companies, [:firm_id, :type], :name => "company_partial_index", :where => "rating > 10"
26
-
27
- create_table :keyboards, :force => true, :id => false do |t|
28
- t.primary_key :key_number
29
- t.string :name
30
- end
31
-
32
- create_table :people, :force => true do |t|
33
- t.string :first_name, :null => false
34
- t.string :gender, :limit => 1
35
- t.string :comments
36
- t.references :best_friend
37
- t.references :best_friend_of
38
- t.timestamps
39
- end
40
-
41
- create_table :subscribers, :force => true, :id => false do |t|
42
- t.string :nick, :null => false
43
- t.string :name
44
- end
45
- add_index :subscribers, :nick, :unique => true
46
-
47
- create_table :tasks, :force => true do |t|
48
- t.datetime :starting
49
- t.datetime :ending
50
- end
51
-
52
- create_table :pirates, :force => true do |t|
53
- t.string :name
54
- end
55
-
56
- create_table :groups, :force => true do |t|
57
- end
58
-
59
- create_table :memberships, :force => true do |t|
60
- t.integer "group_id"
61
- t.integer "pirate_id"
62
- end
63
-
64
- create_table :teams, :force => true
65
- create_table :wolves, :force => true
66
- create_table :vampires, :force => true
67
- create_table :battles, :force => true do |t|
68
- t.integer "team_id"
69
- t.integer "battle_id"
70
- t.string "battle_type"
71
- end
72
- end
73
-
74
- QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type')