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