Permalink
Browse files

Add a way to allow content_types that file misses

There are some file types that the file command doesn't understand.
Notably, files that have a format, but are ASCII-text based (like ruby,
certificates, etc), show up as text/plain. This presents a problem,
because the mime-types gem either doesn't report them at all (as for
.pem files) or reports them differently (as for .rb files).

This change allows a Paperclip.options[:content_type_mapping] hash,
which allows for a mapping of { :pem => "text/plain" } which tells the
spoof detector that this is an OK matchup and to allow it.
  • Loading branch information...
1 parent 7084ddc commit c5f2b1450567d11fc4e03eb852bf0489cec31616 @jyurek jyurek committed Feb 7, 2014
Showing with 49 additions and 10 deletions.
  1. +6 −5 lib/paperclip.rb
  2. +30 −5 lib/paperclip/media_type_spoof_detector.rb
  3. +13 −0 test/media_type_spoof_detector_test.rb
View
11 lib/paperclip.rb
@@ -77,12 +77,13 @@ module Paperclip
# nil, which uses the first executable found in the user's search path.
def self.options
@options ||= {
- :whiny => true,
+ :whiny => true,
:image_magick_path => nil,
- :command_path => nil,
- :log => true,
- :log_command => true,
- :swallow_stderr => true
+ :command_path => nil,
+ :log => true,
+ :log_command => true,
+ :swallow_stderr => true,
+ :content_type_mappings => {}
}
end
View
35 lib/paperclip/media_type_spoof_detector.rb
@@ -10,19 +10,44 @@ def initialize(file, name)
end
def spoofed?
- if ! @name.blank?
- ! supplied_file_media_type.include?(calculated_media_type)
+ if @name.present? && media_type_mismatch? && mapping_override_mismatch?
+ Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_file_content_types}), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
+ true
end
end
private
- def supplied_file_media_type
- MIME::Types.type_for(@name).collect(&:media_type)
+ def media_type_mismatch?
+ ! supplied_file_media_types.include?(calculated_media_type)
+ end
+
+ def mapping_override_mismatch?
+ mapped_content_type != calculated_content_type
+ end
+
+ def supplied_file_media_types
+ @supplied_file_media_types ||= MIME::Types.type_for(@name).collect(&:media_type)
end
def calculated_media_type
- type_from_file_command.split("/").first
+ @calculated_media_type ||= calculated_content_type.split("/").first
+ end
+
+ def supplied_file_content_types
+ @supplied_file_content_types ||= MIME::Types.type_for(@name).collect(&:content_type)
+ end
+
+ def calculated_content_type
+ @calculated_content_type ||= type_from_file_command.chomp
+ end
+
+ def mapped_content_type
+ Paperclip.options[:content_type_mappings][filename_extension]
+ end
+
+ def filename_extension
+ File.extname(@name.to_s.downcase).sub(/^\./, '').to_sym
end
def type_from_file_command
View
13 test/media_type_spoof_detector_test.rb
@@ -25,4 +25,17 @@ class MediaTypeSpoofDetectorTest < Test::Unit::TestCase
adapter = Paperclip.io_adapters.for(File.new(fixture_file("5k.png")))
assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename).spoofed?
end
+
+ should 'not reject when the extension => content_type is in :content_type_mappings' do
+ begin
+ Paperclip.options[:content_type_mappings] = { pem: "text/plain" }
+ file = Tempfile.open(["test", ".PEM"])
+ file.puts "Certificate!"
+ file.close
+ adapter = Paperclip.io_adapters.for(File.new(file.path));
+ assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename).spoofed?
+ ensure
+ Paperclip.options[:content_type_mappings] = {}
+ end
+ end
end

0 comments on commit c5f2b14

Please sign in to comment.