origami 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +6 -5
- data/bin/pdf2pdfa +1 -1
- data/bin/pdfcop +5 -5
- data/bin/pdfsh +1 -1
- data/bin/shell/{.irbrc → irbrc} +0 -0
- data/lib/origami/array.rb +12 -3
- data/lib/origami/dictionary.rb +0 -2
- data/lib/origami/encryption.rb +77 -77
- data/lib/origami/filters.rb +0 -2
- data/lib/origami/filters/ccitt.rb +41 -33
- data/lib/origami/filters/lzw.rb +12 -13
- data/lib/origami/graphics/patterns.rb +3 -1
- data/lib/origami/graphics/render.rb +1 -0
- data/lib/origami/graphics/xobject.rb +2 -2
- data/lib/origami/signature.rb +68 -118
- data/lib/origami/stream.rb +0 -2
- data/lib/origami/version.rb +1 -1
- data/test/test_streams.rb +7 -5
- metadata +4 -21
- data/bin/gui/COPYING +0 -674
- data/bin/gui/about.rb +0 -36
- data/bin/gui/config.rb +0 -120
- data/bin/gui/file.rb +0 -314
- data/bin/gui/gtkhex.rb +0 -1326
- data/bin/gui/hexview.rb +0 -84
- data/bin/gui/imgview.rb +0 -69
- data/bin/gui/menu.rb +0 -382
- data/bin/gui/properties.rb +0 -126
- data/bin/gui/signing.rb +0 -558
- data/bin/gui/textview.rb +0 -88
- data/bin/gui/treeview.rb +0 -416
- data/bin/gui/walker.rb +0 -308
- data/bin/gui/xrefs.rb +0 -75
- data/bin/pdfwalker +0 -6
data/bin/gui/properties.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
|
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/>.
|
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
|
data/bin/gui/signing.rb
DELETED
@@ -1,558 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
|
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/>.
|
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
|