How do I create a checksum of carrierwave upload to verify the download? - ruby-on-rails

How do I create a checksum (MD5, sha512, whatever) of a file when I upload it, so that when I download (using cache_stored_file!), I can verify that it is indeed the original file that was uploaded?

The Ruby Digest module can help with this.
One way solution would be to read the file on upload and assign it a unique digest with a before_create callback. I would add it as a column on the file table in your database.
Here's some output from IRB to show how it would work:
2.2.2 :001 > require 'digest'
=> true
2.2.2 :002 > f = File.read 'test.rb'
=> "Original content\n"
2.2.2 :003 > Digest::SHA256.hexdigest(f)
=> "646722e7ee99e28d618142b9d3a1bfcbe2196d8332ae632cc867ae5d1c8c57b5"
# (... file modified ...)
2.2.2 :004 > f = File.read 'test.rb'
=> "Original content with more content\n"
2.2.2 :005 > Digest::SHA256.hexdigest(f)
=> "c29f2f77c0777a78dbdf119bf0a58b470c098635dfc8279542e4c49d6f20e62c"
You can use this digest in your download method to check the integrity of the file. If you read the file again, produce a digest, and it matches the original digest, you can be confident the file hasn't been altered since it was uploaded.
Ruby Digest Module

md5 = Digest::MD5.file('path_to_file').hexdigest
This would read file in blocks and avoid reading the whole file in RAM which is done in File.read()
For SHA checksum
Digest::SHA2.hexdigest( File.read("/path/to/my/file.txt") );
OR
Digest::SHA2.file(myFile).hexdigest
=> "fa5880ac744f3c05c649a864739530ac387c8c8b0231a7d008c27f0f6a2753c7"
More details for SHA checksum generation SHA Checksum

Related

Edit existing pdf file metadata with ruby (Apply Password protection)

I am uploading a pdf file using paperclip to s3. I want to apply password protection on the fly to the uploaded pdf file.
I tried to use the code given in question How to edit or write on existing PDF with Ruby?! to edit existing pdf file (the tmp file used by the paperclip) and try to apply password protection using
Prawn::Document.generate("tmp/abc.pdf",:template => params[:ebook].path) do encrypt_document(:user_password => 'foo', :owner_password => 'bar',
:permissions => { :print_document => false,
:modify_contents => false,
:copy_contents => false,
:modify_annotations => false } end
Is the template support still exist in prawn or it had been deprecated as i didn't find anything regarding template in the prawn manual! ?
Is there any other way or any other gem to do so ?
Thanks.
template was removed in version 0.13.0 because it was too buggy :
Support for templates was dropped in Prawn 0.13.0, disabled by default in 0.14.0, and extracted in 0.15.0.
This gem includes the extracted templates code, which is completely unsupported, but provides the old functionality that was in Prawn 0.12.0 for years.
source : https://github.com/prawnpdf/prawn-templates
As he said, you can try to add the library to your current Prawn installation.
Otherwise you can use pdftk with Open3 module (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/) :
require 'open3'
file_name = 'hello_world_1.pdf' # input
file_name_output = 'hello_world_2.pdf' # output
usr = 'foo'
pwd = 'bar'
pdftek = './pdftk.exe' # tested on windows
Open3.popen3("#{pdftek} #{file_name} output #{file_name_output} owner_pw #{pwd} user_pw #{usr}") do |stdin,stdout,stderr|
# ...
end
There is also a wrapper for ruby but I haven't test it yet : https://github.com/tcocca/active_pdftk

iTMSTransporter metadata.xml md5 utility ios

So I have 100 achievements to upload, rather than using the website I thought it may be faster to create a metadata.xml file and use iTMSTransporter to upload the data. Unfortunately one snag is a MD5 checksum must be computed for each image file, or Apple rejects the entire itmsp package. Requiring this almost invalidates the whole "ease" of using iTMSTransporter.
Is there a utility to parse the metadata file and update it with the checksums? Or perhaps something which generates a metadata file and does it?
There is a command line program that will generate the metadata.xml file and compute the files' checksums. It requires you to put your metadata in a YAML file which it turns into a metadata.xml: https://github.com/colinhumber/itunes_transporter_generator
You can use this script to update a directory containing a metadata.xml file (or files) and assets:
require "rexml/document"
require "digest"
def set_checksum(path)
xml = File.read(path)
doc = Document.new(xml)
doc.get_elements("//achievement//file_name").each do |e|
next unless e.text =~ /\S/
file = File.join($source, e.text.strip)
puts "Computing checksum for #{file}"
$md5.file(file)
checksum = $md5.hexdigest!
node = e.parent.elements["checksum"]
node = Element.new("checksum", e.parent) unless node
node.text = checksum
node.add_attribute("type", "md5")
end
puts "Saving update file"
File.write(path, doc.to_s)
end
include REXML
$source = ARGV.shift || Dir.pwd
$md5 = Digest::MD5.new
Dir["#$source/*.xml"].each do |path|
puts "Processing #{path}"
set_checksum(path)
end
Use it as follows:
> ruby script.rb
or
> ruby script.rb /path/to/metadata/directory

Download file from PostgreSQL bytea escape

I have some issue to allow users download file, which stored in PostgreSQL bytea escaped field (http://www.postgresql.org/docs/current/interactive/datatype-binary.html).
1.9.3p385 :023 > data = PG::Connection.unescape_bytea(m[:data])
=> "JVBERi0xLjMKJcTl8uXrp/Og0MTGCjQgMCBvYmoKPDwgL0xlbmd0aCA1IDAg\r\nUiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpzd..."
1.9.3p385 :023 > data.encoding.name
=> "ASCII-8BIT"
1.9.3p385 :023 > data.bytesize
=> 3878164
But when I used "send_data" or "send_file" with tempfile, I getting file in invalid format (this is pdf file). It much bigger, than original and not opening by pdf readers.
This data in field is mime part of email. If I build raw email from all this parts (using boundary as separator), this email will contain valid pdf attachment.
How should I convert this data to bytes to allow user download this file separately?
See the following: http://rubyforge.org/tracker/index.php?func=detail&aid=27845&group_id=234&atid=967
The syntax is something like PGConn.unescape_bytea($field);
Depending on your version of pg, you may need to upgrade that gem

Rails 3, check CSV file encoding before import

In my app (Rails 3.0.5, Ruby 1.8.7), I created an import tool to import CSV data from file.
Problem: I asked my users to export the CSV file from Excel in UTF-8 encoding but they don't do it most of time.
How can I just verify if the file is UTF-8 before importing ? Else the import will run but give strange results. I use FasterCSV to import.
Exemple of bad CSV file:
;VallÈe du RhÙne;CÙte Rotie;
Thanks.
You can use Charlock Holmes, a character encoding detecting library for Ruby.
https://github.com/brianmario/charlock_holmes
To use it, you just read the file, and use the detect method.
contents = File.read('test.xml')
detection = CharlockHolmes::EncodingDetector.detect(contents)
# => {:encoding => 'UTF-8', :confidence => 100, :type => :text}
You can also convert the encoding to UTF-8 if it is not in the correct format:
utf8_encoded_content = CharlockHolmes::Converter.convert contents, detection[:encoding], 'UTF-8'
This saves users from having to do it themselves before uploading it again.
For 1.9 it's obvious, you just tell it to expect utf8 and it will raise an error if it isn't:
begin
lines = CSV.read('bad.csv', :encoding => 'utf-8')
rescue ArgumentError
puts "My users don't listen to me!"
end

How can I find the size of an uploaded file in Ruby on Rails?

I am not using carrierwave or paperclip for my file upload. I want to find out the file extension and the size in bytes of a file that the user has uploaded? Any ideas on how I can achieve this?
File.size(doc.filename)
Just throw the name of the file into the curly brackets and you should be set.
If you want KB/MB use:
number_to_human_size(File.size(doc.filename))
EDIT:
You can use the exact path or Pathname
1.9.3p125 :005 > x=Pathname.new("/usr/bin/ruby")
=> #<Pathname:/usr/bin/ruby>
1.9.3p125 :006 > File.size(x)
=> 5488
For extension:
File.extname("test.rb") #=> ".rb"
params[:file].size
File.extname(params[:file].original_name)
or params[:file].original_name.match(/\.(\S*)$/).try(:"[]",1)
You can use Ruby's File class methods.
File.size
File.extname

Resources