Index: lib/technoweenie/attachment_fu.rb
===================================================================
--- lib/technoweenie/attachment_fu.rb (.../vendor/attachment_fu/2007_11_27) (revision 626)
+++ lib/technoweenie/attachment_fu.rb (.../place_gather/trunk/vendor/plugins/attachment_fu) (revision 631)
@@ -1,8 +1,8 @@
module Technoweenie # :nodoc:
module AttachmentFu # :nodoc:
- @@default_processors = %w(ImageScience Rmagick MiniMagick)
- @@tempfile_path = File.join(RAILS_ROOT, 'tmp', 'attachment_fu')
- @@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg']
+ @@default_processors = %w(ImageScience Rmagick MiniMagick)
+ @@tempfile_path = File.join(RAILS_ROOT, 'tmp', 'attachment_fu')
+ @@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg']
mattr_reader :content_types, :tempfile_path, :default_processors
mattr_writer :tempfile_path
@@ -12,6 +12,7 @@
module ActMethods
# Options:
# * :content_type - Allowed content types. Allows all by default. Use :image to allow all standard image types.
+ # * :content_type_validation - Validate that the uploaded file actually has data of the allowed content_types. Unix only. Defaults to false.
# * :min_size - Minimum size allowed. 1 byte is the default.
# * :max_size - Maximum size allowed. 1.megabyte is the default.
# * :size - Range of sizes allowed. (1..1.megabyte) is the default. This overrides the :min_size and :max_size options.
@@ -45,6 +46,7 @@
options[:thumbnail_class] ||= self
options[:s3_access] ||= :public_read
options[:content_type] = [options[:content_type]].flatten.collect! { |t| t == :image ? Technoweenie::AttachmentFu.content_types : t }.flatten unless options[:content_type].nil?
+ options[:content_type_validation] ||= false
unless options[:thumbnails].is_a?(Hash)
raise ArgumentError, ":thumbnails option should be a hash: e.g. :thumbnails => { :foo => '50x50' }"
@@ -57,7 +59,7 @@
# only need to define these once on a class
unless included_modules.include?(InstanceMethods)
attr_accessor :thumbnail_resize_options
-
+ attachment_options[:content_type_regexp] = Regexp.new(attachment_options[:content_type].join('|'))
attachment_options[:storage] ||= (attachment_options[:file_system_path] || attachment_options[:path_prefix]) ? :file_system : :db_file
attachment_options[:path_prefix] ||= attachment_options[:file_system_path]
if attachment_options[:path_prefix].nil?
@@ -97,7 +99,7 @@
puts "Problems loading #{options[:processor]}Processor: #{$!}"
end
end
- after_validation :process_attachment
+ before_save :process_attachment
end
end
end
@@ -109,6 +111,7 @@
def validates_as_attachment
validates_presence_of :size, :content_type, :filename
validate :attachment_attributes_valid?
+ validate :attachment_content_type_valid? if self.attachment_options[:content_type_validation]
end
# Returns true or false if the given content type is recognized as an image.
@@ -352,6 +355,27 @@
end
end
+ #
+ # Validates that the uploaded file's data is actually of
+ # an acceptable mime type.
+ # This is necessary because the CGI mime-type identifier just uses
+ # the filename, which can be inaccurate.
+ #
+ # Unix-dependent method. Calls unix file(1) command to determine mime type by
+ # investigating the first bytes of the file.
+ def attachment_content_type_valid?
+ cmd = "file -i #{self.temp_path}"
+ output = `#{cmd}`
+ exit_code = $?
+ # if the whole job failed, report that to the log
+ unless exit_code.success?
+ logger.warn("Failed to validate attachment with command: [#{cmd}]. Exit code: #{exit_code}, Output: #{output}")
+ end
+ unless exit_code.success? && (! output.blank?) && (output =~ attachment_options[:content_type_regexp])
+ errors.add_to_base("File must have a valid content type")
+ end
+ end
+
# Initializes a new thumbnail with the given suffix.
def find_or_initialize_thumbnail(file_name_suffix)
respond_to?(:parent_id) ?