file_validators 2.0.2 → 3.0.0.beta2

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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.tool-versions +1 -0
  5. data/.travis.yml +33 -5
  6. data/Appraisals +16 -10
  7. data/CHANGELOG.md +26 -0
  8. data/Gemfile +2 -0
  9. data/README.md +32 -21
  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.1.gemfile +1 -0
  15. data/gemfiles/activemodel_4.2.gemfile +2 -1
  16. data/gemfiles/{activemodel_3.0.gemfile → activemodel_5.0.gemfile} +1 -1
  17. data/gemfiles/{activemodel_3.1.gemfile → activemodel_5.2.gemfile} +1 -1
  18. data/lib/file_validators.rb +11 -2
  19. data/lib/file_validators/error.rb +6 -0
  20. data/lib/file_validators/locale/en.yml +0 -2
  21. data/lib/file_validators/mime_type_analyzer.rb +106 -0
  22. data/lib/file_validators/validators/file_content_type_validator.rb +37 -42
  23. data/lib/file_validators/validators/file_size_validator.rb +62 -19
  24. data/lib/file_validators/version.rb +3 -1
  25. data/spec/integration/combined_validators_integration_spec.rb +3 -1
  26. data/spec/integration/file_content_type_validation_integration_spec.rb +117 -11
  27. data/spec/integration/file_size_validator_integration_spec.rb +100 -10
  28. data/spec/lib/file_validators/mime_type_analyzer_spec.rb +139 -0
  29. data/spec/lib/file_validators/validators/file_content_type_validator_spec.rb +93 -36
  30. data/spec/lib/file_validators/validators/file_size_validator_spec.rb +87 -34
  31. data/spec/spec_helper.rb +9 -1
  32. data/spec/support/fakeio.rb +17 -0
  33. data/spec/support/helpers.rb +7 -0
  34. data/spec/support/matchers/allow_content_type.rb +2 -0
  35. data/spec/support/matchers/allow_file_size.rb +2 -0
  36. metadata +87 -27
  37. data/lib/file_validators/utils/content_type_detector.rb +0 -46
  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,46 +0,0 @@
1
- begin
2
- require 'cocaine'
3
- rescue LoadError
4
- end
5
-
6
- module FileValidators
7
- module Utils
8
-
9
- class ContentTypeDetector
10
- EMPTY_CONTENT_TYPE = 'inode/x-empty'
11
- DEFAULT_CONTENT_TYPE = 'application/octet-stream'
12
-
13
- def initialize(file_path)
14
- @file_path = file_path
15
- end
16
-
17
- # content type detection strategy:
18
- #
19
- # 1. empty file: returns 'inode/x-empty'
20
- # 2. nonempty file: if the file is not empty then returns the content type using file command
21
- # 3. invalid file: file command raises error and returns 'application/octet-stream'
22
-
23
- def detect
24
- empty_file? ? EMPTY_CONTENT_TYPE : content_type_from_file_command
25
- end
26
-
27
- private
28
-
29
- def empty_file?
30
- File.exists?(@file_path) && File.size(@file_path) == 0
31
- end
32
-
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"
38
- rescue Cocaine::CommandLineError => e
39
- # TODO: log command failure
40
- DEFAULT_CONTENT_TYPE
41
- end.strip
42
- end
43
- end
44
-
45
- end
46
- 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(FileValidators::Utils::ContentTypeDetector.new(tempfile).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(FileValidators::Utils::ContentTypeDetector.new(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(FileValidators::Utils::ContentTypeDetector.new('').detect).to eql('application/octet-stream')
21
- end
22
-
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')
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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.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(FileValidators::Utils::MediaTypeSpoofDetector.new('image/png', '.jpg')).not_to be_spoofed
30
- end
31
- end