1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
# encoding: utf-8
require "tempfile"
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
describe "Document encryption" do
describe "Password padding" do
include Prawn::Document::Security
it "should truncate long passwords" do
pw = "Long long string" * 30
padded = pad_password(pw)
expect(padded.length).to eq(32)
expect(padded).to eq(pw[0, 32])
end
it "should pad short passwords" do
pw = "abcd"
padded = pad_password(pw)
expect(padded.length).to eq(32)
expect(padded).to eq(pw + Prawn::Document::Security::PasswordPadding[0, 28])
end
it "should fully pad null passwords" do
pw = ""
padded = pad_password(pw)
expect(padded.length).to eq(32)
expect(padded).to eq(Prawn::Document::Security::PasswordPadding)
end
end
describe "Setting permissions" do
def doc_with_permissions(permissions)
pdf = Prawn::Document.new
class << pdf
# Make things easier to test
public :permissions_value
end
pdf.encrypt_document(:permissions => permissions)
pdf
end
it "should default to full permissions" do
expect(doc_with_permissions({}).permissions_value).to eq(0xFFFFFFFF)
expect(doc_with_permissions(:print_document => true,
:modify_contents => true,
:copy_contents => true,
:modify_annotations => true).permissions_value).
to eq(0xFFFFFFFF)
end
it "should clear the appropriate bits for each permission flag" do
expect(doc_with_permissions(:print_document => false).permissions_value).
to eq(0b1111_1111_1111_1111_1111_1111_1111_1011)
expect(doc_with_permissions(:modify_contents => false).permissions_value).
to eq(0b1111_1111_1111_1111_1111_1111_1111_0111)
expect(doc_with_permissions(:copy_contents => false).permissions_value).
to eq(0b1111_1111_1111_1111_1111_1111_1110_1111)
expect(doc_with_permissions(:modify_annotations => false).permissions_value).
to eq(0b1111_1111_1111_1111_1111_1111_1101_1111)
end
it "should raise_error ArgumentError if invalid option is provided" do
expect {
doc_with_permissions(:modify_document => false)
}.to raise_error(ArgumentError)
end
end
describe "Encryption keys" do
# Since PDF::Reader doesn't read encrypted PDF files, we just take the
# roundabout method of verifying each step of the encryption. This works
# fine because the encryption method is deterministic.
before(:each) do
@pdf = Prawn::Document.new
class << @pdf
public :owner_password_hash, :user_password_hash, :user_encryption_key
end
@pdf.encrypt_document :user_password => 'foo',
:owner_password => 'bar',
:permissions => { :print_document => false }
end
it "should calculate the correct owner hash" do
expect(@pdf.owner_password_hash.unpack("H*").first).to match(/^61CA855012/i)
end
it "should calculate the correct user hash" do
expect(@pdf.user_password_hash.unpack("H*").first).to match(/^6BC8C51031/i)
end
it "should calculate the correct user_encryption_key" do
expect(@pdf.user_encryption_key.unpack("H*").first.upcase).to eq("B100AB6429")
end
end
describe "EncryptedPdfObject" do
it "should delegate to PdfObject for simple types" do
expect(PDF::Core::EncryptedPdfObject(true, nil, nil, nil)).to eq("true")
expect(PDF::Core::EncryptedPdfObject(42, nil, nil, nil)).to eq("42")
end
it "should encrypt strings properly" do
expect(PDF::Core::EncryptedPdfObject("foo", "12345", 123, 0)).to eq("<4ad6e3>")
end
it "should encrypt literal strings properly" do
expect(PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("foo"), "12345", 123, 0)).to eq(bin_string("(J\xD6\xE3)"))
expect(PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("lhfbqg3do5u0satu3fjf"), nil, 123, 0)).to eq(bin_string("(\xF1\x8B\\(\b\xBB\xE18S\x130~4*#\\(%\x87\xE7\x8E\\\n)"))
end
it "should encrypt time properly" do
expect(PDF::Core::EncryptedPdfObject(Time.utc(2050, 04, 26, 10, 17, 10), "12345", 123, 0)).to eq(bin_string("(h\x83\xBE\xDC\xEC\x99\x0F\xD7\\)%\x13\xD4$\xB8\xF0\x16\xB8\x80\xC5\xE91+\xCF)"))
end
it "should properly handle compound types" do
expect(PDF::Core::EncryptedPdfObject({ :Bar => "foo" }, "12345", 123, 0)).to eq(
"<< /Bar <4ad6e3>\n>>"
)
expect(PDF::Core::EncryptedPdfObject(["foo", "bar"], "12345", 123, 0)).to eq(
"[<4ad6e3> <4ed8fe>]"
)
end
end
describe "Reference#encrypted_object" do
it "should encrypt references properly" do
ref = PDF::Core::Reference(1, ["foo"])
expect(ref.encrypted_object(nil)).to eq("1 0 obj\n[<4fca3f>]\nendobj\n")
end
it "should encrypt references with streams properly" do
ref = PDF::Core::Reference(1, {})
ref << 'foo'
result = bin_string("1 0 obj\n<< /Length 3\n>>\nstream\nO\xCA?\nendstream\nendobj\n")
expect(ref.encrypted_object(nil)).to eq(result)
end
end
describe "String#encrypted_object" do
it "should encrypt stream properly" do
stream = PDF::Core::Stream.new
stream << "foo"
result = bin_string("stream\nO\xCA?\nendstream\n")
expect(stream.encrypted_object(nil, 1, 0)).to eq(result)
end
end
end
|