origami 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,25 +1,20 @@
1
1
  =begin
2
2
 
3
- = File
4
- formats/ppklite.rb
5
-
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- Origami is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU Lesser General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
15
-
16
- Origami is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
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
- # Class representing a certificate store header.
52
- #
53
- class Header
54
-
55
- MAGIC = /\A%PPKLITE-(\d)\.(\d)/
56
-
57
- attr_accessor :majorversion, :minorversion
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
- # Creates a file header, with the given major and minor versions.
61
- # _majorversion_:: Major version.
62
- # _minorversion_:: Minor version.
52
+ # Class representing a certificate store header.
63
53
  #
64
- def initialize(majorversion = 2, minorversion = 1)
65
- @majorversion, @minorversion = majorversion, minorversion
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
- def self.parse(stream) #:nodoc:
69
-
70
- if not stream.scan(MAGIC).nil?
71
- maj = stream[1].to_i
72
- min = stream[2].to_i
73
- else
74
- raise InvalidHeader, "Invalid header format"
75
- end
76
-
77
- PPKLite::Header.new(maj,min)
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
- # Outputs self into PDF code.
82
- #
83
- def to_s
84
- "%PPKLITE-#{@majorversion}.#{@minorversion}" + EOL
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
- def to_sym #:nodoc:
88
- "#{@majorversion}.#{@minorversion}".to_sym
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
- def to_f #:nodoc:
92
- to_sym.to_s.to_f
178
+
179
+ class UserList < Dictionary
180
+ include StandardObject
181
+
182
+ field :Type, :Type => Name, :Default => :User, :Required => true
93
183
  end
94
-
95
- end
96
-
97
- class Revision #:nodoc;
98
- attr_accessor :pdf
99
- attr_accessor :body, :xreftable, :trailer
100
-
101
- def initialize(adbk)
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
- def trailer=(trl)
109
- trl.pdf = @pdf
110
- @trailer = trl
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
- end
113
-
114
- attr_accessor :header, :revisions
115
-
116
- def initialize #:nodoc:
117
- @header = PPKLite::Header.new
118
- @revisions = [ Revision.new(self) ]
119
- @revisions.first.trailer = Trailer.new
120
- end
121
-
122
- def objects
123
- def append_subobj(root, objset)
124
- if objset.find{ |o| o.object_id == root.object_id }.nil?
125
- objset << root
126
- if root.is_a?(Array) or root.is_a?(Dictionary)
127
- root.each { |subobj| append_subobj(subobj, objset) unless subobj.is_a?(Reference) }
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
- objset = []
133
- @revisions.first.body.values.each do |object|
134
- unless object.is_a?(Reference)
135
- append_subobj(object, objset)
136
- end
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
- objset
140
- end
141
-
142
- def <<(object)
143
-
144
- object.set_indirect(true)
145
-
146
- if object.no.zero?
147
- maxno = 1
148
- while get_object(maxno) do maxno = maxno.succ end
149
-
150
- object.generation = 0
151
- object.no = maxno
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
- @revisions.first.body[object.reference] = object
155
-
156
- object.reference
157
- end
158
-
159
- def Catalog
160
- get_object(@trailer.Root)
161
- end
162
-
163
- def save(filename)
164
-
165
- bin = ""
166
- bin << @header.to_s
167
-
168
- lastno, brange = 0, 0
169
-
170
- xrefs = [ XRef.new(0, XRef::LASTFREE, XRef::FREE) ]
171
- xrefsection = XRef::Section.new
172
-
173
- @revisions.first.body.values.sort.each { |obj|
174
- if (obj.no - lastno).abs > 1
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
- brange = obj.no
177
- xrefs.clear
178
- end
179
-
180
- xrefs << XRef.new(bin.size, obj.generation, XRef::USED)
181
- lastno = obj.no
182
-
183
- bin << obj.to_s
184
- }
185
-
186
- xrefsection << XRef::Subsection.new(brange, xrefs)
187
-
188
- @xreftable = xrefsection
189
- @trailer ||= Trailer.new
190
- @trailer.Size = rev.body.size + 1
191
- @trailer.startxref = bin.size
192
-
193
- bin << @xreftable.to_s
194
- bin << @trailer.to_s
195
-
196
- fd = File.open(filename, "w").binmode
197
- fd << bin
198
- fd.close
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
- nil
241
- end
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
- nil
257
- end
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
- end
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
- end
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
- end
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
- end
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
- def initialize(hash = {}) #:nodoc:
355
- super(hash)
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
- end
359
-
360
- class User < Dictionary
361
-
362
- include StandardObject
363
- include Descriptor
364
-
365
- field :ABEType, :Type => Integer, :Default => Descriptor::USER, :Required => true
366
- field :Name, :Type => String, :Required => true
367
- field :Encrypt, :Type => Integer
368
- field :Certs, :Type => Array, :Default => [], :Required => true
369
-
370
- def show
371
- puts "ID: #{self.ID}"
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
- end
377
-
378
- class Certificate < Dictionary
379
-
380
- include StandardObject
381
- include Descriptor
382
-
383
- module Flags
384
-
385
- CAN_CERTIFY = 1 << 1
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
- field :ABEType, :Type => Integer, :Default => Descriptor::CERTIFICATE, :Required => true
397
- field :Usage, :Type => Integer, :Default => 1, :Required => true
398
- field :Viewable, :Type => Boolean, :Default => true
399
- field :Editable, :Type => Boolean, :Default => true
400
- field :Cert, :Type => String, :Required => true
401
- field :Trust, :Type => Integer, :Default => Flags::UNKNOWN_2, :Required => true
402
-
403
- def show
404
- puts "ID: #{self.ID}"
405
- puts "Viewable: #{self.Viewable}"
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
- end
411
-
412
- def get_object(no, generation = 0) #:nodoc:
413
-
414
- case no
415
- when Reference
416
- target = no
417
- when ::Integer
418
- target = Reference.new(no, generation)
419
- when Origami::Object
420
- return no
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
-