protected_attributes 1.0.9 → 1.1.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.
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')