file_validators 2.0.2 → 2.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: ff6c87fab7ee11b1ce0fb5770332f0f1b22c5b96
4
- data.tar.gz: c5b54b8b7b01b685b0f9ee3097c3f8cecbe8ddc0
3
+ metadata.gz: 451e981eb130a49dc6c51834bd7ed4dd30652c9a
4
+ data.tar.gz: e6b28941ccf9ced999b0e201ad17738efb8bc767
5
5
  SHA512:
6
- metadata.gz: 87bf7a8b288777610e8365b486ba806715ee155cc2c5b808aadea4b4f95e1bb18398d394b10af215ffde63fe0babbbc9ea70d265005a727cb31d7b01966ad69a
7
- data.tar.gz: d05f373a6c43907891cbdc0358e3f0389027b2b10b41d788a83db65cb6edca23b3bdf3910bd82c8ebb45b350c368b94884033a0f98f5d65093bf00ff7b0d034d
6
+ metadata.gz: 8c40fa1dae6faf187cc4d3ba77db40691b9bfe58fe9fa99bc88b9fc36477b49ef06bd360ffa8a8af4e2d6f4d56421259b9d9623ab3732a06883b8e64c3f57eb4
7
+ data.tar.gz: 4c6aed01f6c15c42c3f917dcdbbbb4c28907ed662a16f823e33d7416005122e159f2504d4991f5fd4b7b20405b332566a1d52137164f224ce5c1504df1c45407
data/.gitignore CHANGED
@@ -10,3 +10,4 @@ Gemfile.lock
10
10
  gemfiles/*.lock
11
11
  coverage/
12
12
  /.idea
13
+ .ruby-version
data/.travis.yml CHANGED
@@ -1,7 +1,11 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
- - 1.9.3
4
- - 2.2.2
4
+ - 2.0
5
+ - 2.2.3
6
+ - ruby-head
7
+ - jruby-9.0.4.0
8
+
5
9
  gemfile:
6
10
  - gemfiles/activemodel_4.2.gemfile
7
11
  - gemfiles/activemodel_4.1.gemfile
@@ -9,3 +13,7 @@ gemfile:
9
13
  - gemfiles/activemodel_3.2.gemfile
10
14
  - gemfiles/activemodel_3.1.gemfile
11
15
  - gemfiles/activemodel_3.0.gemfile
16
+
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: ruby-head
data/CHANGELOG.mod ADDED
@@ -0,0 +1,6 @@
1
+ # 2.1.0
2
+
3
+ * Use autoload for lazy loading of libraries
4
+ * Media type spoof valiation is moved to content type detector
5
+ * spoofed_file_media_type message isn't needed anymore
6
+ * Show logger info and warning
data/README.md CHANGED
@@ -191,8 +191,6 @@ File Size Errors
191
191
  * `file_size_is_greater_than_or_equal_to`: takes `count` as replacement
192
192
 
193
193
  Content Type Errors
194
- * `spoofed_file_media_type`: generated when file media type from its extension doesn't match the media type of its
195
- content. learn more from [security](#Security).
196
194
  * `allowed_file_content_types`: generated when you have specified allowed types but the content type
197
195
  of the file doesn't match. takes `types` as replacement.
198
196
  * `excluded_file_content_types`: generated when you have specified excluded types and the content type
@@ -249,10 +247,14 @@ uploaders start processing a file immediately after its assignment (even before
249
247
 
250
248
  ## Tests
251
249
 
252
- ```ruby
253
- rake
254
- rake test:unit
255
- rake test:integration
250
+ ```Shell
251
+ $ rake
252
+ $ rake test:unit
253
+ $ rake test:integration
254
+
255
+ # test different active model versions
256
+ $ appraisal install
257
+ $ appraisal rake
256
258
  ```
257
259
 
258
260
  ## Problems
@@ -1,6 +1,16 @@
1
1
  require 'active_model'
2
- require 'file_validators/validators/file_size_validator'
3
- require 'file_validators/validators/file_content_type_validator'
2
+ require 'ostruct'
3
+
4
+ module FileValidators
5
+ module Utils
6
+ extend ActiveSupport::Autoload
7
+
8
+ autoload :ContentTypeDetector
9
+ autoload :MediaTypeSpoofDetector
10
+ end
11
+ end
12
+
13
+ Dir[File.dirname(__FILE__) + "/file_validators/validators/*.rb"].each { |file| require file }
4
14
 
5
15
  locale_path = Dir.glob(File.dirname(__FILE__) + '/file_validators/locale/*.yml')
6
16
  I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
@@ -7,7 +7,5 @@ en:
7
7
  file_size_is_greater_than: ! 'file size must be greater than %{count}'
8
8
  file_size_is_greater_than_or_equal_to: ! 'file size must be greater than or equal to %{count}'
9
9
 
10
- spoofed_file_media_type: file has an extension that does not match its contents
11
10
  allowed_file_content_types: ! 'file should be one of %{types}'
12
11
  excluded_file_content_types: ! 'file cannot be %{types}'
13
-
@@ -1,6 +1,9 @@
1
+ require 'logger'
2
+
1
3
  begin
2
4
  require 'cocaine'
3
5
  rescue LoadError
6
+ puts "file_validators requires 'cocaine' gem as you are using file content type validations in strict mode"
4
7
  end
5
8
 
6
9
  module FileValidators
@@ -10,8 +13,11 @@ module FileValidators
10
13
  EMPTY_CONTENT_TYPE = 'inode/x-empty'
11
14
  DEFAULT_CONTENT_TYPE = 'application/octet-stream'
12
15
 
13
- def initialize(file_path)
16
+ attr_accessor :file_path, :file_name
17
+
18
+ def initialize(file_path, file_name)
14
19
  @file_path = file_path
20
+ @file_name = file_name
15
21
  end
16
22
 
17
23
  # content type detection strategy:
@@ -21,24 +27,36 @@ module FileValidators
21
27
  # 3. invalid file: file command raises error and returns 'application/octet-stream'
22
28
 
23
29
  def detect
24
- empty_file? ? EMPTY_CONTENT_TYPE : content_type_from_file_command
30
+ empty_file? ? EMPTY_CONTENT_TYPE : content_type_from_content
25
31
  end
26
32
 
27
33
  private
28
34
 
29
35
  def empty_file?
30
- File.exists?(@file_path) && File.size(@file_path) == 0
36
+ File.exists?(file_path) && File.size(file_path) == 0
31
37
  end
32
38
 
33
- def content_type_from_file_command
34
- type = begin
35
- Cocaine::CommandLine.new('file', '-b --mime-type :file').run(file: @file_path)
36
- rescue NameError => e
37
- puts "file_validators: Add 'cocaine' gem as you are using file content type validations in strict mode"
39
+ def content_type_from_content
40
+ content_type = type_from_file_command
41
+
42
+ if FileValidators::Utils::MediaTypeSpoofDetector.new(content_type, file_name).spoofed?
43
+ logger.warn('A file with a spoofed media type has been detected by the file validators.')
44
+ else
45
+ content_type
46
+ end
47
+ end
48
+
49
+ def type_from_file_command
50
+ begin
51
+ Cocaine::CommandLine.new('file', '-b --mime-type :file').run(file: @file_path).strip
38
52
  rescue Cocaine::CommandLineError => e
39
- # TODO: log command failure
53
+ logger.info(e.message)
40
54
  DEFAULT_CONTENT_TYPE
41
- end.strip
55
+ end
56
+ end
57
+
58
+ def logger
59
+ Logger.new(STDOUT)
42
60
  end
43
61
  end
44
62
 
@@ -1,6 +1,3 @@
1
- require 'file_validators/utils/content_type_detector'
2
- require 'file_validators/utils/media_type_spoof_detector'
3
-
4
1
  module ActiveModel
5
2
  module Validations
6
3
 
@@ -19,7 +16,6 @@ module ActiveModel
19
16
  allowed_types = option_content_types(record, :allow)
20
17
  forbidden_types = option_content_types(record, :exclude)
21
18
 
22
- validate_media_type(record, attribute, content_type, get_file_name(value)) if mode == :strict
23
19
  validate_whitelist(record, attribute, content_type, allowed_types)
24
20
  validate_blacklist(record, attribute, content_type, forbidden_types)
25
21
  end
@@ -59,7 +55,8 @@ module ActiveModel
59
55
  case mode
60
56
  when :strict
61
57
  file_path = get_file_path(value)
62
- FileValidators::Utils::ContentTypeDetector.new(file_path).detect
58
+ file_name = get_file_name(value)
59
+ FileValidators::Utils::ContentTypeDetector.new(file_path, file_name).detect
63
60
  when :relaxed
64
61
  file_name = get_file_name(value)
65
62
  MIME::Types.type_for(file_name).first
@@ -77,12 +74,6 @@ module ActiveModel
77
74
  options[key].is_a?(Proc) ? options[key].call(record) : options[key]
78
75
  end
79
76
 
80
- def validate_media_type(record, attribute, content_type, file_name)
81
- if FileValidators::Utils::MediaTypeSpoofDetector.new(content_type, file_name).spoofed?
82
- record.errors.add attribute, :spoofed_file_media_type
83
- end
84
- end
85
-
86
77
  def validate_whitelist(record, attribute, content_type, allowed_types)
87
78
  if allowed_types.present? and allowed_types.none? { |type| type === content_type }
88
79
  mark_invalid record, attribute, :allowed_file_content_types, allowed_types
@@ -1,3 +1,3 @@
1
1
  module FileValidators
2
- VERSION = '2.0.2'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -4,7 +4,7 @@ require 'tempfile'
4
4
  describe FileValidators::Utils::ContentTypeDetector do
5
5
  it 'returns the empty content type when the file is empty' do
6
6
  tempfile = Tempfile.new('empty')
7
- expect(FileValidators::Utils::ContentTypeDetector.new(tempfile).detect).to eql('inode/x-empty')
7
+ expect(described_class.new(tempfile.path, tempfile.path).detect).to eql('inode/x-empty')
8
8
  tempfile.close
9
9
  end
10
10
 
@@ -12,16 +12,16 @@ describe FileValidators::Utils::ContentTypeDetector do
12
12
  tempfile = Tempfile.new('something')
13
13
  tempfile.write('This is a file.')
14
14
  tempfile.rewind
15
- expect(FileValidators::Utils::ContentTypeDetector.new(tempfile.path).detect).to eql('text/plain')
15
+ expect(described_class.new(tempfile.path, tempfile.path).detect).to eql('text/plain')
16
16
  tempfile.close
17
17
  end
18
18
 
19
19
  it 'returns a sensible default when the file path is empty' do
20
- expect(FileValidators::Utils::ContentTypeDetector.new('').detect).to eql('application/octet-stream')
20
+ expect(described_class.new('', '').detect).to eql('application/octet-stream')
21
21
  end
22
22
 
23
23
  it 'returns a sensible default if the file path is invalid' do
24
- @filename = '/path/to/nothing'
25
- expect(FileValidators::Utils::ContentTypeDetector.new(@filename).detect).to eql('application/octet-stream')
24
+ file_path = '/path/to/nothing'
25
+ expect(described_class.new(file_path, file_path).detect).to eql('application/octet-stream')
26
26
  end
27
27
  end
@@ -2,30 +2,30 @@ require 'spec_helper'
2
2
 
3
3
  describe FileValidators::Utils::MediaTypeSpoofDetector do
4
4
  it 'rejects a file with an extension .html and identifies as jpeg' do
5
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('image/jpeg', 'sample.html')).to be_spoofed
5
+ expect(described_class.new('image/jpeg', 'sample.html')).to be_spoofed
6
6
  end
7
7
 
8
8
  it 'does not reject a file with an extension .jpg and identifies as png' do
9
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('image/png', 'sample.jpg')).not_to be_spoofed
9
+ expect(described_class.new('image/png', 'sample.jpg')).not_to be_spoofed
10
10
  end
11
11
 
12
12
  it 'does not reject a file with an extension .txt and identifies as text' do
13
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('text/plain', 'sample.txt')).not_to be_spoofed
13
+ expect(described_class.new('text/plain', 'sample.txt')).not_to be_spoofed
14
14
  end
15
15
 
16
16
  it 'does not reject a file that does not have any name' do
17
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('text/plain', '')).not_to be_spoofed
17
+ expect(described_class.new('text/plain', '')).not_to be_spoofed
18
18
  end
19
19
 
20
20
  it 'does not reject a file that does not have any extension' do
21
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('text/plain', 'sample')).not_to be_spoofed
21
+ expect(described_class.new('text/plain', 'sample')).not_to be_spoofed
22
22
  end
23
23
 
24
24
  it 'rejects a file that does not have a basename but has an extension with mismatched media type' do
25
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('image/jpeg', '.html')).to be_spoofed
25
+ expect(described_class.new('image/jpeg', '.html')).to be_spoofed
26
26
  end
27
27
 
28
28
  it 'does not reject a file that does not have a basename but has an extension with valid media type' do
29
- expect(FileValidators::Utils::MediaTypeSpoofDetector.new('image/png', '.jpg')).not_to be_spoofed
29
+ expect(described_class.new('image/png', '.jpg')).not_to be_spoofed
30
30
  end
31
31
  end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'file_validators/validators/file_content_type_validator'
3
2
 
4
3
  describe ActiveModel::Validations::FileContentTypeValidator do
5
4
  class Dummy
@@ -9,7 +8,7 @@ describe ActiveModel::Validations::FileContentTypeValidator do
9
8
  subject { Dummy }
10
9
 
11
10
  def build_validator(options)
12
- @validator = ActiveModel::Validations::FileContentTypeValidator.new(options.merge(attributes: :avatar))
11
+ @validator = described_class.new(options.merge(attributes: :avatar))
13
12
  end
14
13
 
15
14
  context 'whitelist format' do
@@ -138,7 +137,7 @@ describe ActiveModel::Validations::FileContentTypeValidator do
138
137
  before { Dummy.validates_file_content_type :avatar, allow: 'image/jpg' }
139
138
 
140
139
  it 'adds the validator to the class' do
141
- expect(Dummy.validators_on(:avatar)).to include(ActiveModel::Validations::FileContentTypeValidator)
140
+ expect(Dummy.validators_on(:avatar)).to include(described_class)
142
141
  end
143
142
  end
144
143
 
@@ -147,7 +146,7 @@ describe ActiveModel::Validations::FileContentTypeValidator do
147
146
  expect { build_validator message: 'Some message' }.to raise_error(ArgumentError)
148
147
  end
149
148
 
150
- ActiveModel::Validations::FileContentTypeValidator::CHECKS.each do |argument|
149
+ described_class::CHECKS.each do |argument|
151
150
  it "does not raise error if :#{argument} is string, array, regexp or a proc" do
152
151
  expect { build_validator argument => 'image/jpg' }.not_to raise_error
153
152
  expect { build_validator argument => ['image/jpg'] }.not_to raise_error
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'file_validators/validators/file_size_validator'
3
2
 
4
3
  describe ActiveModel::Validations::FileSizeValidator do
5
4
  class Dummy
@@ -21,7 +20,7 @@ describe ActiveModel::Validations::FileSizeValidator do
21
20
  subject { Dummy }
22
21
 
23
22
  def build_validator(options)
24
- @validator = ActiveModel::Validations::FileSizeValidator.new(options.merge(attributes: :avatar))
23
+ @validator = described_class.new(options.merge(attributes: :avatar))
25
24
  end
26
25
 
27
26
  context 'with :in option' do
@@ -174,7 +173,7 @@ describe ActiveModel::Validations::FileSizeValidator do
174
173
  before { Dummy.validates_file_size :avatar, in: (5.kilobytes..10.kilobytes) }
175
174
 
176
175
  it 'adds the validator to the class' do
177
- expect(Dummy.validators_on(:avatar)).to include(ActiveModel::Validations::FileSizeValidator)
176
+ expect(Dummy.validators_on(:avatar)).to include(described_class)
178
177
  end
179
178
  end
180
179
 
@@ -183,7 +182,7 @@ describe ActiveModel::Validations::FileSizeValidator do
183
182
  expect { build_validator message: 'Some message' }.to raise_error(ArgumentError)
184
183
  end
185
184
 
186
- (ActiveModel::Validations::FileSizeValidator::CHECKS.keys - [:in]).each do |argument|
185
+ (described_class::CHECKS.keys - [:in]).each do |argument|
187
186
  it "does not raise argument error if :#{argument} is numeric or a proc" do
188
187
  expect { build_validator argument => 5.kilobytes }.not_to raise_error
189
188
  expect { build_validator argument => lambda { |record| 5.kilobytes } }.not_to raise_error
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,7 @@ ENV['RAILS_ENV'] ||= 'test'
2
2
 
3
3
  require 'active_support'
4
4
  require 'active_support/core_ext'
5
- require_relative '../lib/file_validators'
5
+ require 'file_validators'
6
6
  require 'rspec'
7
7
  require 'coveralls'
8
8
 
@@ -10,8 +10,11 @@ Coveralls.wear!
10
10
 
11
11
  locale_path = Dir.glob(File.dirname(__FILE__) + '/locale/*.yml')
12
12
  I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
13
+ I18n.enforce_available_locales = false
13
14
 
14
15
  Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f }
15
16
 
16
17
  RSpec.configure do |config|
18
+ # Suppress stdout in the console
19
+ config.before { allow($stdout).to receive(:write) }
17
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file_validators
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmad Musaffa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-08 00:00:00.000000000 Z
11
+ date: 2016-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -119,6 +119,7 @@ files:
119
119
  - ".rspec"
120
120
  - ".travis.yml"
121
121
  - Appraisals
122
+ - CHANGELOG.mod
122
123
  - Gemfile
123
124
  - MIT-LICENSE
124
125
  - README.md
@@ -174,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
175
  version: '0'
175
176
  requirements: []
176
177
  rubyforge_project:
177
- rubygems_version: 2.4.5.1
178
+ rubygems_version: 2.5.1
178
179
  signing_key:
179
180
  specification_version: 4
180
181
  summary: ActiveModel file validators