file_validators 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +32 -0
  4. data/.tool-versions +1 -0
  5. data/.travis.yml +43 -7
  6. data/Appraisals +13 -13
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +2 -0
  9. data/README.md +26 -18
  10. data/Rakefile +3 -1
  11. data/file_validators.gemspec +13 -7
  12. data/gemfiles/activemodel_3.2.gemfile +2 -1
  13. data/gemfiles/activemodel_4.0.gemfile +2 -1
  14. data/gemfiles/{activemodel_4.2.gemfile → activemodel_5.0.gemfile} +1 -1
  15. data/gemfiles/{activemodel_4.1.gemfile → activemodel_6.0.gemfile} +1 -1
  16. data/gemfiles/{activemodel_3.0.gemfile → activemodel_6.1.gemfile} +1 -1
  17. data/lib/file_validators.rb +6 -7
  18. data/lib/file_validators/error.rb +6 -0
  19. data/lib/file_validators/mime_type_analyzer.rb +106 -0
  20. data/lib/file_validators/validators/file_content_type_validator.rb +37 -33
  21. data/lib/file_validators/validators/file_size_validator.rb +62 -19
  22. data/lib/file_validators/version.rb +3 -1
  23. data/spec/integration/combined_validators_integration_spec.rb +3 -1
  24. data/spec/integration/file_content_type_validation_integration_spec.rb +117 -11
  25. data/spec/integration/file_size_validator_integration_spec.rb +100 -10
  26. data/spec/lib/file_validators/mime_type_analyzer_spec.rb +139 -0
  27. data/spec/lib/file_validators/validators/file_content_type_validator_spec.rb +90 -32
  28. data/spec/lib/file_validators/validators/file_size_validator_spec.rb +84 -30
  29. data/spec/spec_helper.rb +5 -0
  30. data/spec/support/fakeio.rb +17 -0
  31. data/spec/support/helpers.rb +7 -0
  32. data/spec/support/matchers/allow_content_type.rb +2 -0
  33. data/spec/support/matchers/allow_file_size.rb +2 -0
  34. metadata +86 -28
  35. data/CHANGELOG.mod +0 -6
  36. data/gemfiles/activemodel_3.1.gemfile +0 -8
  37. data/lib/file_validators/utils/content_type_detector.rb +0 -64
  38. data/lib/file_validators/utils/media_type_spoof_detector.rb +0 -46
  39. data/spec/lib/file_validators/utils/content_type_detector_spec.rb +0 -27
  40. data/spec/lib/file_validators/utils/media_type_spoof_detector_spec.rb +0 -31
@@ -1,6 +0,0 @@
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
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "activemodel", "3.1.12"
7
-
8
- gemspec :path => "../"
@@ -1,64 +0,0 @@
1
- require 'logger'
2
-
3
- begin
4
- require 'cocaine'
5
- rescue LoadError
6
- puts "file_validators requires 'cocaine' gem as you are using file content type validations in strict mode"
7
- end
8
-
9
- module FileValidators
10
- module Utils
11
-
12
- class ContentTypeDetector
13
- EMPTY_CONTENT_TYPE = 'inode/x-empty'
14
- DEFAULT_CONTENT_TYPE = 'application/octet-stream'
15
-
16
- attr_accessor :file_path, :file_name
17
-
18
- def initialize(file_path, file_name)
19
- @file_path = file_path
20
- @file_name = file_name
21
- end
22
-
23
- # content type detection strategy:
24
- #
25
- # 1. empty file: returns 'inode/x-empty'
26
- # 2. nonempty file: if the file is not empty then returns the content type using file command
27
- # 3. invalid file: file command raises error and returns 'application/octet-stream'
28
-
29
- def detect
30
- empty_file? ? EMPTY_CONTENT_TYPE : content_type_from_content
31
- end
32
-
33
- private
34
-
35
- def empty_file?
36
- File.exists?(file_path) && File.size(file_path) == 0
37
- end
38
-
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
52
- rescue Cocaine::CommandLineError => e
53
- logger.info(e.message)
54
- DEFAULT_CONTENT_TYPE
55
- end
56
- end
57
-
58
- def logger
59
- Logger.new(STDOUT)
60
- end
61
- end
62
-
63
- end
64
- end
@@ -1,46 +0,0 @@
1
- require 'mime/types'
2
-
3
- module FileValidators
4
- module Utils
5
-
6
- class MediaTypeSpoofDetector
7
- def initialize(content_type, file_name)
8
- @content_type = content_type
9
- @file_name = file_name
10
- end
11
-
12
- # media type spoof detection strategy:
13
- #
14
- # 1. it will not identify as spoofed if file name doesn't have any extension
15
- # 2. it will identify as spoofed if any of the file extension's media types
16
- # matches the media type of the content type. So it will return true for
17
- # `text` of `text/plain` mismatch with `image` of `image/jpeg`, but return false
18
- # for `image` of `image/png` match with `image` of `image/jpeg`.
19
-
20
- def spoofed?
21
- has_extension? and media_type_mismatch?
22
- end
23
-
24
- private
25
-
26
- def has_extension?
27
- # the following code replaced File.extname(@file_name).present? because it cannot
28
- # return the extension of a extension-only file names, e.g. '.html', '.jpg' etc
29
- @file_name.split('.').length > 1
30
- end
31
-
32
- def media_type_mismatch?
33
- supplied_media_types.none? { |type| type == detected_media_type }
34
- end
35
-
36
- def supplied_media_types
37
- MIME::Types.type_for(@file_name).collect(&:media_type)
38
- end
39
-
40
- def detected_media_type
41
- @content_type.split('/').first
42
- end
43
- end
44
-
45
- end
46
- end
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
- require 'tempfile'
3
-
4
- describe FileValidators::Utils::ContentTypeDetector do
5
- it 'returns the empty content type when the file is empty' do
6
- tempfile = Tempfile.new('empty')
7
- expect(described_class.new(tempfile.path, tempfile.path).detect).to eql('inode/x-empty')
8
- tempfile.close
9
- end
10
-
11
- it 'returns a content type based on the content of the file' do
12
- tempfile = Tempfile.new('something')
13
- tempfile.write('This is a file.')
14
- tempfile.rewind
15
- expect(described_class.new(tempfile.path, tempfile.path).detect).to eql('text/plain')
16
- tempfile.close
17
- end
18
-
19
- it 'returns a sensible default when the file path is empty' do
20
- expect(described_class.new('', '').detect).to eql('application/octet-stream')
21
- end
22
-
23
- it 'returns a sensible default if the file path is invalid' do
24
- file_path = '/path/to/nothing'
25
- expect(described_class.new(file_path, file_path).detect).to eql('application/octet-stream')
26
- end
27
- end
@@ -1,31 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FileValidators::Utils::MediaTypeSpoofDetector do
4
- it 'rejects a file with an extension .html and identifies as jpeg' do
5
- expect(described_class.new('image/jpeg', 'sample.html')).to be_spoofed
6
- end
7
-
8
- it 'does not reject a file with an extension .jpg and identifies as png' do
9
- expect(described_class.new('image/png', 'sample.jpg')).not_to be_spoofed
10
- end
11
-
12
- it 'does not reject a file with an extension .txt and identifies as text' do
13
- expect(described_class.new('text/plain', 'sample.txt')).not_to be_spoofed
14
- end
15
-
16
- it 'does not reject a file that does not have any name' do
17
- expect(described_class.new('text/plain', '')).not_to be_spoofed
18
- end
19
-
20
- it 'does not reject a file that does not have any extension' do
21
- expect(described_class.new('text/plain', 'sample')).not_to be_spoofed
22
- end
23
-
24
- it 'rejects a file that does not have a basename but has an extension with mismatched media type' do
25
- expect(described_class.new('image/jpeg', '.html')).to be_spoofed
26
- end
27
-
28
- it 'does not reject a file that does not have a basename but has an extension with valid media type' do
29
- expect(described_class.new('image/png', '.jpg')).not_to be_spoofed
30
- end
31
- end