mileszs / wicked_pdf

PDF generator (from HTML) plugin for Ruby on Rails
http://www.mileszs.com/wicked-pdf-plugin
MIT License
3.53k stars 644 forks source link

PDF Password Protection #546

Open liam-lagay-14 opened 8 years ago

liam-lagay-14 commented 8 years ago

Hi,

I'm currently looking at wicked_pdf as a possible solution for our PDF Generation that we do. One of the requirements I've been given is the ability to provide Password Protection as this is required for some of the PDFs we generate. I see that the gem provides username and password attributes but when I try them out, nothing happens.

I've also tried to get this working by setting basic_auth: true. Is there anything extra I need to do to get this working? I can't see much around this via Google, so any assistance would be greatly appreciated.

unixmonkey commented 8 years ago

The basic auth feature is to allow the html used to generate the final pdf the ability to reach out to basic auth protected sources to pull in stuff like images or javascripts that live on a basic-auth protected server, and don't have anything to do with password protecting the final pdf.

You could save the WickedPDF generated PDF file somewhere and then apply password protection afterward though.

I think a solution kind of like this should work for you with pure ruby code with Prawn (warning: untested, and may totally not at all work, but I think illustrates what you could do):

require 'prawn'
def index
  pdf = render_to_string(pdf: 'foo')
  foo_tempfile = Tempfile.new(['foo', '.pdf'])
  foo_tempfile.write(pdf)
  foo_tempfile.rewind
  foo_tempfile.close

  encrypted_tempfile = Tempfile.new(['encrypted', '.pdf'])
  Prawn::Document.generate(encrypted_tempfile.path, template: foo_tempfile.path) do |pdf|
    pdf.encrypt_document(user_password: 'foo', owner_password:  'foo')
  end

  send_data(encrypted_tempfile.read, filename: 'foo.pdf',  type: 'application/pdf')
ensure
  foo_tempfile.unlink
  encrypted_tempfile.unlink
end

Or you can shell out to the utility PDFtk something like this:

require 'open3'
def index
  pdf = render_to_string(pdf: 'foo')
  infile = Tempfile.new(['in', '.pdf'])
  infile.write(pdf)
  infile.rewind
  infile.close
  outfile = Tempfile.new(['out', '.pdf'])

  Open3.popen3("pdftk #{infile} output #{outfile} owner_pw 'foo' user_pw 'foo") do |stdin,stdout,stderr|
    # handle errors here maybe?
  end

  send_data(outfile.read, filename: 'foo.pdf',  type: 'application/pdf')
ensure
  infile.unlink
  outfile.unlink
end

Let me know if any of this works for you or not, and how it goes!

liam-lagay-14 commented 8 years ago

Thank you for this suggestion @unixmonkey I will give this a shot and see how this goes! Much appreciated!

unixmonkey commented 8 years ago

Did this work out?

liam-lagay-14 commented 8 years ago

Hi @unixmonkey,

I found a way to do this using a utility called qpdf which did the trick for me as well. Password protection is coming up in a future task so will let you guys know how it goes.

Thanks for the help!

liam-lagay-14 commented 8 years ago

Once I have a solution I'll leave a code snippet for knowledge share puroses!

varghesethomase commented 8 years ago

Hi @liam-lagay-14, Can you let me know the solution that had worked for you?

liam-lagay-14 commented 8 years ago

Hi @varghesethomase,

We are going to use PDFtk to do the work required to allow for password protection. I haven't got around to doing it yet as other priorities came up. I'll ensure when I do come to do it, that a knowledge share is done! As for timeframes, I can't put an estimate on this just yet, so apologies for the delay!

Thanks, Liam

300sandeep commented 7 years ago

Has anyone got an idea to make wicked pdf passowrd protective? Please provide me help. It's urgent. Or Any alternative so that wicked pdf can be made password protective.

300sandeep commented 7 years ago

I had gone through above solution but not worked.

shah-disha commented 6 years ago

@300sandeep Did you find solution with WickedPdf?

viveks1422 commented 6 years ago

@unixmonkey Appreciated help! Thanks

pratha-solutelabs commented 6 years ago

@300sandeep did get any solution for password protection on wicked pdf. I also tried above solutions but they are not working

unixmonkey commented 6 years ago

@pratha23 Can you elaborate what isn't working for you? The Prawn example probably doesn't work any longer under the current version of Prawn because they removed template support, but the PDFtk example should work, but you'll need to install pdftk first.

pdftk #{infile} output #{outfile} owner_pw 'foo' user_pw 'foo'

staroflead commented 5 years ago

I used a combination with gem origami to generate password protected pdf. First I use wicked_pdf to convert html to a pdf file. Then I used origami to read that file and encrypt it. So far so good.

   # Convert html to pdf
   pdf = WickedPdf.new.pdf_from_url(pdf_params[:url])
    temp_file = Tempfile.new('temp', encoding: 'ascii-8bit')
    temp_file.write(pdf)

    # Creates an encrypted document with AES256 and passwords.
    pdf = PDF.read(temp_file.path).encrypt(cipher: 'aes', key_size: 256,user_passwd: pdf_params[:user_password], owner_passwd: pdf_params[:owner_password])
    save_path = "#{File.basename(__FILE__, ".rb")}.pdf"

    pdf.save(save_path)
    temp_file.close
prsanjay commented 4 years ago

@staroflead, I used origami as per the example you given but the downloaded PDF has some encrypted contents. Do you know the reason?

staroflead commented 4 years ago

@prsanjay password protected file have illegible content after you open it with password? I don't know the reason. I tried with converting a news website and it was ok. That's all i tried, because client want to use Java instead of ruby so i didn't explore more. However, you could seek help from Origami because it's the problem of encryption.

prsanjay commented 4 years ago

@staroflead Thank you for the response. But eventually, it did work. I think the problem was with this method: render_to_string

But now, if I use WickedPdf.new.pdf_from_string(html_string) then footer is not working, however, it works if I call from below block

format.pdf do
    render pdf: 'file',
    template: 'template.html.erb',
    footer: {html: {template: {'footer.html.erb'}}}
end