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
- properties.rb
5
-
6
- = Info
7
- This file is part of PDF Walker, a graphical PDF file browser
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- PDF Walker is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU 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
- PDF Walker 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 General Public License for more details.
20
-
21
- You should have received a copy of the GNU General Public License
22
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
3
+ This file is part of PDF Walker, a graphical PDF file browser
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ PDF Walker is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU 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
+ PDF Walker 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 General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
23
18
 
24
19
  =end
25
20
 
@@ -27,118 +22,107 @@ require 'digest/md5'
27
22
 
28
23
  module PDFWalker
29
24
 
30
- class Walker < Window
31
-
32
- def display_file_properties
33
- if @opened
34
- prop = Properties.new(self, @opened)
35
- end
36
- end
37
-
38
- class Properties < Dialog
39
-
40
- @@acrobat_versions =
41
- {
42
- 1.0 => "1.x",
43
- 1.1 => "2.x",
44
- 1.2 => "3.x",
45
- 1.3 => "4.x",
46
- 1.4 => "5.x",
47
- 1.5 => "6.x",
48
- 1.6 => "7.x",
49
- 1.7 => "8.x / 9.x / 10.x"
50
- }
51
-
52
- def initialize(parent, pdf)
53
- super("Document properties", parent, Dialog::MODAL, [Stock::CLOSE, Dialog::RESPONSE_NONE])
54
-
55
- docframe = Frame.new(" File properties ")
56
- stat = File.stat(parent.filename)
57
-
58
- if RUBY_VERSION < '1.9'
59
- require 'iconv'
60
- i = Iconv.new("UTF-8//IGNORE//TRANSLIT", "ISO-8859-1")
61
-
62
- creation_date = i.iconv(stat.ctime.to_s)
63
- last_modified = i.iconv(stat.mtime.to_s)
64
- fd = File.open(parent.filename, 'rb')
65
- md5sum = Digest::MD5.hexdigest(fd.read)
66
- fd.close
67
- i.close
68
- else
69
- creation_date = stat.ctime.to_s.encode("utf-8", :invalid => :replace, :undef => :replace)
70
- last_modified = stat.mtime.to_s.encode("utf-8", :invalid => :replace, :undef => :replace)
71
- md5sum = Digest::MD5.hexdigest(File.binread(parent.filename))
72
- end
73
-
74
- labels =
75
- [
76
- [ "Filename:", parent.filename ],
77
- [ "File size:", "#{File.size(parent.filename)} bytes" ],
78
- [ "MD5:", md5sum ],
79
- [ "Read-only:", "#{not stat.writable?}" ],
80
- [ "Creation date:", creation_date ],
81
- [ "Last modified:", last_modified ]
82
- ]
83
-
84
- doctable = Table.new(labels.size + 1, 3)
85
-
86
- row = 0
87
- labels.each do |name, value|
88
-
89
- doctable.attach(Label.new(name).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
90
- doctable.attach(Label.new(value).set_alignment(0,0), 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
91
-
92
- row = row.succ
25
+ class Walker < Window
26
+
27
+ def display_file_properties
28
+ Properties.new(self, @opened) if @opened
93
29
  end
94
-
95
- docframe.border_width = 5
96
- docframe.shadow_type = Gtk::SHADOW_IN
97
- docframe.add(doctable)
98
-
99
- pdfframe = Frame.new(" PDF properties ")
100
-
101
- labels =
102
- [
103
- [ "Version:", "#{pdf.header.to_f} (Acrobat #{ if pdf.header.to_f >= 1.0 and pdf.header.to_f <= 1.7 then @@acrobat_versions[pdf.header.to_f] else "unknown version" end})" ],
104
- [ "Number of revisions:", "#{pdf.revisions.size}" ],
105
- [ "Number of indirect objects:", "#{pdf.indirect_objects.size}" ],
106
- [ "Number of pages:", "#{pdf.pages.size}" ],
107
- [ "Is linearized:", "#{pdf.is_linearized?}" ],
108
- [ "Is encrypted:", "#{pdf.is_encrypted?}" ],
109
- [ "Is signed:", "#{pdf.is_signed?}" ],
110
- [ "Has usage rights:", "#{pdf.has_usage_rights?}"],
111
- [ "Contains Acroform:", "#{pdf.has_form?}" ],
112
- #[ "Contains XFA forms:", "#{pdf.has_xfa_forms?}" ]
113
- [ "Has document information:", "#{pdf.has_document_info?}" ],
114
- [ "Has metadata:", "#{pdf.has_metadata?}" ]
115
- ]
116
-
117
- pdftable = Table.new(labels.size + 1, 3)
118
-
119
- row = 0
120
- labels.each do |name, value|
121
-
122
- pdftable.attach(Label.new(name).set_alignment(1,0), 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 4, 4)
123
- pdftable.attach(Label.new(value).set_alignment(0,0), 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
124
-
125
- row = row.succ
30
+
31
+ class Properties < Dialog
32
+
33
+ @@acrobat_versions =
34
+ {
35
+ 1.0 => "1.x",
36
+ 1.1 => "2.x",
37
+ 1.2 => "3.x",
38
+ 1.3 => "4.x",
39
+ 1.4 => "5.x",
40
+ 1.5 => "6.x",
41
+ 1.6 => "7.x",
42
+ 1.7 => "8.x / 9.x / 10.x"
43
+ }
44
+
45
+ def initialize(parent, pdf)
46
+ super("Document properties", parent, Dialog::MODAL, [Stock::CLOSE, Dialog::RESPONSE_NONE])
47
+
48
+ docframe = Frame.new(" File properties ")
49
+ stat = File.stat(parent.filename)
50
+
51
+ creation_date = stat.ctime.to_s.encode("utf-8", :invalid => :replace, :undef => :replace)
52
+ last_modified = stat.mtime.to_s.encode("utf-8", :invalid => :replace, :undef => :replace)
53
+ md5sum = Digest::MD5.hexdigest(File.binread(parent.filename))
54
+
55
+ labels =
56
+ [
57
+ [ "Filename:", parent.filename ],
58
+ [ "File size:", "#{File.size(parent.filename)} bytes" ],
59
+ [ "MD5:", md5sum ],
60
+ [ "Read-only:", "#{not stat.writable?}" ],
61
+ [ "Creation date:", creation_date ],
62
+ [ "Last modified:", last_modified ]
63
+ ]
64
+
65
+ doctable = Table.new(labels.size + 1, 3)
66
+
67
+ row = 0
68
+ labels.each do |name, value|
69
+ doctable.attach(Label.new(name).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
70
+ doctable.attach(Label.new(value).set_alignment(0,0), 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
71
+
72
+ row = row.succ
73
+ end
74
+
75
+ docframe.border_width = 5
76
+ docframe.shadow_type = Gtk::SHADOW_IN
77
+ docframe.add(doctable)
78
+
79
+ pdfframe = Frame.new(" PDF properties ")
80
+
81
+ pdf_version = pdf.header.to_f
82
+ if pdf_version >= 1.0 and pdf_version <= 1.7
83
+ acrobat_version = @@acrobat_versions[pdf_version]
84
+ else
85
+ acrobat_version = "unknown version"
86
+ end
87
+
88
+ labels =
89
+ [
90
+ [ "Version:", "#{pdf_version} (Acrobat #{acrobat_version})" ],
91
+ [ "Number of revisions:", "#{pdf.revisions.size}" ],
92
+ [ "Number of indirect objects:", "#{pdf.indirect_objects.size}" ],
93
+ [ "Number of pages:", "#{pdf.pages.count}" ],
94
+ [ "Linearized:", pdf.linearized? ? 'yes' : 'no' ],
95
+ [ "Encrypted:", pdf.encrypted? ? 'yes' : 'no' ],
96
+ [ "Signed:", pdf.signed? ? 'yes' : 'no' ],
97
+ [ "Has usage rights:", pdf.usage_rights? ? 'yes' : 'no' ],
98
+ [ "Form:", pdf.form? ? 'yes' : 'no' ],
99
+ [ "XFA form:", pdf.xfa_form? ? 'yes' : 'no' ],
100
+ [ "Document information:", pdf.document_info? ? 'yes' : 'no' ],
101
+ [ "Metadata:", pdf.metadata? ? 'yes' : 'no' ]
102
+ ]
103
+
104
+ pdftable = Table.new(labels.size + 1, 3)
105
+
106
+ row = 0
107
+ labels.each do |name, value|
108
+ pdftable.attach(Label.new(name).set_alignment(1,0), 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 4, 4)
109
+ pdftable.attach(Label.new(value).set_alignment(0,0), 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
110
+
111
+ row = row.succ
112
+ end
113
+
114
+ pdfframe.border_width = 5
115
+ pdfframe.shadow_type = Gtk::SHADOW_IN
116
+ pdfframe.add(pdftable)
117
+
118
+ vbox.add(docframe)
119
+ vbox.add(pdfframe)
120
+
121
+ signal_connect('response') { destroy }
122
+
123
+ show_all
124
+ end
126
125
  end
127
-
128
- pdfframe.border_width = 5
129
- pdfframe.shadow_type = Gtk::SHADOW_IN
130
- pdfframe.add(pdftable)
131
-
132
- vbox.add(docframe)
133
- vbox.add(pdfframe)
134
-
135
- signal_connect('response') { destroy }
136
-
137
- show_all
138
- end
139
-
140
126
  end
141
-
142
- end
143
127
 
144
128
  end
@@ -1,635 +1,589 @@
1
1
  =begin
2
2
 
3
- = File
4
- signing.rb
5
-
6
- = Info
7
- This file is part of PDF Walker, a graphical PDF file browser
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- PDF Walker is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU 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
- PDF Walker 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 General Public License for more details.
20
-
21
- You should have received a copy of the GNU General Public License
22
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
3
+ This file is part of PDF Walker, a graphical PDF file browser
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ PDF Walker is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU 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
+ PDF Walker 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 General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
23
18
 
24
19
  =end
25
20
 
26
21
  module PDFWalker
27
22
 
28
- class Walker < Window
29
-
30
- def display_signing_wizard
31
-
32
- if @opened
33
- SignWizard.new(self, @opened)
34
- end
35
-
36
- end
37
-
38
- def display_usage_rights_wizard
39
-
40
- if @opened
41
- UsageRightsWizard.new(self, @opened)
42
- end
43
-
44
- end
45
-
46
- class UsageRightsWizard < Assistant
47
-
48
- def initialize(parent, pdf)
49
-
50
- super()
51
-
52
- @parent = parent
53
-
54
- @pkey, @cert = nil, nil
55
-
56
- create_intro_page
57
- create_rights_selection_page
58
- create_termination_page
59
-
60
- signal_connect('delete_event') { self.destroy }
61
- signal_connect('cancel') { self.destroy }
62
- signal_connect('close') { self.destroy }
63
-
64
- signal_connect('apply') {
65
-
66
- rights = []
67
-
68
- rights << UsageRights::Rights::DOCUMENT_FULLSAVE if @document_fullsave.active?
69
-
70
- rights << UsageRights::Rights::ANNOTS_CREATE if @annots_create.active?
71
- rights << UsageRights::Rights::ANNOTS_DELETE if @annots_delete.active?
72
- rights << UsageRights::Rights::ANNOTS_MODIFY if @annots_modify.active?
73
- rights << UsageRights::Rights::ANNOTS_COPY if @annots_copy.active?
74
- rights << UsageRights::Rights::ANNOTS_IMPORT if @annots_import.active?
75
- rights << UsageRights::Rights::ANNOTS_EXPORT if @annots_export.active?
76
- rights << UsageRights::Rights::ANNOTS_ONLINE if @annots_online.active?
77
- rights << UsageRights::Rights::ANNOTS_SUMMARYVIEW if @annots_sumview.active?
78
-
79
- rights << UsageRights::Rights::FORM_FILLIN if @form_fillin.active?
80
- rights << UsageRights::Rights::FORM_IMPORT if @form_import.active?
81
- rights << UsageRights::Rights::FORM_EXPORT if @form_export.active?
82
- rights << UsageRights::Rights::FORM_SUBMITSTANDALONE if @form_submit.active?
83
- rights << UsageRights::Rights::FORM_SPAWNTEMPLATE if @form_spawntemplate.active?
84
- rights << UsageRights::Rights::FORM_BARCODEPLAINTEXT if @form_barcode.active?
85
- rights << UsageRights::Rights::FORM_ONLINE if @form_online.active?
86
-
87
- rights << UsageRights::Rights::SIGNATURE_MODIFY if @signature_modify.active?
88
-
89
- rights << UsageRights::Rights::EF_CREATE if @ef_create.active?
90
- rights << UsageRights::Rights::EF_DELETE if @ef_delete.active?
91
- rights << UsageRights::Rights::EF_MODIFY if @ef_modify.active?
92
- rights << UsageRights::Rights::EF_IMPORT if @ef_import.active?
93
-
94
- begin
95
- pdf.enable_usage_rights(*rights)
96
-
97
- set_page_title(@lastpage, "Usage Rights have been enabled")
98
- @msg_status.text = "Usage Rights have been enabled for the current document.\n You should consider saving it now."
99
-
100
- @parent.reload
101
- rescue Exception => e
102
- puts e
103
- puts e.backtrace
104
-
105
- set_page_title(@lastpage, "Usage Rights have not been enabled")
106
- @msg_status.text = "An error occured during the signature process."
107
- end
108
- }
109
-
110
- show_all
111
-
112
- end
113
-
114
- private
115
-
116
- def create_intro_page
117
-
118
- intro = <<INTRO
119
- You are about to enable Usage Rights for the current PDF document.
120
- To enable these features, you need to have an Adobe public/private key pair in your possession.
121
-
122
- Make sure you have adobe.crt and adobe.key located in the current directory.
123
- INTRO
124
-
125
- vbox = VBox.new(false, 5)
126
- vbox.set_border_width(5)
127
-
128
- lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
129
-
130
- vbox.pack_start(lbl, true, true, 0)
131
-
132
- append_page(vbox)
133
- set_page_title(vbox, "Usage Rights Wizard")
134
- set_page_type(vbox, Assistant::PAGE_INTRO)
135
- set_page_complete(vbox, true)
136
-
137
- end
138
-
139
- def create_rights_selection_page
140
-
141
- vbox = VBox.new(false, 5)
142
-
143
- docframe = Frame.new(" Document ")
144
- docframe.border_width = 5
145
- docframe.shadow_type = Gtk::SHADOW_IN
146
-
147
- doctable = Table.new(1, 2)
148
- doctable.attach(@document_fullsave = CheckButton.new("Full Save").set_active(true), 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
149
- docframe.add(doctable)
150
-
151
- annotsframe = Frame.new(" Annotations ")
152
- annotsframe.border_width = 5
153
- annotsframe.shadow_type = Gtk::SHADOW_IN
154
-
155
- annotstable = Table.new(4,2)
156
- annots =
157
- [
158
- [ @annots_create = CheckButton.new("Create").set_active(true), @annots_import = CheckButton.new("Import").set_active(true) ],
159
- [ @annots_delete = CheckButton.new("Delete").set_active(true), @annots_export = CheckButton.new("Export").set_active(true) ],
160
- [ @annots_modify = CheckButton.new("Modify").set_active(true), @annots_online = CheckButton.new("Online").set_active(true) ],
161
- [ @annots_copy = CheckButton.new("Copy").set_active(true), @annots_sumview = CheckButton.new("Summary View").set_active(true) ]
162
- ]
163
-
164
- tt = Tooltips.new.enable
165
- tt.set_tip(@annots_create, "test", "")
166
-
167
- row = 0
168
- annots.each do |col1, col2|
169
-
170
- annotstable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
171
- annotstable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
172
-
173
- row = row.succ
174
- end
175
-
176
- annotsframe.add(annotstable)
177
-
178
- formframe = Frame.new(" Forms ")
179
- formframe.border_width = 5
180
- formframe.shadow_type = Gtk::SHADOW_IN
181
-
182
- formtable = Table.new(4,2)
183
- forms =
184
- [
185
- [ @form_fillin = CheckButton.new("Fill in").set_active(true), @form_spawntemplate = CheckButton.new("Spawn template").set_active(true) ],
186
- [ @form_import = CheckButton.new("Import").set_active(true), @form_barcode = CheckButton.new("Barcode plaintext").set_active(true) ],
187
- [ @form_export = CheckButton.new("Export").set_active(true), @form_online = CheckButton.new("Online").set_active(true) ],
188
- [ @form_submit = CheckButton.new("Submit stand-alone").set_active(true), nil ]
189
- ]
190
-
191
- row = 0
192
- forms.each do |col1, col2|
193
-
194
- formtable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
195
- formtable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
196
-
197
- row = row.succ
198
- end
199
-
200
- formframe.add(formtable)
201
-
202
- signatureframe = Frame.new(" Signature ")
203
- signatureframe.border_width = 5
204
- signatureframe.shadow_type = Gtk::SHADOW_IN
205
-
206
- signaturetable = Table.new(1, 2)
207
- signaturetable.attach(@signature_modify = CheckButton.new("Modify").set_active(true), 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
208
- signatureframe.add(signaturetable)
209
-
210
- efframe = Frame.new(" Embedded files ")
211
- efframe.border_width = 5
212
- efframe.shadow_type = Gtk::SHADOW_IN
213
-
214
- eftable = Table.new(2,2)
215
- efitems =
216
- [
217
- [ @ef_create = CheckButton.new("Create").set_active(true), @ef_modify = CheckButton.new("Modify").set_active(true) ],
218
- [ @ef_delete = CheckButton.new("Delete").set_active(true), @ef_import = CheckButton.new("Import").set_active(true) ]
219
- ]
220
-
221
- row = 0
222
- efitems.each do |col1, col2|
223
-
224
- eftable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
225
- eftable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
226
-
227
- row = row.succ
23
+ class Walker < Window
24
+
25
+ def display_signing_wizard
26
+ SignWizard.new(self, @opened) if @opened
228
27
  end
229
-
230
- efframe.add(eftable)
231
-
232
- vbox.add(docframe)
233
- vbox.add(annotsframe)
234
- vbox.add(formframe)
235
- vbox.add(signatureframe)
236
- vbox.add(efframe)
237
-
238
- append_page(vbox)
239
- set_page_title(vbox, "Select Usage Rights to enable")
240
- set_page_type(vbox, Assistant::PAGE_CONFIRM)
241
- set_page_complete(vbox, true)
242
-
243
- end
244
-
245
- def create_termination_page
246
-
247
- @lastpage = VBox.new(false, 5)
248
-
249
- @msg_status = Label.new
250
- @lastpage.pack_start(@msg_status, true, true, 0)
251
-
252
- append_page(@lastpage)
253
- set_page_title(@lastpage, "Usage Rights have not been enabled")
254
- set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
255
-
256
- end
257
-
258
- end
259
-
260
- class SignWizard < Assistant
261
-
262
- INTRO_PAGE = 0
263
- KEY_SELECT_PAGE = 1
264
- PKCS12_IMPORT_PAGE = 2
265
- KEYPAIR_IMPORT_PAGE = 3
266
- SIGNATURE_INFO_PAGE = 4
267
- SIGNATURE_RESULT_PAGE = 5
268
-
269
- def initialize(parent, pdf)
270
-
271
- super()
272
-
273
- @parent = parent
274
-
275
- @pkey, @cert, @ca = nil, nil, []
276
-
277
- create_intro_page
278
- create_key_selection_page
279
- create_pkcs12_import_page
280
- create_keypair_import_page
281
- create_signature_info_page
282
- create_termination_page
283
-
284
- set_forward_page_func { |current_page|
285
- case current_page
286
- when KEY_SELECT_PAGE
287
- if @p12button.active? then PKCS12_IMPORT_PAGE else KEYPAIR_IMPORT_PAGE end
288
-
289
- when PKCS12_IMPORT_PAGE, KEYPAIR_IMPORT_PAGE
290
- SIGNATURE_INFO_PAGE
291
-
292
- else current_page.succ
293
- end
294
- }
295
-
296
- signal_connect('delete_event') { self.destroy }
297
- signal_connect('cancel') { self.destroy }
298
- signal_connect('close') { self.destroy }
299
-
300
- signal_connect('apply') {
301
-
302
- location = @location.text.empty? ? nil : @location.text
303
- contact = @email.text.empty? ? nil : @email.text
304
- reason = @reason.text.empty? ? nil : @reason.text
305
-
306
- begin
307
- pdf.sign(@cert, @pkey, @ca, nil, location, contact, reason)
308
-
309
- set_page_title(@lastpage, "Document has been signed")
310
- @msg_status.text = "The document has been signed.\n You should consider saving it now."
311
-
312
- @parent.reload
313
- rescue Exception => e
314
- puts e
315
- puts e.backtrace
316
-
317
- set_page_title(@lastpage, "Document has not been signed")
318
- @msg_status.text = "An error occured during the signature process."
319
- end
320
- }
321
-
322
- show_all
323
-
324
- end
325
-
326
- private
327
-
328
- def create_intro_page
329
-
330
- intro = <<INTRO
331
- You are about to sign the current PDF document.
332
- Once the document will be signed, no further modification will be allowed.
333
-
334
- The signature process is based on assymetric cryptography, so you will basically need a public/private RSA key pair (between 1024 and 4096 bits).
335
- INTRO
336
-
337
- vbox = VBox.new(false, 5)
338
- vbox.set_border_width(5)
339
-
340
- lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
341
-
342
- vbox.pack_start(lbl, true, true, 0)
343
-
344
- append_page(vbox)
345
- set_page_title(vbox, "Signature Wizard")
346
- set_page_type(vbox, Assistant::PAGE_INTRO)
347
- set_page_complete(vbox, true)
348
-
349
- end
350
-
351
- def create_key_selection_page
352
-
353
- vbox = VBox.new(false, 5)
354
-
355
- @p12button = RadioButton.new("Import keys from a PKCS12 container")
356
- @rawbutton = RadioButton.new(@p12button, "Import keys from separate PEM/DER encoded files")
357
-
358
- vbox.pack_start(@p12button, true, true, 0)
359
- vbox.pack_start(@rawbutton, true, true, 0)
360
-
361
- append_page(vbox)
362
- set_page_title(vbox, "Choose a key importation method")
363
- set_page_type(vbox, Assistant::PAGE_CONTENT)
364
- set_page_complete(vbox, true)
365
-
366
- end
367
-
368
- def create_pkcs12_import_page
369
-
370
- def get_passwd
371
-
372
- dialog = Dialog.new("Enter passphrase",
373
- @parent,
374
- Dialog::MODAL,
375
- [Stock::OK, Dialog::RESPONSE_OK]
376
- )
377
-
378
- pwd_entry = Entry.new.set_visibility(false).show
379
-
380
- dialog.vbox.pack_start(pwd_entry, true, true, 0)
381
-
382
- pwd = (dialog.run == Dialog::RESPONSE_OK) ? pwd_entry.text : ""
383
-
384
- dialog.destroy
385
-
386
- return pwd
387
-
28
+
29
+ def display_usage_rights_wizard
30
+ UsageRightsWizard.new(self, @opened) if @opened
388
31
  end
389
-
390
- def open_file_dialog(page)
391
-
392
- dialog = FileChooserDialog.new("Open PKCS12 container",
393
- @parent,
394
- FileChooser::ACTION_OPEN,
395
- nil,
396
- [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
397
- [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
398
- filter = FileFilter.new
399
- filter.add_pattern("*.pfx")
400
- filter.add_pattern("*.p12")
401
-
402
- dialog.filter = filter
403
-
404
- if dialog.run == Dialog::RESPONSE_ACCEPT
405
-
406
- begin
407
- p12 = OpenSSL::PKCS12::PKCS12.new(File.open(dialog.filename, 'r').binmode.read, get_passwd)
408
-
409
- if not p12.key.is_a?(OpenSSL::PKey::RSA) then raise TypeError end
410
- if not p12.certificate.is_a?(OpenSSL::X509::Certificate) then raise TypeError end
411
-
412
- @pkey = p12.key
413
- @cert = p12.certificate
414
- @ca = p12.ca_certs
415
-
416
- @p12filename.set_text(dialog.filename)
417
- set_page_complete(page, true)
418
-
419
- rescue Exception => e
420
- puts e.backtrace
421
- error = MessageDialog.new(@parent,
422
- Dialog::MODAL,
423
- Gtk::MessageDialog::ERROR,
424
- Gtk::MessageDialog::BUTTONS_CLOSE,
425
- "Error loading file '#{File.basename(dialog.filename)}'")
426
- error.run
427
- error.destroy
428
-
429
- @pkey, @cert, @ca = nil, nil, []
430
- @p12filename.text = ""
431
- set_page_complete(page, false)
432
-
32
+
33
+ module SignatureDialogs
34
+ private
35
+
36
+ def open_private_key_dialog(page)
37
+ dialog = FileChooserDialog.new("Choose a private RSA key",
38
+ @parent,
39
+ FileChooser::ACTION_OPEN,
40
+ nil,
41
+ [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
42
+ [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
43
+
44
+ filter = FileFilter.new
45
+ filter.add_pattern("*.key")
46
+ filter.add_pattern("*.pem")
47
+ filter.add_pattern("*.der")
48
+
49
+ dialog.set_filter(filter)
50
+
51
+ if dialog.run == Dialog::RESPONSE_ACCEPT
52
+ begin
53
+ @pkey = OpenSSL::PKey::RSA.new(File.binread(dialog.filename))
54
+
55
+ @pkeyfilename.set_text(dialog.filename)
56
+ set_page_complete(page, true) if @cert
57
+ rescue
58
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
59
+
60
+ @pkey = nil
61
+ @pkeyfilename.text = ""
62
+ set_page_complete(page, false)
63
+ ensure
64
+ @ca = [] # Shall be added to the GUI
65
+ end
66
+ end
67
+
68
+ dialog.destroy
433
69
  end
434
-
435
- end
436
-
437
- dialog.destroy
438
-
439
- end
440
-
441
- vbox = VBox.new(false, 5)
442
-
443
- hbox = HBox.new(false, 5)
444
- vbox.pack_start(hbox, true, false, 10)
445
-
446
- @p12filename = Entry.new.set_editable(false).set_sensitive(false)
447
- choosebtn = Button.new(Gtk::Stock::OPEN)
448
-
449
- choosebtn.signal_connect('clicked') { open_file_dialog(vbox) }
450
-
451
- hbox.pack_start(@p12filename, true, true, 5)
452
- hbox.pack_start(choosebtn, false, false, 5)
453
-
454
- append_page(vbox)
455
- set_page_title(vbox, "Import a PKCS12 container")
456
- set_page_type(vbox, Assistant::PAGE_CONTENT)
457
-
458
- end
459
-
460
- def create_keypair_import_page
461
-
462
- def open_pkey_dialog(page)
463
-
464
- dialog = FileChooserDialog.new("Choose a private RSA key",
465
- @parent,
466
- FileChooser::ACTION_OPEN,
467
- nil,
468
- [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
469
- [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
470
- filter = FileFilter.new
471
- filter.add_pattern("*.key")
472
- filter.add_pattern("*.pem")
473
- filter.add_pattern("*.der")
474
-
475
- dialog.set_filter(filter)
476
-
477
- if dialog.run == Dialog::RESPONSE_ACCEPT
478
-
479
- begin
480
- @pkey = OpenSSL::PKey::RSA.new(File.open(dialog.filename, 'r').binmode.read)
481
-
482
- @pkeyfilename.set_text(dialog.filename)
483
- if @cert then set_page_complete(page, true) end
484
-
485
- rescue Exception => e
486
- puts e.backtrace
487
- error = MessageDialog.new(@parent,
488
- Dialog::MODAL,
489
- Gtk::MessageDialog::ERROR,
490
- Gtk::MessageDialog::BUTTONS_CLOSE,
491
- "Error loading file '#{File.basename(dialog.filename)}'")
492
- error.run
493
- error.destroy
494
-
495
- @pkey = nil
496
- @pkeyfilename.text = ""
497
- set_page_complete(page, false)
498
-
499
- ensure
500
- @ca = [] # Shall be added to the GUI
70
+
71
+ def open_certificate_dialog(page)
72
+ dialog = FileChooserDialog.new("Choose a x509 certificate",
73
+ @parent,
74
+ FileChooser::ACTION_OPEN,
75
+ nil,
76
+ [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
77
+ [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
78
+ filter = FileFilter.new
79
+ filter.add_pattern("*.crt")
80
+ filter.add_pattern("*.cer")
81
+ filter.add_pattern("*.pem")
82
+ filter.add_pattern("*.der")
83
+
84
+ dialog.set_filter(filter)
85
+
86
+ if dialog.run == Dialog::RESPONSE_ACCEPT
87
+ begin
88
+ @cert = OpenSSL::X509::Certificate.new(File.binread(dialog.filename))
89
+
90
+ @certfilename.set_text(dialog.filename)
91
+ if @pkey then set_page_complete(page, true) end
92
+
93
+ rescue
94
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
95
+
96
+ @cert = nil
97
+ @certfilename.text = ""
98
+ set_page_complete(page, false)
99
+ ensure
100
+ @ca = [] # Shall be added to the GUI
101
+ end
102
+ end
103
+
104
+ dialog.destroy
501
105
  end
502
-
503
- end
504
-
505
- dialog.destroy
506
-
507
- end
508
-
509
- def open_cert_dialog(page)
510
-
511
- dialog = FileChooserDialog.new("Choose a private RSA key",
512
- @parent,
513
- FileChooser::ACTION_OPEN,
514
- nil,
515
- [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
516
- [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
517
- filter = FileFilter.new
518
- filter.add_pattern("*.crt")
519
- filter.add_pattern("*.cer")
520
- filter.add_pattern("*.pem")
521
- filter.add_pattern("*.der")
522
-
523
- dialog.set_filter(filter)
524
-
525
- if dialog.run == Dialog::RESPONSE_ACCEPT
526
-
527
- begin
528
- @cert = OpenSSL::X509::Certificate.new(File.open(dialog.filename, 'r').binmode.read)
529
-
530
- @certfilename.set_text(dialog.filename)
531
- if @pkey then set_page_complete(page, true) end
532
-
533
- rescue Exception => e
534
- puts e.backtrace
535
- error = MessageDialog.new(@parent,
536
- Dialog::MODAL,
537
- Gtk::MessageDialog::ERROR,
538
- Gtk::MessageDialog::BUTTONS_CLOSE,
539
- "Error loading file '#{File.basename(dialog.filename)}'")
540
- error.run
541
- error.destroy
542
-
543
- @cert = nil
544
- @certfilename.text = ""
545
- set_page_complete(page, false)
546
-
547
- ensure
548
- @ca = [] # Shall be added to the GUI
106
+
107
+ def open_pkcs12_file_dialog(page)
108
+
109
+ get_passwd = -> () do
110
+ dialog = Dialog.new("Enter passphrase",
111
+ @parent,
112
+ Dialog::MODAL,
113
+ [Stock::OK, Dialog::RESPONSE_OK]
114
+ )
115
+
116
+ pwd_entry = Entry.new.set_visibility(false).show
117
+ dialog.vbox.pack_start(pwd_entry, true, true, 0)
118
+
119
+ pwd = (dialog.run == Dialog::RESPONSE_OK) ? pwd_entry.text : ""
120
+
121
+ dialog.destroy
122
+ return pwd
123
+ end
124
+
125
+ dialog = FileChooserDialog.new("Open PKCS12 container",
126
+ @parent,
127
+ FileChooser::ACTION_OPEN,
128
+ nil,
129
+ [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
130
+ [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
131
+ filter = FileFilter.new
132
+ filter.add_pattern("*.pfx")
133
+ filter.add_pattern("*.p12")
134
+
135
+ dialog.filter = filter
136
+
137
+ if dialog.run == Dialog::RESPONSE_ACCEPT
138
+ begin
139
+ p12 = OpenSSL::PKCS12::PKCS12.new(File.binread(dialog.filename), get_passwd)
140
+
141
+ raise TypeError, "PKCS12 does not contain a RSA key" unless p12.key.is_a?(OpenSSL::PKey::RSA)
142
+ raise TypeError, "PKCS12 does not contain a x509 certificate" unless p12.certificate.is_a?(OpenSSL::X509::Certificate)
143
+
144
+ @pkey = p12.key
145
+ @cert = p12.certificate
146
+ @ca = p12.ca_certs
147
+
148
+ @p12filename.set_text(dialog.filename)
149
+ set_page_complete(page, true)
150
+ rescue
151
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
152
+
153
+ @pkey, @cert, @ca = nil, nil, []
154
+ @p12filename.text = ""
155
+ set_page_complete(page, false)
156
+
157
+ end
158
+ end
159
+
160
+ dialog.destroy
549
161
  end
550
-
551
- end
552
-
553
- dialog.destroy
554
-
555
162
  end
556
-
557
- labels =
558
- [
559
- [ "Private RSA key:", @pkeyfilename = Entry.new, pkeychoosebtn = Button.new(Gtk::Stock::OPEN) ],
560
- [ "Public certificate:", @certfilename = Entry.new, certchoosebtn = Button.new(Gtk::Stock::OPEN) ]
561
- ]
562
-
563
- row = 0
564
- table = Table.new(2, 3)
565
- labels.each do |lbl, entry, btn|
566
-
567
- entry.editable = entry.sensitive = false
568
-
569
- table.attach(Label.new(lbl).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
570
- table.attach(entry, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
571
- table.attach(btn, 2, 3, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
572
-
573
- row = row.succ
163
+
164
+ class UsageRightsWizard < Assistant
165
+ include SignatureDialogs
166
+
167
+ def initialize(parent, pdf)
168
+ super()
169
+
170
+ @parent = parent
171
+ @pkey, @cert = nil, nil
172
+
173
+ create_intro_page
174
+ create_keypair_import_page
175
+ create_rights_selection_page
176
+ create_termination_page
177
+
178
+ signal_connect('delete_event') { self.destroy }
179
+ signal_connect('cancel') { self.destroy }
180
+ signal_connect('close') { self.destroy }
181
+
182
+ signal_connect('apply') {
183
+ rights = []
184
+
185
+ rights << Origami::UsageRights::Rights::DOCUMENT_FULLSAVE if @document_fullsave.active?
186
+
187
+ rights << Origami::UsageRights::Rights::ANNOTS_CREATE if @annots_create.active?
188
+ rights << Origami::UsageRights::Rights::ANNOTS_DELETE if @annots_delete.active?
189
+ rights << Origami::UsageRights::Rights::ANNOTS_MODIFY if @annots_modify.active?
190
+ rights << Origami::UsageRights::Rights::ANNOTS_COPY if @annots_copy.active?
191
+ rights << Origami::UsageRights::Rights::ANNOTS_IMPORT if @annots_import.active?
192
+ rights << Origami::UsageRights::Rights::ANNOTS_EXPORT if @annots_export.active?
193
+ rights << Origami::UsageRights::Rights::ANNOTS_ONLINE if @annots_online.active?
194
+ rights << Origami::UsageRights::Rights::ANNOTS_SUMMARYVIEW if @annots_sumview.active?
195
+
196
+ rights << Origami::UsageRights::Rights::FORM_FILLIN if @form_fillin.active?
197
+ rights << Origami::UsageRights::Rights::FORM_IMPORT if @form_import.active?
198
+ rights << Origami::UsageRights::Rights::FORM_EXPORT if @form_export.active?
199
+ rights << Origami::UsageRights::Rights::FORM_SUBMITSTANDALONE if @form_submit.active?
200
+ rights << Origami::UsageRights::Rights::FORM_SPAWNTEMPLATE if @form_spawntemplate.active?
201
+ rights << Origami::UsageRights::Rights::FORM_BARCODEPLAINTEXT if @form_barcode.active?
202
+ rights << Origami::UsageRights::Rights::FORM_ONLINE if @form_online.active?
203
+
204
+ rights << Origami::UsageRights::Rights::SIGNATURE_MODIFY if @signature_modify.active?
205
+
206
+ rights << Origami::UsageRights::Rights::EF_CREATE if @ef_create.active?
207
+ rights << Origami::UsageRights::Rights::EF_DELETE if @ef_delete.active?
208
+ rights << Origami::UsageRights::Rights::EF_MODIFY if @ef_modify.active?
209
+ rights << Origami::UsageRights::Rights::EF_IMPORT if @ef_import.active?
210
+
211
+ begin
212
+ pdf.enable_usage_rights(@cert, @pkey, *rights)
213
+
214
+ set_page_title(@lastpage, "Usage Rights have been enabled")
215
+ @msg_status.text = "Usage Rights have been enabled for the current document.\n You should consider saving it now."
216
+
217
+ @parent.reload
218
+ rescue
219
+ @parent.error("#{$!}: #{$!.backtrace.join($/)}")
220
+
221
+ set_page_title(@lastpage, "Usage Rights have not been enabled")
222
+ @msg_status.text = "An error occured during the signature process."
223
+ end
224
+ }
225
+
226
+ set_modal(true)
227
+
228
+ show_all
229
+ end
230
+
231
+ private
232
+
233
+ def create_intro_page
234
+ intro = <<-INTRO
235
+ You are about to enable Usage Rights for the current PDF document.
236
+ To enable these features, you need to have an Adobe public/private key pair in your possession.
237
+
238
+ Make sure you have adobe.crt and adobe.key located in the current directory.
239
+ INTRO
240
+
241
+ vbox = VBox.new(false, 5)
242
+ vbox.set_border_width(5)
243
+
244
+ lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
245
+
246
+ vbox.pack_start(lbl, true, true, 0)
247
+
248
+ append_page(vbox)
249
+ set_page_title(vbox, "Usage Rights Wizard")
250
+ set_page_type(vbox, Assistant::PAGE_INTRO)
251
+ set_page_complete(vbox, true)
252
+ end
253
+
254
+ def create_keypair_import_page
255
+
256
+ labels =
257
+ [
258
+ [ "Private RSA key:", @pkeyfilename = Entry.new, pkeychoosebtn = Button.new(Gtk::Stock::OPEN) ],
259
+ [ "Public certificate:", @certfilename = Entry.new, certchoosebtn = Button.new(Gtk::Stock::OPEN) ]
260
+ ]
261
+
262
+ row = 0
263
+ table = Table.new(2, 3)
264
+ labels.each do |lbl, entry, btn|
265
+ entry.editable = entry.sensitive = false
266
+
267
+ table.attach(Label.new(lbl).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
268
+ table.attach(entry, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
269
+ table.attach(btn, 2, 3, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
270
+
271
+ row = row.succ
272
+ end
273
+
274
+ pkeychoosebtn.signal_connect('clicked') { open_private_key_dialog(table) }
275
+ certchoosebtn.signal_connect('clicked') { open_certificate_dialog(table) }
276
+
277
+ append_page(table)
278
+ set_page_title(table, "Import a public/private key pair")
279
+ set_page_type(table, Assistant::PAGE_CONTENT)
280
+ end
281
+
282
+ def create_rights_selection_page
283
+ vbox = VBox.new(false, 5)
284
+
285
+ docframe = Frame.new(" Document ")
286
+ docframe.border_width = 5
287
+ docframe.shadow_type = Gtk::SHADOW_IN
288
+
289
+ doctable = Table.new(1, 2)
290
+ doctable.attach(@document_fullsave = CheckButton.new("Full Save").set_active(true), 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
291
+ docframe.add(doctable)
292
+
293
+ annotsframe = Frame.new(" Annotations ")
294
+ annotsframe.border_width = 5
295
+ annotsframe.shadow_type = Gtk::SHADOW_IN
296
+
297
+ annotstable = Table.new(4,2)
298
+ annots =
299
+ [
300
+ [ @annots_create = CheckButton.new("Create").set_active(true), @annots_import = CheckButton.new("Import").set_active(true) ],
301
+ [ @annots_delete = CheckButton.new("Delete").set_active(true), @annots_export = CheckButton.new("Export").set_active(true) ],
302
+ [ @annots_modify = CheckButton.new("Modify").set_active(true), @annots_online = CheckButton.new("Online").set_active(true) ],
303
+ [ @annots_copy = CheckButton.new("Copy").set_active(true), @annots_sumview = CheckButton.new("Summary View").set_active(true) ]
304
+ ]
305
+
306
+ row = 0
307
+ annots.each do |col1, col2|
308
+ annotstable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
309
+ annotstable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
310
+
311
+ row = row.succ
312
+ end
313
+
314
+ annotsframe.add(annotstable)
315
+
316
+ formframe = Frame.new(" Forms ")
317
+ formframe.border_width = 5
318
+ formframe.shadow_type = Gtk::SHADOW_IN
319
+
320
+ formtable = Table.new(4,2)
321
+ forms =
322
+ [
323
+ [ @form_fillin = CheckButton.new("Fill in").set_active(true), @form_spawntemplate = CheckButton.new("Spawn template").set_active(true) ],
324
+ [ @form_import = CheckButton.new("Import").set_active(true), @form_barcode = CheckButton.new("Barcode plaintext").set_active(true) ],
325
+ [ @form_export = CheckButton.new("Export").set_active(true), @form_online = CheckButton.new("Online").set_active(true) ],
326
+ [ @form_submit = CheckButton.new("Submit stand-alone").set_active(true), nil ]
327
+ ]
328
+
329
+ row = 0
330
+ forms.each do |col1, col2|
331
+ formtable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
332
+ formtable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4) unless col2.nil?
333
+
334
+ row = row.succ
335
+ end
336
+
337
+ formframe.add(formtable)
338
+
339
+ signatureframe = Frame.new(" Signature ")
340
+ signatureframe.border_width = 5
341
+ signatureframe.shadow_type = Gtk::SHADOW_IN
342
+
343
+ signaturetable = Table.new(1, 2)
344
+ signaturetable.attach(@signature_modify = CheckButton.new("Modify").set_active(true), 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
345
+ signatureframe.add(signaturetable)
346
+
347
+ efframe = Frame.new(" Embedded files ")
348
+ efframe.border_width = 5
349
+ efframe.shadow_type = Gtk::SHADOW_IN
350
+
351
+ eftable = Table.new(2,2)
352
+ efitems =
353
+ [
354
+ [ @ef_create = CheckButton.new("Create").set_active(true), @ef_modify = CheckButton.new("Modify").set_active(true) ],
355
+ [ @ef_delete = CheckButton.new("Delete").set_active(true), @ef_import = CheckButton.new("Import").set_active(true) ]
356
+ ]
357
+
358
+ row = 0
359
+ efitems.each do |col1, col2|
360
+ eftable.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
361
+ eftable.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
362
+
363
+ row = row.succ
364
+ end
365
+
366
+ efframe.add(eftable)
367
+
368
+ vbox.add(docframe)
369
+ vbox.add(annotsframe)
370
+ vbox.add(formframe)
371
+ vbox.add(signatureframe)
372
+ vbox.add(efframe)
373
+
374
+ append_page(vbox)
375
+ set_page_title(vbox, "Select Usage Rights to enable")
376
+ set_page_type(vbox, Assistant::PAGE_CONFIRM)
377
+ set_page_complete(vbox, true)
378
+ end
379
+
380
+ def create_termination_page
381
+ @lastpage = VBox.new(false, 5)
382
+
383
+ @msg_status = Label.new
384
+ @lastpage.pack_start(@msg_status, true, true, 0)
385
+
386
+ append_page(@lastpage)
387
+ set_page_title(@lastpage, "Usage Rights have not been enabled")
388
+ set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
389
+ end
574
390
  end
575
-
576
- pkeychoosebtn.signal_connect('clicked') { open_pkey_dialog(table) }
577
- certchoosebtn.signal_connect('clicked') { open_cert_dialog(table) }
578
-
579
- append_page(table)
580
- set_page_title(table, "Import a public/private key pair")
581
- set_page_type(table, Assistant::PAGE_CONTENT)
582
-
583
- end
584
-
585
- def create_signature_info_page
586
-
587
- vbox = VBox.new(false, 5)
588
-
589
- lbl = Label.new("Here are a few optional information you can add with your signature.")
590
- vbox.pack_start(lbl, true, true, 0)
591
-
592
- labels =
593
- [
594
- [ "Location:", @location = Entry.new ],
595
- [ "Contact:", @email = Entry.new ],
596
- [ "Reason:", @reason = Entry.new ]
597
- ]
598
-
599
- row = 0
600
- table = Table.new(4, 3)
601
- labels.each do |label|
602
-
603
- table.attach(Label.new(label[0]).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
604
- table.attach(label[1], 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
605
-
606
- row = row.succ
391
+
392
+ class SignWizard < Assistant
393
+ include SignatureDialogs
394
+
395
+ INTRO_PAGE = 0
396
+ KEY_SELECT_PAGE = 1
397
+ PKCS12_IMPORT_PAGE = 2
398
+ KEYPAIR_IMPORT_PAGE = 3
399
+ SIGNATURE_INFO_PAGE = 4
400
+ SIGNATURE_RESULT_PAGE = 5
401
+
402
+ def initialize(parent, pdf)
403
+ super()
404
+
405
+ @parent = parent
406
+
407
+ @pkey, @cert, @ca = nil, nil, []
408
+
409
+ create_intro_page
410
+ create_key_selection_page
411
+ create_pkcs12_import_page
412
+ create_keypair_import_page
413
+ create_signature_info_page
414
+ create_termination_page
415
+
416
+ set_forward_page_func { |current_page|
417
+ case current_page
418
+ when KEY_SELECT_PAGE
419
+ if @p12button.active? then PKCS12_IMPORT_PAGE else KEYPAIR_IMPORT_PAGE end
420
+
421
+ when PKCS12_IMPORT_PAGE, KEYPAIR_IMPORT_PAGE
422
+ SIGNATURE_INFO_PAGE
423
+
424
+ else current_page.succ
425
+ end
426
+ }
427
+
428
+ signal_connect('delete_event') { self.destroy }
429
+ signal_connect('cancel') { self.destroy }
430
+ signal_connect('close') { self.destroy }
431
+
432
+ signal_connect('apply') {
433
+ location = @location.text.empty? ? nil : @location.text
434
+ contact = @email.text.empty? ? nil : @email.text
435
+ reason = @reason.text.empty? ? nil : @reason.text
436
+
437
+ begin
438
+ pdf.sign(@cert, @pkey,
439
+ ca: @ca,
440
+ location: location,
441
+ contact: contact,
442
+ reason: reason)
443
+
444
+ set_page_title(@lastpage, "Document has been signed")
445
+ @msg_status.text = "The document has been signed.\n You should consider saving it now."
446
+
447
+ @parent.reload
448
+ rescue
449
+ @parent.error("#{$!}: #{$!.backtrace.join($/)}")
450
+
451
+ set_page_title(@lastpage, "Document has not been signed")
452
+ @msg_status.text = "An error occured during the signature process."
453
+ end
454
+ }
455
+
456
+ set_modal(true)
457
+
458
+ show_all
459
+ end
460
+
461
+ private
462
+
463
+ def create_intro_page
464
+ intro = <<-INTRO
465
+ You are about to sign the current PDF document.
466
+ Once the document will be signed, no further modification will be allowed.
467
+
468
+ The signature process is based on assymetric cryptography, so you will basically need a public/private RSA key pair (between 1024 and 4096 bits).
469
+ INTRO
470
+
471
+ vbox = VBox.new(false, 5)
472
+ vbox.set_border_width(5)
473
+
474
+ lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
475
+
476
+ vbox.pack_start(lbl, true, true, 0)
477
+
478
+ append_page(vbox)
479
+ set_page_title(vbox, "Signature Wizard")
480
+ set_page_type(vbox, Assistant::PAGE_INTRO)
481
+ set_page_complete(vbox, true)
482
+ end
483
+
484
+ def create_key_selection_page
485
+ vbox = VBox.new(false, 5)
486
+
487
+ @rawbutton = RadioButton.new("Import keys from separate PEM/DER encoded files")
488
+ @p12button = RadioButton.new(@rawbutton, "Import keys from a PKCS12 container")
489
+
490
+ vbox.pack_start(@rawbutton, true, true, 0)
491
+ vbox.pack_start(@p12button, true, true, 0)
492
+
493
+ append_page(vbox)
494
+ set_page_title(vbox, "Choose a key importation method")
495
+ set_page_type(vbox, Assistant::PAGE_CONTENT)
496
+ set_page_complete(vbox, true)
497
+ end
498
+
499
+ def create_pkcs12_import_page
500
+ vbox = VBox.new(false, 5)
501
+
502
+ hbox = HBox.new(false, 5)
503
+ vbox.pack_start(hbox, true, false, 10)
504
+
505
+ @p12filename = Entry.new.set_editable(false).set_sensitive(false)
506
+ choosebtn = Button.new(Gtk::Stock::OPEN)
507
+
508
+ choosebtn.signal_connect('clicked') { open_pkcs12_file_dialog(vbox) }
509
+
510
+ hbox.pack_start(@p12filename, true, true, 5)
511
+ hbox.pack_start(choosebtn, false, false, 5)
512
+
513
+ append_page(vbox)
514
+ set_page_title(vbox, "Import a PKCS12 container")
515
+ set_page_type(vbox, Assistant::PAGE_CONTENT)
516
+ end
517
+
518
+ def create_keypair_import_page
519
+
520
+ labels =
521
+ [
522
+ [ "Private RSA key:", @pkeyfilename = Entry.new, pkeychoosebtn = Button.new(Gtk::Stock::OPEN) ],
523
+ [ "Public certificate:", @certfilename = Entry.new, certchoosebtn = Button.new(Gtk::Stock::OPEN) ]
524
+ ]
525
+
526
+ row = 0
527
+ table = Table.new(2, 3)
528
+ labels.each do |lbl, entry, btn|
529
+ entry.editable = entry.sensitive = false
530
+
531
+ table.attach(Label.new(lbl).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
532
+ table.attach(entry, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
533
+ table.attach(btn, 2, 3, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
534
+
535
+ row = row.succ
536
+ end
537
+
538
+ pkeychoosebtn.signal_connect('clicked') { open_private_key_dialog(table) }
539
+ certchoosebtn.signal_connect('clicked') { open_certificate_dialog(table) }
540
+
541
+ append_page(table)
542
+ set_page_title(table, "Import a public/private key pair")
543
+ set_page_type(table, Assistant::PAGE_CONTENT)
544
+ end
545
+
546
+ def create_signature_info_page
547
+ vbox = VBox.new(false, 5)
548
+
549
+ lbl = Label.new("Here are a few optional information you can add with your signature.")
550
+ vbox.pack_start(lbl, true, true, 0)
551
+
552
+ labels =
553
+ [
554
+ [ "Location:", @location = Entry.new ],
555
+ [ "Contact:", @email = Entry.new ],
556
+ [ "Reason:", @reason = Entry.new ]
557
+ ]
558
+
559
+ row = 0
560
+ table = Table.new(4, 3)
561
+ labels.each do |label|
562
+ table.attach(Label.new(label[0]).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
563
+ table.attach(label[1], 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
564
+
565
+ row = row.succ
566
+ end
567
+
568
+ vbox.pack_start(table, true, true, 0)
569
+
570
+ append_page(vbox)
571
+ set_page_title(vbox, "Fill in signature details")
572
+ set_page_type(vbox, Assistant::PAGE_CONFIRM)
573
+ set_page_complete(vbox, true)
574
+ end
575
+
576
+ def create_termination_page
577
+ @lastpage = VBox.new(false, 5)
578
+
579
+ @msg_status = Label.new
580
+ @lastpage.pack_start(@msg_status, true, true, 0)
581
+
582
+ append_page(@lastpage)
583
+ set_page_title(@lastpage, "Document has not been signed")
584
+ set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
585
+ end
607
586
  end
608
-
609
- vbox.pack_start(table, true, true, 0)
610
-
611
- append_page(vbox)
612
- set_page_title(vbox, "Fill in signature details")
613
- set_page_type(vbox, Assistant::PAGE_CONFIRM)
614
- set_page_complete(vbox, true)
615
-
616
- end
617
-
618
- def create_termination_page
619
-
620
- @lastpage = VBox.new(false, 5)
621
-
622
- @msg_status = Label.new
623
- @lastpage.pack_start(@msg_status, true, true, 0)
624
-
625
- append_page(@lastpage)
626
- set_page_title(@lastpage, "Document has not been signed")
627
- set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
628
-
629
- end
630
-
631
587
  end
632
-
633
- end
634
588
 
635
589
  end