protected_attributes_continued 1.4.0 → 1.8.1

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
  SHA256:
3
- metadata.gz: 8e01eccbad4a21cdd10334379dc742f0edc97dd8a6b99b03e8d1e105d5a159a4
4
- data.tar.gz: e41d9f31ea96a9ed1edbc30063ac258f820452554d64d58f6ce0e2945027e74c
3
+ metadata.gz: 5e881236bacf8378d98f06eb98269417a5082383de65360f522e524062fbcdfb
4
+ data.tar.gz: 45f598ce1954ed9542934e676af3ac8f53e6b5c6dea2c35e87b3100721d2522a
5
5
  SHA512:
6
- metadata.gz: 9317411a772594accc0cbc59ca0c07a755b58f1b0c1b6553d5843cb37b6e7f3ec0defb4b5e84686a8564fafff6bb43cd803768fe230dd8b990ee236aa1281620
7
- data.tar.gz: 608d732479681ce5d90a231e8f44862e54a7cb0a6ce323088c90f6dc22b52eaa85a0a7e471ee5cbe8979d6514f9f45be3fb6533a4def88dfcd2ae8a12a1ca13c
6
+ metadata.gz: 30fb108c2db47feeb17c7787dc1427a44e93b7ac47450d79f20d59a3bf814d3f8314eb42ee71a76bd3e1f54dbec508d56e917ab0f57d5a6c7c7e5a68a4ac2d8d
7
+ data.tar.gz: '0486645654d15f177a2ba9abd27069c598b9d08884a7beb4db9d7813ce79604265d0eab9263f937aa0957c963cbd66dc435d4628993381793789068d04d0573b'
data/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # Protected Attributes Continued
2
2
  <a href="https://badge.fury.io/rb/protected_attributes_continued" target="_blank"><img height="21" style='border:0px;height:21px;' border='0' src="https://badge.fury.io/rb/protected_attributes_continued.svg" alt="Gem Version"></a>
3
- <a href='https://travis-ci.org/westonganger/protected_attributes_continued' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://api.travis-ci.org/westonganger/protected_attributes_continued.svg?branch=master' border='0' alt='Build Status' /></a>
3
+ <a href='https://github.com/westonganger/protected_attributes_continued/actions' target='_blank'><img src="https://github.com/westonganger/protected_attributes_continued/workflows/Tests/badge.svg" style="max-width:100%;" height='21' style='border:0px;height:21px;' border='0' alt="CI Status"></a>
4
4
  <a href='https://rubygems.org/gems/protected_attributes_continued' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://ruby-gem-downloads-badge.herokuapp.com/protected_attributes_continued?label=rubygems&type=total&total_label=downloads&color=brightgreen' border='0' alt='RubyGems Downloads' /></a>
5
5
 
6
- This is the community continued version of `protected_attributes`. It works with Rails 5+ only and I recommend you only use it to support legacy portions of your application that you do not want to upgrade. Note that this feature was dropped by the Rails team and switched to strong_parameters because of security issues, just so you understand your risks. This is in use successfully in some of my Rails 5 apps in which security like this is a non-issue. For people who would like to continue using this feature in their Rails 5 apps lets continue the work here. If you are looking for a similar approach see my [recommended alternative](https://github.com/westonganger/protected_attributes_continued#a-better-alternative)
6
+ > This is the community continued version of [`protected_attributes`](https://github.com/rails/protected_attributes) for Rails 5+. The Rails team dropped this feature and switched to `strong_parameters`. However some applications simply cannot be upgraded or the reduced granularity in params management is a non-issue. To continue supporting this feature going forward we continue the work here.
7
7
 
8
- Protect attributes from mass-assignment in Active Record models.
9
-
10
- This plugin adds the class methods `attr_accessible` and `attr_protected` to your models to be able to declare white or black lists of attributes.
8
+ Protect attributes from mass-assignment in Active Record models. This gem adds the class methods `attr_accessible` and `attr_protected` to declare white or black lists of attributes.
11
9
 
12
10
 
13
11
  ## Installation
@@ -98,10 +96,11 @@ config.active_record.mass_assignment_sanitizer = :strict
98
96
 
99
97
  Any protected attributes violation raises `ActiveModel::MassAssignmentSecurity::Error` then.
100
98
 
101
-
102
99
  ## Contributing
103
100
 
104
- We use the `appraisal` gem for testing multiple versions of `Rails`. Please use the following steps to test using `appraisal`.
101
+ For quicker feedback during gem development or debugging feel free to use the provided `rake console` task. It is defined within the [`Rakefile`](./Rakefile).
102
+
103
+ We test multiple versions of `Rails` using the `appraisal` gem. Please use the following steps to test using `appraisal`.
105
104
 
106
105
  1. `bundle exec appraisal install`
107
106
  2. `bundle exec appraisal rake test`
@@ -110,27 +109,41 @@ We use the `appraisal` gem for testing multiple versions of `Rails`. Please use
110
109
 
111
110
  Created & Maintained by [Weston Ganger](https://westonganger.com) - [@westonganger](https://github.com/westonganger)
112
111
 
113
- Originally forked from the dead/unmaintained `protected_attributes` gem by the Rails team.
112
+ Originally forked from the dead/unmaintained [`protected_attributes`](https://github.com/rails/protected_attributes) gem by the Rails team.
114
113
 
115
- ## A Better Alternative
114
+ ## A Simple and Similar strong_params Alternative
116
115
 
117
- While I do utilize this gem in some legacy projects I have adopted an alternative approach that is similar to this gem but only utilizes Rails built-in `strong_params` which is a much more future proof way of doing things. See the following example for how to implement.
116
+ While I do utilize this gem in some legacy projects. The latest approach I have adopted is similar to this gem but only utilizes Rails built-in `strong_params` which is a much more future proof way of doing things. The following is an example implementation.
118
117
 
119
118
  ```ruby
119
+ ### Model
120
120
  class Post < ActiveRecord::Base
121
+ has_many :comments
121
122
 
123
+ accepts_nested_attributes_for :comments, allow_destroy: true
124
+
122
125
  def self.strong_params(params)
123
- params.permit(:post).permit(:name, :content, :published_at)
126
+ params.permit(:post).permit(*PERMITTED_ATTRIBUTES)
124
127
  end
125
-
128
+
129
+ PERMITTED_PARAMETERS = [
130
+ :id,
131
+ :name,
132
+ :content,
133
+ :published_at,
134
+ {
135
+ comments_attributes: Comment::PERMITTED_PARAMETERS,
136
+ }
137
+ ].freeze
138
+
126
139
  end
127
140
 
141
+ ### Controller
128
142
  class PostsController < ApplicationController
129
-
130
143
  def create
131
- @post = Post.new
132
-
133
- @post.assign_attributes(Post.strong_params(params))
144
+ @post = Post.new(Post.strong_params(params))
145
+
146
+ @post.save
134
147
 
135
148
  respond_with @post
136
149
  end
@@ -142,6 +155,5 @@ class PostsController < ApplicationController
142
155
 
143
156
  respond_with @post
144
157
  end
145
-
146
158
  end
147
159
  ```
@@ -7,6 +7,7 @@ require "active_record/mass_assignment_security/nested_attributes"
7
7
  require "active_record/mass_assignment_security/persistence"
8
8
  require "active_record/mass_assignment_security/reflection"
9
9
  require "active_record/mass_assignment_security/relation"
10
+ require "active_record/mass_assignment_security/association_relation"
10
11
  require "active_record/mass_assignment_security/validations"
11
12
  require "active_record/mass_assignment_security/associations"
12
13
  require "active_record/mass_assignment_security/inheritance"
@@ -0,0 +1,45 @@
1
+ module ActiveRecord
2
+ class AssociationRelation
3
+ undef :new
4
+ undef :create
5
+ undef :create!
6
+
7
+ def build(attributes = nil, options = {}, &block)
8
+ block = protected_attributes_scope_block('new', block)
9
+ scoping { @association.build(attributes, options, &block) }
10
+ end
11
+ alias new build
12
+
13
+ def create(attributes = nil, options = {}, &block)
14
+ block = protected_attributes_scope_block('create', block)
15
+ scoping { @association.create(attributes, options, &block) }
16
+ end
17
+
18
+ def create!(attributes = nil, options = {}, &block)
19
+ block = protected_attributes_scope_block('create!', block)
20
+ scoping { @association.create!(attributes, options, &block) }
21
+ end
22
+
23
+ private
24
+
25
+ if ActiveRecord.gem_version < Gem::Version.new('6.0')
26
+
27
+ def protected_attributes_scope_block(_label, block)
28
+ block
29
+ end
30
+
31
+ elsif ActiveRecord.gem_version < Gem::Version.new('6.1')
32
+
33
+ def protected_attributes_scope_block(label, block)
34
+ _deprecated_scope_block(label, &block)
35
+ end
36
+
37
+ else
38
+
39
+ def protected_attributes_scope_block(_label, block)
40
+ current_scope_restoring_block(&block)
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -1,3 +1,5 @@
1
+ ### Original Rails Code - https://github.com/rails/rails/tree/master/activerecord/lib/active_record/associations
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class Association
@@ -10,7 +12,6 @@ module ActiveRecord
10
12
  record.assign_attributes(attributes, without_protection: true)
11
13
  end
12
14
  end
13
-
14
15
  private :build_record
15
16
  end
16
17
 
@@ -53,7 +54,6 @@ module ActiveRecord
53
54
  end
54
55
  end
55
56
  end
56
-
57
57
  private :create_record
58
58
  end
59
59
 
@@ -76,26 +76,41 @@ module ActiveRecord
76
76
  end
77
77
 
78
78
  module ThroughAssociation
79
- undef :build_record if respond_to?(:build_record, false)
79
+ ### Cant use respond_to?(method, true) because its a module instead of a class
80
+ undef :build_record if self.private_instance_methods.include?(:build_record)
81
+ def build_record(attributes, options={})
82
+ inverse = source_reflection.inverse_of
83
+ target = through_association.target
80
84
 
81
- private
85
+ if inverse && target && !target.is_a?(Array)
86
+ attributes[inverse.foreign_key] = target.id
87
+ end
82
88
 
83
- def build_record(attributes, options={})
84
- inverse = source_reflection.inverse_of
85
- target = through_association.target
89
+ super(attributes, options)
90
+ end
91
+ private :build_record
92
+ end
86
93
 
87
- if inverse && target && !target.is_a?(Array)
88
- attributes[inverse.foreign_key] = target.id
94
+ class HasManyThroughAssociation
95
+ if ActiveRecord.version >= Gem::Version.new('5.2.3')
96
+ undef :build_through_record
97
+ def build_through_record(record)
98
+ @through_records[record.object_id] ||= begin
99
+ ensure_mutable
100
+
101
+ attributes = through_scope_attributes
102
+ attributes[source_reflection.name] = record
103
+ attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
104
+
105
+ # Pass in `without_protection: true` here because `options_for_through_record`
106
+ # was removed in https://github.com/rails/rails/pull/35799
107
+ through_association.build(attributes, without_protection: true)
89
108
  end
90
-
91
- super(attributes, options)
92
109
  end
93
- end
110
+ private :build_through_record
111
+ end
94
112
 
95
- class HasManyThroughAssociation
96
113
  undef :build_record
97
- undef :options_for_through_record if respond_to?(:options_for_through_record, false)
98
-
99
114
  def build_record(attributes, options = {})
100
115
  ensure_not_nested
101
116
 
@@ -114,6 +129,7 @@ module ActiveRecord
114
129
  end
115
130
  private :build_record
116
131
 
132
+ undef :options_for_through_record if respond_to?(:options_for_through_record, true)
117
133
  def options_for_through_record
118
134
  [through_scope_attributes, without_protection: true]
119
135
  end
@@ -12,9 +12,17 @@ module ActiveRecord
12
12
 
13
13
  # The primary key and inheritance column can never be set by mass-assignment for security reasons.
14
14
  def attributes_protected_by_default
15
- default = [ primary_key, inheritance_column ]
16
- default << 'id' unless primary_key.eql? 'id'
17
- default
15
+ begin
16
+ default = [primary_key, inheritance_column]
17
+
18
+ if !primary_key.eql?('id')
19
+ default << 'id'
20
+ end
21
+ rescue ActiveRecord::NoDatabaseError
22
+ default = []
23
+ end
24
+
25
+ return default
18
26
  end
19
27
  end
20
28
 
@@ -3,6 +3,7 @@ module ActiveRecord
3
3
  module Core
4
4
 
5
5
  def initialize(attributes = nil, options = {})
6
+ @new_record = true
6
7
  self.class.define_attribute_methods
7
8
  @attributes = self.class._default_attributes.deep_dup
8
9
 
@@ -54,6 +54,7 @@ module ActiveRecord
54
54
 
55
55
  def assign_nested_attributes_for_one_to_one_association(association_name, attributes, assignment_opts = {})
56
56
  options = self.nested_attributes_options[association_name]
57
+
57
58
  if attributes.class.name == 'ActionController::Parameters'
58
59
  attributes = attributes.to_unsafe_h
59
60
  elsif !attributes.is_a?(Hash) && !attributes.is_a?(Array)
@@ -62,8 +63,7 @@ module ActiveRecord
62
63
 
63
64
  attributes = attributes.with_indifferent_access
64
65
 
65
- if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) &&
66
- (options[:update_only] || record.id.to_s == attributes['id'].to_s)
66
+ if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) && (options[:update_only] || record.id.to_s == attributes['id'].to_s)
67
67
  assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy], assignment_opts) unless call_reject_if(association_name, attributes)
68
68
 
69
69
  elsif attributes['id'].present? && !assignment_opts[:without_protection]
@@ -122,6 +122,12 @@ module ActiveRecord
122
122
  end
123
123
 
124
124
  attributes_collection.each do |attributes|
125
+ if attributes.class.name == 'ActionController::Parameters'
126
+ attributes = attributes.to_unsafe_h
127
+ elsif !attributes.is_a?(Hash) && !attributes.is_a?(Array)
128
+ raise ArgumentError, "ActionController::Parameters or Hash or Array expected, got #{attributes.class.name} (#{attributes.inspect})"
129
+ end
130
+
125
131
  attributes = attributes.with_indifferent_access
126
132
 
127
133
  if attributes['id'].blank?
@@ -1,3 +1,3 @@
1
1
  module ProtectedAttributes
2
- VERSION = "1.4.0"
2
+ VERSION = "1.8.1".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protected_attributes_continued
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Weston Ganger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-28 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '5.0'
69
- - !ruby/object:Gem::Dependency
70
- name: sqlite3
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: mocha
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +108,7 @@ files:
122
108
  - lib/active_model/mass_assignment_security/permission_set.rb
123
109
  - lib/active_model/mass_assignment_security/sanitizer.rb
124
110
  - lib/active_record/mass_assignment_security.rb
111
+ - lib/active_record/mass_assignment_security/association_relation.rb
125
112
  - lib/active_record/mass_assignment_security/associations.rb
126
113
  - lib/active_record/mass_assignment_security/attribute_assignment.rb
127
114
  - lib/active_record/mass_assignment_security/core.rb
@@ -154,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
141
  - !ruby/object:Gem::Version
155
142
  version: '0'
156
143
  requirements: []
157
- rubygems_version: 3.0.1
144
+ rubygems_version: 3.1.2
158
145
  signing_key:
159
146
  specification_version: 4
160
147
  summary: Protect attributes from mass assignment in Active Record models