wicked_pdf icon indicating copy to clipboard operation
wicked_pdf copied to clipboard

PDF Password Protection

Open liam-lagay-14 opened this issue 8 years ago • 17 comments

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.

liam-lagay-14 avatar Jun 03 '16 16:06 liam-lagay-14

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!

unixmonkey avatar Jun 03 '16 18:06 unixmonkey

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

liam-lagay-14 avatar Jun 05 '16 19:06 liam-lagay-14

Did this work out?

unixmonkey avatar Jul 09 '16 21:07 unixmonkey

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 avatar Jul 10 '16 07:07 liam-lagay-14

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

liam-lagay-14 avatar Jul 10 '16 07:07 liam-lagay-14

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

varghesethomase avatar Aug 17 '16 10:08 varghesethomase

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

liam-lagay-14 avatar Aug 17 '16 11:08 liam-lagay-14

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 avatar Mar 29 '17 17:03 300sandeep

I had gone through above solution but not worked.

300sandeep avatar Mar 29 '17 17:03 300sandeep

@300sandeep Did you find solution with WickedPdf?

shah-disha avatar Jun 13 '18 06:06 shah-disha

@unixmonkey Appreciated help! Thanks

viveks1422 avatar Aug 08 '18 10:08 viveks1422

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

pratha-solutelabs avatar Sep 14 '18 07:09 pratha-solutelabs

@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'

unixmonkey avatar Sep 14 '18 10:09 unixmonkey

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

staroflead avatar Jan 04 '19 05:01 staroflead

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

prsanjay avatar Jul 08 '20 10:07 prsanjay

@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.

staroflead avatar Jul 08 '20 13:07 staroflead

@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

prsanjay avatar Jul 09 '20 08:07 prsanjay