1 | /* poppler-form.h: qt interface to poppler |
2 | * Copyright (C) 2007-2008, 2011, Pino Toscano <pino@kde.org> |
3 | * Copyright (C) 2008, 2011, 2012, 2015-2023 Albert Astals Cid <aacid@kde.org> |
4 | * Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org> |
5 | * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com> |
6 | * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de> |
7 | * Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de> |
8 | * Copyright (C) 2018, Andre Heinecke <aheinecke@intevation.de> |
9 | * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich |
10 | * Copyright (C) 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com> |
11 | * Copyright (C) 2018, 2020, 2021 Oliver Sander <oliver.sander@tu-dresden.de> |
12 | * Copyright (C) 2019 João Netto <joaonetto901@gmail.com> |
13 | * Copyright (C) 2020 David García Garzón <voki@canvoki.net> |
14 | * Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens@CIB.de> |
15 | * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden |
16 | * Copyright (C) 2021 Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net. |
17 | * Copyright (C) 2021 Theofilos Intzoglou <int.teo@gmail.com> |
18 | * Copyright (C) 2022 Alexander Sulfrian <asulfrian@zedat.fu-berlin.de> |
19 | * Copyright (C) 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk> |
20 | * |
21 | * This program is free software; you can redistribute it and/or modify |
22 | * it under the terms of the GNU General Public License as published by |
23 | * the Free Software Foundation; either version 2, or (at your option) |
24 | * any later version. |
25 | * |
26 | * This program is distributed in the hope that it will be useful, |
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
29 | * GNU General Public License for more details. |
30 | * |
31 | * You should have received a copy of the GNU General Public License |
32 | * along with this program; if not, write to the Free Software |
33 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
34 | */ |
35 | |
36 | #include "poppler-form.h" |
37 | |
38 | #include <config.h> |
39 | |
40 | #include <QtCore/QSizeF> |
41 | #include <QUrl> |
42 | |
43 | #include <Form.h> |
44 | #include <Object.h> |
45 | #include <Link.h> |
46 | #include <SignatureInfo.h> |
47 | #include <CertificateInfo.h> |
48 | #include <CryptoSignBackend.h> |
49 | #ifdef ENABLE_NSS3 |
50 | # include <NSSCryptoSignBackend.h> |
51 | #endif |
52 | |
53 | #include "poppler-page-private.h" |
54 | #include "poppler-private.h" |
55 | #include "poppler-annotation-helper.h" |
56 | |
57 | #include <cmath> |
58 | #include <cctype> |
59 | |
60 | namespace { |
61 | |
62 | Qt::Alignment formTextAlignment(::FormWidget *fm) |
63 | { |
64 | Qt::Alignment qtalign = Qt::AlignLeft; |
65 | switch (fm->getField()->getTextQuadding()) { |
66 | case VariableTextQuadding::centered: |
67 | qtalign = Qt::AlignHCenter; |
68 | break; |
69 | case VariableTextQuadding::rightJustified: |
70 | qtalign = Qt::AlignRight; |
71 | break; |
72 | case VariableTextQuadding::leftJustified: |
73 | qtalign = Qt::AlignLeft; |
74 | } |
75 | return qtalign; |
76 | } |
77 | |
78 | } |
79 | |
80 | namespace Poppler { |
81 | |
82 | FormFieldIcon::FormFieldIcon(FormFieldIconData *data) : d_ptr(data) { } |
83 | |
84 | FormFieldIcon::FormFieldIcon(const FormFieldIcon &ffIcon) |
85 | { |
86 | d_ptr = new FormFieldIconData; |
87 | d_ptr->icon = ffIcon.d_ptr->icon; |
88 | } |
89 | |
90 | FormFieldIcon &FormFieldIcon::operator=(const FormFieldIcon &ffIcon) |
91 | { |
92 | if (this != &ffIcon) { |
93 | delete d_ptr; |
94 | d_ptr = nullptr; |
95 | |
96 | d_ptr = new FormFieldIconData; |
97 | *d_ptr = *ffIcon.d_ptr; |
98 | } |
99 | |
100 | return *this; |
101 | } |
102 | |
103 | FormFieldIcon::~FormFieldIcon() |
104 | { |
105 | delete d_ptr; |
106 | } |
107 | |
108 | FormField::FormField(std::unique_ptr<FormFieldData> dd) : m_formData(std::move(dd)) |
109 | { |
110 | if (m_formData->page) { |
111 | const int rotation = m_formData->page->getRotate(); |
112 | // reading the coords |
113 | double left, top, right, bottom; |
114 | m_formData->fm->getRect(x1: &left, y1: &bottom, x2: &right, y2: &top); |
115 | // build a normalized transform matrix for this page at 100% scale |
116 | GfxState gfxState(72.0, 72.0, m_formData->page->getCropBox(), rotation, true); |
117 | const double *gfxCTM = gfxState.getCTM(); |
118 | double MTX[6]; |
119 | double pageWidth = m_formData->page->getCropWidth(); |
120 | double pageHeight = m_formData->page->getCropHeight(); |
121 | // landscape and seascape page rotation: be sure to use the correct (== rotated) page size |
122 | if (((rotation / 90) % 2) == 1) { |
123 | qSwap(value1&: pageWidth, value2&: pageHeight); |
124 | } |
125 | for (int i = 0; i < 6; i += 2) { |
126 | MTX[i] = gfxCTM[i] / pageWidth; |
127 | MTX[i + 1] = gfxCTM[i + 1] / pageHeight; |
128 | } |
129 | QPointF topLeft; |
130 | XPDFReader::transform(M: MTX, x: qMin(a: left, b: right), y: qMax(a: top, b: bottom), res&: topLeft); |
131 | QPointF bottomRight; |
132 | XPDFReader::transform(M: MTX, x: qMax(a: left, b: right), y: qMin(a: top, b: bottom), res&: bottomRight); |
133 | m_formData->box = QRectF(topLeft, QSizeF(bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y())); |
134 | } |
135 | } |
136 | |
137 | FormField::~FormField() = default; |
138 | |
139 | QRectF FormField::rect() const |
140 | { |
141 | return m_formData->box; |
142 | } |
143 | |
144 | int FormField::id() const |
145 | { |
146 | return m_formData->fm->getID(); |
147 | } |
148 | |
149 | QString FormField::name() const |
150 | { |
151 | QString name; |
152 | if (const GooString *goo = m_formData->fm->getPartialName()) { |
153 | name = UnicodeParsedString(s1: goo); |
154 | } |
155 | return name; |
156 | } |
157 | |
158 | void FormField::setName(const QString &name) const |
159 | { |
160 | GooString *goo = QStringToGooString(s: name); |
161 | m_formData->fm->setPartialName(*goo); |
162 | delete goo; |
163 | } |
164 | |
165 | QString FormField::fullyQualifiedName() const |
166 | { |
167 | QString name; |
168 | if (GooString *goo = m_formData->fm->getFullyQualifiedName()) { |
169 | name = UnicodeParsedString(s1: goo); |
170 | } |
171 | return name; |
172 | } |
173 | |
174 | QString FormField::uiName() const |
175 | { |
176 | QString name; |
177 | if (const GooString *goo = m_formData->fm->getAlternateUiName()) { |
178 | name = UnicodeParsedString(s1: goo); |
179 | } |
180 | return name; |
181 | } |
182 | |
183 | bool FormField::isReadOnly() const |
184 | { |
185 | return m_formData->fm->isReadOnly(); |
186 | } |
187 | |
188 | void FormField::setReadOnly(bool value) |
189 | { |
190 | m_formData->fm->setReadOnly(value); |
191 | } |
192 | |
193 | bool FormField::isVisible() const |
194 | { |
195 | const unsigned int flags = m_formData->fm->getWidgetAnnotation()->getFlags(); |
196 | if (flags & Annot::flagHidden) { |
197 | return false; |
198 | } |
199 | if (flags & Annot::flagNoView) { |
200 | return false; |
201 | } |
202 | return true; |
203 | } |
204 | |
205 | void FormField::setVisible(bool value) |
206 | { |
207 | unsigned int flags = m_formData->fm->getWidgetAnnotation()->getFlags(); |
208 | if (value) { |
209 | flags &= ~Annot::flagHidden; |
210 | flags &= ~Annot::flagNoView; |
211 | } else { |
212 | flags |= Annot::flagHidden; |
213 | } |
214 | m_formData->fm->getWidgetAnnotation()->setFlags(flags); |
215 | } |
216 | |
217 | bool FormField::isPrintable() const |
218 | { |
219 | return (m_formData->fm->getWidgetAnnotation()->getFlags() & Annot::flagPrint); |
220 | } |
221 | |
222 | void FormField::setPrintable(bool value) |
223 | { |
224 | unsigned int flags = m_formData->fm->getWidgetAnnotation()->getFlags(); |
225 | if (value) { |
226 | flags |= Annot::flagPrint; |
227 | } else { |
228 | flags &= ~Annot::flagPrint; |
229 | } |
230 | m_formData->fm->getWidgetAnnotation()->setFlags(flags); |
231 | } |
232 | |
233 | std::unique_ptr<Link> FormField::activationAction() const |
234 | { |
235 | if (::LinkAction *act = m_formData->fm->getActivationAction()) { |
236 | return PageData::convertLinkActionToLink(a: act, parentDoc: m_formData->doc, linkArea: QRectF()); |
237 | } |
238 | |
239 | return {}; |
240 | } |
241 | |
242 | std::unique_ptr<Link> FormField::additionalAction(AdditionalActionType type) const |
243 | { |
244 | Annot::FormAdditionalActionsType actionType = Annot::actionFieldModified; |
245 | switch (type) { |
246 | case FieldModified: |
247 | actionType = Annot::actionFieldModified; |
248 | break; |
249 | case FormatField: |
250 | actionType = Annot::actionFormatField; |
251 | break; |
252 | case ValidateField: |
253 | actionType = Annot::actionValidateField; |
254 | break; |
255 | case CalculateField: |
256 | actionType = Annot::actionCalculateField; |
257 | break; |
258 | } |
259 | |
260 | if (std::unique_ptr<::LinkAction> act = m_formData->fm->getAdditionalAction(type: actionType)) { |
261 | return PageData::convertLinkActionToLink(a: act.get(), parentDoc: m_formData->doc, linkArea: QRectF()); |
262 | } |
263 | |
264 | return {}; |
265 | } |
266 | |
267 | std::unique_ptr<Link> FormField::additionalAction(Annotation::AdditionalActionType type) const |
268 | { |
269 | ::AnnotWidget *w = m_formData->fm->getWidgetAnnotation(); |
270 | if (!w) { |
271 | return {}; |
272 | } |
273 | |
274 | const Annot::AdditionalActionsType actionType = toPopplerAdditionalActionType(type); |
275 | |
276 | if (std::unique_ptr<::LinkAction> act = w->getAdditionalAction(type: actionType)) { |
277 | return PageData::convertLinkActionToLink(a: act.get(), parentDoc: m_formData->doc, linkArea: QRectF()); |
278 | } |
279 | |
280 | return {}; |
281 | } |
282 | |
283 | FormFieldButton::FormFieldButton(DocumentData *doc, ::Page *p, ::FormWidgetButton *w) : FormField(std::make_unique<FormFieldData>(args&: doc, args&: p, args&: w)) { } |
284 | |
285 | FormFieldButton::~FormFieldButton() { } |
286 | |
287 | FormFieldButton::FormType FormFieldButton::type() const |
288 | { |
289 | return FormField::FormButton; |
290 | } |
291 | |
292 | FormFieldButton::ButtonType FormFieldButton::buttonType() const |
293 | { |
294 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
295 | switch (fwb->getButtonType()) { |
296 | case formButtonCheck: |
297 | return FormFieldButton::CheckBox; |
298 | break; |
299 | case formButtonPush: |
300 | return FormFieldButton::Push; |
301 | break; |
302 | case formButtonRadio: |
303 | return FormFieldButton::Radio; |
304 | break; |
305 | } |
306 | return FormFieldButton::CheckBox; |
307 | } |
308 | |
309 | QString FormFieldButton::caption() const |
310 | { |
311 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
312 | QString ret; |
313 | if (fwb->getButtonType() == formButtonPush) { |
314 | Dict *dict = m_formData->fm->getObj()->getDict(); |
315 | Object obj1 = dict->lookup(key: "MK" ); |
316 | if (obj1.isDict()) { |
317 | AnnotAppearanceCharacs appearCharacs(obj1.getDict()); |
318 | if (appearCharacs.getNormalCaption()) { |
319 | ret = UnicodeParsedString(s1: appearCharacs.getNormalCaption()); |
320 | } |
321 | } |
322 | } else { |
323 | if (const char *goo = fwb->getOnStr()) { |
324 | ret = QString::fromUtf8(utf8: goo); |
325 | } |
326 | } |
327 | return ret; |
328 | } |
329 | |
330 | FormFieldIcon FormFieldButton::icon() const |
331 | { |
332 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
333 | if (fwb->getButtonType() == formButtonPush) { |
334 | Dict *dict = m_formData->fm->getObj()->getDict(); |
335 | FormFieldIconData *data = new FormFieldIconData; |
336 | data->icon = dict; |
337 | return FormFieldIcon(data); |
338 | } |
339 | return FormFieldIcon(nullptr); |
340 | } |
341 | |
342 | void FormFieldButton::setIcon(const FormFieldIcon &icon) |
343 | { |
344 | if (FormFieldIconData::getData(f: icon) == nullptr) { |
345 | return; |
346 | } |
347 | |
348 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
349 | if (fwb->getButtonType() == formButtonPush) { |
350 | ::AnnotWidget *w = m_formData->fm->getWidgetAnnotation(); |
351 | FormFieldIconData *data = FormFieldIconData::getData(f: icon); |
352 | if (data->icon != nullptr) { |
353 | w->setNewAppearance(data->icon->lookup(key: "AP" )); |
354 | } |
355 | } |
356 | } |
357 | |
358 | bool FormFieldButton::state() const |
359 | { |
360 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
361 | return fwb->getState(); |
362 | } |
363 | |
364 | void FormFieldButton::setState(bool state) |
365 | { |
366 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
367 | fwb->setState((bool)state); |
368 | } |
369 | |
370 | QList<int> FormFieldButton::siblings() const |
371 | { |
372 | FormWidgetButton *fwb = static_cast<FormWidgetButton *>(m_formData->fm); |
373 | ::FormFieldButton *ffb = static_cast<::FormFieldButton *>(fwb->getField()); |
374 | if (fwb->getButtonType() == formButtonPush) { |
375 | return QList<int>(); |
376 | } |
377 | |
378 | QList<int> ret; |
379 | for (int i = 0; i < ffb->getNumSiblings(); ++i) { |
380 | ::FormFieldButton *sibling = static_cast<::FormFieldButton *>(ffb->getSibling(i)); |
381 | for (int j = 0; j < sibling->getNumWidgets(); ++j) { |
382 | FormWidget *w = sibling->getWidget(i: j); |
383 | if (w) { |
384 | ret.append(t: w->getID()); |
385 | } |
386 | } |
387 | } |
388 | |
389 | return ret; |
390 | } |
391 | |
392 | FormFieldText::FormFieldText(DocumentData *doc, ::Page *p, ::FormWidgetText *w) : FormField(std::make_unique<FormFieldData>(args&: doc, args&: p, args&: w)) { } |
393 | |
394 | FormFieldText::~FormFieldText() { } |
395 | |
396 | FormField::FormType FormFieldText::type() const |
397 | { |
398 | return FormField::FormText; |
399 | } |
400 | |
401 | FormFieldText::TextType FormFieldText::textType() const |
402 | { |
403 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
404 | if (fwt->isFileSelect()) { |
405 | return FormFieldText::FileSelect; |
406 | } else if (fwt->isMultiline()) { |
407 | return FormFieldText::Multiline; |
408 | } |
409 | return FormFieldText::Normal; |
410 | } |
411 | |
412 | QString FormFieldText::text() const |
413 | { |
414 | const GooString *goo = static_cast<FormWidgetText *>(m_formData->fm)->getContent(); |
415 | return UnicodeParsedString(s1: goo); |
416 | } |
417 | |
418 | void FormFieldText::setText(const QString &text) |
419 | { |
420 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
421 | GooString *goo = QStringToUnicodeGooString(s: text); |
422 | fwt->setContent(goo); |
423 | delete goo; |
424 | } |
425 | |
426 | void FormFieldText::setAppearanceText(const QString &text) |
427 | { |
428 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
429 | GooString *goo = QStringToUnicodeGooString(s: text); |
430 | fwt->setAppearanceContent(goo); |
431 | delete goo; |
432 | } |
433 | |
434 | bool FormFieldText::isPassword() const |
435 | { |
436 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
437 | return fwt->isPassword(); |
438 | } |
439 | |
440 | bool FormFieldText::isRichText() const |
441 | { |
442 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
443 | return fwt->isRichText(); |
444 | } |
445 | |
446 | int FormFieldText::maximumLength() const |
447 | { |
448 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
449 | const int maxlen = fwt->getMaxLen(); |
450 | return maxlen > 0 ? maxlen : -1; |
451 | } |
452 | |
453 | Qt::Alignment FormFieldText::textAlignment() const |
454 | { |
455 | return formTextAlignment(fm: m_formData->fm); |
456 | } |
457 | |
458 | bool FormFieldText::canBeSpellChecked() const |
459 | { |
460 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
461 | return !fwt->noSpellCheck(); |
462 | } |
463 | |
464 | double FormFieldText::getFontSize() const |
465 | { |
466 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
467 | return fwt->getTextFontSize(); |
468 | } |
469 | |
470 | void FormFieldText::setFontSize(int fontSize) |
471 | { |
472 | FormWidgetText *fwt = static_cast<FormWidgetText *>(m_formData->fm); |
473 | fwt->setTextFontSize(fontSize); |
474 | } |
475 | |
476 | FormFieldChoice::FormFieldChoice(DocumentData *doc, ::Page *p, ::FormWidgetChoice *w) : FormField(std::make_unique<FormFieldData>(args&: doc, args&: p, args&: w)) { } |
477 | |
478 | FormFieldChoice::~FormFieldChoice() { } |
479 | |
480 | FormFieldChoice::FormType FormFieldChoice::type() const |
481 | { |
482 | return FormField::FormChoice; |
483 | } |
484 | |
485 | FormFieldChoice::ChoiceType FormFieldChoice::choiceType() const |
486 | { |
487 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
488 | if (fwc->isCombo()) { |
489 | return FormFieldChoice::ComboBox; |
490 | } |
491 | return FormFieldChoice::ListBox; |
492 | } |
493 | |
494 | QStringList FormFieldChoice::choices() const |
495 | { |
496 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
497 | QStringList ret; |
498 | int num = fwc->getNumChoices(); |
499 | ret.reserve(asize: num); |
500 | for (int i = 0; i < num; ++i) { |
501 | ret.append(t: UnicodeParsedString(s1: fwc->getChoice(i))); |
502 | } |
503 | return ret; |
504 | } |
505 | |
506 | QVector<QPair<QString, QString>> FormFieldChoice::choicesWithExportValues() const |
507 | { |
508 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
509 | QVector<QPair<QString, QString>> ret; |
510 | const int num = fwc->getNumChoices(); |
511 | ret.reserve(asize: num); |
512 | for (int i = 0; i < num; ++i) { |
513 | const QString display = UnicodeParsedString(s1: fwc->getChoice(i)); |
514 | const GooString *exportValueG = fwc->getExportVal(i); |
515 | const QString exportValue = exportValueG ? UnicodeParsedString(s1: exportValueG) : display; |
516 | ret.append(t: { display, exportValue }); |
517 | } |
518 | return ret; |
519 | } |
520 | |
521 | bool FormFieldChoice::isEditable() const |
522 | { |
523 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
524 | return fwc->isCombo() ? fwc->hasEdit() : false; |
525 | } |
526 | |
527 | bool FormFieldChoice::multiSelect() const |
528 | { |
529 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
530 | return !fwc->isCombo() ? fwc->isMultiSelect() : false; |
531 | } |
532 | |
533 | QList<int> FormFieldChoice::currentChoices() const |
534 | { |
535 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
536 | int num = fwc->getNumChoices(); |
537 | QList<int> choices; |
538 | for (int i = 0; i < num; ++i) { |
539 | if (fwc->isSelected(i)) { |
540 | choices.append(t: i); |
541 | } |
542 | } |
543 | return choices; |
544 | } |
545 | |
546 | void FormFieldChoice::setCurrentChoices(const QList<int> &choice) |
547 | { |
548 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
549 | fwc->deselectAll(); |
550 | for (int i = 0; i < choice.count(); ++i) { |
551 | fwc->select(i: choice.at(i)); |
552 | } |
553 | } |
554 | |
555 | QString FormFieldChoice::editChoice() const |
556 | { |
557 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
558 | |
559 | if (fwc->isCombo() && fwc->hasEdit()) { |
560 | return UnicodeParsedString(s1: fwc->getEditChoice()); |
561 | } else { |
562 | return QString(); |
563 | } |
564 | } |
565 | |
566 | void FormFieldChoice::setEditChoice(const QString &text) |
567 | { |
568 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
569 | |
570 | if (fwc->isCombo() && fwc->hasEdit()) { |
571 | GooString *goo = QStringToUnicodeGooString(s: text); |
572 | fwc->setEditChoice(goo); |
573 | delete goo; |
574 | } |
575 | } |
576 | |
577 | Qt::Alignment FormFieldChoice::textAlignment() const |
578 | { |
579 | return formTextAlignment(fm: m_formData->fm); |
580 | } |
581 | |
582 | bool FormFieldChoice::canBeSpellChecked() const |
583 | { |
584 | FormWidgetChoice *fwc = static_cast<FormWidgetChoice *>(m_formData->fm); |
585 | return !fwc->noSpellCheck(); |
586 | } |
587 | |
588 | class CertificateInfoPrivate |
589 | { |
590 | public: |
591 | struct EntityInfo |
592 | { |
593 | QString common_name; |
594 | QString email_address; |
595 | QString org_name; |
596 | QString distinguished_name; |
597 | }; |
598 | |
599 | EntityInfo issuer_info; |
600 | EntityInfo subject_info; |
601 | QString nick_name; |
602 | QByteArray certificate_der; |
603 | QByteArray serial_number; |
604 | QByteArray public_key; |
605 | QDateTime validity_start; |
606 | QDateTime validity_end; |
607 | int public_key_type; |
608 | int public_key_strength; |
609 | int ku_extensions; |
610 | int version; |
611 | bool is_self_signed; |
612 | bool is_null; |
613 | CertificateInfo::KeyLocation keyLocation; |
614 | }; |
615 | |
616 | CertificateInfo::CertificateInfo() : d_ptr(new CertificateInfoPrivate()) |
617 | { |
618 | d_ptr->is_null = true; |
619 | } |
620 | |
621 | CertificateInfo::CertificateInfo(CertificateInfoPrivate *priv) : d_ptr(priv) { } |
622 | |
623 | CertificateInfo::CertificateInfo(const CertificateInfo &other) : d_ptr(other.d_ptr) { } |
624 | |
625 | CertificateInfo::~CertificateInfo() = default; |
626 | |
627 | CertificateInfo &CertificateInfo::operator=(const CertificateInfo &other) |
628 | { |
629 | if (this != &other) { |
630 | d_ptr = other.d_ptr; |
631 | } |
632 | |
633 | return *this; |
634 | } |
635 | |
636 | bool CertificateInfo::isNull() const |
637 | { |
638 | Q_D(const CertificateInfo); |
639 | return d->is_null; |
640 | } |
641 | |
642 | int CertificateInfo::version() const |
643 | { |
644 | Q_D(const CertificateInfo); |
645 | return d->version; |
646 | } |
647 | |
648 | QByteArray CertificateInfo::serialNumber() const |
649 | { |
650 | Q_D(const CertificateInfo); |
651 | return d->serial_number; |
652 | } |
653 | |
654 | QString CertificateInfo::issuerInfo(EntityInfoKey key) const |
655 | { |
656 | Q_D(const CertificateInfo); |
657 | switch (key) { |
658 | case CommonName: |
659 | return d->issuer_info.common_name; |
660 | case DistinguishedName: |
661 | return d->issuer_info.distinguished_name; |
662 | case EmailAddress: |
663 | return d->issuer_info.email_address; |
664 | case Organization: |
665 | return d->issuer_info.org_name; |
666 | default: |
667 | return QString(); |
668 | } |
669 | } |
670 | |
671 | QString CertificateInfo::subjectInfo(EntityInfoKey key) const |
672 | { |
673 | Q_D(const CertificateInfo); |
674 | switch (key) { |
675 | case CommonName: |
676 | return d->subject_info.common_name; |
677 | case DistinguishedName: |
678 | return d->subject_info.distinguished_name; |
679 | case EmailAddress: |
680 | return d->subject_info.email_address; |
681 | case Organization: |
682 | return d->subject_info.org_name; |
683 | default: |
684 | return QString(); |
685 | } |
686 | } |
687 | |
688 | QString CertificateInfo::nickName() const |
689 | { |
690 | Q_D(const CertificateInfo); |
691 | return d->nick_name; |
692 | } |
693 | |
694 | QDateTime CertificateInfo::validityStart() const |
695 | { |
696 | Q_D(const CertificateInfo); |
697 | return d->validity_start; |
698 | } |
699 | |
700 | QDateTime CertificateInfo::validityEnd() const |
701 | { |
702 | Q_D(const CertificateInfo); |
703 | return d->validity_end; |
704 | } |
705 | |
706 | CertificateInfo::KeyUsageExtensions CertificateInfo::keyUsageExtensions() const |
707 | { |
708 | Q_D(const CertificateInfo); |
709 | |
710 | KeyUsageExtensions kuExtensions = KuNone; |
711 | if (d->ku_extensions & KU_DIGITAL_SIGNATURE) { |
712 | kuExtensions |= KuDigitalSignature; |
713 | } |
714 | if (d->ku_extensions & KU_NON_REPUDIATION) { |
715 | kuExtensions |= KuNonRepudiation; |
716 | } |
717 | if (d->ku_extensions & KU_KEY_ENCIPHERMENT) { |
718 | kuExtensions |= KuKeyEncipherment; |
719 | } |
720 | if (d->ku_extensions & KU_DATA_ENCIPHERMENT) { |
721 | kuExtensions |= KuDataEncipherment; |
722 | } |
723 | if (d->ku_extensions & KU_KEY_AGREEMENT) { |
724 | kuExtensions |= KuKeyAgreement; |
725 | } |
726 | if (d->ku_extensions & KU_KEY_CERT_SIGN) { |
727 | kuExtensions |= KuKeyCertSign; |
728 | } |
729 | if (d->ku_extensions & KU_CRL_SIGN) { |
730 | kuExtensions |= KuClrSign; |
731 | } |
732 | if (d->ku_extensions & KU_ENCIPHER_ONLY) { |
733 | kuExtensions |= KuEncipherOnly; |
734 | } |
735 | |
736 | return kuExtensions; |
737 | } |
738 | |
739 | CertificateInfo::KeyLocation CertificateInfo::keyLocation() const |
740 | { |
741 | Q_D(const CertificateInfo); |
742 | return d->keyLocation; |
743 | } |
744 | |
745 | QByteArray CertificateInfo::publicKey() const |
746 | { |
747 | Q_D(const CertificateInfo); |
748 | return d->public_key; |
749 | } |
750 | |
751 | CertificateInfo::PublicKeyType CertificateInfo::publicKeyType() const |
752 | { |
753 | Q_D(const CertificateInfo); |
754 | switch (d->public_key_type) { |
755 | case RSAKEY: |
756 | return RsaKey; |
757 | case DSAKEY: |
758 | return DsaKey; |
759 | case ECKEY: |
760 | return EcKey; |
761 | default: |
762 | return OtherKey; |
763 | } |
764 | } |
765 | |
766 | int CertificateInfo::publicKeyStrength() const |
767 | { |
768 | Q_D(const CertificateInfo); |
769 | return d->public_key_strength; |
770 | } |
771 | |
772 | bool CertificateInfo::isSelfSigned() const |
773 | { |
774 | Q_D(const CertificateInfo); |
775 | return d->is_self_signed; |
776 | } |
777 | |
778 | QByteArray CertificateInfo::certificateData() const |
779 | { |
780 | Q_D(const CertificateInfo); |
781 | return d->certificate_der; |
782 | } |
783 | |
784 | bool CertificateInfo::checkPassword(const QString &password) const |
785 | { |
786 | #ifdef ENABLE_SIGNATURES |
787 | auto backend = CryptoSign::Factory::createActive(); |
788 | if (!backend) { |
789 | return false; |
790 | } |
791 | Q_D(const CertificateInfo); |
792 | auto sigHandler = backend->createSigningHandler(certID: d->nick_name.toStdString(), digestAlgTag: HashAlgorithm::Sha256); |
793 | unsigned char buffer[5]; |
794 | memcpy(dest: buffer, src: "test" , n: 5); |
795 | sigHandler->addData(data_block: buffer, data_len: 5); |
796 | std::optional<GooString> tmpSignature = sigHandler->signDetached(password: password.toStdString()); |
797 | return tmpSignature.has_value(); |
798 | #else |
799 | return false; |
800 | #endif |
801 | } |
802 | |
803 | class SignatureValidationInfoPrivate |
804 | { |
805 | public: |
806 | explicit SignatureValidationInfoPrivate(CertificateInfo &&ci) : cert_info(ci) { } |
807 | |
808 | SignatureValidationInfo::SignatureStatus signature_status; |
809 | SignatureValidationInfo::CertificateStatus certificate_status; |
810 | CertificateInfo cert_info; |
811 | |
812 | QByteArray signature; |
813 | QString signer_name; |
814 | QString signer_subject_dn; |
815 | QString location; |
816 | QString reason; |
817 | HashAlgorithm hash_algorithm; |
818 | time_t signing_time; |
819 | QList<qint64> range_bounds; |
820 | qint64 docLength; |
821 | }; |
822 | |
823 | SignatureValidationInfo::SignatureValidationInfo(SignatureValidationInfoPrivate *priv) : d_ptr(priv) { } |
824 | |
825 | SignatureValidationInfo::SignatureValidationInfo(const SignatureValidationInfo &other) : d_ptr(other.d_ptr) { } |
826 | |
827 | SignatureValidationInfo::~SignatureValidationInfo() { } |
828 | |
829 | SignatureValidationInfo::SignatureStatus SignatureValidationInfo::signatureStatus() const |
830 | { |
831 | Q_D(const SignatureValidationInfo); |
832 | return d->signature_status; |
833 | } |
834 | |
835 | SignatureValidationInfo::CertificateStatus SignatureValidationInfo::certificateStatus() const |
836 | { |
837 | Q_D(const SignatureValidationInfo); |
838 | return d->certificate_status; |
839 | } |
840 | |
841 | QString SignatureValidationInfo::signerName() const |
842 | { |
843 | Q_D(const SignatureValidationInfo); |
844 | return d->signer_name; |
845 | } |
846 | |
847 | QString SignatureValidationInfo::signerSubjectDN() const |
848 | { |
849 | Q_D(const SignatureValidationInfo); |
850 | return d->signer_subject_dn; |
851 | } |
852 | |
853 | QString SignatureValidationInfo::location() const |
854 | { |
855 | Q_D(const SignatureValidationInfo); |
856 | return d->location; |
857 | } |
858 | |
859 | QString SignatureValidationInfo::reason() const |
860 | { |
861 | Q_D(const SignatureValidationInfo); |
862 | return d->reason; |
863 | } |
864 | |
865 | SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const |
866 | { |
867 | #ifdef ENABLE_SIGNATURES |
868 | Q_D(const SignatureValidationInfo); |
869 | |
870 | switch (d->hash_algorithm) { |
871 | case ::HashAlgorithm::Md2: |
872 | return HashAlgorithmMd2; |
873 | case ::HashAlgorithm::Md5: |
874 | return HashAlgorithmMd5; |
875 | case ::HashAlgorithm::Sha1: |
876 | return HashAlgorithmSha1; |
877 | case ::HashAlgorithm::Sha256: |
878 | return HashAlgorithmSha256; |
879 | case ::HashAlgorithm::Sha384: |
880 | return HashAlgorithmSha384; |
881 | case ::HashAlgorithm::Sha512: |
882 | return HashAlgorithmSha512; |
883 | case ::HashAlgorithm::Sha224: |
884 | return HashAlgorithmSha224; |
885 | case ::HashAlgorithm::Unknown: |
886 | return HashAlgorithmUnknown; |
887 | } |
888 | #endif |
889 | return HashAlgorithmUnknown; |
890 | } |
891 | |
892 | time_t SignatureValidationInfo::signingTime() const |
893 | { |
894 | Q_D(const SignatureValidationInfo); |
895 | return d->signing_time; |
896 | } |
897 | |
898 | QByteArray SignatureValidationInfo::signature() const |
899 | { |
900 | Q_D(const SignatureValidationInfo); |
901 | return d->signature; |
902 | } |
903 | |
904 | QList<qint64> SignatureValidationInfo::signedRangeBounds() const |
905 | { |
906 | Q_D(const SignatureValidationInfo); |
907 | return d->range_bounds; |
908 | } |
909 | |
910 | bool SignatureValidationInfo::signsTotalDocument() const |
911 | { |
912 | Q_D(const SignatureValidationInfo); |
913 | if (d->range_bounds.size() == 4 && d->range_bounds.value(i: 0) == 0 && d->range_bounds.value(i: 1) >= 0 && d->range_bounds.value(i: 2) > d->range_bounds.value(i: 1) && d->range_bounds.value(i: 3) >= d->range_bounds.value(i: 2)) { |
914 | // The range from d->range_bounds.value(1) to d->range_bounds.value(2) is |
915 | // not authenticated by the signature and should only contain the signature |
916 | // itself padded with 0 bytes. This has been checked in readSignature(). |
917 | // If it failed, d->signature is empty. |
918 | // A potential range after d->range_bounds.value(3) would be also not |
919 | // authenticated. Therefore d->range_bounds.value(3) should coincide with |
920 | // the end of the document. |
921 | if (d->docLength == d->range_bounds.value(i: 3) && !d->signature.isEmpty()) { |
922 | return true; |
923 | } |
924 | } |
925 | return false; |
926 | } |
927 | |
928 | CertificateInfo SignatureValidationInfo::certificateInfo() const |
929 | { |
930 | Q_D(const SignatureValidationInfo); |
931 | return d->cert_info; |
932 | } |
933 | |
934 | SignatureValidationInfo &SignatureValidationInfo::operator=(const SignatureValidationInfo &other) |
935 | { |
936 | if (this != &other) { |
937 | d_ptr = other.d_ptr; |
938 | } |
939 | |
940 | return *this; |
941 | } |
942 | |
943 | FormFieldSignature::FormFieldSignature(DocumentData *doc, ::Page *p, ::FormWidgetSignature *w) : FormField(std::make_unique<FormFieldData>(args&: doc, args&: p, args&: w)) { } |
944 | |
945 | FormFieldSignature::~FormFieldSignature() { } |
946 | |
947 | FormField::FormType FormFieldSignature::type() const |
948 | { |
949 | return FormField::FormSignature; |
950 | } |
951 | |
952 | FormFieldSignature::SignatureType FormFieldSignature::signatureType() const |
953 | { |
954 | SignatureType sigType = AdbePkcs7detached; |
955 | FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm); |
956 | switch (fws->signatureType()) { |
957 | case adbe_pkcs7_sha1: |
958 | sigType = AdbePkcs7sha1; |
959 | break; |
960 | case adbe_pkcs7_detached: |
961 | sigType = AdbePkcs7detached; |
962 | break; |
963 | case ETSI_CAdES_detached: |
964 | sigType = EtsiCAdESdetached; |
965 | break; |
966 | case unknown_signature_type: |
967 | sigType = UnknownSignatureType; |
968 | break; |
969 | case unsigned_signature_field: |
970 | sigType = UnsignedSignature; |
971 | break; |
972 | } |
973 | return sigType; |
974 | } |
975 | |
976 | SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const |
977 | { |
978 | auto tempResult = validateAsync(opt); |
979 | tempResult.first.d_ptr->certificate_status = validateResult(); |
980 | return tempResult.first; |
981 | } |
982 | |
983 | static CertificateInfo::KeyLocation fromPopplerCore(KeyLocation location) |
984 | { |
985 | switch (location) { |
986 | case KeyLocation::Computer: |
987 | return CertificateInfo::KeyLocation::Computer; |
988 | case KeyLocation::Other: |
989 | return CertificateInfo::KeyLocation::Other; |
990 | case KeyLocation::Unknown: |
991 | return CertificateInfo::KeyLocation::Unknown; |
992 | case KeyLocation::HardwareToken: |
993 | return CertificateInfo::KeyLocation::HardwareToken; |
994 | } |
995 | return CertificateInfo::KeyLocation::Unknown; |
996 | } |
997 | |
998 | static CertificateInfoPrivate *createCertificateInfoPrivate(const X509CertificateInfo *ci) |
999 | { |
1000 | CertificateInfoPrivate *certPriv = new CertificateInfoPrivate; |
1001 | certPriv->is_null = true; |
1002 | if (ci) { |
1003 | certPriv->version = ci->getVersion(); |
1004 | certPriv->ku_extensions = ci->getKeyUsageExtensions(); |
1005 | certPriv->keyLocation = fromPopplerCore(location: ci->getKeyLocation()); |
1006 | |
1007 | const GooString &certSerial = ci->getSerialNumber(); |
1008 | certPriv->serial_number = QByteArray(certSerial.c_str(), certSerial.getLength()); |
1009 | |
1010 | const X509CertificateInfo::EntityInfo &issuerInfo = ci->getIssuerInfo(); |
1011 | certPriv->issuer_info.common_name = issuerInfo.commonName.c_str(); |
1012 | certPriv->issuer_info.distinguished_name = issuerInfo.distinguishedName.c_str(); |
1013 | certPriv->issuer_info.email_address = issuerInfo.email.c_str(); |
1014 | certPriv->issuer_info.org_name = issuerInfo.organization.c_str(); |
1015 | |
1016 | const X509CertificateInfo::EntityInfo &subjectInfo = ci->getSubjectInfo(); |
1017 | certPriv->subject_info.common_name = subjectInfo.commonName.c_str(); |
1018 | certPriv->subject_info.distinguished_name = subjectInfo.distinguishedName.c_str(); |
1019 | certPriv->subject_info.email_address = subjectInfo.email.c_str(); |
1020 | certPriv->subject_info.org_name = subjectInfo.organization.c_str(); |
1021 | |
1022 | certPriv->nick_name = ci->getNickName().c_str(); |
1023 | |
1024 | X509CertificateInfo::Validity certValidity = ci->getValidity(); |
1025 | certPriv->validity_start = QDateTime::fromSecsSinceEpoch(secs: certValidity.notBefore, spec: Qt::UTC); |
1026 | certPriv->validity_end = QDateTime::fromSecsSinceEpoch(secs: certValidity.notAfter, spec: Qt::UTC); |
1027 | |
1028 | const X509CertificateInfo::PublicKeyInfo &pkInfo = ci->getPublicKeyInfo(); |
1029 | certPriv->public_key = QByteArray(pkInfo.publicKey.c_str(), pkInfo.publicKey.getLength()); |
1030 | certPriv->public_key_type = static_cast<int>(pkInfo.publicKeyType); |
1031 | certPriv->public_key_strength = pkInfo.publicKeyStrength; |
1032 | |
1033 | const GooString &certDer = ci->getCertificateDER(); |
1034 | certPriv->certificate_der = QByteArray(certDer.c_str(), certDer.getLength()); |
1035 | |
1036 | certPriv->is_null = false; |
1037 | } |
1038 | |
1039 | return certPriv; |
1040 | } |
1041 | |
1042 | static SignatureValidationInfo::CertificateStatus fromInternal(CertificateValidationStatus status) |
1043 | { |
1044 | switch (status) { |
1045 | case CERTIFICATE_TRUSTED: |
1046 | return SignatureValidationInfo::CertificateTrusted; |
1047 | case CERTIFICATE_UNTRUSTED_ISSUER: |
1048 | return SignatureValidationInfo::CertificateUntrustedIssuer; |
1049 | case CERTIFICATE_UNKNOWN_ISSUER: |
1050 | return SignatureValidationInfo::CertificateUnknownIssuer; |
1051 | case CERTIFICATE_REVOKED: |
1052 | return SignatureValidationInfo::CertificateRevoked; |
1053 | case CERTIFICATE_EXPIRED: |
1054 | return SignatureValidationInfo::CertificateExpired; |
1055 | default: |
1056 | case CERTIFICATE_GENERIC_ERROR: |
1057 | return SignatureValidationInfo::CertificateGenericError; |
1058 | case CERTIFICATE_NOT_VERIFIED: |
1059 | return SignatureValidationInfo::CertificateNotVerified; |
1060 | } |
1061 | } |
1062 | |
1063 | static SignatureValidationInfo fromInternal(SignatureInfo *si, FormWidgetSignature *fws) |
1064 | { |
1065 | // get certificate info |
1066 | const X509CertificateInfo *ci = si->getCertificateInfo(); |
1067 | CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(ci); |
1068 | |
1069 | SignatureValidationInfoPrivate *priv = new SignatureValidationInfoPrivate(CertificateInfo(certPriv)); |
1070 | switch (si->getSignatureValStatus()) { |
1071 | case SIGNATURE_VALID: |
1072 | priv->signature_status = SignatureValidationInfo::SignatureValid; |
1073 | break; |
1074 | case SIGNATURE_INVALID: |
1075 | priv->signature_status = SignatureValidationInfo::SignatureInvalid; |
1076 | break; |
1077 | case SIGNATURE_DIGEST_MISMATCH: |
1078 | priv->signature_status = SignatureValidationInfo::SignatureDigestMismatch; |
1079 | break; |
1080 | case SIGNATURE_DECODING_ERROR: |
1081 | priv->signature_status = SignatureValidationInfo::SignatureDecodingError; |
1082 | break; |
1083 | default: |
1084 | case SIGNATURE_GENERIC_ERROR: |
1085 | priv->signature_status = SignatureValidationInfo::SignatureGenericError; |
1086 | break; |
1087 | case SIGNATURE_NOT_FOUND: |
1088 | priv->signature_status = SignatureValidationInfo::SignatureNotFound; |
1089 | break; |
1090 | case SIGNATURE_NOT_VERIFIED: |
1091 | priv->signature_status = SignatureValidationInfo::SignatureNotVerified; |
1092 | break; |
1093 | } |
1094 | priv->certificate_status = SignatureValidationInfo::CertificateVerificationInProgress; |
1095 | priv->signer_name = QString::fromStdString(s: si->getSignerName()); |
1096 | priv->signer_subject_dn = QString::fromStdString(s: si->getSubjectDN()); |
1097 | priv->hash_algorithm = si->getHashAlgorithm(); |
1098 | priv->location = UnicodeParsedString(s1: si->getLocation().toStr()); |
1099 | priv->reason = UnicodeParsedString(s1: si->getReason().toStr()); |
1100 | |
1101 | priv->signing_time = si->getSigningTime(); |
1102 | const std::vector<Goffset> ranges = fws->getSignedRangeBounds(); |
1103 | if (!ranges.empty()) { |
1104 | for (Goffset bound : ranges) { |
1105 | priv->range_bounds.append(t: bound); |
1106 | } |
1107 | } |
1108 | const std::optional<GooString> checkedSignature = fws->getCheckedSignature(checkedFileSize: &priv->docLength); |
1109 | if (priv->range_bounds.size() == 4 && checkedSignature) { |
1110 | priv->signature = QByteArray::fromHex(hexEncoded: checkedSignature->c_str()); |
1111 | } |
1112 | |
1113 | return SignatureValidationInfo(priv); |
1114 | } |
1115 | |
1116 | SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &validationTime) const |
1117 | { |
1118 | auto tempResult = validateAsync(opt: static_cast<ValidateOptions>(opt), validationTime); |
1119 | tempResult.first.d_ptr->certificate_status = validateResult(); |
1120 | return tempResult.first; |
1121 | } |
1122 | |
1123 | class AsyncObjectPrivate |
1124 | { /*Currently unused. Created for abi future proofing*/ |
1125 | }; |
1126 | |
1127 | AsyncObject::AsyncObject() : QObject(nullptr), d {} { } |
1128 | |
1129 | AsyncObject::~AsyncObject() = default; |
1130 | |
1131 | std::pair<SignatureValidationInfo, std::shared_ptr<Poppler::AsyncObject>> FormFieldSignature::validateAsync(ValidateOptions opt, const QDateTime &validationTime) const |
1132 | { |
1133 | auto object = std::make_shared<AsyncObject>(); |
1134 | FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm); |
1135 | const time_t validationTimeT = validationTime.isValid() ? validationTime.toSecsSinceEpoch() : -1; |
1136 | SignatureInfo *si = fws->validateSignatureAsync(doVerifyCert: opt & ValidateVerifyCertificate, forceRevalidation: opt & ValidateForceRevalidation, validationTime: validationTimeT, ocspRevocationCheck: !(opt & ValidateWithoutOCSPRevocationCheck), enableAIA: opt & ValidateUseAIACertFetch, |
1137 | doneCallback: [obj = std::weak_ptr<AsyncObject>(object)]() { |
1138 | if (auto l = obj.lock()) { |
1139 | // We need to roundtrip over the eventloop |
1140 | // to ensure callers have a chance of connecting to AsyncObject::done |
1141 | QMetaObject::invokeMethod( |
1142 | object: l.get(), |
1143 | function: [innerObj = std::weak_ptr<AsyncObject>(l)]() { |
1144 | if (auto innerLocked = innerObj.lock()) { |
1145 | emit innerLocked->done(); |
1146 | } |
1147 | }, |
1148 | type: Qt::QueuedConnection); |
1149 | } |
1150 | }); |
1151 | |
1152 | return { fromInternal(si, fws), object }; |
1153 | } |
1154 | |
1155 | SignatureValidationInfo::CertificateStatus FormFieldSignature::validateResult() const |
1156 | { |
1157 | return fromInternal(status: static_cast<FormWidgetSignature *>(m_formData->fm)->validateSignatureResult()); |
1158 | } |
1159 | |
1160 | FormFieldSignature::SigningResult FormFieldSignature::sign(const QString &outputFileName, const PDFConverter::NewSignatureData &data) const |
1161 | { |
1162 | FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm); |
1163 | if (fws->signatureType() != unsigned_signature_field) { |
1164 | return FieldAlreadySigned; |
1165 | } |
1166 | |
1167 | Goffset file_size = 0; |
1168 | const std::optional<GooString> sig = fws->getCheckedSignature(checkedFileSize: &file_size); |
1169 | if (sig) { |
1170 | // the above unsigned_signature_field check |
1171 | // should already catch this, but double check |
1172 | return FieldAlreadySigned; |
1173 | } |
1174 | const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(s: data.reason())); |
1175 | const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(s: data.location())); |
1176 | const auto ownerPwd = std::optional<GooString>(data.documentOwnerPassword().constData()); |
1177 | const auto userPwd = std::optional<GooString>(data.documentUserPassword().constData()); |
1178 | const auto gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(s: data.signatureText())); |
1179 | const auto gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(s: data.signatureLeftText())); |
1180 | |
1181 | const bool success = fws->signDocumentWithAppearance(filename: outputFileName.toStdString(), certNickname: data.certNickname().toStdString(), password: data.password().toStdString(), reason: reason.get(), location: location.get(), ownerPassword: ownerPwd, userPassword: userPwd, signatureText: *gSignatureText, signatureTextLeft: *gSignatureLeftText, |
1182 | fontSize: data.fontSize(), leftFontSize: data.leftFontSize(), fontColor: convertQColor(color: data.fontColor()), borderWidth: data.borderWidth(), borderColor: convertQColor(color: data.borderColor()), backgroundColor: convertQColor(color: data.backgroundColor())); |
1183 | |
1184 | return success ? SigningSuccess : GenericSigningError; |
1185 | } |
1186 | |
1187 | bool hasNSSSupport() |
1188 | { |
1189 | #ifdef ENABLE_NSS3 |
1190 | return true; |
1191 | #else |
1192 | return false; |
1193 | #endif |
1194 | } |
1195 | |
1196 | QVector<CertificateInfo> getAvailableSigningCertificates() |
1197 | { |
1198 | auto backend = CryptoSign::Factory::createActive(); |
1199 | if (!backend) { |
1200 | return {}; |
1201 | } |
1202 | QVector<CertificateInfo> vReturnCerts; |
1203 | std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = backend->getAvailableSigningCertificates(); |
1204 | |
1205 | for (auto &cert : vCerts) { |
1206 | CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(ci: cert.get()); |
1207 | vReturnCerts.append(t: CertificateInfo(certPriv)); |
1208 | } |
1209 | |
1210 | return vReturnCerts; |
1211 | } |
1212 | |
1213 | static std::optional<CryptoSignBackend> convertToFrontend(std::optional<CryptoSign::Backend::Type> type) |
1214 | { |
1215 | if (!type) { |
1216 | return std::nullopt; |
1217 | } |
1218 | switch (type.value()) { |
1219 | case CryptoSign::Backend::Type::NSS3: |
1220 | return CryptoSignBackend::NSS; |
1221 | case CryptoSign::Backend::Type::GPGME: |
1222 | return CryptoSignBackend::GPG; |
1223 | } |
1224 | return std::nullopt; |
1225 | } |
1226 | |
1227 | static std::optional<CryptoSign::Backend::Type> convertToBackend(std::optional<CryptoSignBackend> backend) |
1228 | { |
1229 | if (!backend) { |
1230 | return std::nullopt; |
1231 | } |
1232 | |
1233 | switch (backend.value()) { |
1234 | case CryptoSignBackend::NSS: |
1235 | return CryptoSign::Backend::Type::NSS3; |
1236 | case CryptoSignBackend::GPG: |
1237 | return CryptoSign::Backend::Type::GPGME; |
1238 | } |
1239 | return std::nullopt; |
1240 | } |
1241 | |
1242 | QVector<CryptoSignBackend> availableCryptoSignBackends() |
1243 | { |
1244 | QVector<CryptoSignBackend> backends; |
1245 | for (auto &backend : CryptoSign::Factory::getAvailable()) { |
1246 | auto converted = convertToFrontend(type: backend); |
1247 | if (converted) { |
1248 | backends.push_back(t: converted.value()); |
1249 | } |
1250 | } |
1251 | return backends; |
1252 | } |
1253 | |
1254 | std::optional<CryptoSignBackend> activeCryptoSignBackend() |
1255 | { |
1256 | return convertToFrontend(type: CryptoSign::Factory::getActive()); |
1257 | } |
1258 | |
1259 | bool setActiveCryptoSignBackend(CryptoSignBackend backend) |
1260 | { |
1261 | auto available = availableCryptoSignBackends(); |
1262 | if (!available.contains(t: backend)) { |
1263 | return false; |
1264 | } |
1265 | auto converted = convertToBackend(backend); |
1266 | if (!converted) { |
1267 | return false; |
1268 | } |
1269 | CryptoSign::Factory::setPreferredBackend(converted.value()); |
1270 | return activeCryptoSignBackend() == backend; |
1271 | } |
1272 | |
1273 | static bool hasNSSBackendFeature(CryptoSignBackendFeature feature) |
1274 | { |
1275 | switch (feature) { |
1276 | case CryptoSignBackendFeature::BackendAsksPassphrase: |
1277 | return false; |
1278 | } |
1279 | return false; |
1280 | } |
1281 | |
1282 | static bool hasGPGBackendFeature(CryptoSignBackendFeature feature) |
1283 | { |
1284 | switch (feature) { |
1285 | case CryptoSignBackendFeature::BackendAsksPassphrase: |
1286 | return true; |
1287 | } |
1288 | return false; |
1289 | } |
1290 | |
1291 | bool hasCryptoSignBackendFeature(CryptoSignBackend backend, CryptoSignBackendFeature feature) |
1292 | { |
1293 | switch (backend) { |
1294 | case CryptoSignBackend::NSS: |
1295 | return hasNSSBackendFeature(feature); |
1296 | case CryptoSignBackend::GPG: |
1297 | return hasGPGBackendFeature(feature); |
1298 | } |
1299 | return false; |
1300 | } |
1301 | |
1302 | QString POPPLER_QT6_EXPORT getNSSDir() |
1303 | { |
1304 | #ifdef ENABLE_NSS3 |
1305 | return QString::fromLocal8Bit(ba: NSSSignatureConfiguration::getNSSDir().c_str()); |
1306 | #else |
1307 | return QString(); |
1308 | #endif |
1309 | } |
1310 | |
1311 | void setNSSDir(const QString &path) |
1312 | { |
1313 | #ifdef ENABLE_NSS3 |
1314 | if (path.isEmpty()) { |
1315 | return; |
1316 | } |
1317 | |
1318 | GooString *goo = QStringToGooString(s: path); |
1319 | NSSSignatureConfiguration::setNSSDir(*goo); |
1320 | delete goo; |
1321 | #else |
1322 | (void)path; |
1323 | #endif |
1324 | } |
1325 | |
1326 | namespace { |
1327 | std::function<QString(const QString &)> nssPasswordCall; |
1328 | } |
1329 | |
1330 | void setNSSPasswordCallback(const std::function<char *(const char *)> &f) |
1331 | { |
1332 | #ifdef ENABLE_NSS3 |
1333 | NSSSignatureConfiguration::setNSSPasswordCallback(f); |
1334 | #else |
1335 | qWarning() << "setNSSPasswordCallback called but this poppler is built without NSS support" ; |
1336 | (void)f; |
1337 | #endif |
1338 | } |
1339 | } |
1340 | |