Paperclip + RSpec: content_type validation - ruby-on-rails

I am using Paperclip in my Rails application for attaching images.
I declared validation for content_type in my model as
validates_attachment :image,
:content_type => { :content_type => ["image/jpg", "image/gif", "image/png"] }
I have two examples, one with a valid image and other with an invalid image
For an invalid image, i just renamed a .txt file to a .png
it "Image is valid" do
image = File.new("#{Rails.root}/spec/support/right.png")
expect(FactoryGirl.build(:pin, image: image)).to be_valid
end
it "Image is invalid" do
image = File.new("#{Rails.root}/spec/support/wrong.png")
expect(FactoryGirl.build(:pin, image: image)).to have(1).errors_on(:image_content_type)
end
I expected that both my examples should run successfully. BUT, my second example fails.
I don't get any error for content_type of wrong.png.
I thought that Paperclip's content_type validation would actually check file format(binary data encoding) of an uploaded file. BUT it seems that here, its just checking for the file extension. Does this validation only check extension of an uploaded file?
I maybe missing something here(configuration?). Is there any other validation available in Paperclip to achieve this? Or should I opt for a Custom Validator in this case?

This issue is resolved in Paperclip's latest version 4.1.1 released on February 21, 2014.
Both of my following examples pass correctly now.
it "Image is valid" do
image = File.new("#{Rails.root}/spec/support/right.png")
expect(FactoryGirl.build(:pin, image: image)).to be_valid
end
it "Image is invalid" do
image = File.new("#{Rails.root}/spec/support/wrong.png")
expect(FactoryGirl.build(:pin, image: image)).to have(1).errors_on(:image_content_type)
end
After a little bit of research found out that,
When I upload an invalid image,
For example: spoof(renamed) wrong.txt file as wrong.png and upload.
In prior release of Paperclip, wrong.png passes the content_type validation with flying colors without giving any error because Paperclip only used to check the extensions of the uploaded file and not content within.
Whereas, In the current release of Paperclip 4.1.1, same spoofed wrong.png fails the validation and throws the following error in view:
Image has an extension that does not match its contents
Upon investigating server log entries, I found the following:
Command :: file -b --mime-type
'/var/folders/tg/8sxl1vss4fb0sqtcrv3lzcfm0000gn/T/a7f21d0002b0d9d91eb158d702cd930320140317-531-swkmb8'
[paperclip] Content Type Spoof: Filename wrong.png (["image/png"]),
content type discovered from file command: text/plain. See
documentation to allow this combination.
Here, you can see that Paperclip actually checked the content of the uploaded file stating text/plain and also erred out saying Content Type Spoof.
Hope my findings will help others to understand how Paperclip's content-type validation has improved over the time.

Related

Error when upload images/documents via Paperclip: "has an extension that does not match its contents"

I ran into the error that when I upload images to S3 via Paperclip, I get an error: has an extension that does not match its contents. On a local machine, I do not experience such problems, only for production. This was observed after the update of rails 4.1.1 -> 4.1.16 and ruby 2.1.5 -> 2.3.1 and changing the instance to AWS.
Here is my validation:
validates_attachment :document,
content_type: { not: "application/x-msdownload" }
I do not understand what the problem is. Any file I upload, whether it's an image or a document (any extension) gets this error. Tell me please, with what it can be connected?
UPD
I found in log this:
[paperclip] Content Type Spoof: Filename example1.png (["image/png"]), content type discovered from file command: . See documentation to allow this combination.
UPD 2
This solved my problem

Add XSLT validation on XSLT File Upload

I have a Rails application with Paperclip file upload which is used to upload a XSLT file. I am looking for ways to validate the XSLT file before uploading. i can actually validate the content_type using paperclip
validates_attachment_content_type :xslt, content_type: "application/xslt+xml", message: 'Invalid Content Type. Please upload a valid XSLT file'
Is there a way I validate the XSLT file completely for syntax before saving it?
Yes, you can use Oxygen Editor to validate it or you can write the .net tool to validate it using Saxon dll.
Assuming you have the xslt files you could use the Nokogiri gem and do it as follows:
validate :xslt_validation
def xslt_validation(xml_message)
xml = Nokogiri::XML(xml_message)
template = Nokogiri::XSLT(File.open(Rails.root.join('path from root to xslt')))
validation = template.transform(xml)
result = Hash.from_xml(validation.to_s)['Name of the error report']
errors.add(:xslt_field, "XSLT errors: #{result['Errors']}") if result['Errors'].present?
end

How do I upload a csv file on Windows using Paperclip paperclip 4.3.2

There is this well known issue with Paperclip.
https://github.com/thoughtbot/paperclip/issues/1924
How do I configure my model so that this stupid spoofing validation will work?
Before the problem was discovered I was using:
validates_attachment_content_type :csv_import, :content_type => 'text/csv'
But that would not work on some versions of Windows. On Windows 7 Professional I get this error:
[paperclip] Content Type Spoof: Filename delivery_detail.csv (application/octet-stream from Headers, [#<MIME::Type:0x00000005077f38 #content_type="text/csv", #raw_media_type="text", #raw_sub_type="csv", #simplified="text/csv", #media_type="text", #sub_type="csv", #extensions=["csv"], #encoding="8bit", #system=nil, #registered=true, #url=["IANA", "RFC4180"], #obsolete=nil, #docs=nil>, #<MIME::Type:0x000000050c7f60 #content_type="text/comma-separated-values", #raw_media_type="text", #raw_sub_type="comma-separated-values", #simplified="text/comma-separated-values", #media_type="text", #sub_type="comma-separated-values", #extensions=["csv"], #encoding="8bit", #system=nil, #registered=false, #url=nil, #obsolete="!", #docs="use-instead:text/csv", #use_instead=["text/csv"]>] from Extension), content type discovered from file command: text/plain. See documentation to allow this combination.
Has anyone ever succeded in making paperclip upload csv files?
I tried every possible workaround from Github issue reports and nothing has worked. I need to see working example solution.
update 1
sonianand11 commented on 2 Oct 2014
https://github.com/thoughtbot/paperclip/issues/1470
This works, but it involves switching off content validation, Is there a better way to do it?.
I came up with the following solution:
add to the model:
validates_attachment_content_type :my_csv_uploaded_file, content_type: ['text/plain', 'text/csv', 'application/vnd.ms-excel']
and to the initializer:
Paperclip.options[:content_type_mappings] = { csv: 'application/vnd.ms-excel' }
It worked for me. It was tested using Windows 7 Professional

CDF V2 Document, No summary info. while using paperclip

Content type not recognizing while uploading files using paperclip + jquery file upload.
Throwing below error "content type discovered from file command: CDF V2 Document, No summary info. See documentation to allow this combination"
fail to upload the same.
We can fix this issue by adding below file in the intializers in rails -
# config/initializers/paperclip.rb
Paperclip.options[:content_type_mappings] = {
:xls => "CDF V2 Document, No summary info"
}
This solve my problem, hope this will help you as well.
Thank you.

Decoding attachments using Mail Gem and Paperclip

I can receive emails via imap through the mail gem and would like to add the attachments to my model (called message). I receive this error based on my code taken from this blog post:
Encoding::UndefinedConversionError ("\xC1" from ASCII-8BIT to UTF-8):
My code:
mail.attachments.each_with_index do | attachment, index |
fake_file = AttachmentFile.new("test.jpg")
fake_file.write(attachment.decoded)
fake_file.flush
fake_file.original_filename = attachment.filename
fake_file.content_type = "image/gif"
#message.doc1 = fake_file if index == 0 and attachment.content_type.start_with?("image/")
end
Not sure what I am doing wrong to cause the error - maybe because the file is not read in binary mode? Another alternative was given in the same post:
file = StringIO.new(attachment.decoded)
file.class.class_eval { attr_accessor :original_filename, :content_type }
file.original_filename = attachment.filename
file.content_type = attachment.mime_type
This worked once with a gif but failed with a pdf, providing rollbacks. Also, I am on Windows for Dev, which has lead to problems with paperclip in the past (file size not read properly etc.)
The model has the following validations:
validates_attachment_content_type :doc1, :content_type => [ 'application/pdf', /image/ ], :message => "only pdf or img"
My log files are not that helpful, only normal output for the first and second option:
Command :: SET PATH=/usr/bin;%PATH% & file -b --mime "C:/Users/FOUNDA~1/AppData/Local/Temp/c81e728d9d4c2f636f067f89cc14862c20150412-5216-1utzh29.gif"
Not sure what kind of initialization there is for the mail gem - it is able to pull the emails correctly. Sorry, maybe I misunderstood your reply.
I made a mistake by having a validation that requested a certain structure for the filename, which was causing problems. The second option I listed works flawlessly now. Can't speak for the first one - the problems there would be the same, probably.

Resources