file_validators 2.3.0 → 3.0.0.beta1
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 +4 -4
- data/.rubocop.yml +32 -0
- data/Appraisals +2 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +2 -0
- data/README.md +10 -9
- data/Rakefile +3 -1
- data/file_validators.gemspec +9 -6
- data/gemfiles/activemodel_3.2.gemfile +7 -5
- data/gemfiles/activemodel_4.0.gemfile +7 -5
- data/gemfiles/activemodel_4.1.gemfile +7 -5
- data/gemfiles/activemodel_4.2.gemfile +7 -5
- data/gemfiles/activemodel_5.0.gemfile +6 -4
- data/lib/file_validators.rb +3 -1
- data/lib/file_validators/utils/content_type_detector.rb +9 -10
- data/lib/file_validators/utils/media_type_spoof_detector.rb +4 -4
- data/lib/file_validators/validators/file_content_type_validator.rb +15 -15
- data/lib/file_validators/validators/file_size_validator.rb +36 -18
- data/lib/file_validators/version.rb +3 -1
- data/spec/integration/combined_validators_integration_spec.rb +3 -1
- data/spec/integration/file_content_type_validation_integration_spec.rb +43 -17
- data/spec/integration/file_size_validator_integration_spec.rb +37 -15
- data/spec/lib/file_validators/utils/content_type_detector_spec.rb +2 -0
- data/spec/lib/file_validators/utils/media_type_spoof_detector_spec.rb +2 -0
- data/spec/lib/file_validators/validators/file_content_type_validator_spec.rb +90 -32
- data/spec/lib/file_validators/validators/file_size_validator_spec.rb +78 -30
- data/spec/spec_helper.rb +2 -0
- data/spec/support/matchers/allow_content_type.rb +2 -0
- data/spec/support/matchers/allow_file_size.rb +2 -0
- metadata +34 -19
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'rack/test/uploaded_file'
|
3
5
|
|
@@ -52,7 +54,7 @@ describe 'Combined File Validators integration with ActiveModel' do
|
|
52
54
|
before :all do
|
53
55
|
Person.class_eval do
|
54
56
|
Person.reset_callbacks(:validate)
|
55
|
-
validates_file_size :avatar,
|
57
|
+
validates_file_size :avatar, less_than: 20.kilobytes
|
56
58
|
validates_file_content_type :avatar, allow: 'image/jpeg'
|
57
59
|
end
|
58
60
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'rack/test/uploaded_file'
|
3
5
|
|
@@ -69,7 +71,8 @@ describe 'File Content Type integration with ActiveModel' do
|
|
69
71
|
before :all do
|
70
72
|
Person.class_eval do
|
71
73
|
Person.reset_callbacks(:validate)
|
72
|
-
validates :avatar, file_content_type: { allow: ['image/jpeg', 'text/plain'],
|
74
|
+
validates :avatar, file_content_type: { allow: ['image/jpeg', 'text/plain'],
|
75
|
+
mode: :strict }
|
73
76
|
end
|
74
77
|
end
|
75
78
|
|
@@ -97,7 +100,7 @@ describe 'File Content Type integration with ActiveModel' do
|
|
97
100
|
before :all do
|
98
101
|
Person.class_eval do
|
99
102
|
Person.reset_callbacks(:validate)
|
100
|
-
validates :avatar, file_content_type: { allow:
|
103
|
+
validates :avatar, file_content_type: { allow: ->(_record) { ['image/jpeg', 'text/plain'] },
|
101
104
|
mode: :strict }
|
102
105
|
end
|
103
106
|
end
|
@@ -177,7 +180,8 @@ describe 'File Content Type integration with ActiveModel' do
|
|
177
180
|
before :all do
|
178
181
|
Person.class_eval do
|
179
182
|
Person.reset_callbacks(:validate)
|
180
|
-
validates :avatar, file_content_type: { exclude: ['image/jpeg', 'text/plain'],
|
183
|
+
validates :avatar, file_content_type: { exclude: ['image/jpeg', 'text/plain'],
|
184
|
+
mode: :strict }
|
181
185
|
end
|
182
186
|
end
|
183
187
|
|
@@ -205,7 +209,8 @@ describe 'File Content Type integration with ActiveModel' do
|
|
205
209
|
before :all do
|
206
210
|
Person.class_eval do
|
207
211
|
Person.reset_callbacks(:validate)
|
208
|
-
validates :avatar, file_content_type: { exclude:
|
212
|
+
validates :avatar, file_content_type: { exclude: ->(_record) { /^image\/.*/ },
|
213
|
+
mode: :strict }
|
209
214
|
end
|
210
215
|
end
|
211
216
|
|
@@ -229,7 +234,8 @@ describe 'File Content Type integration with ActiveModel' do
|
|
229
234
|
before :all do
|
230
235
|
Person.class_eval do
|
231
236
|
Person.reset_callbacks(:validate)
|
232
|
-
validates :avatar, file_content_type: { allow: /^image\/.*/, exclude: 'image/png',
|
237
|
+
validates :avatar, file_content_type: { allow: /^image\/.*/, exclude: 'image/png',
|
238
|
+
mode: :strict }
|
233
239
|
end
|
234
240
|
end
|
235
241
|
|
@@ -334,22 +340,28 @@ describe 'File Content Type integration with ActiveModel' do
|
|
334
340
|
subject { Person.new }
|
335
341
|
|
336
342
|
context 'for invalid content type' do
|
337
|
-
before
|
343
|
+
before do
|
344
|
+
subject.avatar = '{"filename":"img140910_88338.GIF","content_type":"image/gif","size":13150}'
|
345
|
+
end
|
346
|
+
|
338
347
|
it { is_expected.not_to be_valid }
|
339
348
|
end
|
340
349
|
|
341
350
|
context 'for valid content type' do
|
342
|
-
before
|
351
|
+
before do
|
352
|
+
subject.avatar = '{"filename":"img140910_88338.jpg","content_type":"image/jpeg","size":13150}'
|
353
|
+
end
|
354
|
+
|
343
355
|
it { is_expected.to be_valid }
|
344
356
|
end
|
345
357
|
|
346
358
|
context 'empty json string' do
|
347
|
-
before { subject.avatar =
|
359
|
+
before { subject.avatar = '{}' }
|
348
360
|
it { is_expected.to be_valid }
|
349
361
|
end
|
350
362
|
|
351
363
|
context 'empty string' do
|
352
|
-
before { subject.avatar =
|
364
|
+
before { subject.avatar = '' }
|
353
365
|
it { is_expected.to be_valid }
|
354
366
|
end
|
355
367
|
end
|
@@ -365,12 +377,26 @@ describe 'File Content Type integration with ActiveModel' do
|
|
365
377
|
subject { Person.new }
|
366
378
|
|
367
379
|
context 'for invalid content type' do
|
368
|
-
before
|
380
|
+
before do
|
381
|
+
subject.avatar = {
|
382
|
+
'filename' => 'img140910_88338.GIF',
|
383
|
+
'content_type' => 'image/gif',
|
384
|
+
'size' => 13_150
|
385
|
+
}
|
386
|
+
end
|
387
|
+
|
369
388
|
it { is_expected.not_to be_valid }
|
370
389
|
end
|
371
390
|
|
372
391
|
context 'for valid content type' do
|
373
|
-
before
|
392
|
+
before do
|
393
|
+
subject.avatar = {
|
394
|
+
'filename' => 'img140910_88338.jpg',
|
395
|
+
'content_type' => 'image/jpeg',
|
396
|
+
'size' => 13_150
|
397
|
+
}
|
398
|
+
end
|
399
|
+
|
374
400
|
it { is_expected.to be_valid }
|
375
401
|
end
|
376
402
|
|
@@ -391,22 +417,22 @@ describe 'File Content Type integration with ActiveModel' do
|
|
391
417
|
subject { Person.new }
|
392
418
|
|
393
419
|
context 'for one invalid content type' do
|
394
|
-
before
|
420
|
+
before do
|
395
421
|
subject.avatar = [
|
396
422
|
Rack::Test::UploadedFile.new(@sample_text_path, 'text/plain'),
|
397
423
|
Rack::Test::UploadedFile.new(@cute_path, 'image/jpeg')
|
398
424
|
]
|
399
|
-
|
425
|
+
end
|
400
426
|
it { is_expected.not_to be_valid }
|
401
427
|
end
|
402
428
|
|
403
429
|
context 'for two invalid content types' do
|
404
|
-
before
|
430
|
+
before do
|
405
431
|
subject.avatar = [
|
406
432
|
Rack::Test::UploadedFile.new(@sample_text_path, 'text/plain'),
|
407
433
|
Rack::Test::UploadedFile.new(@sample_text_path, 'text/plain')
|
408
434
|
]
|
409
|
-
|
435
|
+
end
|
410
436
|
|
411
437
|
it 'is invalid and adds just one error' do
|
412
438
|
expect(subject).not_to be_valid
|
@@ -415,12 +441,12 @@ describe 'File Content Type integration with ActiveModel' do
|
|
415
441
|
end
|
416
442
|
|
417
443
|
context 'for valid content type' do
|
418
|
-
before
|
444
|
+
before do
|
419
445
|
subject.avatar = [
|
420
446
|
Rack::Test::UploadedFile.new(@cute_path, 'image/jpeg'),
|
421
447
|
Rack::Test::UploadedFile.new(@cute_path, 'image/jpeg')
|
422
448
|
]
|
423
|
-
|
449
|
+
end
|
424
450
|
it { is_expected.to be_valid }
|
425
451
|
end
|
426
452
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'rack/test/uploaded_file'
|
3
5
|
|
@@ -44,7 +46,7 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
44
46
|
before :all do
|
45
47
|
Person.class_eval do
|
46
48
|
Person.reset_callbacks(:validate)
|
47
|
-
validates :avatar, file_size: { in:
|
49
|
+
validates :avatar, file_size: { in: ->(_record) { 20.kilobytes..40.kilobytes } }
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
@@ -99,8 +101,8 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
99
101
|
before :all do
|
100
102
|
Person.class_eval do
|
101
103
|
Person.reset_callbacks(:validate)
|
102
|
-
validates :avatar, file_size: { greater_than:
|
103
|
-
less_than:
|
104
|
+
validates :avatar, file_size: { greater_than: ->(_record) { 20.kilobytes },
|
105
|
+
less_than: ->(_record) { 40.kilobytes } }
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
@@ -218,22 +220,28 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
218
220
|
subject { Person.new }
|
219
221
|
|
220
222
|
context 'when file size is less than the specified size' do
|
221
|
-
before
|
223
|
+
before do
|
224
|
+
subject.avatar = '{"filename":"img140910_88338.GIF","content_type":"image/gif","size":13150}'
|
225
|
+
end
|
226
|
+
|
222
227
|
it { is_expected.not_to be_valid }
|
223
228
|
end
|
224
229
|
|
225
230
|
context 'when file size within the specified size' do
|
226
|
-
before
|
231
|
+
before do
|
232
|
+
subject.avatar = '{"filename":"img140910_88338.GIF","content_type":"image/gif","size":33150}'
|
233
|
+
end
|
234
|
+
|
227
235
|
it { is_expected.to be_valid }
|
228
236
|
end
|
229
237
|
|
230
238
|
context 'empty json string' do
|
231
|
-
before { subject.avatar =
|
239
|
+
before { subject.avatar = '{}' }
|
232
240
|
it { is_expected.to be_valid }
|
233
241
|
end
|
234
242
|
|
235
243
|
context 'empty json string' do
|
236
|
-
before { subject.avatar =
|
244
|
+
before { subject.avatar = '' }
|
237
245
|
it { is_expected.to be_valid }
|
238
246
|
end
|
239
247
|
end
|
@@ -249,12 +257,26 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
249
257
|
subject { Person.new }
|
250
258
|
|
251
259
|
context 'when file size is less than the specified size' do
|
252
|
-
before
|
260
|
+
before do
|
261
|
+
subject.avatar = {
|
262
|
+
'filename' => 'img140910_88338.GIF',
|
263
|
+
'content_type' => 'image/gif',
|
264
|
+
'size' => 13_150
|
265
|
+
}
|
266
|
+
end
|
267
|
+
|
253
268
|
it { is_expected.not_to be_valid }
|
254
269
|
end
|
255
270
|
|
256
271
|
context 'when file size within the specified size' do
|
257
|
-
before
|
272
|
+
before do
|
273
|
+
subject.avatar = {
|
274
|
+
'filename' => 'img140910_88338.GIF',
|
275
|
+
'content_type' => 'image/gif',
|
276
|
+
'size' => 33_150
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
258
280
|
it { is_expected.to be_valid }
|
259
281
|
end
|
260
282
|
|
@@ -275,22 +297,22 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
275
297
|
subject { Person.new }
|
276
298
|
|
277
299
|
context 'when size of one file is less than the specified size' do
|
278
|
-
before
|
300
|
+
before do
|
279
301
|
subject.avatar = [
|
280
302
|
Rack::Test::UploadedFile.new(@cute_path),
|
281
303
|
Rack::Test::UploadedFile.new(@chubby_bubble_path)
|
282
304
|
]
|
283
|
-
|
305
|
+
end
|
284
306
|
it { is_expected.not_to be_valid }
|
285
307
|
end
|
286
308
|
|
287
309
|
context 'when size of all files is within the specified size' do
|
288
|
-
before
|
310
|
+
before do
|
289
311
|
subject.avatar = [
|
290
312
|
Rack::Test::UploadedFile.new(@cute_path),
|
291
313
|
Rack::Test::UploadedFile.new(@cute_path)
|
292
314
|
]
|
293
|
-
|
315
|
+
end
|
294
316
|
|
295
317
|
it 'is invalid and adds just one error' do
|
296
318
|
expect(subject).not_to be_valid
|
@@ -299,12 +321,12 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
299
321
|
end
|
300
322
|
|
301
323
|
context 'when size of all files is less than the specified size' do
|
302
|
-
before
|
324
|
+
before do
|
303
325
|
subject.avatar = [
|
304
326
|
Rack::Test::UploadedFile.new(@chubby_bubble_path),
|
305
327
|
Rack::Test::UploadedFile.new(@chubby_bubble_path)
|
306
328
|
]
|
307
|
-
|
329
|
+
end
|
308
330
|
|
309
331
|
it { is_expected.to be_valid }
|
310
332
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe ActiveModel::Validations::FileContentTypeValidator do
|
@@ -17,57 +19,85 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
17
19
|
before { build_validator allow: 'image/jpg' }
|
18
20
|
it { is_expected.to allow_file_content_type('image/jpg', @validator) }
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
context 'as an regexp' do
|
22
24
|
before { build_validator allow: /^image\/.*/ }
|
23
25
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
24
26
|
end
|
25
|
-
|
27
|
+
|
26
28
|
context 'as a list' do
|
27
29
|
before { build_validator allow: ['image/png', 'image/jpg', 'image/jpeg'] }
|
28
30
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
29
31
|
end
|
30
32
|
|
31
33
|
context 'as a proc' do
|
32
|
-
before { build_validator allow:
|
34
|
+
before { build_validator allow: ->(_record) { ['image/png', 'image/jpg', 'image/jpeg'] } }
|
33
35
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
34
36
|
end
|
35
37
|
end
|
36
|
-
|
38
|
+
|
37
39
|
context 'with a disallowed type' do
|
38
40
|
context 'as a string' do
|
39
41
|
before { build_validator allow: 'image/png' }
|
40
42
|
it { is_expected.not_to allow_file_content_type('image/jpeg', @validator) }
|
41
43
|
end
|
42
|
-
|
44
|
+
|
43
45
|
context 'as a regexp' do
|
44
46
|
before { build_validator allow: /^text\/.*/ }
|
45
47
|
it { is_expected.not_to allow_file_content_type('image/png', @validator) }
|
46
48
|
end
|
47
49
|
|
48
50
|
context 'as a proc' do
|
49
|
-
before { build_validator allow:
|
51
|
+
before { build_validator allow: ->(_record) { /^text\/.*/ } }
|
50
52
|
it { is_expected.not_to allow_file_content_type('image/png', @validator) }
|
51
53
|
end
|
52
|
-
|
54
|
+
|
53
55
|
context 'with :message option' do
|
54
56
|
context 'without interpolation' do
|
55
|
-
before
|
56
|
-
|
57
|
+
before do
|
58
|
+
build_validator allow: 'image/png',
|
59
|
+
message: 'should be a PNG image'
|
60
|
+
end
|
61
|
+
|
62
|
+
it do
|
63
|
+
is_expected.not_to allow_file_content_type(
|
64
|
+
'image/jpeg', @validator,
|
65
|
+
message: 'Avatar should be a PNG image'
|
66
|
+
)
|
67
|
+
end
|
57
68
|
end
|
58
|
-
|
69
|
+
|
59
70
|
context 'with interpolation' do
|
60
|
-
before
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
71
|
+
before do
|
72
|
+
build_validator allow: 'image/png',
|
73
|
+
message: 'should have content type %{types}'
|
74
|
+
end
|
75
|
+
|
76
|
+
it do
|
77
|
+
is_expected.not_to allow_file_content_type(
|
78
|
+
'image/jpeg', @validator,
|
79
|
+
message: 'Avatar should have content type image/png'
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
it do
|
84
|
+
is_expected.to allow_file_content_type(
|
85
|
+
'image/png', @validator,
|
86
|
+
message: 'Avatar should have content type image/png'
|
87
|
+
)
|
88
|
+
end
|
65
89
|
end
|
66
90
|
end
|
67
91
|
|
68
92
|
context 'default message' do
|
69
93
|
before { build_validator allow: 'image/png' }
|
70
|
-
|
94
|
+
|
95
|
+
it do
|
96
|
+
is_expected.not_to allow_file_content_type(
|
97
|
+
'image/jpeg', @validator,
|
98
|
+
message: 'Avatar file should be one of image/png'
|
99
|
+
)
|
100
|
+
end
|
71
101
|
end
|
72
102
|
end
|
73
103
|
end
|
@@ -78,23 +108,23 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
78
108
|
before { build_validator exclude: 'image/gif' }
|
79
109
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
80
110
|
end
|
81
|
-
|
111
|
+
|
82
112
|
context 'as an regexp' do
|
83
113
|
before { build_validator exclude: /^text\/.*/ }
|
84
114
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
85
115
|
end
|
86
|
-
|
116
|
+
|
87
117
|
context 'as a list' do
|
88
118
|
before { build_validator exclude: ['image/png', 'image/jpg', 'image/jpeg'] }
|
89
119
|
it { is_expected.to allow_file_content_type('image/gif', @validator) }
|
90
120
|
end
|
91
121
|
|
92
122
|
context 'as a proc' do
|
93
|
-
before { build_validator exclude:
|
123
|
+
before { build_validator exclude: ->(_record) { ['image/png', 'image/jpg', 'image/jpeg'] } }
|
94
124
|
it { is_expected.to allow_file_content_type('image/gif', @validator) }
|
95
125
|
end
|
96
126
|
end
|
97
|
-
|
127
|
+
|
98
128
|
context 'with a disallowed type' do
|
99
129
|
context 'as a string' do
|
100
130
|
before { build_validator exclude: 'image/gif' }
|
@@ -107,28 +137,56 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
107
137
|
end
|
108
138
|
|
109
139
|
context 'as an proc' do
|
110
|
-
before { build_validator exclude:
|
140
|
+
before { build_validator exclude: ->(_record) { /^text\/.*/ } }
|
111
141
|
it { is_expected.not_to allow_file_content_type('text/plain', @validator) }
|
112
142
|
end
|
113
|
-
|
143
|
+
|
114
144
|
context 'with :message option' do
|
115
145
|
context 'without interpolation' do
|
116
|
-
before
|
117
|
-
|
146
|
+
before do
|
147
|
+
build_validator exclude: 'image/png',
|
148
|
+
message: 'should not be a PNG image'
|
149
|
+
end
|
150
|
+
|
151
|
+
it do
|
152
|
+
is_expected.not_to allow_file_content_type(
|
153
|
+
'image/png', @validator,
|
154
|
+
message: 'Avatar should not be a PNG image'
|
155
|
+
)
|
156
|
+
end
|
118
157
|
end
|
119
|
-
|
158
|
+
|
120
159
|
context 'with interpolation' do
|
121
|
-
before
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
160
|
+
before do
|
161
|
+
build_validator exclude: 'image/png',
|
162
|
+
message: 'should not have content type %{types}'
|
163
|
+
end
|
164
|
+
|
165
|
+
it do
|
166
|
+
is_expected.not_to allow_file_content_type(
|
167
|
+
'image/png', @validator,
|
168
|
+
message: 'Avatar should not have content type image/png'
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
it do
|
173
|
+
is_expected.to allow_file_content_type(
|
174
|
+
'image/jpeg', @validator,
|
175
|
+
message: 'Avatar should not have content type image/jpeg'
|
176
|
+
)
|
177
|
+
end
|
126
178
|
end
|
127
179
|
end
|
128
180
|
|
129
181
|
context 'default message' do
|
130
182
|
before { build_validator exclude: 'image/png' }
|
131
|
-
|
183
|
+
|
184
|
+
it do
|
185
|
+
is_expected.not_to allow_file_content_type(
|
186
|
+
'image/png', @validator,
|
187
|
+
message: 'Avatar file cannot be image/png'
|
188
|
+
)
|
189
|
+
end
|
132
190
|
end
|
133
191
|
end
|
134
192
|
end
|
@@ -151,7 +209,7 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
151
209
|
expect { build_validator argument => 'image/jpg' }.not_to raise_error
|
152
210
|
expect { build_validator argument => ['image/jpg'] }.not_to raise_error
|
153
211
|
expect { build_validator argument => /^image\/.*/ }.not_to raise_error
|
154
|
-
expect { build_validator argument =>
|
212
|
+
expect { build_validator argument => ->(_record) { 'image/jpg' } }.not_to raise_error
|
155
213
|
end
|
156
214
|
|
157
215
|
it "raises argument error if :#{argument} is neither a string, array, regexp nor proc" do
|