pdfwalker 1.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.
@@ -0,0 +1,126 @@
1
+ =begin
2
+
3
+ This file is part of PDF Walker, a graphical PDF file browser
4
+ Copyright (C) 2017 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/>.
18
+
19
+ =end
20
+
21
+ require 'digest/md5'
22
+
23
+ module PDFWalker
24
+
25
+ class Walker < Window
26
+
27
+ def display_file_properties
28
+ Properties.new(self, @opened) if @opened
29
+ end
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
+ file_frame = create_file_frame(parent)
49
+ pdf_frame = create_document_frame(pdf)
50
+
51
+ vbox.add(file_frame)
52
+ vbox.add(pdf_frame)
53
+
54
+ signal_connect('response') { destroy }
55
+
56
+ show_all
57
+ end
58
+
59
+ private
60
+
61
+ def create_file_frame(parent)
62
+ file_frame = Frame.new(" File properties ")
63
+ stat = File.stat(parent.filename)
64
+
65
+ labels =
66
+ [
67
+ [ "Filename:", parent.filename ],
68
+ [ "File size:", "#{File.size(parent.filename)} bytes" ],
69
+ [ "MD5:", Digest::MD5.file(parent.filename).hexdigest ],
70
+ [ "Read-only:", "#{not stat.writable?}" ],
71
+ [ "Creation date:", stat.ctime.to_s ],
72
+ [ "Last modified:", stat.mtime.to_s ]
73
+ ]
74
+
75
+ create_table(file_frame, labels)
76
+ end
77
+
78
+ def create_document_frame(pdf)
79
+ pdf_frame = 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:", boolean_text(pdf.linearized?) ],
95
+ [ "Encrypted:", boolean_text(pdf.encrypted?) ],
96
+ [ "Signed:", boolean_text(pdf.signed?) ],
97
+ [ "Has usage rights:", boolean_text(pdf.usage_rights?) ],
98
+ [ "Form:", boolean_text(pdf.form?) ],
99
+ [ "XFA form:", boolean_text(pdf.xfa_form?) ],
100
+ [ "Document information:", boolean_text(pdf.document_info?) ],
101
+ [ "Metadata:", boolean_text(pdf.metadata?) ]
102
+ ]
103
+
104
+ create_table(pdf_frame, labels)
105
+ end
106
+
107
+ def create_table(frame, labels)
108
+ table = Table.new(labels.size + 1, 3)
109
+
110
+ labels.each_with_index do |label, row|
111
+ table.attach(Label.new(label[0]).set_alignment(1,0), 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 4, 4)
112
+ table.attach(Label.new(label[1]).set_alignment(0,0), 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
113
+ end
114
+
115
+ frame.border_width = 5
116
+ frame.shadow_type = Gtk::SHADOW_IN
117
+ frame.add(table)
118
+ end
119
+
120
+ def boolean_text(value)
121
+ value ? 'yes' : 'no'
122
+ end
123
+ end
124
+ end
125
+
126
+ end
@@ -0,0 +1,558 @@
1
+ =begin
2
+
3
+ This file is part of PDF Walker, a graphical PDF file browser
4
+ Copyright (C) 2017 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/>.
18
+
19
+ =end
20
+
21
+ module PDFWalker
22
+
23
+ class Walker < Window
24
+
25
+ def display_signing_wizard
26
+ SignWizard.new(self, @opened) if @opened
27
+ end
28
+
29
+ def display_usage_rights_wizard
30
+ UsageRightsWizard.new(self, @opened) if @opened
31
+ end
32
+
33
+ module SignatureDialogs
34
+ private
35
+
36
+ def open_private_key_dialog(page)
37
+ file_chooser_dialog('Choose a private RSA key', '*.key', '*.pem', '*.der') do |dialog|
38
+ begin
39
+ @pkey = OpenSSL::PKey::RSA.new(File.binread(dialog.filename))
40
+
41
+ @pkeyfilename.set_text(dialog.filename)
42
+ set_page_complete(page, true) if @cert
43
+ rescue
44
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
45
+
46
+ @pkey = nil
47
+ @pkeyfilename.text = ""
48
+ set_page_complete(page, false)
49
+ ensure
50
+ @ca = [] # Shall be added to the GUI
51
+ end
52
+ end
53
+ end
54
+
55
+ def open_certificate_dialog(page)
56
+ file_chooser_dialog('Choose a x509 certificate', '*.crt', '*.cer', '*.pem', '*.der') do |dialog|
57
+ begin
58
+ @cert = OpenSSL::X509::Certificate.new(File.binread(dialog.filename))
59
+
60
+ @certfilename.set_text(dialog.filename)
61
+ set_page_complete(page, true) if @pkey
62
+
63
+ rescue
64
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
65
+
66
+ @cert = nil
67
+ @certfilename.text = ""
68
+ set_page_complete(page, false)
69
+ ensure
70
+ @ca = [] # Shall be added to the GUI
71
+ end
72
+ end
73
+ end
74
+
75
+ def open_pkcs12_file_dialog(page)
76
+
77
+ file_chooser_dialog('Open PKCS12 container', '*.pfx', '*.p12') do |dialog|
78
+ begin
79
+ p12 = OpenSSL::PKCS12::PKCS12.new(File.binread(dialog.filename), method(:prompt_passphrase))
80
+
81
+ raise TypeError, "PKCS12 does not contain a RSA key" unless p12.key.is_a?(OpenSSL::PKey::RSA)
82
+ raise TypeError, "PKCS12 does not contain a x509 certificate" unless p12.certificate.is_a?(OpenSSL::X509::Certificate)
83
+
84
+ @pkey = p12.key
85
+ @cert = p12.certificate
86
+ @ca = p12.ca_certs
87
+
88
+ @p12filename.set_text(dialog.filename)
89
+ set_page_complete(page, true)
90
+ rescue
91
+ @parent.error("Error loading file '#{File.basename(dialog.filename)}'")
92
+
93
+ @pkey, @cert, @ca = nil, nil, []
94
+ @p12filename.text = ""
95
+ set_page_complete(page, false)
96
+ end
97
+ end
98
+ end
99
+
100
+ def create_keypair_import_page
101
+ labels =
102
+ [
103
+ [ "Private RSA key:", @pkeyfilename = Entry.new, pkeychoosebtn = Button.new(Gtk::Stock::OPEN) ],
104
+ [ "Public certificate:", @certfilename = Entry.new, certchoosebtn = Button.new(Gtk::Stock::OPEN) ]
105
+ ]
106
+
107
+ row = 0
108
+ table = Table.new(2, 3)
109
+ labels.each do |lbl, entry, btn|
110
+ entry.editable = entry.sensitive = false
111
+
112
+ table.attach(Label.new(lbl).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
113
+ table.attach(entry, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
114
+ table.attach(btn, 2, 3, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
115
+
116
+ row = row.succ
117
+ end
118
+
119
+ pkeychoosebtn.signal_connect('clicked') { open_private_key_dialog(table) }
120
+ certchoosebtn.signal_connect('clicked') { open_certificate_dialog(table) }
121
+
122
+ append_page(table)
123
+ set_page_title(table, "Import a public/private key pair")
124
+ set_page_type(table, Assistant::PAGE_CONTENT)
125
+ end
126
+
127
+ def prompt_passphrase
128
+ dialog = Dialog.new("Enter passphrase",
129
+ @parent,
130
+ Dialog::MODAL,
131
+ [Stock::OK, Dialog::RESPONSE_OK]
132
+ )
133
+
134
+ pwd_entry = Entry.new.set_visibility(false).show
135
+ dialog.vbox.pack_start(pwd_entry, true, true, 0)
136
+
137
+ pwd = pwd_entry.text if dialog.run == Dialog::RESPONSE_OK
138
+
139
+ dialog.destroy
140
+ pwd.to_s
141
+ end
142
+
143
+ def file_chooser_dialog(title, *patterns)
144
+ dialog = FileChooserDialog.new(title,
145
+ @parent,
146
+ FileChooser::ACTION_OPEN,
147
+ nil,
148
+ [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
149
+ [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
150
+
151
+ filter = FileFilter.new
152
+ patterns.each do |pattern|
153
+ filter.add_pattern(pattern)
154
+ end
155
+
156
+ dialog.set_filter(filter)
157
+
158
+ if dialog.run == Dialog::RESPONSE_ACCEPT
159
+ yield(dialog)
160
+ end
161
+
162
+ dialog.destroy
163
+ end
164
+ end
165
+
166
+ class UsageRightsWizard < Assistant
167
+ include SignatureDialogs
168
+
169
+ def initialize(parent, pdf)
170
+ super()
171
+
172
+ @parent = parent
173
+ @pkey, @cert = nil, nil
174
+
175
+ create_intro_page
176
+ create_keypair_import_page
177
+ create_rights_selection_page
178
+ create_termination_page
179
+
180
+ signal_connect('delete_event') { self.destroy }
181
+ signal_connect('cancel') { self.destroy }
182
+ signal_connect('close') { self.destroy }
183
+
184
+ signal_connect('apply') {
185
+ rights = selected_usage_rights
186
+
187
+ begin
188
+ pdf.enable_usage_rights(@cert, @pkey, *rights)
189
+
190
+ set_page_title(@lastpage, "Usage Rights have been enabled")
191
+ @msg_status.text = "Usage Rights have been enabled for the current document.\n You should consider saving it now."
192
+
193
+ @parent.reload
194
+ rescue
195
+ @parent.error("#{$!}: #{$!.backtrace.join($/)}")
196
+
197
+ set_page_title(@lastpage, "Usage Rights have not been enabled")
198
+ @msg_status.text = "An error occured during the signature process."
199
+ end
200
+ }
201
+
202
+ set_modal(true)
203
+
204
+ show_all
205
+ end
206
+
207
+ private
208
+
209
+ def selected_usage_rights
210
+ [
211
+ [ Origami::UsageRights::Rights::DOCUMENT_FULLSAVE, @document_fullsave ],
212
+
213
+ [ Origami::UsageRights::Rights::ANNOTS_CREATE, @annots_create ],
214
+ [ Origami::UsageRights::Rights::ANNOTS_DELETE, @annots_delete ],
215
+ [ Origami::UsageRights::Rights::ANNOTS_MODIFY, @annots_modify ],
216
+ [ Origami::UsageRights::Rights::ANNOTS_COPY, @annots_copy ],
217
+ [ Origami::UsageRights::Rights::ANNOTS_IMPORT, @annots_import ],
218
+ [ Origami::UsageRights::Rights::ANNOTS_EXPORT, @annots_export ],
219
+ [ Origami::UsageRights::Rights::ANNOTS_ONLINE, @annots_online ],
220
+ [ Origami::UsageRights::Rights::ANNOTS_SUMMARYVIEW, @annots_sumview ],
221
+
222
+ [ Origami::UsageRights::Rights::FORM_FILLIN, @form_fillin ],
223
+ [ Origami::UsageRights::Rights::FORM_IMPORT, @form_import ],
224
+ [ Origami::UsageRights::Rights::FORM_EXPORT, @form_export ],
225
+ [ Origami::UsageRights::Rights::FORM_SUBMITSTANDALONE, @form_submit ],
226
+ [ Origami::UsageRights::Rights::FORM_SPAWNTEMPLATE, @form_spawntemplate ],
227
+ [ Origami::UsageRights::Rights::FORM_BARCODEPLAINTEXT, @form_barcode ],
228
+ [ Origami::UsageRights::Rights::FORM_ONLINE, @form_online ],
229
+
230
+ [ Origami::UsageRights::Rights::SIGNATURE_MODIFY, @signature_modify ],
231
+
232
+ [ Origami::UsageRights::Rights::EF_CREATE, @ef_create ],
233
+ [ Origami::UsageRights::Rights::EF_DELETE, @ef_delete ],
234
+ [ Origami::UsageRights::Rights::EF_MODIFY, @ef_modify ],
235
+ [ Origami::UsageRights::Rights::EF_IMPORT, @ef_import ],
236
+ ].select { |_, button| button.active? }
237
+ .map { |right, _| right }
238
+ end
239
+
240
+ def create_intro_page
241
+ intro = <<-INTRO.gsub(/^\s+/, '')
242
+ You are about to enable Usage Rights for the current PDF document.
243
+ To enable these features, you need to have an Adobe public/private key pair in your possession.
244
+
245
+ Make sure you have adobe.crt and adobe.key located in the current directory.
246
+ INTRO
247
+
248
+ vbox = VBox.new(false, 5)
249
+ vbox.set_border_width(5)
250
+
251
+ lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
252
+
253
+ vbox.pack_start(lbl, true, true, 0)
254
+
255
+ append_page(vbox)
256
+ set_page_title(vbox, "Usage Rights Wizard")
257
+ set_page_type(vbox, Assistant::PAGE_INTRO)
258
+ set_page_complete(vbox, true)
259
+ end
260
+
261
+ def create_rights_frame(name)
262
+ frame = Frame.new(name)
263
+ frame.border_width = 5
264
+ frame.shadow_type = Gtk::SHADOW_IN
265
+
266
+ frame
267
+ end
268
+
269
+ def create_document_rights_frame
270
+ frame = create_rights_frame(" Document ")
271
+
272
+ @document_fullsave = CheckButton.new("Full Save").set_active(true)
273
+
274
+ doc_table = Table.new(1, 2)
275
+ doc_table.attach(@document_fullsave, 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
276
+ frame.add(doc_table)
277
+ end
278
+
279
+ def create_annotations_rights_frame
280
+ frame = create_rights_frame(" Annotations ")
281
+
282
+ annots_table = Table.new(4, 2)
283
+ annots =
284
+ [
285
+ [ @annots_create = CheckButton.new("Create"), @annots_import = CheckButton.new("Import") ],
286
+ [ @annots_delete = CheckButton.new("Delete"), @annots_export = CheckButton.new("Export") ],
287
+ [ @annots_modify = CheckButton.new("Modify"), @annots_online = CheckButton.new("Online") ],
288
+ [ @annots_copy = CheckButton.new("Copy"), @annots_sumview = CheckButton.new("Summary View") ]
289
+ ]
290
+
291
+ annots.each_with_index do |cols, row|
292
+ col1, col2 = cols
293
+
294
+ col1.active = true
295
+ col2.active = true
296
+
297
+ annots_table.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
298
+ annots_table.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
299
+ end
300
+
301
+ frame.add(annots_table)
302
+ end
303
+
304
+ def create_form_rights_frame
305
+ frame = create_rights_frame(" Forms ")
306
+
307
+ form_table = Table.new(4, 2)
308
+ forms =
309
+ [
310
+ [ @form_fillin = CheckButton.new("Fill in"), @form_spawntemplate = CheckButton.new("Spawn template") ],
311
+ [ @form_import = CheckButton.new("Import"), @form_barcode = CheckButton.new("Barcode plaintext") ],
312
+ [ @form_export = CheckButton.new("Export"), @form_online = CheckButton.new("Online") ],
313
+ [ @form_submit = CheckButton.new("Submit stand-alone"), nil ]
314
+ ]
315
+
316
+ forms.each_with_index do |cols, row|
317
+ col1, col2 = cols
318
+
319
+ col1.active = true
320
+ col2.active = true unless col2.nil?
321
+
322
+ form_table.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
323
+ form_table.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4) unless col2.nil?
324
+ end
325
+
326
+ frame.add(form_table)
327
+ end
328
+
329
+ def create_signature_rights_frame
330
+ frame = create_rights_frame(" Signature ")
331
+
332
+ @signature_modify = CheckButton.new("Modify").set_active(true)
333
+
334
+ signature_table = Table.new(1, 2)
335
+ signature_table.attach(@signature_modify, 0, 1, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
336
+ frame.add(signature_table)
337
+ end
338
+
339
+ def create_embedded_files_rights_frame
340
+ frame = create_rights_frame(" Embedded files ")
341
+
342
+ ef_table = Table.new(2,2)
343
+ ef_buttons =
344
+ [
345
+ [ @ef_create = CheckButton.new("Create"), @ef_modify = CheckButton.new("Modify") ],
346
+ [ @ef_delete = CheckButton.new("Delete"), @ef_import = CheckButton.new("Import") ]
347
+ ]
348
+
349
+ ef_buttons.each_with_index do |cols, row|
350
+ col1, col2 = cols
351
+
352
+ col1.active = true
353
+ col2.active = true
354
+
355
+ ef_table.attach(col1, 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
356
+ ef_table.attach(col2, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
357
+ end
358
+
359
+ frame.add(ef_table)
360
+ end
361
+
362
+ def create_rights_selection_page
363
+ vbox = VBox.new(false, 5)
364
+
365
+ vbox.add create_document_rights_frame
366
+ vbox.add create_annotations_rights_frame
367
+ vbox.add create_form_rights_frame
368
+ vbox.add create_signature_rights_frame
369
+ vbox.add create_embedded_files_rights_frame
370
+
371
+ append_page(vbox)
372
+ set_page_title(vbox, "Select Usage Rights to enable")
373
+ set_page_type(vbox, Assistant::PAGE_CONFIRM)
374
+ set_page_complete(vbox, true)
375
+ end
376
+
377
+ def create_termination_page
378
+ @lastpage = VBox.new(false, 5)
379
+
380
+ @msg_status = Label.new
381
+ @lastpage.pack_start(@msg_status, true, true, 0)
382
+
383
+ append_page(@lastpage)
384
+ set_page_title(@lastpage, "Usage Rights have not been enabled")
385
+ set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
386
+ end
387
+ end
388
+
389
+ class SignWizard < Assistant
390
+ include SignatureDialogs
391
+
392
+ INTRO_PAGE = 0
393
+ KEY_SELECT_PAGE = 1
394
+ PKCS12_IMPORT_PAGE = 2
395
+ KEYPAIR_IMPORT_PAGE = 3
396
+ SIGNATURE_INFO_PAGE = 4
397
+ SIGNATURE_RESULT_PAGE = 5
398
+
399
+ def initialize(parent, pdf)
400
+ super()
401
+
402
+ @parent = parent
403
+
404
+ @pkey, @cert, @ca = nil, nil, []
405
+
406
+ create_intro_page
407
+ create_key_selection_page
408
+ create_pkcs12_import_page
409
+ create_keypair_import_page
410
+ create_signature_info_page
411
+ create_termination_page
412
+
413
+ set_forward_page_func { |current_page|
414
+ case current_page
415
+ when KEY_SELECT_PAGE
416
+ if @p12button.active? then PKCS12_IMPORT_PAGE else KEYPAIR_IMPORT_PAGE end
417
+
418
+ when PKCS12_IMPORT_PAGE, KEYPAIR_IMPORT_PAGE
419
+ SIGNATURE_INFO_PAGE
420
+
421
+ else current_page.succ
422
+ end
423
+ }
424
+
425
+ signal_connect('delete_event') { self.destroy }
426
+ signal_connect('cancel') { self.destroy }
427
+ signal_connect('close') { self.destroy }
428
+
429
+ signal_connect('apply') {
430
+ location = @location.text.empty? ? nil : @location.text
431
+ contact = @email.text.empty? ? nil : @email.text
432
+ reason = @reason.text.empty? ? nil : @reason.text
433
+
434
+ begin
435
+ pdf.sign(@cert, @pkey,
436
+ ca: @ca,
437
+ location: location,
438
+ contact: contact,
439
+ reason: reason)
440
+
441
+ set_page_title(@lastpage, "Document has been signed")
442
+ @msg_status.text = "The document has been signed.\n You should consider saving it now."
443
+
444
+ @parent.reload
445
+ rescue
446
+ @parent.error("#{$!}: #{$!.backtrace.join($/)}")
447
+
448
+ set_page_title(@lastpage, "Document has not been signed")
449
+ @msg_status.text = "An error occured during the signature process."
450
+ end
451
+ }
452
+
453
+ set_modal(true)
454
+
455
+ show_all
456
+ end
457
+
458
+ private
459
+
460
+ def create_intro_page
461
+ intro = <<-INTRO.gsub(/^\s+/, '')
462
+ You are about to sign the current PDF document.
463
+ Once the document will be signed, no further modification will be allowed.
464
+
465
+ The signature process is based on assymetric cryptography, so you will basically need a public/private RSA key pair (between 1024 and 4096 bits).
466
+ INTRO
467
+
468
+ vbox = VBox.new(false, 5)
469
+ vbox.set_border_width(5)
470
+
471
+ lbl = Label.new(intro).set_justify(Gtk::JUSTIFY_LEFT).set_wrap(true)
472
+
473
+ vbox.pack_start(lbl, true, true, 0)
474
+
475
+ append_page(vbox)
476
+ set_page_title(vbox, "Signature Wizard")
477
+ set_page_type(vbox, Assistant::PAGE_INTRO)
478
+ set_page_complete(vbox, true)
479
+ end
480
+
481
+ def create_key_selection_page
482
+ vbox = VBox.new(false, 5)
483
+
484
+ @rawbutton = RadioButton.new("Import keys from separate PEM/DER encoded files")
485
+ @p12button = RadioButton.new(@rawbutton, "Import keys from a PKCS12 container")
486
+
487
+ vbox.pack_start(@rawbutton, true, true, 0)
488
+ vbox.pack_start(@p12button, true, true, 0)
489
+
490
+ append_page(vbox)
491
+ set_page_title(vbox, "Choose a key importation method")
492
+ set_page_type(vbox, Assistant::PAGE_CONTENT)
493
+ set_page_complete(vbox, true)
494
+ end
495
+
496
+ def create_pkcs12_import_page
497
+ vbox = VBox.new(false, 5)
498
+
499
+ hbox = HBox.new(false, 5)
500
+ vbox.pack_start(hbox, true, false, 10)
501
+
502
+ @p12filename = Entry.new.set_editable(false).set_sensitive(false)
503
+ choosebtn = Button.new(Gtk::Stock::OPEN)
504
+
505
+ choosebtn.signal_connect('clicked') { open_pkcs12_file_dialog(vbox) }
506
+
507
+ hbox.pack_start(@p12filename, true, true, 5)
508
+ hbox.pack_start(choosebtn, false, false, 5)
509
+
510
+ append_page(vbox)
511
+ set_page_title(vbox, "Import a PKCS12 container")
512
+ set_page_type(vbox, Assistant::PAGE_CONTENT)
513
+ end
514
+
515
+ def create_signature_info_page
516
+ vbox = VBox.new(false, 5)
517
+
518
+ lbl = Label.new("Here are a few optional information you can add with your signature.")
519
+ vbox.pack_start(lbl, true, true, 0)
520
+
521
+ labels =
522
+ [
523
+ [ "Location:", @location = Entry.new ],
524
+ [ "Contact:", @email = Entry.new ],
525
+ [ "Reason:", @reason = Entry.new ]
526
+ ]
527
+
528
+ row = 0
529
+ table = Table.new(4, 3)
530
+ labels.each do |label|
531
+ table.attach(Label.new(label[0]).set_alignment(1,0), 0, 1, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
532
+ table.attach(label[1], 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 4, 4)
533
+
534
+ row = row.succ
535
+ end
536
+
537
+ vbox.pack_start(table, true, true, 0)
538
+
539
+ append_page(vbox)
540
+ set_page_title(vbox, "Fill in signature details")
541
+ set_page_type(vbox, Assistant::PAGE_CONFIRM)
542
+ set_page_complete(vbox, true)
543
+ end
544
+
545
+ def create_termination_page
546
+ @lastpage = VBox.new(false, 5)
547
+
548
+ @msg_status = Label.new
549
+ @lastpage.pack_start(@msg_status, true, true, 0)
550
+
551
+ append_page(@lastpage)
552
+ set_page_title(@lastpage, "Document has not been signed")
553
+ set_page_type(@lastpage, Assistant::PAGE_SUMMARY)
554
+ end
555
+ end
556
+ end
557
+
558
+ end