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