Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: checksum of uploaded files

I am generating the checksum (sha256) of an uploaded image in Ruby on Rails.

upload = params[:file]
data1 = upload.read
data2 = File.read(upload.tempfile)
checksum1 = Digest::SHA256.hexdigest(data1)
checksum2 = Digest::SHA256.hexdigest(data2)
puts checksum1
puts checksum2

Last two statements are returning different values. checksum1 is generated by reading the data using the UploadedFile object. checksum2 is generated by reading the temporary file from the file system.

Does an object of ActionDispatch::Http::UploadedFile return anything more than the contents of the uploaded file? When I generate the checksum of the uploaded file written to the file-system, it is matching with checksum2 (temporary file checksum) , not with checksum1 (UploadedFile.read).

I am assuming that the checksum generated by reading the temporary file from the filesystem is more reliable as the object (UploadedFile) implementation might change. If needed, it will be easier to generate checksums of existing files on the file system.

So, what is the reason for the difference of checksums and which one is more reliable?

Thank you.


Update 1: As per @pablo-castellazzi suggestion i generated the hash by using Digest::SHA256.file(upload.path).hexdigest . Let us call this checksum3

This checksum3 equals checksum1 but differs from checksum2


Update 2: If i use the binary mode to read the file as mentioned by @Arsen7 , then all the checksums are equal.

like image 895
Srisa Avatar asked Oct 24 '22 08:10

Srisa


2 Answers

Have you compared the 'data1' and 'data2' contents? Try to save them to files and take a look.

I suppose, you may want to call upload.rewind before you do the first read, but the first thing is to take a look at the raw data read from the files.

Update:

You did not say that you are on Windows. In this case you should take care and read the files in so-called 'binary' mode.

Change the File.read method to something like this:

data2 = nil
File.open(upload.path, "rb") {|f| data2 = f.read }

(Implement Pablo Castellazzi suggestion of using .path method)

I was suggesting that you open the files in some binary-safe editor (vim, for example) and compare what differs. You would notice that maybe most of the data is the same, but in one of the files line endings are different, or maybe you would spot some other differences.

In case of Windows, the most popular problem is the binary mode.

like image 169
Arsen7 Avatar answered Oct 27 '22 09:10

Arsen7


Assuming you are using Rails 3.x data1 checksum is correct. data2 content should be read with:

data2 = File.read(upload.path)

upload.tempfile is the instance holding the file object, not the path to the temporary file.

Here are the relevant implementation details.

Also this is weird, because File.read(File.read) should throw some kind of exception about a file not found or an invalid file name.

like image 39
Pablo Castellazzi Avatar answered Oct 27 '22 10:10

Pablo Castellazzi