stronger_parameters 2.7.0 → 2.8.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: 44698724e39acaded3b387e94f5c2c6e83b88555
4
- data.tar.gz: 49aa2b14a5d4d9348c92e79c58310552e1dcdddc
3
+ metadata.gz: 0765498e474bdda1bbd86952faeb949bb8dee68d
4
+ data.tar.gz: 552b525dd274336986326681a21a334139bfbb25
5
5
  SHA512:
6
- metadata.gz: 98d2d44613d8c56f59e42143d344160ab4a7240cca977555e6576c7f391908d1b6e5e3c7ac7222f49eb8ced23095a370382dc47d5f76d186162ce9bbd6567bb3
7
- data.tar.gz: f83fb3b52e66157edb4a8d9c184d8e3b594d65d7285f3a355d3d9c93bd8c60f3a0464072795ac63e9bce25d59a152bf90edee491ee2d196dc8d5c5e8dd6a4b2d
6
+ metadata.gz: f1317839557a9579b3710b15c314de07a02766e6ac511a84ef3b98fe3dd8fe8dd5c00c442d3c952d67f0287cc57589944eac80e41fe2e2eaa27101f8bb612f06
7
+ data.tar.gz: 5abbe1cc2b805bf72ff355c4d79de711bb09c18aaa1a4e97aceaf13d4e7bfe8c321d890f7d118fcef69036fb19ee5613f86dce9cfa2065c7e1f5d6f6c47d8e74
data/README.md CHANGED
@@ -158,6 +158,68 @@ Just want to log violations in production:
158
158
  ActionController::Parameters.action_on_invalid_parameters = :log
159
159
  ```
160
160
 
161
+ ## Controller support (compatible with Rails 3 and 4, untested on Rails 5)
162
+
163
+ Include `PermittedParameters` into a controller to force the developer
164
+ to explicitly permit params for every action.
165
+
166
+ Examples:
167
+
168
+ ```ruby
169
+ class TestController < ApplicationController
170
+ include StrongerParameters::ControllerSupport::PermittedParameters
171
+
172
+ permitted_parameters :all, locale: Parameters.string # permit :locale in all actions for this controller
173
+
174
+ permitted_parameters :show, id: Parameters.integer
175
+ def show
176
+ end
177
+
178
+ permitted_parameters :create, topic: { forum: { id: Parameters.integer } }
179
+ def create
180
+ end
181
+
182
+ permitted_parameters :index, {} # no parameters permitted
183
+ def index
184
+ end
185
+
186
+ permitted_parameters :update, :anything # all parameters permitted, use when migrating old controllers/actions
187
+ def update
188
+ end
189
+ ```
190
+
191
+
192
+ ### Log only mode
193
+
194
+ Just want to log violations in production, let all params pass through:
195
+
196
+ ```ruby
197
+ class MyController < ApplicationController
198
+ log_unpermitted_parameters! if Rails.env.production? # Still want other environments to raise
199
+
200
+ permitted_parameters :update, user: { name: Parameters.string }
201
+ def update
202
+ end
203
+ end
204
+ ```
205
+
206
+ ### Notifying users about unpermitted params
207
+
208
+ Add headers to all requests that have unpermitted params:
209
+
210
+ ```Ruby
211
+ # config/application.rb
212
+ config.stronger_parameters_violation_header = 'X-StrongerParameters-API-Warn'
213
+ ```
214
+
215
+ ```shell
216
+ curl -I 'http://localhost/api/users/1.json' -X POST -d '{ "user": { "id": 1 } }'
217
+ => HTTP/1.1 200 OK
218
+ => ...
219
+ => X-StrongerParameters-API-Warn: Removed restricted keys ["user.id"] from parameters
220
+ ```
221
+
222
+
161
223
  ## Types
162
224
 
163
225
  | Syntax | (Simplified) Definition |
@@ -0,0 +1,159 @@
1
+ require 'stronger_parameters/constraints'
2
+
3
+ module StrongerParameters
4
+ module ControllerSupport
5
+ module PermittedParameters
6
+ def self.included(klass)
7
+ klass.extend ClassMethods
8
+ if klass.respond_to?(:before_action)
9
+ klass.before_action :permit_parameters
10
+ else
11
+ klass.before_filter :permit_parameters
12
+ end
13
+ end
14
+
15
+ class PermittedParametersHash < Hash
16
+ def initialize(other = nil)
17
+ super()
18
+ merge!(other) unless other.nil?
19
+ end
20
+
21
+ def merge!(other)
22
+ other.each do |key, value|
23
+ value = sugar(value)
24
+
25
+ if value.is_a?(StrongerParameters::Constraint)
26
+ self[key] = value
27
+ else
28
+ self[key] ||= self.class.new
29
+ self[key].merge!(value)
30
+ end
31
+ end
32
+
33
+ self
34
+ end
35
+
36
+ def merge(other)
37
+ dup.merge!(other)
38
+ end
39
+
40
+ private
41
+
42
+ def sugar(value)
43
+ case value
44
+ when Array
45
+ ActionController::Parameters.array(*value.map { |v| sugar(v) })
46
+ when Hash
47
+ constraints = value.each_with_object({}) do |(key, v), memo|
48
+ memo[key] = sugar(v)
49
+ end
50
+ ActionController::Parameters.map(constraints)
51
+ else
52
+ value
53
+ end
54
+ end
55
+ end
56
+
57
+ DEFAULT_PERMITTED = PermittedParametersHash.new(
58
+ controller: ActionController::Parameters.anything,
59
+ action: ActionController::Parameters.anything,
60
+ format: ActionController::Parameters.anything,
61
+ authenticity_token: ActionController::Parameters.string
62
+ )
63
+
64
+ module ClassMethods
65
+ def self.extended(base)
66
+ base.send :class_attribute, :log_unpermitted_parameters, instance_accessor: false
67
+ end
68
+
69
+ def log_unpermitted_parameters!
70
+ self.log_unpermitted_parameters = true
71
+ end
72
+
73
+ def permitted_parameters(action, permitted)
74
+ if permit_parameters[action] == :anything && permitted != :anything
75
+ raise ArgumentError, "#{self}/#{action} can not add to :anything"
76
+ end
77
+
78
+ permit_parameters.deep_merge!(action => permitted)
79
+ end
80
+
81
+ def permitted_parameters_for(action)
82
+ unless for_action = permit_parameters[action]
83
+ location = instance_method(action).source_location
84
+ raise KeyError, "Action #{action} for #{self} does not have any permitted parameters (#{location.join(":")})"
85
+ end
86
+ return :anything if for_action == :anything
87
+ permit_parameters[:all].merge(for_action)
88
+ end
89
+
90
+ private
91
+
92
+ def permit_parameters
93
+ @permit_parameters ||= if superclass.respond_to?(:permit_parameters, true)
94
+ superclass.send(:permit_parameters).deep_dup
95
+ else
96
+ { all: DEFAULT_PERMITTED.dup }
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def permit_parameters
104
+ action = params[:action].to_sym
105
+ permitted = self.class.permitted_parameters_for(action)
106
+
107
+ if permitted == :anything
108
+ Rails.logger.warn("#{params[:controller]}/#{params[:action]} does not filter parameters")
109
+ return
110
+ end
111
+
112
+ permitted_params = without_invalid_parameter_exceptions { params.permit(permitted) }
113
+ unpermitted_keys = flat_keys(params) - flat_keys(permitted_params)
114
+ log_unpermitted = self.class.log_unpermitted_parameters
115
+
116
+ show_unpermitted_keys(unpermitted_keys, log_unpermitted)
117
+
118
+ return if log_unpermitted
119
+
120
+ params.replace(permitted_params)
121
+ params.permit!
122
+ request.params.replace(permitted_params)
123
+
124
+ logged_params = request.send(:parameter_filter).filter(permitted_params) # Removing passwords, etc
125
+ Rails.logger.info(" Filtered Parameters: #{logged_params.inspect}")
126
+ end
127
+
128
+ def show_unpermitted_keys(unpermitted_keys, log_unpermitted)
129
+ return if unpermitted_keys.empty?
130
+
131
+ log_prefix = (log_unpermitted ? 'Found' : 'Removed')
132
+ message = "#{log_prefix} restricted keys #{unpermitted_keys.inspect} from parameters according to permitted list"
133
+
134
+ header = Rails.configuration.stronger_parameters_violation_header if Rails.configuration.respond_to?(:stronger_parameters_violation_header)
135
+ response.headers[header] = message if response && header
136
+
137
+ Rails.logger.info(" #{message}")
138
+ end
139
+
140
+ def without_invalid_parameter_exceptions
141
+ if self.class.log_unpermitted_parameters
142
+ begin
143
+ old = ActionController::Parameters.action_on_invalid_parameters
144
+ ActionController::Parameters.action_on_invalid_parameters = :log
145
+ yield
146
+ ensure
147
+ ActionController::Parameters.action_on_invalid_parameters = old
148
+ end
149
+ else
150
+ yield
151
+ end
152
+ end
153
+
154
+ def flat_keys(hash)
155
+ hash.flat_map { |k, v| v.is_a?(Hash) ? flat_keys(v).map { |x| "#{k}.#{x}" }.push(k) : k }
156
+ end
157
+ end
158
+ end
159
+ end
@@ -1,3 +1,3 @@
1
1
  module StrongerParameters
2
- VERSION = '2.7.0'
2
+ VERSION = '2.8.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stronger_parameters
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-15 00:00:00.000000000 Z
11
+ date: 2017-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -168,6 +168,7 @@ files:
168
168
  - lib/stronger_parameters/constraints/nil_string_constraint.rb
169
169
  - lib/stronger_parameters/constraints/regexp_constraint.rb
170
170
  - lib/stronger_parameters/constraints/string_constraint.rb
171
+ - lib/stronger_parameters/controller_support/permitted_parameters.rb
171
172
  - lib/stronger_parameters/errors.rb
172
173
  - lib/stronger_parameters/parameters.rb
173
174
  - lib/stronger_parameters/version.rb
@@ -191,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
192
  version: '0'
192
193
  requirements: []
193
194
  rubyforge_project:
194
- rubygems_version: 2.5.1
195
+ rubygems_version: 2.4.5.1
195
196
  signing_key:
196
197
  specification_version: 4
197
198
  summary: Type checking and type casting of parameters for Action Pack