Commit c5f2b145 by Jon Yurek

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.
parent 7084ddc6
...@@ -77,12 +77,13 @@ module Paperclip ...@@ -77,12 +77,13 @@ module Paperclip
# nil, which uses the first executable found in the user's search path. # nil, which uses the first executable found in the user's search path.
def self.options def self.options
@options ||= { @options ||= {
:whiny => true, :whiny => true,
:image_magick_path => nil, :image_magick_path => nil,
:command_path => nil, :command_path => nil,
:log => true, :log => true,
:log_command => true, :log_command => true,
:swallow_stderr => true :swallow_stderr => true,
:content_type_mappings => {}
} }
end end
......
...@@ -10,19 +10,44 @@ module Paperclip ...@@ -10,19 +10,44 @@ module Paperclip
end end
def spoofed? def spoofed?
if ! @name.blank? if @name.present? && media_type_mismatch? && mapping_override_mismatch?
! supplied_file_media_type.include?(calculated_media_type) 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
end end
private private
def supplied_file_media_type def media_type_mismatch?
MIME::Types.type_for(@name).collect(&:media_type) ! 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 end
def calculated_media_type 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 end
def type_from_file_command def type_from_file_command
......
...@@ -25,4 +25,17 @@ class MediaTypeSpoofDetectorTest < Test::Unit::TestCase ...@@ -25,4 +25,17 @@ class MediaTypeSpoofDetectorTest < Test::Unit::TestCase
adapter = Paperclip.io_adapters.for(File.new(fixture_file("5k.png"))) adapter = Paperclip.io_adapters.for(File.new(fixture_file("5k.png")))
assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename).spoofed? assert ! Paperclip::MediaTypeSpoofDetector.using(adapter, adapter.original_filename).spoofed?
end 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 end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment