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
|
@@ -1,25 +1,20 @@
|
|
|
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
|
|
|
@@ -40,452 +35,390 @@ require 'openssl'
|
|
|
40
35
|
|
|
41
36
|
module Origami
|
|
42
37
|
|
|
43
|
-
module Adobe
|
|
44
|
-
|
|
45
38
|
#
|
|
46
39
|
# Class representing an Adobe Reader certificate store.
|
|
47
40
|
#
|
|
48
41
|
class PPKLite
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
|
|
43
|
+
class Error < Origami::Error; end
|
|
44
|
+
|
|
45
|
+
def self.read(path, options = {})
|
|
46
|
+
path = File.expand_path(path) if path.is_a?(::String)
|
|
47
|
+
|
|
48
|
+
PPKLite::Parser.new(options).parse(path)
|
|
49
|
+
end
|
|
50
|
+
|
|
59
51
|
#
|
|
60
|
-
#
|
|
61
|
-
# _majorversion_:: Major version.
|
|
62
|
-
# _minorversion_:: Minor version.
|
|
52
|
+
# Class representing a certificate store header.
|
|
63
53
|
#
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
class Header
|
|
55
|
+
MAGIC = /%PPKLITE-(?<major>\d)\.(?<minor>\d)/
|
|
56
|
+
|
|
57
|
+
attr_accessor :major_version, :minor_version
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Creates a file header, with the given major and minor versions.
|
|
61
|
+
# _major_version_:: Major version.
|
|
62
|
+
# _minor_version_:: Minor version.
|
|
63
|
+
#
|
|
64
|
+
def initialize(major_version = 2, minor_version = 1)
|
|
65
|
+
@major_version, @minor_version = major_version, minor_version
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.parse(stream) #:nodoc:
|
|
69
|
+
if not stream.scan(MAGIC).nil?
|
|
70
|
+
maj = stream['major'].to_i
|
|
71
|
+
min = stream['minor'].to_i
|
|
72
|
+
else
|
|
73
|
+
raise InvalidHeader, "Invalid header format"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
stream.skip(REGEXP_WHITESPACES)
|
|
77
|
+
|
|
78
|
+
PPKLite::Header.new(maj, min)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
#
|
|
82
|
+
# Outputs self into PDF code.
|
|
83
|
+
#
|
|
84
|
+
def to_s
|
|
85
|
+
"%PPKLITE-#{@major_version}.#{@minor_version}".b + EOL
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def to_sym #:nodoc:
|
|
89
|
+
"#{@major_version}.#{@minor_version}".to_sym
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def to_f #:nodoc:
|
|
93
|
+
to_sym.to_s.to_f
|
|
94
|
+
end
|
|
66
95
|
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
96
|
+
|
|
97
|
+
class Revision #:nodoc;
|
|
98
|
+
attr_accessor :document
|
|
99
|
+
attr_accessor :body, :xreftable
|
|
100
|
+
attr_reader :trailer
|
|
101
|
+
|
|
102
|
+
def initialize(adbk)
|
|
103
|
+
@document = adbk
|
|
104
|
+
@body = {}
|
|
105
|
+
@xreftable = nil
|
|
106
|
+
@trailer = nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def trailer=(trl)
|
|
110
|
+
trl.document = @document
|
|
111
|
+
@trailer = trl
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def each_object(&b)
|
|
115
|
+
@body.each_value(&b)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def objects
|
|
119
|
+
@body.values
|
|
120
|
+
end
|
|
78
121
|
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
122
|
+
|
|
123
|
+
module Descriptor
|
|
124
|
+
CERTIFICATE = 1
|
|
125
|
+
USER = 2
|
|
126
|
+
|
|
127
|
+
def self.included(receiver) #:nodoc:
|
|
128
|
+
receiver.field :ID, :Type => Integer, :Required => true
|
|
129
|
+
receiver.field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
class Certificate < Dictionary
|
|
134
|
+
include StandardObject
|
|
135
|
+
include Descriptor
|
|
136
|
+
|
|
137
|
+
add_type_info self, :ABEType, Descriptor::CERTIFICATE
|
|
138
|
+
|
|
139
|
+
module Flags
|
|
140
|
+
CAN_CERTIFY = 1 << 1
|
|
141
|
+
ALLOW_DYNAMIC_CONTENT = 1 << 2
|
|
142
|
+
UNKNOWN_1 = 1 << 3
|
|
143
|
+
ALLOW_HIGH_PRIV_JS = 1 << 4
|
|
144
|
+
UNKNOWN_2 = 1 << 5
|
|
145
|
+
IS_ROOT_CA = 1 << 6
|
|
146
|
+
|
|
147
|
+
#FULL_TRUST = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6
|
|
148
|
+
FULL_TRUST = 8190
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
|
|
152
|
+
field :Usage, :Type => Integer, :Default => 1, :Required => true
|
|
153
|
+
field :Viewable, :Type => Boolean, :Default => true
|
|
154
|
+
field :Editable, :Type => Boolean, :Default => true
|
|
155
|
+
field :Cert, :Type => String, :Required => true
|
|
156
|
+
field :Trust, :Type => Integer, :Default => Flags::UNKNOWN_2, :Required => true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class User < Dictionary
|
|
160
|
+
include StandardObject
|
|
161
|
+
include Descriptor
|
|
162
|
+
|
|
163
|
+
add_type_info self, :ABEType, Descriptor::USER
|
|
164
|
+
|
|
165
|
+
field :ABEType, :Type => Integer, :Default => Descriptor::USER, :Required => true
|
|
166
|
+
field :Name, :Type => String, :Required => true
|
|
167
|
+
field :Encrypt, :Type => Integer
|
|
168
|
+
field :Certs, :Type => Array.of(Certificate), :Default => [], :Required => true
|
|
85
169
|
end
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
170
|
+
|
|
171
|
+
class AddressList < Dictionary
|
|
172
|
+
include StandardObject
|
|
173
|
+
|
|
174
|
+
field :Type, :Type => Name, :Default => :AddressBook, :Required => true
|
|
175
|
+
field :NextID, :Type => Integer
|
|
176
|
+
field :Entries, :Type => Array.of(Descriptor), :Default => [], :Required => true
|
|
89
177
|
end
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
178
|
+
|
|
179
|
+
class UserList < Dictionary
|
|
180
|
+
include StandardObject
|
|
181
|
+
|
|
182
|
+
field :Type, :Type => Name, :Default => :User, :Required => true
|
|
93
183
|
end
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@pdf = adbk
|
|
103
|
-
@body = {}
|
|
104
|
-
@xreftable = nil
|
|
105
|
-
@trailer = nil
|
|
184
|
+
|
|
185
|
+
class PPK < Dictionary
|
|
186
|
+
include StandardObject
|
|
187
|
+
|
|
188
|
+
field :Type, :Type => Name, :Default => :PPK, :Required => true
|
|
189
|
+
field :User, :Type => UserList, :Required => true
|
|
190
|
+
field :AddressBook, :Type => AddressList, :Required => true
|
|
191
|
+
field :V, :Type => Integer, :Default => 0x10001, :Required => true
|
|
106
192
|
end
|
|
107
193
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
194
|
+
class Catalog < Dictionary
|
|
195
|
+
include StandardObject
|
|
196
|
+
|
|
197
|
+
field :Type, :Type => Name, :Default => :Catalog, :Required => true
|
|
198
|
+
field :PPK, :Type => PPK, :Required => true
|
|
111
199
|
end
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
200
|
+
|
|
201
|
+
attr_accessor :header, :revisions
|
|
202
|
+
|
|
203
|
+
def initialize(parser = nil) #:nodoc:
|
|
204
|
+
@header = PPKLite::Header.new
|
|
205
|
+
@revisions = [ Revision.new(self) ]
|
|
206
|
+
@revisions.first.trailer = Trailer.new
|
|
207
|
+
|
|
208
|
+
init if parser.nil?
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def indirect_objects
|
|
212
|
+
@revisions.inject([]) do |set, rev| set.concat(rev.objects) end
|
|
213
|
+
end
|
|
214
|
+
alias root_objects indirect_objects
|
|
215
|
+
|
|
216
|
+
def cast_object(reference, type, parser = nil) #:nodoc:
|
|
217
|
+
@revisions.each do |rev|
|
|
218
|
+
if rev.body.include?(reference) and type < rev.body[reference].class
|
|
219
|
+
rev.body[reference] = rev.body[reference].cast_to(type, parser)
|
|
220
|
+
|
|
221
|
+
rev.body[reference]
|
|
222
|
+
else
|
|
223
|
+
nil
|
|
224
|
+
end
|
|
128
225
|
end
|
|
129
|
-
end
|
|
130
226
|
end
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
227
|
+
|
|
228
|
+
def get_object(no, generation = 0) #:nodoc:
|
|
229
|
+
case no
|
|
230
|
+
when Reference
|
|
231
|
+
target = no
|
|
232
|
+
when ::Integer
|
|
233
|
+
target = Reference.new(no, generation)
|
|
234
|
+
when Origami::Object
|
|
235
|
+
return no
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
@revisions.first.body[target]
|
|
137
239
|
end
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
240
|
+
|
|
241
|
+
def <<(object)
|
|
242
|
+
object.set_indirect(true)
|
|
243
|
+
object.set_document(self)
|
|
244
|
+
|
|
245
|
+
if object.no.zero?
|
|
246
|
+
maxno = 1
|
|
247
|
+
maxno = maxno.succ while get_object(maxno)
|
|
248
|
+
|
|
249
|
+
object.generation = 0
|
|
250
|
+
object.no = maxno
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
@revisions.first.body[object.reference] = object
|
|
254
|
+
|
|
255
|
+
object.reference
|
|
256
|
+
end
|
|
257
|
+
alias insert <<
|
|
258
|
+
|
|
259
|
+
def Catalog
|
|
260
|
+
get_object(@revisions.first.trailer.Root)
|
|
152
261
|
end
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
262
|
+
|
|
263
|
+
def indirect_objects
|
|
264
|
+
@revisions.inject([]) do |set, rev| set.concat(rev.objects) end
|
|
265
|
+
end
|
|
266
|
+
alias root_objects indirect_objects
|
|
267
|
+
|
|
268
|
+
def save(path)
|
|
269
|
+
bin = "".b
|
|
270
|
+
bin << @header.to_s
|
|
271
|
+
|
|
272
|
+
lastno, brange = 0, 0
|
|
273
|
+
|
|
274
|
+
xrefs = [ XRef.new(0, XRef::FIRSTFREE, XRef::FREE) ]
|
|
275
|
+
xrefsection = XRef::Section.new
|
|
276
|
+
|
|
277
|
+
@revisions.first.body.values.sort.each { |obj|
|
|
278
|
+
if (obj.no - lastno).abs > 1
|
|
279
|
+
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
280
|
+
brange = obj.no
|
|
281
|
+
xrefs.clear
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
xrefs << XRef.new(bin.size, obj.generation, XRef::USED)
|
|
285
|
+
lastno = obj.no
|
|
286
|
+
|
|
287
|
+
obj.pre_build
|
|
288
|
+
|
|
289
|
+
bin << obj.to_s
|
|
290
|
+
|
|
291
|
+
obj.post_build
|
|
292
|
+
}
|
|
293
|
+
|
|
175
294
|
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
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
|
-
show_entries
|
|
201
|
-
end
|
|
202
|
-
alias saveas save
|
|
203
|
-
|
|
204
|
-
#
|
|
205
|
-
# Prints registered users in the address book
|
|
206
|
-
#
|
|
207
|
-
def show_users
|
|
208
|
-
|
|
209
|
-
puts "----------"
|
|
210
|
-
puts "Users list"
|
|
211
|
-
puts "----------"
|
|
212
|
-
|
|
213
|
-
@revisions.first.body.values.each { |obj| if obj.is_a?(User) then obj.show; puts end }
|
|
214
|
-
|
|
215
|
-
nil
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
#
|
|
219
|
-
# Prints registered certificates in the addressbook
|
|
220
|
-
#
|
|
221
|
-
def show_certs
|
|
222
|
-
puts "-----------------"
|
|
223
|
-
puts "Certificates list"
|
|
224
|
-
puts "-----------------"
|
|
225
|
-
|
|
226
|
-
@revisions.first.body.values.each { |obj| if obj.is_a?(Certificate) then obj.show; puts end }
|
|
227
|
-
|
|
228
|
-
nil
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
#
|
|
232
|
-
# Prints certificate with the specified id
|
|
233
|
-
#
|
|
234
|
-
def show_cert(id)
|
|
235
|
-
@revisions.first.body.values.find_all { |obj| obj.is_a?(Certificate) and obj.ID == id }.each do |cert|
|
|
236
|
-
cert.show
|
|
237
|
-
puts
|
|
295
|
+
|
|
296
|
+
@xreftable = xrefsection
|
|
297
|
+
@trailer ||= Trailer.new
|
|
298
|
+
@trailer.Size = @revisions.first.body.size + 1
|
|
299
|
+
@trailer.startxref = bin.size
|
|
300
|
+
|
|
301
|
+
bin << @xreftable.to_s
|
|
302
|
+
bin << @trailer.to_s
|
|
303
|
+
|
|
304
|
+
if path.respond_to?(:write)
|
|
305
|
+
io = path
|
|
306
|
+
else
|
|
307
|
+
path = File.expand_path(path)
|
|
308
|
+
io = File.open(path, "wb", encoding: 'binary')
|
|
309
|
+
close = true
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
begin
|
|
313
|
+
io.write(bin)
|
|
314
|
+
ensure
|
|
315
|
+
io.close if close
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
self
|
|
238
319
|
end
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
#
|
|
244
|
-
# Returns a Certificate dictionary corresponding to the specified id
|
|
245
|
-
#
|
|
246
|
-
def get_cert(id)
|
|
247
|
-
@revisions.first.body.values.find { |obj| obj.is_a?(Certificate) and obj.ID == id }
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def show_user(id)
|
|
251
|
-
users = @revisions.first.body.values.find_all { |obj| obj.is_a?(User) and obj.ID == id }.each do |user|
|
|
252
|
-
user.show
|
|
253
|
-
puts
|
|
320
|
+
|
|
321
|
+
def each_user(&b)
|
|
322
|
+
each_entry(Descriptor::USER, &b)
|
|
254
323
|
end
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
#
|
|
260
|
-
# Prints users and certificates registered in the address book
|
|
261
|
-
#
|
|
262
|
-
def show_entries
|
|
263
|
-
show_users
|
|
264
|
-
show_certs
|
|
265
|
-
|
|
266
|
-
puts "End of address book."
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
#
|
|
270
|
-
# Add a certificate into the address book
|
|
271
|
-
#
|
|
272
|
-
def add_certificate(certfile, attributes, viewable = false, editable = false)
|
|
273
|
-
|
|
274
|
-
cert = Certificate.new
|
|
275
|
-
cert.Cert = OpenSSL::X509::Certificate.new(certfile).to_der
|
|
276
|
-
cert.ID = self.Catalog.PPK.AddressBook.NextID
|
|
277
|
-
self.Catalog.PPK.AddressBook.NextID += 1
|
|
278
|
-
cert.Trust = attributes
|
|
279
|
-
cert.Viewable = viewable
|
|
280
|
-
cert.Editable = editable
|
|
281
|
-
|
|
282
|
-
self.Catalog.PPK.AddressBook.Entries.push(self << cert)
|
|
283
|
-
|
|
284
|
-
show_certs
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
alias to_s show_entries
|
|
288
|
-
alias to_str show_entries
|
|
289
|
-
|
|
290
|
-
class Catalog < Dictionary
|
|
291
|
-
|
|
292
|
-
include StandardObject
|
|
293
|
-
|
|
294
|
-
field :Type, :Type => Name, :Default => :Catalog, :Required => true
|
|
295
|
-
field :PPK, :Type => Dictionary, :Required => true
|
|
296
|
-
|
|
297
|
-
def initialize(hash = {}) #:nodoc:
|
|
298
|
-
super(hash)
|
|
324
|
+
|
|
325
|
+
def get_user(id)
|
|
326
|
+
self.each_user.find {|user| user.ID == id }
|
|
299
327
|
end
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
class PPK < Dictionary
|
|
304
|
-
|
|
305
|
-
include StandardObject
|
|
306
|
-
|
|
307
|
-
field :Type, :Type => Name, :Default => :PPK, :Required => true
|
|
308
|
-
field :User, :Type => Dictionary, :Required => true
|
|
309
|
-
field :AddressBook, :Type => Dictionary, :Required => true
|
|
310
|
-
field :V, :Type => Integer, :Default => 0x10001, :Required => true
|
|
311
|
-
|
|
312
|
-
def initialize(hash = {}) #:nodoc:
|
|
313
|
-
super(hash)
|
|
328
|
+
|
|
329
|
+
def users
|
|
330
|
+
self.each_user.to_a
|
|
314
331
|
end
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
class UserList < Dictionary
|
|
319
|
-
|
|
320
|
-
include StandardObject
|
|
321
|
-
|
|
322
|
-
field :Type, :Type => Name, :Default => :User, :Required => true
|
|
323
|
-
|
|
324
|
-
def initialize(hash = {})
|
|
325
|
-
super(hash)
|
|
332
|
+
|
|
333
|
+
def each_certificate(&b)
|
|
334
|
+
each_entry(Descriptor::CERTIFICATE, &b)
|
|
326
335
|
end
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
class AddressList < Dictionary
|
|
331
|
-
|
|
332
|
-
include StandardObject
|
|
333
|
-
|
|
334
|
-
field :Type, :Type => Name, :Default => :AddressBook, :Required => true
|
|
335
|
-
field :NextID, :Type => Integer
|
|
336
|
-
field :Entries, :Type => Array, :Default => [], :Required => true
|
|
337
|
-
|
|
338
|
-
def initialize(hash = {}) #:nodoc:
|
|
339
|
-
super(hash)
|
|
336
|
+
|
|
337
|
+
def get_certificate(id)
|
|
338
|
+
self.each_certificate.find {|cert| cert.ID == id }
|
|
340
339
|
end
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
module Descriptor
|
|
345
|
-
|
|
346
|
-
CERTIFICATE = 1
|
|
347
|
-
USER = 2
|
|
348
|
-
|
|
349
|
-
def self.included(receiver) #:nodoc:
|
|
350
|
-
receiver.field :ID, :Type => Integer, :Required => true
|
|
351
|
-
receiver.field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
|
|
340
|
+
|
|
341
|
+
def certificates
|
|
342
|
+
self.each_certificate.to_a
|
|
352
343
|
end
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
344
|
+
|
|
345
|
+
#
|
|
346
|
+
# Add a certificate into the address book
|
|
347
|
+
#
|
|
348
|
+
def add_certificate(certfile, attributes, viewable: false, editable: false)
|
|
349
|
+
if certfile.is_a?(OpenSSL::X509::Certificate)
|
|
350
|
+
x509 = certfile
|
|
351
|
+
else
|
|
352
|
+
x509 = OpenSSL::X509::Certificate.new(certfile)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
address_book = get_address_book
|
|
356
|
+
|
|
357
|
+
cert = Certificate.new
|
|
358
|
+
cert.Cert = x509.to_der
|
|
359
|
+
cert.ID = address_book.NextID
|
|
360
|
+
address_book.NextID += 1
|
|
361
|
+
|
|
362
|
+
cert.Trust = attributes
|
|
363
|
+
cert.Viewable = viewable
|
|
364
|
+
cert.Editable = editable
|
|
365
|
+
|
|
366
|
+
address_book.Entries.push(self << cert)
|
|
356
367
|
end
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
puts "Name: #{self.Name}"
|
|
373
|
-
puts "Certificates: " + self.Certs.join(", ")
|
|
368
|
+
|
|
369
|
+
private
|
|
370
|
+
|
|
371
|
+
def init
|
|
372
|
+
catalog = Catalog.new(
|
|
373
|
+
PPK: PPK.new(
|
|
374
|
+
User: UserList.new,
|
|
375
|
+
AddressBook: AddressList.new(
|
|
376
|
+
Entries: [],
|
|
377
|
+
NextID: 1
|
|
378
|
+
)
|
|
379
|
+
)
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
@revisions.first.trailer.Root = self.insert(catalog)
|
|
374
383
|
end
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
ALLOW_DYNAMIC_CONTENT = 1 << 2
|
|
387
|
-
UNKNOWN_1 = 1 << 3
|
|
388
|
-
ALLOW_HIGH_PRIV_JS = 1 << 4
|
|
389
|
-
UNKNOWN_2 = 1 << 5
|
|
390
|
-
IS_ROOT_CA = 1 << 6
|
|
391
|
-
|
|
392
|
-
#~ FULL_TRUST = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6
|
|
393
|
-
FULL_TRUST = 8190
|
|
384
|
+
|
|
385
|
+
def each_entry(type)
|
|
386
|
+
return enum_for(__method__, type) unless block_given?
|
|
387
|
+
|
|
388
|
+
address_book = get_address_book
|
|
389
|
+
|
|
390
|
+
address_book.Entries.each do |entry|
|
|
391
|
+
entry = entry.solve
|
|
392
|
+
|
|
393
|
+
yield(entry) if entry.is_a?(Dictionary) and entry.ABEType == type
|
|
394
|
+
end
|
|
394
395
|
end
|
|
395
396
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
puts "Editable: #{self.Editable}"
|
|
407
|
-
puts "Trust attributes: #{self.Trust}"
|
|
397
|
+
def get_address_book
|
|
398
|
+
raise Error, "Broken catalog" unless self.Catalog.is_a?(Dictionary) and self.Catalog.PPK.is_a?(Dictionary)
|
|
399
|
+
|
|
400
|
+
ppk = self.Catalog.PPK
|
|
401
|
+
raise Error, "Broken PPK" unless ppk.AddressBook.is_a?(Dictionary)
|
|
402
|
+
|
|
403
|
+
address_book = ppk.AddressBook
|
|
404
|
+
raise Error, "Broken address book" unless address_book.Entries.is_a?(Array)
|
|
405
|
+
|
|
406
|
+
address_book
|
|
408
407
|
end
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
408
|
+
|
|
409
|
+
def get_object_offset(no,generation) #:nodoc:
|
|
410
|
+
bodyoffset = @header.to_s.size
|
|
411
|
+
objectoffset = bodyoffset
|
|
412
|
+
|
|
413
|
+
@revisions.first.body.values.each { |object|
|
|
414
|
+
if object.no == no and object.generation == generation then return objectoffset
|
|
415
|
+
else
|
|
416
|
+
objectoffset += object.to_s.size
|
|
417
|
+
end
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
nil
|
|
421
421
|
end
|
|
422
|
-
|
|
423
|
-
@revisions.first.body[target]
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
private
|
|
427
|
-
|
|
428
|
-
def rebuildxrefs #:nodoc:
|
|
429
|
-
|
|
430
|
-
startxref = @header.to_s.size
|
|
431
|
-
|
|
432
|
-
@revisions.first.body.values.each { |object|
|
|
433
|
-
startxref += object.to_s.size
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
@xreftable = buildxrefs(@revisions.first.body)
|
|
437
|
-
|
|
438
|
-
@trailer ||= Trailer.new
|
|
439
|
-
@trailer.Size = @revisions.first.body.size + 1
|
|
440
|
-
@trailer.startxref = startxref
|
|
441
|
-
|
|
442
|
-
self
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
def buildxrefs(objects) #:nodoc:
|
|
446
|
-
|
|
447
|
-
lastno = 0
|
|
448
|
-
brange = 0
|
|
449
|
-
|
|
450
|
-
xrefs = [ XRef.new(0, XRef::LASTFREE, XRef::FREE) ]
|
|
451
|
-
|
|
452
|
-
xrefsection = XRef::Section.new
|
|
453
|
-
objects.sort.each { |object|
|
|
454
|
-
if (object.no - lastno).abs > 1
|
|
455
|
-
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
456
|
-
brange = object.no
|
|
457
|
-
xrefs.clear
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
xrefs << XRef.new(get_object_offset(object.no, object.generation), object.generation, XRef::USED)
|
|
461
|
-
|
|
462
|
-
lastno = object.no
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
xrefsection << XRef::Subsection.new(brange, xrefs)
|
|
466
|
-
|
|
467
|
-
xrefsection
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
def get_object_offset(no,generation) #:nodoc:
|
|
471
|
-
|
|
472
|
-
bodyoffset = @header.to_s.size
|
|
473
|
-
|
|
474
|
-
objectoffset = bodyoffset
|
|
475
|
-
|
|
476
|
-
@revisions.first.body.values.each { |object|
|
|
477
|
-
if object.no == no and object.generation == generation then return objectoffset
|
|
478
|
-
else
|
|
479
|
-
objectoffset += object.to_s.size
|
|
480
|
-
end
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
nil
|
|
484
|
-
end
|
|
485
|
-
|
|
422
|
+
|
|
486
423
|
end
|
|
487
|
-
|
|
488
|
-
end
|
|
489
|
-
|
|
490
424
|
end
|
|
491
|
-
|