origami 1.2.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/README.md +112 -0
- data/bin/config/pdfcop.conf.yml +232 -233
- data/bin/gui/about.rb +27 -37
- data/bin/gui/config.rb +108 -117
- data/bin/gui/file.rb +416 -365
- data/bin/gui/gtkhex.rb +1138 -1153
- data/bin/gui/hexview.rb +55 -57
- data/bin/gui/imgview.rb +48 -51
- data/bin/gui/menu.rb +388 -386
- data/bin/gui/properties.rb +114 -130
- data/bin/gui/signing.rb +571 -617
- data/bin/gui/textview.rb +77 -95
- data/bin/gui/treeview.rb +382 -387
- data/bin/gui/walker.rb +227 -232
- data/bin/gui/xrefs.rb +56 -60
- data/bin/pdf2pdfa +53 -57
- data/bin/pdf2ruby +212 -228
- data/bin/pdfcop +338 -348
- data/bin/pdfdecompress +58 -65
- data/bin/pdfdecrypt +56 -60
- data/bin/pdfencrypt +75 -80
- data/bin/pdfexplode +185 -182
- data/bin/pdfextract +201 -218
- data/bin/pdfmetadata +83 -82
- data/bin/pdfsh +4 -5
- data/bin/pdfwalker +1 -2
- data/bin/shell/.irbrc +45 -82
- data/bin/shell/console.rb +105 -130
- data/bin/shell/hexdump.rb +40 -64
- data/examples/README.md +34 -0
- data/examples/attachments/attachment.rb +38 -0
- data/examples/attachments/nested_document.rb +51 -0
- data/examples/encryption/encryption.rb +28 -0
- data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
- data/examples/flash/flash.rb +37 -0
- data/{samples → examples}/flash/helloworld.swf +0 -0
- data/examples/forms/javascript.rb +54 -0
- data/examples/forms/xfa.rb +115 -0
- data/examples/javascript/hello_world.rb +22 -0
- data/examples/javascript/js_emulation.rb +54 -0
- data/examples/loop/goto.rb +32 -0
- data/examples/loop/named.rb +33 -0
- data/examples/signature/signature.rb +65 -0
- data/examples/uri/javascript.rb +56 -0
- data/examples/uri/open-uri.rb +21 -0
- data/examples/uri/submitform.rb +47 -0
- data/lib/origami.rb +29 -42
- data/lib/origami/3d.rb +350 -225
- data/lib/origami/acroform.rb +262 -288
- data/lib/origami/actions.rb +268 -288
- data/lib/origami/annotations.rb +697 -722
- data/lib/origami/array.rb +258 -184
- data/lib/origami/boolean.rb +74 -84
- data/lib/origami/catalog.rb +397 -434
- data/lib/origami/collections.rb +144 -0
- data/lib/origami/destinations.rb +233 -194
- data/lib/origami/dictionary.rb +253 -232
- data/lib/origami/encryption.rb +1274 -1243
- data/lib/origami/export.rb +232 -268
- data/lib/origami/extensions/fdf.rb +307 -220
- data/lib/origami/extensions/ppklite.rb +368 -435
- data/lib/origami/filespec.rb +197 -0
- data/lib/origami/filters.rb +301 -295
- data/lib/origami/filters/ascii.rb +177 -180
- data/lib/origami/filters/ccitt.rb +528 -535
- data/lib/origami/filters/crypt.rb +26 -35
- data/lib/origami/filters/dct.rb +46 -52
- data/lib/origami/filters/flate.rb +95 -94
- data/lib/origami/filters/jbig2.rb +49 -55
- data/lib/origami/filters/jpx.rb +38 -44
- data/lib/origami/filters/lzw.rb +189 -183
- data/lib/origami/filters/predictors.rb +221 -235
- data/lib/origami/filters/runlength.rb +103 -104
- data/lib/origami/font.rb +173 -186
- data/lib/origami/functions.rb +67 -81
- data/lib/origami/graphics.rb +25 -21
- data/lib/origami/graphics/colors.rb +178 -187
- data/lib/origami/graphics/instruction.rb +79 -85
- data/lib/origami/graphics/path.rb +142 -148
- data/lib/origami/graphics/patterns.rb +160 -167
- data/lib/origami/graphics/render.rb +43 -50
- data/lib/origami/graphics/state.rb +138 -153
- data/lib/origami/graphics/text.rb +188 -205
- data/lib/origami/graphics/xobject.rb +819 -815
- data/lib/origami/header.rb +63 -78
- data/lib/origami/javascript.rb +596 -597
- data/lib/origami/linearization.rb +285 -290
- data/lib/origami/metadata.rb +139 -148
- data/lib/origami/name.rb +112 -148
- data/lib/origami/null.rb +53 -62
- data/lib/origami/numeric.rb +162 -175
- data/lib/origami/obfuscation.rb +186 -174
- data/lib/origami/object.rb +593 -573
- data/lib/origami/outline.rb +42 -47
- data/lib/origami/outputintents.rb +73 -82
- data/lib/origami/page.rb +703 -592
- data/lib/origami/parser.rb +238 -290
- data/lib/origami/parsers/fdf.rb +41 -33
- data/lib/origami/parsers/pdf.rb +75 -95
- data/lib/origami/parsers/pdf/lazy.rb +137 -0
- data/lib/origami/parsers/pdf/linear.rb +64 -66
- data/lib/origami/parsers/ppklite.rb +34 -70
- data/lib/origami/pdf.rb +1030 -1005
- data/lib/origami/reference.rb +102 -102
- data/lib/origami/signature.rb +591 -609
- data/lib/origami/stream.rb +668 -551
- data/lib/origami/string.rb +397 -373
- data/lib/origami/template/patterns.rb +56 -0
- data/lib/origami/template/widgets.rb +151 -0
- data/lib/origami/trailer.rb +144 -158
- data/lib/origami/tree.rb +62 -0
- data/lib/origami/version.rb +23 -0
- data/lib/origami/webcapture.rb +88 -79
- data/lib/origami/xfa.rb +2863 -2882
- data/lib/origami/xreftable.rb +472 -384
- data/test/dataset/calc.pdf +85 -0
- data/test/dataset/crypto.pdf +82 -0
- data/test/dataset/empty.pdf +49 -0
- data/test/test_actions.rb +27 -0
- data/test/test_annotations.rb +90 -0
- data/test/test_pages.rb +31 -0
- data/test/test_pdf.rb +16 -0
- data/test/test_pdf_attachment.rb +34 -0
- data/test/test_pdf_create.rb +24 -0
- data/test/test_pdf_encrypt.rb +95 -0
- data/test/test_pdf_parse.rb +96 -0
- data/test/test_pdf_sign.rb +58 -0
- data/test/test_streams.rb +182 -0
- data/test/test_xrefs.rb +67 -0
- metadata +88 -58
- data/README +0 -67
- data/bin/pdf2graph +0 -121
- data/bin/pdfcocoon +0 -104
- data/lib/origami/file.rb +0 -233
- data/samples/README.txt +0 -45
- data/samples/actions/launch/calc.rb +0 -87
- data/samples/actions/launch/winparams.rb +0 -22
- data/samples/actions/loop/loopgoto.rb +0 -24
- data/samples/actions/loop/loopnamed.rb +0 -21
- data/samples/actions/named/named.rb +0 -31
- data/samples/actions/samba/smbrelay.rb +0 -26
- data/samples/actions/webbug/submitform.js +0 -26
- data/samples/actions/webbug/webbug-browser.rb +0 -68
- data/samples/actions/webbug/webbug-js.rb +0 -67
- data/samples/actions/webbug/webbug-reader.rb +0 -90
- data/samples/attachments/attach.rb +0 -40
- data/samples/attachments/attached.txt +0 -1
- data/samples/crypto/crypto.rb +0 -28
- data/samples/digsig/signed.rb +0 -46
- data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
- data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
- data/samples/exploits/exploit_customdictopen.rb +0 -55
- data/samples/exploits/getannots.rb +0 -69
- data/samples/flash/flash.rb +0 -31
- data/samples/javascript/attached.txt +0 -1
- data/samples/javascript/js.rb +0 -52
- data/templates/patterns.rb +0 -66
- data/templates/widgets.rb +0 -173
- data/templates/xdp.rb +0 -92
- data/test/ts_pdf.rb +0 -50
data/lib/origami/reference.rb
CHANGED
|
@@ -1,116 +1,116 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
-
GNU Lesser General Public License for more details.
|
|
20
|
-
|
|
21
|
-
You should have received a copy of the GNU Lesser General Public License
|
|
22
|
-
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
3
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
|
4
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
5
|
+
|
|
6
|
+
Origami is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
Origami is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Lesser General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
23
18
|
|
|
24
19
|
=end
|
|
25
20
|
|
|
26
21
|
module Origami
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
# Class representing a Reference Object.
|
|
33
|
-
# Reference are like symbolic links pointing to a particular object into the file.
|
|
34
|
-
#
|
|
35
|
-
class Reference
|
|
36
|
-
|
|
37
|
-
include Origami::Object
|
|
38
|
-
|
|
39
|
-
TOKENS = [ "(\\d+)" + WHITESPACES + "(\\d+)" + WHITESPACES + "R" ] #:nodoc:
|
|
40
|
-
REGEXP_TOKEN = Regexp.new(TOKENS.first, Regexp::MULTILINE)
|
|
41
|
-
@@regexp = Regexp.new(WHITESPACES + TOKENS.first + WHITESPACES)
|
|
42
|
-
|
|
43
|
-
attr_accessor :refno, :refgen
|
|
44
|
-
|
|
45
|
-
def initialize(refno, refgen)
|
|
46
|
-
@refno, @refgen = refno, refgen
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.parse(stream, parser = nil) #:nodoc:
|
|
50
|
-
|
|
51
|
-
offset = stream.pos
|
|
52
|
-
|
|
53
|
-
if stream.scan(@@regexp).nil?
|
|
54
|
-
raise InvalidReferenceError, "Bad reference to indirect objet format"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
refno = stream[2].to_i
|
|
58
|
-
refgen = stream[4].to_i
|
|
59
|
-
|
|
60
|
-
ref = Reference.new(refno,refgen)
|
|
61
|
-
ref.file_offset = offset
|
|
62
|
-
|
|
63
|
-
ref
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def solve
|
|
67
|
-
pdfdoc = self.pdf
|
|
68
|
-
|
|
69
|
-
if pdfdoc.nil?
|
|
70
|
-
raise InvalidReferenceError, "Not attached to any PDF"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
target = pdfdoc.get_object(self)
|
|
74
|
-
|
|
75
|
-
if target.nil? and not Origami::OPTIONS[:ignore_bad_references]
|
|
76
|
-
raise InvalidReferenceError, "Cannot resolve reference : #{self.to_s}"
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
target or Null.new
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def eql?(ref) #:nodoc
|
|
83
|
-
ref.is_a?(Reference) and ref.refno == @refno and ref.refgen == @refgen
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def hash #:nodoc:
|
|
87
|
-
self.to_a.hash
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def <=>(ref) #:nodoc
|
|
91
|
-
self.to_a <=> ref.to_a
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
# Returns a Ruby array with the object number and the generation this reference is pointing to.
|
|
96
|
-
#
|
|
97
|
-
def to_a
|
|
98
|
-
[@refno, @refgen]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def to_s #:nodoc:
|
|
102
|
-
super("#{@refno} #{@refgen} R")
|
|
23
|
+
class InvalidReferenceError < Error #:nodoc:
|
|
103
24
|
end
|
|
104
|
-
|
|
25
|
+
|
|
105
26
|
#
|
|
106
|
-
#
|
|
27
|
+
# Class representing a Reference Object.
|
|
28
|
+
# Reference are like symbolic links pointing to a particular object into the file.
|
|
107
29
|
#
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
30
|
+
class Reference
|
|
31
|
+
include Origami::Object
|
|
32
|
+
|
|
33
|
+
TOKENS = [ "(?<no>\\d+)" + WHITESPACES + "(?<gen>\\d+)" + WHITESPACES + "R" ] #:nodoc:
|
|
34
|
+
REGEXP_TOKEN = Regexp.new(TOKENS.first, Regexp::MULTILINE)
|
|
35
|
+
@@regexp = Regexp.new(WHITESPACES + TOKENS.first + WHITESPACES)
|
|
36
|
+
|
|
37
|
+
attr_accessor :refno, :refgen
|
|
38
|
+
|
|
39
|
+
def initialize(refno, refgen)
|
|
40
|
+
super()
|
|
41
|
+
|
|
42
|
+
@refno, @refgen = refno, refgen
|
|
43
|
+
end
|
|
111
44
|
|
|
112
|
-
|
|
45
|
+
def self.parse(stream, parser = nil) #:nodoc:
|
|
46
|
+
offset = stream.pos
|
|
113
47
|
|
|
114
|
-
|
|
48
|
+
if stream.scan(@@regexp).nil?
|
|
49
|
+
raise InvalidReferenceError, "Bad reference to indirect objet format"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
no = stream['no'].to_i
|
|
53
|
+
gen = stream['gen'].to_i
|
|
54
|
+
|
|
55
|
+
ref = Reference.new(no, gen)
|
|
56
|
+
ref.file_offset = offset
|
|
57
|
+
|
|
58
|
+
ref
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def solve
|
|
62
|
+
doc = self.document
|
|
63
|
+
|
|
64
|
+
if doc.nil?
|
|
65
|
+
raise InvalidReferenceError, "Not attached to any document"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
target = doc.get_object(self)
|
|
69
|
+
|
|
70
|
+
if target.nil? and not Origami::OPTIONS[:ignore_bad_references]
|
|
71
|
+
raise InvalidReferenceError, "Cannot resolve reference : #{self.to_s}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
target or Null.new
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def hash #:nodoc:
|
|
78
|
+
self.to_a.hash
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def <=>(ref) #:nodoc
|
|
82
|
+
self.to_a <=> ref.to_a
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Compares to Reference object.
|
|
87
|
+
#
|
|
88
|
+
def ==(ref)
|
|
89
|
+
return false unless ref.is_a?(Reference)
|
|
90
|
+
|
|
91
|
+
self.to_a == ref.to_a
|
|
92
|
+
end
|
|
93
|
+
alias eql? ==
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Returns a Ruby array with the object number and the generation this reference is pointing to.
|
|
97
|
+
#
|
|
98
|
+
def to_a
|
|
99
|
+
[@refno, @refgen]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def to_s #:nodoc:
|
|
103
|
+
super("#{@refno} #{@refgen} R")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# Returns self.
|
|
108
|
+
#
|
|
109
|
+
def value
|
|
110
|
+
self
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.native_type ; Reference end
|
|
114
|
+
end
|
|
115
115
|
|
|
116
116
|
end
|
data/lib/origami/signature.rb
CHANGED
|
@@ -1,643 +1,625 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
-
GNU Lesser General Public License for more details.
|
|
20
|
-
|
|
21
|
-
You should have received a copy of the GNU Lesser General Public License
|
|
22
|
-
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
3
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
|
4
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
5
|
+
|
|
6
|
+
Origami is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
Origami is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Lesser General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
23
18
|
|
|
24
19
|
=end
|
|
25
20
|
|
|
26
21
|
begin
|
|
27
|
-
|
|
22
|
+
require 'openssl' if Origami::OPTIONS[:use_openssl]
|
|
28
23
|
rescue LoadError
|
|
29
|
-
|
|
30
|
-
end
|
|
24
|
+
Origami::OPTIONS[:use_openssl] = false
|
|
25
|
+
end
|
|
31
26
|
|
|
32
27
|
require 'digest/sha1'
|
|
33
28
|
|
|
34
29
|
module Origami
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
class PDF
|
|
32
|
+
class SignatureError < Error #:nodoc:
|
|
33
|
+
end
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
#
|
|
36
|
+
# Verify a document signature.
|
|
37
|
+
# _:trusted_certs_: an array of trusted X509 certificates.
|
|
38
|
+
# If no argument is passed, embedded certificates are treated as trusted.
|
|
39
|
+
#
|
|
40
|
+
def verify(trusted_certs: [])
|
|
41
|
+
unless Origami::OPTIONS[:use_openssl]
|
|
42
|
+
fail "OpenSSL is not present or has been disabled."
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
digsig = self.signature
|
|
46
|
+
|
|
47
|
+
unless digsig[:Contents].is_a?(String)
|
|
48
|
+
raise SignatureError, "Invalid digital signature contents"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
store = OpenSSL::X509::Store.new
|
|
52
|
+
trusted_certs.each do |ca| store.add_cert(ca) end
|
|
53
|
+
flags = 0
|
|
54
|
+
flags |= OpenSSL::PKCS7::NOVERIFY if trusted_certs.empty?
|
|
55
|
+
|
|
56
|
+
stream = StringScanner.new(self.original_data)
|
|
57
|
+
stream.pos = digsig[:Contents].file_offset
|
|
58
|
+
Object.typeof(stream).parse(stream)
|
|
59
|
+
endofsig_offset = stream.pos
|
|
60
|
+
stream.terminate
|
|
61
|
+
|
|
62
|
+
s1,l1,s2,l2 = digsig.ByteRange
|
|
63
|
+
if s1.value != 0 or
|
|
64
|
+
(s2.value + l2.value) != self.original_data.size or
|
|
65
|
+
(s1.value + l1.value) != digsig[:Contents].file_offset or
|
|
66
|
+
s2.value != endofsig_offset
|
|
67
|
+
|
|
68
|
+
raise SignatureError, "Invalid signature byte range"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
data = self.original_data[s1,l1] + self.original_data[s2,l2]
|
|
72
|
+
|
|
73
|
+
case digsig.SubFilter.value.to_s
|
|
74
|
+
when 'adbe.pkcs7.detached'
|
|
75
|
+
flags |= OpenSSL::PKCS7::DETACHED
|
|
76
|
+
p7 = OpenSSL::PKCS7.new(digsig[:Contents].value)
|
|
77
|
+
raise SignatureError, "Not a PKCS7 detached signature" unless p7.detached?
|
|
78
|
+
p7.verify([], store, data, flags)
|
|
79
|
+
|
|
80
|
+
when 'adbe.pkcs7.sha1'
|
|
81
|
+
p7 = OpenSSL::PKCS7.new(digsig[:Contents].value)
|
|
82
|
+
p7.verify([], store, nil, flags) and p7.data == Digest::SHA1.digest(data)
|
|
83
|
+
|
|
84
|
+
else
|
|
85
|
+
raise NotImplementedError, "Unsupported method #{digsig.SubFilter}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
40
88
|
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
digsig.ByteRange[2] = sigoffset + digsig.Contents.size
|
|
225
|
-
|
|
226
|
-
digsig.ByteRange[3] = filesize - digsig.ByteRange[2] until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
|
|
227
|
-
|
|
228
|
-
# From that point the file size remains constant
|
|
229
|
-
|
|
230
|
-
#
|
|
231
|
-
# Correct Xrefs variations caused by ByteRange modifications.
|
|
232
|
-
#
|
|
233
|
-
rebuildxrefs
|
|
234
|
-
|
|
235
|
-
filedata = output()
|
|
236
|
-
signable_data = filedata[digsig.ByteRange[0],digsig.ByteRange[1]] + filedata[digsig.ByteRange[2],digsig.ByteRange[3]]
|
|
237
|
-
|
|
238
|
-
signature =
|
|
239
|
-
case params[:method]
|
|
240
|
-
when 'adbe.pkcs7.detached'
|
|
241
|
-
OpenSSL::PKCS7.sign(
|
|
242
|
-
certificate,
|
|
243
|
-
key,
|
|
244
|
-
signable_data,
|
|
245
|
-
ca,
|
|
246
|
-
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
|
|
247
|
-
).to_der
|
|
89
|
+
#
|
|
90
|
+
# Sign the document with the given key and x509 certificate.
|
|
91
|
+
# _certificate_:: The X509 certificate containing the public key.
|
|
92
|
+
# _key_:: The private key associated with the certificate.
|
|
93
|
+
# _method_:: The PDF signature identifier.
|
|
94
|
+
# _ca_:: Optional CA certificates used to sign the user certificate.
|
|
95
|
+
# _annotation_:: Annotation associated with the signature.
|
|
96
|
+
# _issuer_:: Issuer name.
|
|
97
|
+
# _location_:: Signature location.
|
|
98
|
+
# _contact_:: Signer contact.
|
|
99
|
+
# _reason_:: Signing reason.
|
|
100
|
+
#
|
|
101
|
+
def sign(certificate, key,
|
|
102
|
+
method: "adbe.pkcs7.detached",
|
|
103
|
+
ca: [],
|
|
104
|
+
annotation: nil,
|
|
105
|
+
issuer: nil,
|
|
106
|
+
location: nil,
|
|
107
|
+
contact: nil,
|
|
108
|
+
reason: nil)
|
|
109
|
+
|
|
110
|
+
unless Origami::OPTIONS[:use_openssl]
|
|
111
|
+
fail "OpenSSL is not present or has been disabled."
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
unless certificate.is_a?(OpenSSL::X509::Certificate)
|
|
115
|
+
raise TypeError, "A OpenSSL::X509::Certificate object must be passed."
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
unless key.is_a?(OpenSSL::PKey::RSA)
|
|
119
|
+
raise TypeError, "A OpenSSL::PKey::RSA object must be passed."
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
unless ca.is_a?(::Array)
|
|
123
|
+
raise TypeError, "Expected an Array of CA certificate."
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
unless annotation.nil? or annotation.is_a?(Annotation::Widget::Signature)
|
|
127
|
+
raise TypeError, "Expected a Annotation::Widget::Signature object."
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
case method
|
|
131
|
+
when 'adbe.pkcs7.detached'
|
|
132
|
+
signfield_size = -> (crt, pkey, certs) do
|
|
133
|
+
OpenSSL::PKCS7.sign(
|
|
134
|
+
crt,
|
|
135
|
+
pkey,
|
|
136
|
+
"",
|
|
137
|
+
certs,
|
|
138
|
+
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
|
|
139
|
+
).to_der.size
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
when 'adbe.pkcs7.sha1'
|
|
143
|
+
signfield_size = -> (crt, pkey, certs) do
|
|
144
|
+
OpenSSL::PKCS7.sign(
|
|
145
|
+
crt,
|
|
146
|
+
pkey,
|
|
147
|
+
Digest::SHA1.digest(''),
|
|
148
|
+
certs,
|
|
149
|
+
OpenSSL::PKCS7::BINARY
|
|
150
|
+
).to_der.size
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
when 'adbe.x509.rsa_sha1'
|
|
154
|
+
signfield_size = -> (crt, pkey, certs) do
|
|
155
|
+
pkey.private_encrypt(
|
|
156
|
+
Digest::SHA1.digest('')
|
|
157
|
+
).size
|
|
158
|
+
end
|
|
159
|
+
raise NotImplementedError, "Unsupported method #{method.inspect}"
|
|
160
|
+
|
|
161
|
+
else
|
|
162
|
+
raise NotImplementedError, "Unsupported method #{method.inspect}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
digsig = Signature::DigitalSignature.new.set_indirect(true)
|
|
166
|
+
|
|
167
|
+
if annotation.nil?
|
|
168
|
+
annotation = Annotation::Widget::Signature.new
|
|
169
|
+
annotation.Rect = Rectangle[:llx => 0.0, :lly => 0.0, :urx => 0.0, :ury => 0.0]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
annotation.V = digsig
|
|
173
|
+
add_fields(annotation)
|
|
174
|
+
self.Catalog.AcroForm.SigFlags =
|
|
175
|
+
InteractiveForm::SigFlags::SIGNATURESEXIST | InteractiveForm::SigFlags::APPENDONLY
|
|
176
|
+
|
|
177
|
+
digsig.Type = :Sig #:nodoc:
|
|
178
|
+
digsig.Contents = HexaString.new("\x00" * signfield_size[certificate, key, ca]) #:nodoc:
|
|
179
|
+
digsig.Filter = :"Adobe.PPKLite" #:nodoc:
|
|
180
|
+
digsig.SubFilter = Name.new(method) #:nodoc:
|
|
181
|
+
digsig.ByteRange = [0, 0, 0, 0] #:nodoc:
|
|
182
|
+
digsig.Name = issuer
|
|
183
|
+
|
|
184
|
+
digsig.Location = HexaString.new(location) if location
|
|
185
|
+
digsig.ContactInfo = HexaString.new(contact) if contact
|
|
186
|
+
digsig.Reason = HexaString.new(reason) if reason
|
|
187
|
+
|
|
188
|
+
if method == 'adbe.x509.rsa_sha1'
|
|
189
|
+
digsig.Cert =
|
|
190
|
+
if ca.empty?
|
|
191
|
+
HexaString.new(certificate.to_der)
|
|
192
|
+
else
|
|
193
|
+
[ HexaString.new(certificate.to_der) ] + ca.map{ |crt| HexaString.new(crt.to_der) }
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
#
|
|
198
|
+
# Flattening the PDF to get file view.
|
|
199
|
+
#
|
|
200
|
+
compile
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
# Creating an empty Xref table to compute signature byte range.
|
|
204
|
+
#
|
|
205
|
+
rebuild_dummy_xrefs
|
|
206
|
+
|
|
207
|
+
sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
|
|
208
|
+
|
|
209
|
+
digsig.ByteRange[0] = 0
|
|
210
|
+
digsig.ByteRange[1] = sig_offset
|
|
211
|
+
digsig.ByteRange[2] = sig_offset + digsig.Contents.to_s.bytesize
|
|
212
|
+
|
|
213
|
+
until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
|
|
214
|
+
digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# From that point on, the file size remains constant
|
|
218
|
+
|
|
219
|
+
#
|
|
220
|
+
# Correct Xrefs variations caused by ByteRange modifications.
|
|
221
|
+
#
|
|
222
|
+
rebuild_xrefs
|
|
223
|
+
|
|
224
|
+
file_data = output()
|
|
225
|
+
signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] +
|
|
226
|
+
file_data[digsig.ByteRange[2],digsig.ByteRange[3]]
|
|
227
|
+
|
|
228
|
+
signature =
|
|
229
|
+
case method
|
|
230
|
+
when 'adbe.pkcs7.detached'
|
|
231
|
+
OpenSSL::PKCS7.sign(
|
|
232
|
+
certificate,
|
|
233
|
+
key,
|
|
234
|
+
signable_data,
|
|
235
|
+
ca,
|
|
236
|
+
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
|
|
237
|
+
).to_der
|
|
238
|
+
|
|
239
|
+
when 'adbe.pkcs7.sha1'
|
|
240
|
+
OpenSSL::PKCS7.sign(
|
|
241
|
+
certificate,
|
|
242
|
+
key,
|
|
243
|
+
Digest::SHA1.digest(signable_data),
|
|
244
|
+
ca,
|
|
245
|
+
OpenSSL::PKCS7::BINARY
|
|
246
|
+
).to_der
|
|
247
|
+
|
|
248
|
+
when 'adbe.x509.rsa_sha1'
|
|
249
|
+
key.private_encrypt(Digest::SHA1.digest(signable_data))
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
digsig.Contents[0, signature.size] = signature
|
|
253
|
+
|
|
254
|
+
#
|
|
255
|
+
# No more modification are allowed after signing.
|
|
256
|
+
#
|
|
257
|
+
self.freeze
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
#
|
|
261
|
+
# Returns whether the document contains a digital signature.
|
|
262
|
+
#
|
|
263
|
+
def signed?
|
|
264
|
+
begin
|
|
265
|
+
self.Catalog.AcroForm.is_a?(Dictionary) and
|
|
266
|
+
self.Catalog.AcroForm.has_key?(:SigFlags) and
|
|
267
|
+
(self.Catalog.AcroForm.SigFlags & InteractiveForm::SigFlags::SIGNATURESEXIST != 0)
|
|
268
|
+
rescue InvalidReferenceError
|
|
269
|
+
false
|
|
270
|
+
end
|
|
271
|
+
end
|
|
248
272
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
273
|
+
#
|
|
274
|
+
# Enable the document Usage Rights.
|
|
275
|
+
# _rights_:: list of rights defined in UsageRights::Rights
|
|
276
|
+
#
|
|
277
|
+
def enable_usage_rights(cert, pkey, *rights)
|
|
278
|
+
unless Origami::OPTIONS[:use_openssl]
|
|
279
|
+
fail "OpenSSL is not present or has been disabled."
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
signfield_size = -> (crt, key, ca) do
|
|
283
|
+
OpenSSL::PKCS7.sign(
|
|
284
|
+
crt,
|
|
285
|
+
key,
|
|
286
|
+
'',
|
|
287
|
+
ca,
|
|
288
|
+
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
|
|
289
|
+
).to_der.size
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
#
|
|
293
|
+
# Load key pair
|
|
294
|
+
#
|
|
295
|
+
key = pkey.is_a?(OpenSSL::PKey::RSA) ? pkey : OpenSSL::PKey::RSA.new(pkey)
|
|
296
|
+
certificate = cert.is_a?(OpenSSL::X509::Certificate) ? cert : OpenSSL::X509::Certificate.new(cert)
|
|
297
|
+
|
|
298
|
+
#
|
|
299
|
+
# Forge digital signature dictionary
|
|
300
|
+
#
|
|
301
|
+
digsig = Signature::DigitalSignature.new.set_indirect(true)
|
|
302
|
+
|
|
303
|
+
self.Catalog.AcroForm ||= InteractiveForm.new
|
|
304
|
+
#self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::APPENDONLY
|
|
305
|
+
|
|
306
|
+
digsig.Type = :Sig #:nodoc:
|
|
307
|
+
digsig.Contents = HexaString.new("\x00" * signfield_size[certificate, key, []]) #:nodoc:
|
|
308
|
+
digsig.Filter = :"Adobe.PPKLite" #:nodoc:
|
|
309
|
+
digsig.Name = "ARE Acrobat Product v8.0 P23 0002337" #:nodoc:
|
|
310
|
+
digsig.SubFilter = :"adbe.pkcs7.detached" #:nodoc:
|
|
311
|
+
digsig.ByteRange = [0, 0, 0, 0] #:nodoc:
|
|
312
|
+
|
|
313
|
+
sigref = Signature::Reference.new #:nodoc:
|
|
314
|
+
sigref.Type = :SigRef #:nodoc:
|
|
315
|
+
sigref.TransformMethod = :UR3 #:nodoc:
|
|
316
|
+
sigref.Data = self.Catalog
|
|
317
|
+
|
|
318
|
+
sigref.TransformParams = UsageRights::TransformParams.new
|
|
319
|
+
sigref.TransformParams.P = true #:nodoc:
|
|
320
|
+
sigref.TransformParams.Type = :TransformParams #:nodoc:
|
|
321
|
+
sigref.TransformParams.V = UsageRights::TransformParams::VERSION
|
|
322
|
+
|
|
323
|
+
rights.each do |right|
|
|
324
|
+
sigref.TransformParams[right.first] ||= []
|
|
325
|
+
sigref.TransformParams[right.first].concat(right[1..-1])
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
digsig.Reference = [ sigref ]
|
|
329
|
+
|
|
330
|
+
self.Catalog.Perms ||= Perms.new
|
|
331
|
+
self.Catalog.Perms.UR3 = digsig
|
|
332
|
+
|
|
333
|
+
#
|
|
334
|
+
# Flattening the PDF to get file view.
|
|
335
|
+
#
|
|
336
|
+
compile
|
|
337
|
+
|
|
338
|
+
#
|
|
339
|
+
# Creating an empty Xref table to compute signature byte range.
|
|
340
|
+
#
|
|
341
|
+
rebuild_dummy_xrefs
|
|
342
|
+
|
|
343
|
+
sig_offset = get_object_offset(digsig.no, digsig.generation) + digsig.signature_offset
|
|
344
|
+
|
|
345
|
+
digsig.ByteRange[0] = 0
|
|
346
|
+
digsig.ByteRange[1] = sig_offset
|
|
347
|
+
digsig.ByteRange[2] = sig_offset + digsig.Contents.size
|
|
348
|
+
|
|
349
|
+
until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
|
|
350
|
+
digsig.ByteRange[3] = filesize - digsig.ByteRange[2]
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# From that point on, the file size remains constant
|
|
354
|
+
|
|
355
|
+
#
|
|
356
|
+
# Correct Xrefs variations caused by ByteRange modifications.
|
|
357
|
+
#
|
|
358
|
+
rebuild_xrefs
|
|
359
|
+
|
|
360
|
+
file_data = output()
|
|
361
|
+
signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] +
|
|
362
|
+
file_data[digsig.ByteRange[2],digsig.ByteRange[3]]
|
|
363
|
+
|
|
364
|
+
signature = OpenSSL::PKCS7.sign(
|
|
365
|
+
certificate,
|
|
366
|
+
key,
|
|
367
|
+
signable_data,
|
|
368
|
+
[],
|
|
369
|
+
OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY
|
|
256
370
|
).to_der
|
|
371
|
+
digsig.Contents[0, signature.size] = signature
|
|
257
372
|
|
|
258
|
-
|
|
259
|
-
|
|
373
|
+
#
|
|
374
|
+
# No more modification are allowed after signing.
|
|
375
|
+
#
|
|
376
|
+
self.freeze
|
|
260
377
|
end
|
|
261
378
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
self.Catalog.AcroForm.has_key?(:SigFlags) and
|
|
277
|
-
(self.Catalog.AcroForm.SigFlags & InteractiveForm::SigFlags::SIGNATURESEXIST != 0)
|
|
278
|
-
rescue InvalidReferenceError
|
|
279
|
-
false
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
#
|
|
284
|
-
# Enable the document Usage Rights.
|
|
285
|
-
# _rights_:: list of rights defined in UsageRights::Rights
|
|
286
|
-
#
|
|
287
|
-
def enable_usage_rights(cert, pkey, *rights)
|
|
288
|
-
|
|
289
|
-
unless Origami::OPTIONS[:use_openssl]
|
|
290
|
-
fail "OpenSSL is not present or has been disabled."
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
signfield_size = lambda{|crt, key, ca|
|
|
294
|
-
datatest = "abcdefghijklmnopqrstuvwxyz"
|
|
295
|
-
OpenSSL::PKCS7.sign(crt, key, datatest, ca, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der.size + 128
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
#
|
|
299
|
-
# Load key pair
|
|
300
|
-
#
|
|
301
|
-
key = pkey.is_a?(OpenSSL::PKey::RSA) ? pkey : OpenSSL::PKey::RSA.new(pkey)
|
|
302
|
-
certificate = cert.is_a?(OpenSSL::X509::Certificate) ? cert : OpenSSL::X509::Certificate.new(cert)
|
|
303
|
-
|
|
304
|
-
#
|
|
305
|
-
# Forge digital signature dictionary
|
|
306
|
-
#
|
|
307
|
-
digsig = Signature::DigitalSignature.new.set_indirect(true)
|
|
308
|
-
|
|
309
|
-
self.Catalog.AcroForm ||= InteractiveForm.new
|
|
310
|
-
#self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::APPENDONLY
|
|
311
|
-
|
|
312
|
-
digsig.Type = :Sig #:nodoc:
|
|
313
|
-
digsig.Contents = HexaString.new("\x00" * signfield_size[certificate, key, []]) #:nodoc:
|
|
314
|
-
digsig.Filter = Name.new("Adobe.PPKLite") #:nodoc:
|
|
315
|
-
digsig.Name = "ARE Acrobat Product v8.0 P23 0002337" #:nodoc:
|
|
316
|
-
digsig.SubFilter = Name.new("adbe.pkcs7.detached") #:nodoc:
|
|
317
|
-
digsig.ByteRange = [0, 0, 0, 0] #:nodoc:
|
|
318
|
-
|
|
319
|
-
sigref = Signature::Reference.new #:nodoc:
|
|
320
|
-
sigref.Type = :SigRef #:nodoc:
|
|
321
|
-
sigref.TransformMethod = :UR3 #:nodoc:
|
|
322
|
-
sigref.Data = self.Catalog
|
|
323
|
-
|
|
324
|
-
sigref.TransformParams = UsageRights::TransformParams.new
|
|
325
|
-
sigref.TransformParams.P = true #:nodoc:
|
|
326
|
-
sigref.TransformParams.Type = :TransformParams #:nodoc:
|
|
327
|
-
sigref.TransformParams.V = UsageRights::TransformParams::VERSION
|
|
328
|
-
|
|
329
|
-
rights.each do |right|
|
|
330
|
-
sigref.TransformParams[right.first] ||= []
|
|
331
|
-
sigref.TransformParams[right.first].concat(right[1..-1])
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
digsig.Reference = [ sigref ]
|
|
335
|
-
|
|
336
|
-
self.Catalog.Perms ||= Perms.new
|
|
337
|
-
self.Catalog.Perms.UR3 = digsig
|
|
338
|
-
|
|
339
|
-
#
|
|
340
|
-
# Flattening the PDF to get file view.
|
|
341
|
-
#
|
|
342
|
-
compile
|
|
343
|
-
|
|
344
|
-
#
|
|
345
|
-
# Creating an empty Xref table to compute signature byte range.
|
|
346
|
-
#
|
|
347
|
-
rebuild_dummy_xrefs
|
|
348
|
-
|
|
349
|
-
sigoffset = get_object_offset(digsig.no, digsig.generation) + digsig.sigOffset
|
|
350
|
-
|
|
351
|
-
digsig.ByteRange[0] = 0
|
|
352
|
-
digsig.ByteRange[1] = sigoffset
|
|
353
|
-
digsig.ByteRange[2] = sigoffset + digsig.Contents.size
|
|
354
|
-
|
|
355
|
-
digsig.ByteRange[3] = filesize - digsig.ByteRange[2] until digsig.ByteRange[3] == filesize - digsig.ByteRange[2]
|
|
356
|
-
|
|
357
|
-
# From that point the file size remains constant
|
|
358
|
-
|
|
359
|
-
#
|
|
360
|
-
# Correct Xrefs variations caused by ByteRange modifications.
|
|
361
|
-
#
|
|
362
|
-
rebuildxrefs
|
|
363
|
-
|
|
364
|
-
filedata = output()
|
|
365
|
-
signable_data = filedata[digsig.ByteRange[0],digsig.ByteRange[1]] + filedata[digsig.ByteRange[2],digsig.ByteRange[3]]
|
|
366
|
-
|
|
367
|
-
signature = OpenSSL::PKCS7.sign(certificate, key, signable_data, [], OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der
|
|
368
|
-
digsig.Contents[0, signature.size] = signature
|
|
369
|
-
|
|
370
|
-
#
|
|
371
|
-
# No more modification are allowed after signing.
|
|
372
|
-
#
|
|
373
|
-
self.freeze
|
|
374
|
-
|
|
379
|
+
def usage_rights?
|
|
380
|
+
not self.Catalog.Perms.nil? and
|
|
381
|
+
(not self.Catalog.Perms.has_key?(:UR3) or not self.Catalog.Perms.has_key?(:UR))
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def signature
|
|
385
|
+
raise SignatureError, "Not a signed document" unless self.signed?
|
|
386
|
+
|
|
387
|
+
self.each_field do |field|
|
|
388
|
+
return field.V if field.FT == :Sig and field.V.is_a?(Dictionary)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
raise SignatureError, "Cannot find digital signature"
|
|
392
|
+
end
|
|
375
393
|
end
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
394
|
+
|
|
395
|
+
class Perms < Dictionary
|
|
396
|
+
include StandardObject
|
|
397
|
+
|
|
398
|
+
field :DocMDP, :Type => Dictionary
|
|
399
|
+
field :UR, :Type => Dictionary
|
|
400
|
+
field :UR3, :Type => Dictionary, :Version => "1.6"
|
|
379
401
|
end
|
|
380
402
|
|
|
381
|
-
|
|
382
|
-
|
|
403
|
+
module Signature
|
|
404
|
+
|
|
405
|
+
#
|
|
406
|
+
# Class representing a signature which can be embedded in DigitalSignature dictionary.
|
|
407
|
+
# It must be a direct object.
|
|
408
|
+
#
|
|
409
|
+
class Reference < Dictionary
|
|
410
|
+
include StandardObject
|
|
411
|
+
|
|
412
|
+
field :Type, :Type => Name, :Default => :SigRef
|
|
413
|
+
field :TransformMethod, :Type => Name, :Default => :DocMDP, :Required => true
|
|
414
|
+
field :TransformParams, :Type => Dictionary
|
|
415
|
+
field :Data, :Type => Object
|
|
416
|
+
field :DigestMethod, :Type => Name, :Default => :MD5
|
|
417
|
+
field :DigestValue, :Type => String
|
|
418
|
+
field :DigestLocation, :Type => Array
|
|
419
|
+
|
|
420
|
+
def initialize(hash = {}, parser = nil)
|
|
421
|
+
set_indirect(false)
|
|
383
422
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return field.V
|
|
423
|
+
super(hash, parser)
|
|
424
|
+
end
|
|
387
425
|
end
|
|
388
|
-
end
|
|
389
426
|
|
|
390
|
-
|
|
391
|
-
|
|
427
|
+
class BuildData < Dictionary
|
|
428
|
+
include StandardObject
|
|
429
|
+
|
|
430
|
+
field :Name, :Type => Name, :Version => "1.5"
|
|
431
|
+
field :Date, :Type => String, :Version => "1.5"
|
|
432
|
+
field :R, :Type => Number, :Version => "1.5"
|
|
433
|
+
field :PreRelease, :Type => Boolean, :Default => false, :Version => "1.5"
|
|
434
|
+
field :OS, :Type => Array, :Version => "1.5"
|
|
435
|
+
field :NonEFontNoWarn, :Type => Boolean, :Version => "1.5"
|
|
436
|
+
field :TrustedMode, :Type => Boolean, :Version => "1.5"
|
|
437
|
+
field :V, :Type => Number, :Version => "1.5"
|
|
438
|
+
|
|
439
|
+
def initialize(hash = {}, parser = nil)
|
|
440
|
+
set_indirect(false)
|
|
392
441
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
class Perms < Dictionary
|
|
396
|
-
|
|
397
|
-
include StandardObject
|
|
398
|
-
|
|
399
|
-
field :DocMDP, :Type => Dictionary
|
|
400
|
-
field :UR, :Type => Dictionary
|
|
401
|
-
field :UR3, :Type => Dictionary, :Version => "1.6"
|
|
402
|
-
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
module Signature
|
|
406
|
-
|
|
407
|
-
#
|
|
408
|
-
# Class representing a digital signature.
|
|
409
|
-
#
|
|
410
|
-
class DigitalSignature < Dictionary
|
|
411
|
-
|
|
412
|
-
include StandardObject
|
|
413
|
-
|
|
414
|
-
field :Type, :Type => Name, :Default => :Sig
|
|
415
|
-
field :Filter, :Type => Name, :Default => "Adobe.PPKMS".to_sym, :Required => true
|
|
416
|
-
field :SubFilter, :Type => Name
|
|
417
|
-
field :Contents, :Type => String, :Required => true
|
|
418
|
-
field :Cert, :Type => [ Array, String ]
|
|
419
|
-
field :ByteRange, :Type => Array
|
|
420
|
-
field :Reference, :Type => Array, :Version => "1.5"
|
|
421
|
-
field :Changes, :Type => Array
|
|
422
|
-
field :Name, :Type => String
|
|
423
|
-
field :M, :Type => String
|
|
424
|
-
field :Location, :Type => String
|
|
425
|
-
field :Reason, :Type => String
|
|
426
|
-
field :ContactInfo, :Type => String
|
|
427
|
-
field :R, :Type => Integer
|
|
428
|
-
field :V, :Type => Integer, :Default => 0, :Version => "1.5"
|
|
429
|
-
field :Prop_Build, :Type => Dictionary, :Version => "1.5"
|
|
430
|
-
field :Prop_AuthTime, :Type => Integer, :Version => "1.5"
|
|
431
|
-
field :Prop_AuthType, :Type => Name, :Version => "1.5"
|
|
432
|
-
|
|
433
|
-
def pre_build #:nodoc:
|
|
434
|
-
self.M = Origami::Date.now
|
|
435
|
-
self.Prop_Build ||= BuildProperties.new.pre_build
|
|
436
|
-
|
|
437
|
-
super
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
def to_s(dummy_param = nil) #:nodoc:
|
|
441
|
-
indent = 1
|
|
442
|
-
pairs = self.to_a
|
|
443
|
-
content = TOKENS.first + EOL
|
|
444
|
-
|
|
445
|
-
pairs.sort_by{ |k| k.to_s }.reverse.each do |pair|
|
|
446
|
-
key, value = pair[0].to_o, pair[1].to_o
|
|
447
|
-
|
|
448
|
-
content << "\t" * indent + key.to_s + " " + (value.is_a?(Dictionary) ? value.to_s(indent + 1) : value.to_s) + EOL
|
|
442
|
+
super(hash, parser)
|
|
443
|
+
end
|
|
449
444
|
end
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
445
|
+
|
|
446
|
+
class AppData < BuildData
|
|
447
|
+
field :REx, :Type => String, :Version => "1.6"
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
class SigQData < BuildData
|
|
451
|
+
field :Preview, :Type => Boolean, :Default => false, :Version => "1.7"
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
class BuildProperties < Dictionary
|
|
455
|
+
include StandardObject
|
|
456
|
+
|
|
457
|
+
field :Filter, :Type => BuildData, :Version => "1.5"
|
|
458
|
+
field :PubSec, :Type => BuildData, :Version => "1.5"
|
|
459
|
+
field :App, :Type => AppData, :Version => "1.5"
|
|
460
|
+
field :SigQ, :Type => SigQData, :Version => "1.7"
|
|
461
|
+
|
|
462
|
+
def initialize(hash = {}, parser = nil)
|
|
463
|
+
set_indirect(false)
|
|
464
|
+
|
|
465
|
+
super(hash, parser)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
def pre_build #:nodoc:
|
|
469
|
+
self.Filter ||= BuildData.new
|
|
470
|
+
self.Filter.Name ||= :"Adobe.PPKLite"
|
|
471
|
+
self.Filter.R ||= 0x20020
|
|
472
|
+
self.Filter.V ||= 2
|
|
473
|
+
self.Filter.Date ||= Time.now.to_s
|
|
474
|
+
|
|
475
|
+
self.PubSec ||= BuildData.new
|
|
476
|
+
self.PubSec.NonEFontNoWarn ||= true
|
|
477
|
+
self.PubSec.Date ||= Time.now.to_s
|
|
478
|
+
self.PubSec.R ||= 0x20021
|
|
479
|
+
|
|
480
|
+
self.App ||= AppData.new
|
|
481
|
+
self.App.Name ||= :Reader
|
|
482
|
+
self.App.REx = "11.0.8"
|
|
483
|
+
self.App.TrustedMode ||= true
|
|
484
|
+
self.App.OS ||= [ :Win ]
|
|
485
|
+
self.App.R ||= 0xb0008
|
|
486
|
+
|
|
487
|
+
super
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
#
|
|
492
|
+
# Class representing a digital signature.
|
|
493
|
+
#
|
|
494
|
+
class DigitalSignature < Dictionary
|
|
495
|
+
include StandardObject
|
|
496
|
+
|
|
497
|
+
field :Type, :Type => Name, :Default => :Sig
|
|
498
|
+
field :Filter, :Type => Name, :Default => :"Adobe.PPKLite", :Required => true
|
|
499
|
+
field :SubFilter, :Type => Name
|
|
500
|
+
field :Contents, :Type => String, :Required => true
|
|
501
|
+
field :Cert, :Type => [ String, Array.of(String) ]
|
|
502
|
+
field :ByteRange, :Type => Array.of(Integer, length: 4)
|
|
503
|
+
field :Reference, :Type => Array.of(Reference), :Version => "1.5"
|
|
504
|
+
field :Changes, :Type => Array
|
|
505
|
+
field :Name, :Type => String
|
|
506
|
+
field :M, :Type => String
|
|
507
|
+
field :Location, :Type => String
|
|
508
|
+
field :Reason, :Type => String
|
|
509
|
+
field :ContactInfo, :Type => String
|
|
510
|
+
field :R, :Type => Integer
|
|
511
|
+
field :V, :Type => Integer, :Default => 0, :Version => "1.5"
|
|
512
|
+
field :Prop_Build, :Type => BuildProperties, :Version => "1.5"
|
|
513
|
+
field :Prop_AuthTime, :Type => Integer, :Version => "1.5"
|
|
514
|
+
field :Prop_AuthType, :Type => Name, :Version => "1.5"
|
|
515
|
+
|
|
516
|
+
def pre_build #:nodoc:
|
|
517
|
+
self.M = Origami::Date.now
|
|
518
|
+
self.Prop_Build ||= BuildProperties.new.pre_build
|
|
519
|
+
|
|
520
|
+
super
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def to_s(indent: 1, tab: "\t") #:nodoc:
|
|
524
|
+
|
|
525
|
+
# Must be deterministic.
|
|
526
|
+
indent, tab = 1, "\t"
|
|
527
|
+
|
|
528
|
+
content = TOKENS.first + EOL
|
|
529
|
+
|
|
530
|
+
self.to_a.sort_by{ |key, _| key }.reverse.each do |key, value|
|
|
531
|
+
content << tab * indent << key.to_s << " "
|
|
532
|
+
content << (value.is_a?(Dictionary) ? value.to_s(indent: indent + 1) : value.to_s) << EOL
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
content << tab * (indent - 1) << TOKENS.last
|
|
536
|
+
|
|
537
|
+
output(content)
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
def signature_offset #:nodoc:
|
|
541
|
+
indent, tab = 1, "\t"
|
|
542
|
+
content = "#{no} #{generation} obj" + EOL + TOKENS.first + EOL
|
|
543
|
+
|
|
544
|
+
self.to_a.sort_by{ |key, _| key }.reverse.each do |key, value|
|
|
545
|
+
if key == :Contents
|
|
546
|
+
content << tab * indent + key.to_s + " "
|
|
547
|
+
|
|
548
|
+
return content.size
|
|
549
|
+
else
|
|
550
|
+
content << tab * indent + key.to_s << " "
|
|
551
|
+
content << (value.is_a?(Dictionary) ? value.to_s(indent: indent + 1) : value.to_s) << EOL
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
nil
|
|
556
|
+
end
|
|
471
557
|
end
|
|
472
|
-
|
|
473
|
-
nil
|
|
474
|
-
end
|
|
475
|
-
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
#
|
|
479
|
-
# Class representing a signature which can be embedded in DigitalSignature dictionary.
|
|
480
|
-
# It must be a direct object.
|
|
481
|
-
#
|
|
482
|
-
class Reference < Dictionary
|
|
483
|
-
|
|
484
|
-
include StandardObject
|
|
485
|
-
|
|
486
|
-
field :Type, :Type => Name, :Default => :SigRef
|
|
487
|
-
field :TransformMethod, :Type => Name, :Default => :DocMDP, :Required => true
|
|
488
|
-
field :TransformParams, :Type => Dictionary
|
|
489
|
-
field :Data, :Type => Object
|
|
490
|
-
field :DigestMethod, :Type => Name, :Default => :MD5
|
|
491
|
-
field :DigestValue, :Type => String
|
|
492
|
-
field :DigestLocation, :Type => Array
|
|
493
|
-
|
|
494
|
-
def initialize(hash = {})
|
|
495
|
-
set_indirect(false)
|
|
496
|
-
|
|
497
|
-
super(hash)
|
|
498
|
-
end
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
class BuildProperties < Dictionary
|
|
502
|
-
|
|
503
|
-
include StandardObject
|
|
504
|
-
|
|
505
|
-
field :Filter, :Type => Dictionary, :Version => "1.5"
|
|
506
|
-
field :PubSec, :Type => Dictionary, :Version => "1.5"
|
|
507
|
-
field :App, :Type => Dictionary, :Version => "1.5"
|
|
508
|
-
field :SigQ, :Type => Dictionary, :Version => "1.7"
|
|
509
|
-
|
|
510
|
-
def initialize(hash = {})
|
|
511
|
-
set_indirect(false)
|
|
512
|
-
|
|
513
|
-
super(hash)
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
def pre_build #:nodoc:
|
|
517
|
-
|
|
518
|
-
self.Filter ||= BuildData.new
|
|
519
|
-
self.Filter.Name ||= Name.new("Adobe.PPKMS")
|
|
520
|
-
self.Filter.R ||= 0x2001D
|
|
521
|
-
self.Filter.Date ||= Time.now.to_s
|
|
522
|
-
|
|
523
|
-
self.SigQ ||= SigQData.new
|
|
524
|
-
self.SigQ.Preview ||= false
|
|
525
|
-
self.SigQ.R ||= 0x2001D
|
|
526
|
-
|
|
527
|
-
self.PubSec ||= BuildData.new
|
|
528
|
-
self.PubSec.NonEFontNoWarn ||= false
|
|
529
|
-
self.PubSec.Date ||= Time.now.to_s
|
|
530
|
-
self.PubSec.R ||= 0x2001D
|
|
531
|
-
|
|
532
|
-
self.App ||= AppData.new
|
|
533
|
-
self.App.TrustedMode ||= false
|
|
534
|
-
self.App.OS ||= [ :Win ]
|
|
535
|
-
self.App.R ||= 0x70000
|
|
536
|
-
self.App.Name ||= Name.new("Exchange-Pro")
|
|
537
|
-
|
|
538
|
-
super
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
class BuildData < Dictionary
|
|
544
|
-
|
|
545
|
-
include StandardObject
|
|
546
|
-
|
|
547
|
-
field :Name, :Type => Name, :Version => "1.5"
|
|
548
|
-
field :Date, :Type => String, :Version => "1.5"
|
|
549
|
-
field :R, :Type => Number, :Version => "1.5"
|
|
550
|
-
field :PreRelease, :Type => Boolean, :Default => false, :Version => "1.5"
|
|
551
|
-
field :OS, :Type => Array, :Version => "1.5"
|
|
552
|
-
field :NonEFontNoWarn, :Type => Boolean, :Version => "1.5"
|
|
553
|
-
field :TrustedMode, :Type => Boolean, :Version => "1.5"
|
|
554
|
-
field :V, :Type => Number, :Version => "1.5"
|
|
555
|
-
|
|
556
|
-
def initialize(hash = {})
|
|
557
|
-
set_indirect(false)
|
|
558
|
-
|
|
559
|
-
super(hash)
|
|
560
|
-
end
|
|
561
|
-
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
class AppData < BuildData
|
|
565
|
-
field :REx, :Type => String, :Version => "1.6"
|
|
566
|
-
end
|
|
567
|
-
|
|
568
|
-
class SigQData < BuildData
|
|
569
|
-
field :Preview, :Type => Boolean, :Default => false, :Version => "1.7"
|
|
570
|
-
end
|
|
571
558
|
|
|
572
|
-
end
|
|
573
|
-
|
|
574
|
-
module UsageRights
|
|
575
|
-
|
|
576
|
-
module Rights
|
|
577
|
-
|
|
578
|
-
DOCUMENT_FULLSAVE = [:Document, :FullSave]
|
|
579
|
-
DOCUMENT_ALL = DOCUMENT_FULLSAVE
|
|
580
|
-
|
|
581
|
-
ANNOTS_CREATE = [:Annots, :Create]
|
|
582
|
-
ANNOTS_DELETE = [:Annots, :Delete]
|
|
583
|
-
ANNOTS_MODIFY = [:Annots, :Modify]
|
|
584
|
-
ANNOTS_COPY = [:Annots, :Copy]
|
|
585
|
-
ANNOTS_IMPORT = [:Annots, :Import]
|
|
586
|
-
ANNOTS_EXPORT = [:Annots, :Export]
|
|
587
|
-
ANNOTS_ONLINE = [:Annots, :Online]
|
|
588
|
-
ANNOTS_SUMMARYVIEW = [:Annots, :SummaryView]
|
|
589
|
-
ANNOTS_ALL = [ :Annots, :Create, :Modify, :Copy, :Import, :Export, :Online, :SummaryView ]
|
|
590
|
-
|
|
591
|
-
FORM_FILLIN = [:Form, :FillIn]
|
|
592
|
-
FORM_IMPORT = [:Form, :Import]
|
|
593
|
-
FORM_EXPORT = [:Form, :Export]
|
|
594
|
-
FORM_SUBMITSTANDALONE = [:Form, :SubmitStandAlone]
|
|
595
|
-
FORM_SPAWNTEMPLATE = [:Form, :SpawnTemplate]
|
|
596
|
-
FORM_BARCODEPLAINTEXT = [:Form, :BarcodePlaintext]
|
|
597
|
-
FORM_ONLINE = [:Form, :Online]
|
|
598
|
-
FORM_ALL = [:Form, :FillIn, :Import, :Export, :SubmitStandAlone, :SpawnTemplate, :BarcodePlaintext, :Online]
|
|
599
|
-
|
|
600
|
-
FORMEX_BARCODEPLAINTEXT = [:FormEx, :BarcodePlaintext]
|
|
601
|
-
FORMEX_ALL = FORMEX_BARCODEPLAINTEXT
|
|
602
|
-
|
|
603
|
-
SIGNATURE_MODIFY = [:Signature, :Modify]
|
|
604
|
-
SIGNATURE_ALL = SIGNATURE_MODIFY
|
|
605
|
-
|
|
606
|
-
EF_CREATE = [:EF, :Create]
|
|
607
|
-
EF_DELETE = [:EF, :Delete]
|
|
608
|
-
EF_MODIFY = [:EF, :Modify]
|
|
609
|
-
EF_IMPORT = [:EF, :Import]
|
|
610
|
-
EF_ALL = [:EF, :Create, :Delete, :Modify, :Import]
|
|
611
|
-
|
|
612
|
-
ALL = [ DOCUMENT_ALL, ANNOTS_ALL, FORM_ALL, SIGNATURE_ALL, EF_ALL ]
|
|
613
|
-
|
|
614
559
|
end
|
|
615
|
-
|
|
616
|
-
class TransformParams < Dictionary
|
|
617
|
-
|
|
618
|
-
include StandardObject
|
|
619
|
-
|
|
620
|
-
VERSION = Name.new("2.2")
|
|
621
|
-
|
|
622
|
-
field :Type, :Type => Name, :Default => :TransformParams
|
|
623
|
-
field :Document, :Type => Array
|
|
624
|
-
field :Msg, :Type => String
|
|
625
|
-
field :V, :Type => Name, :Default => VERSION
|
|
626
|
-
field :Annots, :Type => Array
|
|
627
|
-
field :Form, :Type => Array
|
|
628
|
-
field :FormEx, :Type => Array
|
|
629
|
-
field :Signature, :Type => Array
|
|
630
|
-
field :EF, :Type => Array, :Version => "1.6"
|
|
631
|
-
field :P, :Type => Boolean, :Default => false, :Version => "1.6"
|
|
632
|
-
|
|
633
|
-
def initialize(hash = {})
|
|
634
|
-
set_indirect(false)
|
|
635
|
-
|
|
636
|
-
super(hash)
|
|
637
|
-
end
|
|
638
560
|
|
|
561
|
+
module UsageRights
|
|
562
|
+
|
|
563
|
+
module Rights
|
|
564
|
+
DOCUMENT_FULLSAVE = %i[Document FullSave]
|
|
565
|
+
DOCUMENT_ALL = DOCUMENT_FULLSAVE
|
|
566
|
+
|
|
567
|
+
ANNOTS_CREATE = %i[Annots Create]
|
|
568
|
+
ANNOTS_DELETE = %i[Annots Delete]
|
|
569
|
+
ANNOTS_MODIFY = %i[Annots Modify]
|
|
570
|
+
ANNOTS_COPY = %i[Annots Copy]
|
|
571
|
+
ANNOTS_IMPORT = %i[Annots Import]
|
|
572
|
+
ANNOTS_EXPORT = %i[Annots Export]
|
|
573
|
+
ANNOTS_ONLINE = %i[Annots Online]
|
|
574
|
+
ANNOTS_SUMMARYVIEW = %i[Annots SummaryView]
|
|
575
|
+
ANNOTS_ALL = %i[Annots Create Modify Copy Import Export Online SummaryView]
|
|
576
|
+
|
|
577
|
+
FORM_FILLIN = %i[Form FillIn]
|
|
578
|
+
FORM_IMPORT = %i[Form Import]
|
|
579
|
+
FORM_EXPORT = %i[Form Export]
|
|
580
|
+
FORM_SUBMITSTANDALONE = %i[Form SubmitStandAlone]
|
|
581
|
+
FORM_SPAWNTEMPLATE = %i[Form SpawnTemplate]
|
|
582
|
+
FORM_BARCODEPLAINTEXT = %i[Form BarcodePlaintext]
|
|
583
|
+
FORM_ONLINE = %i[Form Online]
|
|
584
|
+
FORM_ALL = %i[Form FillIn Import Export SubmitStandAlone SpawnTemplate BarcodePlaintext Online]
|
|
585
|
+
|
|
586
|
+
FORMEX_BARCODEPLAINTEXT = %i[FormEx BarcodePlaintext]
|
|
587
|
+
FORMEX_ALL = FORMEX_BARCODEPLAINTEXT
|
|
588
|
+
|
|
589
|
+
SIGNATURE_MODIFY = %i[Signature Modify]
|
|
590
|
+
SIGNATURE_ALL = SIGNATURE_MODIFY
|
|
591
|
+
|
|
592
|
+
EF_CREATE = %i[EF Create]
|
|
593
|
+
EF_DELETE = %i[EF Delete]
|
|
594
|
+
EF_MODIFY = %i[EF Modify]
|
|
595
|
+
EF_IMPORT = %i[EF Import]
|
|
596
|
+
EF_ALL = %i[EF Create Delete Modify Import]
|
|
597
|
+
|
|
598
|
+
ALL = [ DOCUMENT_ALL, ANNOTS_ALL, FORM_ALL, SIGNATURE_ALL, EF_ALL ]
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
class TransformParams < Dictionary
|
|
602
|
+
include StandardObject
|
|
603
|
+
|
|
604
|
+
VERSION = Name.new("2.2")
|
|
605
|
+
|
|
606
|
+
field :Type, :Type => Name, :Default => :TransformParams
|
|
607
|
+
field :Document, :Type => Array.of(Name)
|
|
608
|
+
field :Msg, :Type => String
|
|
609
|
+
field :V, :Type => Name, :Default => VERSION
|
|
610
|
+
field :Annots, :Type => Array.of(Name)
|
|
611
|
+
field :Form, :Type => Array.of(Name)
|
|
612
|
+
field :FormEx, :Type => Array.of(Name)
|
|
613
|
+
field :Signature, :Type => Array.of(Name)
|
|
614
|
+
field :EF, :Type => Array.of(Name), :Version => "1.6"
|
|
615
|
+
field :P, :Type => Boolean, :Default => false, :Version => "1.6"
|
|
616
|
+
|
|
617
|
+
def initialize(hash = {}, parser = nil)
|
|
618
|
+
set_indirect(false)
|
|
619
|
+
|
|
620
|
+
super(hash, parser)
|
|
621
|
+
end
|
|
622
|
+
end
|
|
639
623
|
end
|
|
640
|
-
|
|
641
|
-
end
|
|
642
624
|
|
|
643
625
|
end
|