diff --git a/src/crypto/gui/signencryptwidget.cpp b/src/crypto/gui/signencryptwidget.cpp index 1ea8ce8c7..2d2a9a50a 100644 --- a/src/crypto/gui/signencryptwidget.cpp +++ b/src/crypto/gui/signencryptwidget.cpp @@ -1,689 +1,727 @@ /* crypto/gui/signencryptwidget.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "signencryptwidget.h" #include "kleopatra_debug.h" #include "certificatelineedit.h" #include "fileoperationspreferences.h" #include "kleopatraapplication.h" #include "settings.h" #include "unknownrecipientwidget.h" #include "dialogs/certificateselectiondialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; namespace { class SignCertificateFilter: public DefaultKeyFilter { public: SignCertificateFilter(GpgME::Protocol proto) : DefaultKeyFilter() { setRevoked(DefaultKeyFilter::NotSet); setExpired(DefaultKeyFilter::NotSet); setHasSecret(DefaultKeyFilter::Set); setCanSign(DefaultKeyFilter::Set); setValidIfSMIME(DefaultKeyFilter::Set); if (proto == GpgME::OpenPGP) { setIsOpenPGP(DefaultKeyFilter::Set); } else if (proto == GpgME::CMS) { setIsOpenPGP(DefaultKeyFilter::NotSet); } } }; class EncryptCertificateFilter: public DefaultKeyFilter { public: EncryptCertificateFilter(GpgME::Protocol proto): DefaultKeyFilter() { setRevoked(DefaultKeyFilter::NotSet); setExpired(DefaultKeyFilter::NotSet); setCanEncrypt(DefaultKeyFilter::Set); setValidIfSMIME(DefaultKeyFilter::Set); if (proto == GpgME::OpenPGP) { setIsOpenPGP(DefaultKeyFilter::Set); } else if (proto == GpgME::CMS) { setIsOpenPGP(DefaultKeyFilter::NotSet); } } }; class EncryptSelfCertificateFilter: public EncryptCertificateFilter { public: EncryptSelfCertificateFilter(GpgME::Protocol proto): EncryptCertificateFilter(proto) { setRevoked(DefaultKeyFilter::NotSet); setExpired(DefaultKeyFilter::NotSet); setCanEncrypt(DefaultKeyFilter::Set); setHasSecret(DefaultKeyFilter::Set); setValidIfSMIME(DefaultKeyFilter::Set); } }; } +class SignEncryptWidget::Private +{ + SignEncryptWidget *const q; + +public: + explicit Private(SignEncryptWidget *qq, bool sigEncExclusive) + : q{qq} + , mModel{AbstractKeyListModel::createFlatKeyListModel(qq)} + , mIsExclusive{sigEncExclusive} + { + } + + CertificateLineEdit* addRecipientWidget(); + /* Inserts a new recipient widget after widget @p after or at the end + * if @p after is null. */ + CertificateLineEdit* insertRecipientWidget(CertificateLineEdit *after); + void onProtocolChanged(); + void updateCheckBoxes(); + +public: + KeySelectionCombo *mSigSelect = nullptr; + KeySelectionCombo *mSelfSelect = nullptr; + QVector mRecpWidgets; + QVector mUnknownWidgets; + QVector mAddedKeys; + QVector mAddedGroups; + QVBoxLayout *mRecpLayout = nullptr; + Operations mOp; + AbstractKeyListModel *mModel = nullptr; + QCheckBox *mSymmetric = nullptr; + QCheckBox *mSigChk = nullptr; + QCheckBox *mEncOtherChk = nullptr; + QCheckBox *mEncSelfChk = nullptr; + GpgME::Protocol mCurrentProto = GpgME::UnknownProtocol; + const bool mIsExclusive; +}; + SignEncryptWidget::SignEncryptWidget(QWidget *parent, bool sigEncExclusive) - : QWidget(parent), - mModel(AbstractKeyListModel::createFlatKeyListModel(this)), - mIsExclusive(sigEncExclusive) + : QWidget{parent} + , d{new Private{this, sigEncExclusive}} { auto lay = new QVBoxLayout(this); lay->setContentsMargins(0, 0, 0, 0); - mModel->useKeyCache(true, KeyList::IncludeGroups); + d->mModel->useKeyCache(true, KeyList::IncludeGroups); const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty(); const bool havePublicKeys = !KeyCache::instance()->keys().empty(); const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly(); /* The signature selection */ auto sigLay = new QHBoxLayout; auto sigGrp = new QGroupBox(i18nc("@title:group", "Prove authenticity (sign)")); - mSigChk = new QCheckBox(i18n("Sign as:")); - mSigChk->setEnabled(haveSecretKeys); - mSigChk->setChecked(haveSecretKeys); + d->mSigChk = new QCheckBox(i18n("Sign as:")); + d->mSigChk->setEnabled(haveSecretKeys); + d->mSigChk->setChecked(haveSecretKeys); - mSigSelect = new KeySelectionCombo(); - mSigSelect->setEnabled(mSigChk->isChecked()); + d->mSigSelect = new KeySelectionCombo(); + d->mSigSelect->setEnabled(d->mSigChk->isChecked()); - sigLay->addWidget(mSigChk); - sigLay->addWidget(mSigSelect, 1); + sigLay->addWidget(d->mSigChk); + sigLay->addWidget(d->mSigSelect, 1); sigGrp->setLayout(sigLay); lay->addWidget(sigGrp); - connect(mSigChk, &QCheckBox::toggled, mSigSelect, &QWidget::setEnabled); - connect(mSigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); - connect(mSigSelect, &KeySelectionCombo::currentKeyChanged, + connect(d->mSigChk, &QCheckBox::toggled, d->mSigSelect, &QWidget::setEnabled); + connect(d->mSigChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); + connect(d->mSigSelect, &KeySelectionCombo::currentKeyChanged, this, &SignEncryptWidget::updateOp); // Recipient selection auto encBoxLay = new QVBoxLayout; auto encBox = new QGroupBox(i18nc("@title:group", "Encrypt")); encBox->setLayout(encBoxLay); auto recipientGrid = new QGridLayout; // Own key - mEncSelfChk = new QCheckBox(i18n("Encrypt for me:")); - mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly); - mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly); - mSelfSelect = new KeySelectionCombo(); - mSelfSelect->setEnabled(mEncSelfChk->isChecked()); - recipientGrid->addWidget(mEncSelfChk, 0, 0); - recipientGrid->addWidget(mSelfSelect, 0, 1); + d->mEncSelfChk = new QCheckBox(i18n("Encrypt for me:")); + d->mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly); + d->mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly); + d->mSelfSelect = new KeySelectionCombo(); + d->mSelfSelect->setEnabled(d->mEncSelfChk->isChecked()); + recipientGrid->addWidget(d->mEncSelfChk, 0, 0); + recipientGrid->addWidget(d->mSelfSelect, 0, 1); // Checkbox for other keys - mEncOtherChk = new QCheckBox(i18n("Encrypt for others:")); - mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly); - mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly); - recipientGrid->addWidget(mEncOtherChk, 1, 0, Qt::AlignTop); - connect(mEncOtherChk, &QCheckBox::toggled, this, + d->mEncOtherChk = new QCheckBox(i18n("Encrypt for others:")); + d->mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly); + d->mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly); + recipientGrid->addWidget(d->mEncOtherChk, 1, 0, Qt::AlignTop); + connect(d->mEncOtherChk, &QCheckBox::toggled, this, [this](bool toggled) { - for (CertificateLineEdit *edit : std::as_const(mRecpWidgets)) { + for (CertificateLineEdit *edit : std::as_const(d->mRecpWidgets)) { edit->setEnabled(toggled); } updateOp(); }); - mRecpLayout = new QVBoxLayout; - recipientGrid->addLayout(mRecpLayout, 1, 1); + d->mRecpLayout = new QVBoxLayout; + recipientGrid->addLayout(d->mRecpLayout, 1, 1); recipientGrid->setRowStretch(2, 1); // Scroll area for other keys auto recipientWidget = new QWidget; auto recipientScroll = new QScrollArea; recipientWidget->setLayout(recipientGrid); recipientScroll->setWidget(recipientWidget); recipientScroll->setWidgetResizable(true); recipientScroll->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); recipientScroll->setFrameStyle(QFrame::NoFrame); recipientScroll->setFocusPolicy(Qt::NoFocus); recipientGrid->setContentsMargins(0, 0, 0, 0); encBoxLay->addWidget(recipientScroll, 1); auto bar = recipientScroll->verticalScrollBar(); connect (bar, &QScrollBar::rangeChanged, this, [bar] (int, int max) { bar->setValue(max); }); - addRecipientWidget(); + d->addRecipientWidget(); // Checkbox for password - mSymmetric = new QCheckBox(i18n("Encrypt with password. Anyone you share the password with can read the data.")); - mSymmetric->setToolTip(i18nc("Tooltip information for symmetric encryption", + d->mSymmetric = new QCheckBox(i18n("Encrypt with password. Anyone you share the password with can read the data.")); + d->mSymmetric->setToolTip(i18nc("Tooltip information for symmetric encryption", "Additionally to the keys of the recipients you can encrypt your data with a password. " "Anyone who has the password can read the data without any secret key. " "Using a password is less secure then public key cryptography. Even if you pick a very strong password.")); - mSymmetric->setChecked(symmetricOnly || !havePublicKeys); - encBoxLay->addWidget(mSymmetric); + d->mSymmetric->setChecked(symmetricOnly || !havePublicKeys); + encBoxLay->addWidget(d->mSymmetric); // Connect it - connect(mEncSelfChk, &QCheckBox::toggled, mSelfSelect, &QWidget::setEnabled); - connect(mEncSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); - connect(mSymmetric, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); - connect(mSelfSelect, &KeySelectionCombo::currentKeyChanged, + connect(d->mEncSelfChk, &QCheckBox::toggled, d->mSelfSelect, &QWidget::setEnabled); + connect(d->mEncSelfChk, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); + connect(d->mSymmetric, &QCheckBox::toggled, this, &SignEncryptWidget::updateOp); + connect(d->mSelfSelect, &KeySelectionCombo::currentKeyChanged, this, &SignEncryptWidget::updateOp); - if (mIsExclusive) { - connect(mEncOtherChk, &QCheckBox::toggled, this, [this](bool value) { - if (mCurrentProto != GpgME::CMS) { + if (d->mIsExclusive) { + connect(d->mEncOtherChk, &QCheckBox::toggled, this, [this](bool value) { + if (d->mCurrentProto != GpgME::CMS) { return; } if (value) { - mSigChk->setChecked(false); + d->mSigChk->setChecked(false); } }); - connect(mEncSelfChk, &QCheckBox::toggled, this, [this](bool value) { - if (mCurrentProto != GpgME::CMS) { + connect(d->mEncSelfChk, &QCheckBox::toggled, this, [this](bool value) { + if (d->mCurrentProto != GpgME::CMS) { return; } if (value) { - mSigChk->setChecked(false); + d->mSigChk->setChecked(false); } }); - connect(mSigChk, &QCheckBox::toggled, this, [this](bool value) { - if (mCurrentProto != GpgME::CMS) { + connect(d->mSigChk, &QCheckBox::toggled, this, [this](bool value) { + if (d->mCurrentProto != GpgME::CMS) { return; } if (value) { - mEncSelfChk->setChecked(false); - mEncOtherChk->setChecked(false); + d->mEncSelfChk->setChecked(false); + d->mEncOtherChk->setChecked(false); } }); } - // Ensure that the mSigChk is aligned togehter with the encryption check boxes. - mSigChk->setMinimumWidth(qMax(mEncOtherChk->width(), mEncSelfChk->width())); + // Ensure that the d->mSigChk is aligned together with the encryption check boxes. + d->mSigChk->setMinimumWidth(qMax(d->mEncOtherChk->width(), d->mEncSelfChk->width())); lay->addWidget(encBox); connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged, - this, &SignEncryptWidget::updateCheckBoxes); + this, [this]() { d->updateCheckBoxes(); }); connect(KleopatraApplication::instance(), &KleopatraApplication::configurationChanged, - this, &SignEncryptWidget::updateCheckBoxes); + this, [this]() { d->updateCheckBoxes(); }); loadKeys(); - onProtocolChanged(); + d->onProtocolChanged(); updateOp(); } +SignEncryptWidget::~SignEncryptWidget() = default; + void SignEncryptWidget::setSignAsText(const QString &text) { - mSigChk->setText(text); + d->mSigChk->setText(text); } void SignEncryptWidget::setEncryptForMeText(const QString &text) { - mEncSelfChk->setText(text); + d->mEncSelfChk->setText(text); } void SignEncryptWidget::setEncryptForOthersText(const QString &text) { - mEncOtherChk->setText(text); + d->mEncOtherChk->setText(text); } void SignEncryptWidget::setEncryptWithPasswordText(const QString& text) { - mSymmetric->setText(text); + d->mSymmetric->setText(text); } -CertificateLineEdit *SignEncryptWidget::addRecipientWidget() +CertificateLineEdit *SignEncryptWidget::Private::addRecipientWidget() { return insertRecipientWidget(nullptr); } -CertificateLineEdit *SignEncryptWidget::insertRecipientWidget(CertificateLineEdit *after) +CertificateLineEdit *SignEncryptWidget::Private::insertRecipientWidget(CertificateLineEdit *after) { Q_ASSERT(!after || mRecpLayout->indexOf(after) != -1); const auto index = after ? mRecpLayout->indexOf(after) + 1 : mRecpLayout->count(); auto certSel = new CertificateLineEdit(mModel, new EncryptCertificateFilter(mCurrentProto), - this); + q); certSel->setAccessibleNameOfLineEdit(i18nc("text for screen readers", "recipient key")); certSel->setEnabled(mEncOtherChk->isChecked()); mRecpWidgets.insert(index, certSel); if (mRecpLayout->count() > 0) { auto prevWidget = after ? after : mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget(); setTabOrder(prevWidget, certSel); } mRecpLayout->insertWidget(index, certSel); connect(certSel, &CertificateLineEdit::keyChanged, - this, &SignEncryptWidget::recipientsChanged); + q, &SignEncryptWidget::recipientsChanged); connect(certSel, &CertificateLineEdit::editingStarted, - this, &SignEncryptWidget::recipientsChanged); + q, &SignEncryptWidget::recipientsChanged); connect(certSel, &CertificateLineEdit::certificateSelectionRequested, - this, [this, certSel]() { certificateSelectionRequested(certSel); }); + q, [this, certSel]() { q->certificateSelectionRequested(certSel); }); return certSel; } void SignEncryptWidget::addRecipient(const Key &key) { - CertificateLineEdit *certSel = addRecipientWidget(); + CertificateLineEdit *certSel = d->addRecipientWidget(); if (!key.isNull()) { certSel->setKey(key); - mAddedKeys << key; + d->mAddedKeys << key; } } void SignEncryptWidget::addRecipient(const KeyGroup &group) { - CertificateLineEdit *certSel = addRecipientWidget(); + CertificateLineEdit *certSel = d->addRecipientWidget(); if (!group.isNull()) { certSel->setGroup(group); - mAddedGroups << group; + d->mAddedGroups << group; } } void SignEncryptWidget::certificateSelectionRequested(CertificateLineEdit *certificateLineEdit) { CertificateSelectionDialog dlg{this}; dlg.setOptions(CertificateSelectionDialog::Options( CertificateSelectionDialog::MultiSelection | CertificateSelectionDialog::EncryptOnly | - CertificateSelectionDialog::optionsFromProtocol(mCurrentProto) | + CertificateSelectionDialog::optionsFromProtocol(d->mCurrentProto) | CertificateSelectionDialog::IncludeGroups)); if (!certificateLineEdit->key().isNull()) { const auto key = certificateLineEdit->key(); const auto name = QString::fromUtf8(key.userID(0).name()); const auto email = QString::fromUtf8(key.userID(0).email()); dlg.setStringFilter(!name.isEmpty() ? name : email); } else if (!certificateLineEdit->group().isNull()) { dlg.setStringFilter(certificateLineEdit->group().name()); } else { dlg.setStringFilter(certificateLineEdit->text()); } if (dlg.exec()) { const std::vector keys = dlg.selectedCertificates(); const std::vector groups = dlg.selectedGroups(); if (keys.size() == 0 && groups.size() == 0) { return; } CertificateLineEdit *certWidget = nullptr; for (const Key &key : keys) { if (!certWidget) { certWidget = certificateLineEdit; } else { - certWidget = insertRecipientWidget(certWidget); + certWidget = d->insertRecipientWidget(certWidget); } certWidget->setKey(key); } for (const KeyGroup &group : groups) { if (!certWidget) { certWidget = certificateLineEdit; } else { - certWidget = insertRecipientWidget(certWidget); + certWidget = d->insertRecipientWidget(certWidget); } certWidget->setGroup(group); } } recipientsChanged(); } void SignEncryptWidget::clearAddedRecipients() { - for (auto w: std::as_const(mUnknownWidgets)) { - mRecpLayout->removeWidget(w); + for (auto w: std::as_const(d->mUnknownWidgets)) { + d->mRecpLayout->removeWidget(w); delete w; } - for (auto &key: std::as_const(mAddedKeys)) { + for (auto &key: std::as_const(d->mAddedKeys)) { removeRecipient(key); } - for (auto &group: std::as_const(mAddedGroups)) { + for (auto &group: std::as_const(d->mAddedGroups)) { removeRecipient(group); } } void SignEncryptWidget::addUnknownRecipient(const char *keyID) { auto unknownWidget = new UnknownRecipientWidget(keyID); - mUnknownWidgets << unknownWidget; + d->mUnknownWidgets << unknownWidget; - if (mRecpLayout->count() > 0) { - auto lastWidget = mRecpLayout->itemAt(mRecpLayout->count() - 1)->widget(); + if (d->mRecpLayout->count() > 0) { + auto lastWidget = d->mRecpLayout->itemAt(d->mRecpLayout->count() - 1)->widget(); setTabOrder(lastWidget, unknownWidget); } - mRecpLayout->addWidget(unknownWidget); + d->mRecpLayout->addWidget(unknownWidget); connect(KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged, this, [this] () { // Check if any unknown recipient can now be found. - for (auto w: mUnknownWidgets) { + for (auto w: d->mUnknownWidgets) { auto key = KeyCache::instance()->findByKeyIDOrFingerprint(w->keyID().toLatin1().constData()); if (key.isNull()) { std::vector subids; subids.push_back(std::string(w->keyID().toLatin1().constData())); for (const auto &subkey: KeyCache::instance()->findSubkeysByKeyID(subids)) { key = subkey.parent(); } } if (key.isNull()) { continue; } // Key is now available replace by line edit. qCDebug(KLEOPATRA_LOG) << "Removing widget for keyid: " << w->keyID(); - mRecpLayout->removeWidget(w); - mUnknownWidgets.removeAll(w); + d->mRecpLayout->removeWidget(w); + d->mUnknownWidgets.removeAll(w); delete w; addRecipient(key); } }); } void SignEncryptWidget::recipientsChanged() { const bool hasEmptyRecpWidget = - std::any_of(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets), + std::any_of(std::cbegin(d->mRecpWidgets), std::cend(d->mRecpWidgets), [](auto w) { return w->isEmpty(); }); if (!hasEmptyRecpWidget) { - addRecipientWidget(); + d->addRecipientWidget(); } updateOp(); } Key SignEncryptWidget::signKey() const { - if (mSigSelect->isEnabled()) { - return mSigSelect->currentKey(); + if (d->mSigSelect->isEnabled()) { + return d->mSigSelect->currentKey(); } return Key(); } Key SignEncryptWidget::selfKey() const { - if (mSelfSelect->isEnabled()) { - return mSelfSelect->currentKey(); + if (d->mSelfSelect->isEnabled()) { + return d->mSelfSelect->currentKey(); } return Key(); } std::vector SignEncryptWidget::recipients() const { std::vector ret; - for (const CertificateLineEdit *w : std::as_const(mRecpWidgets)) { + for (const CertificateLineEdit *w : std::as_const(d->mRecpWidgets)) { if (!w->isEnabled()) { // If one is disabled, all are disabled. break; } const Key k = w->key(); const KeyGroup g = w->group(); if (!k.isNull()) { ret.push_back(k); } else if (!g.isNull()) { const auto keys = g.keys(); std::copy(keys.begin(), keys.end(), std::back_inserter(ret)); } } const Key k = selfKey(); if (!k.isNull()) { ret.push_back(k); } return ret; } bool SignEncryptWidget::isDeVsAndValid() const { if (!signKey().isNull() && !DeVSCompliance::keyIsCompliant(signKey())) { return false; } if (!selfKey().isNull() && !DeVSCompliance::keyIsCompliant(selfKey())) { return false; } for (const auto &key: recipients()) { if (!DeVSCompliance::keyIsCompliant(key)) { return false; } } return true; } void SignEncryptWidget::updateOp() { const Key sigKey = signKey(); const std::vector recp = recipients(); Operations op = NoOperation; if (!sigKey.isNull()) { op |= Sign; } if (!recp.empty() || encryptSymmetric()) { op |= Encrypt; } - mOp = op; - Q_EMIT operationChanged(mOp); + d->mOp = op; + Q_EMIT operationChanged(d->mOp); Q_EMIT keysChanged(); } SignEncryptWidget::Operations SignEncryptWidget::currentOp() const { - return mOp; + return d->mOp; } namespace { bool recipientWidgetHasFocus(CertificateLineEdit *w) { // check if w (or its focus proxy) or a child widget of w has focus return w->hasFocus() || w->isAncestorOf(qApp->focusWidget()); } } void SignEncryptWidget::recpRemovalRequested(CertificateLineEdit *w) { if (!w) { return; } const int emptyEdits = - std::count_if(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets), + std::count_if(std::cbegin(d->mRecpWidgets), std::cend(d->mRecpWidgets), [](auto w) { return w->isEmpty(); }); if (emptyEdits > 1) { if (recipientWidgetHasFocus(w)) { - const int index = mRecpLayout->indexOf(w); - const auto focusWidget = (index < mRecpLayout->count() - 1) ? - mRecpLayout->itemAt(index + 1)->widget() : - mRecpLayout->itemAt(mRecpLayout->count() - 2)->widget(); + const int index = d->mRecpLayout->indexOf(w); + const auto focusWidget = (index < d->mRecpLayout->count() - 1) ? + d->mRecpLayout->itemAt(index + 1)->widget() : + d->mRecpLayout->itemAt(d->mRecpLayout->count() - 2)->widget(); focusWidget->setFocus(); } - mRecpLayout->removeWidget(w); - mRecpWidgets.removeAll(w); + d->mRecpLayout->removeWidget(w); + d->mRecpWidgets.removeAll(w); w->deleteLater(); } } void SignEncryptWidget::removeRecipient(const GpgME::Key &key) { - for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) { + for (CertificateLineEdit *edit: std::as_const(d->mRecpWidgets)) { const auto editKey = edit->key(); if (key.isNull() && editKey.isNull()) { recpRemovalRequested(edit); return; } if (editKey.primaryFingerprint() && key.primaryFingerprint() && !strcmp(editKey.primaryFingerprint(), key.primaryFingerprint())) { recpRemovalRequested(edit); return; } } } void SignEncryptWidget::removeRecipient(const KeyGroup &group) { - for (CertificateLineEdit *edit: std::as_const(mRecpWidgets)) { + for (CertificateLineEdit *edit: std::as_const(d->mRecpWidgets)) { const auto editGroup = edit->group(); if (group.isNull() && editGroup.isNull()) { recpRemovalRequested(edit); return; } if (editGroup.name() == group.name()) { recpRemovalRequested(edit); return; } } } bool SignEncryptWidget::encryptSymmetric() const { - return mSymmetric->isChecked(); + return d->mSymmetric->isChecked(); } void SignEncryptWidget::loadKeys() { KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys"); auto cache = KeyCache::instance(); - mSigSelect->setDefaultKey(keys.readEntry("SigningKey", QString())); - mSelfSelect->setDefaultKey(keys.readEntry("EncryptKey", QString())); + d->mSigSelect->setDefaultKey(keys.readEntry("SigningKey", QString())); + d->mSelfSelect->setDefaultKey(keys.readEntry("EncryptKey", QString())); } void SignEncryptWidget::saveOwnKeys() const { KConfigGroup keys(KSharedConfig::openConfig(), "SignEncryptKeys"); - auto sigKey = mSigSelect->currentKey(); - auto encKey = mSelfSelect->currentKey(); + auto sigKey = d->mSigSelect->currentKey(); + auto encKey = d->mSelfSelect->currentKey(); if (!sigKey.isNull()) { keys.writeEntry("SigningKey", sigKey.primaryFingerprint()); } if (!encKey.isNull()) { keys.writeEntry("EncryptKey", encKey.primaryFingerprint()); } } void SignEncryptWidget::setSigningChecked(bool value) { - mSigChk->setChecked(value && !KeyCache::instance()->secretKeys().empty()); + d->mSigChk->setChecked(value && !KeyCache::instance()->secretKeys().empty()); } void SignEncryptWidget::setEncryptionChecked(bool checked) { if (checked) { const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty(); const bool havePublicKeys = !KeyCache::instance()->keys().empty(); const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly(); - mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly); - mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly); - mSymmetric->setChecked(symmetricOnly || !havePublicKeys); + d->mEncSelfChk->setChecked(haveSecretKeys && !symmetricOnly); + d->mEncOtherChk->setChecked(havePublicKeys && !symmetricOnly); + d->mSymmetric->setChecked(symmetricOnly || !havePublicKeys); } else { - mEncSelfChk->setChecked(false); - mEncOtherChk->setChecked(false); - mSymmetric->setChecked(false); + d->mEncSelfChk->setChecked(false); + d->mEncOtherChk->setChecked(false); + d->mSymmetric->setChecked(false); } } void SignEncryptWidget::setProtocol(GpgME::Protocol proto) { - if (mCurrentProto == proto) { + if (d->mCurrentProto == proto) { return; } - mCurrentProto = proto; - onProtocolChanged(); + d->mCurrentProto = proto; + d->onProtocolChanged(); } -void Kleo::SignEncryptWidget::onProtocolChanged() +void Kleo::SignEncryptWidget::Private::onProtocolChanged() { mSigSelect->setKeyFilter(std::shared_ptr(new SignCertificateFilter(mCurrentProto))); mSelfSelect->setKeyFilter(std::shared_ptr(new EncryptSelfCertificateFilter(mCurrentProto))); const auto encFilter = std::shared_ptr(new EncryptCertificateFilter(mCurrentProto)); for (CertificateLineEdit *edit : std::as_const(mRecpWidgets)) { edit->setKeyFilter(encFilter); } if (mIsExclusive) { mSymmetric->setDisabled(mCurrentProto == GpgME::CMS); if (mSymmetric->isChecked() && mCurrentProto == GpgME::CMS) { mSymmetric->setChecked(false); } if (mSigChk->isChecked() && mCurrentProto == GpgME::CMS && (mEncSelfChk->isChecked() || mEncOtherChk->isChecked())) { mSigChk->setChecked(false); } } } bool SignEncryptWidget::isComplete() const { return currentOp() != NoOperation - && std::all_of(std::cbegin(mRecpWidgets), std::cend(mRecpWidgets), + && std::all_of(std::cbegin(d->mRecpWidgets), std::cend(d->mRecpWidgets), [](auto w) { return !w->isEnabled() || w->hasAcceptableInput(); }); } bool SignEncryptWidget::validate() { CertificateLineEdit *firstUnresolvedRecipient = nullptr; QStringList unresolvedRecipients; - for (const auto edit: std::as_const(mRecpWidgets)) { + for (const auto edit: std::as_const(d->mRecpWidgets)) { if (edit->isEnabled() && !edit->hasAcceptableInput()) { if (!firstUnresolvedRecipient) { firstUnresolvedRecipient = edit; } unresolvedRecipients.push_back(edit->text().toHtmlEscaped()); } } if (!unresolvedRecipients.isEmpty()) { KMessageBox::errorList(this, i18n("Could not find a key for the following recipients:"), unresolvedRecipients, i18n("Failed to find some keys")); } if (firstUnresolvedRecipient) { firstUnresolvedRecipient->setFocus(); } return unresolvedRecipients.isEmpty(); } -void SignEncryptWidget::updateCheckBoxes() +void SignEncryptWidget::Private::updateCheckBoxes() { const bool haveSecretKeys = !KeyCache::instance()->secretKeys().empty(); const bool havePublicKeys = !KeyCache::instance()->keys().empty(); const bool symmetricOnly = FileOperationsPreferences().symmetricEncryptionOnly(); mSigChk->setEnabled(haveSecretKeys); mEncSelfChk->setEnabled(haveSecretKeys && !symmetricOnly); mEncOtherChk->setEnabled(havePublicKeys && !symmetricOnly); if (symmetricOnly) { mEncSelfChk->setChecked(false); mEncOtherChk->setChecked(false); mSymmetric->setChecked(true); } } diff --git a/src/crypto/gui/signencryptwidget.h b/src/crypto/gui/signencryptwidget.h index 9db551844..34e8d3816 100644 --- a/src/crypto/gui/signencryptwidget.h +++ b/src/crypto/gui/signencryptwidget.h @@ -1,158 +1,139 @@ /* crypto/gui/signencryptwidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include -#include +#include -#include +#include -class QCheckBox; -class QVBoxLayout; +namespace GpgME +{ +class Key; +} namespace Kleo { class CertificateLineEdit; -class KeySelectionCombo; -class AbstractKeyListModel; -class UnknownRecipientWidget; +class KeyGroup; class SignEncryptWidget: public QWidget { Q_OBJECT public: enum Operation { NoOperation = 0x00, Sign = 0x01, Encrypt = 0x02, SignAndEncrypt = Sign | Encrypt }; Q_DECLARE_FLAGS(Operations, Operation) /** If cmsSigEncExclusive is true CMS operations can be * done only either as sign or as encrypt */ explicit SignEncryptWidget(QWidget *parent = nullptr, bool cmsSigEncExclusive = false); + ~SignEncryptWidget() override; + /** Overwrite default text with custom text, e.g. with a character marked * as shortcut key. */ void setSignAsText(const QString &text); void setEncryptForMeText(const QString &text); void setEncryptForOthersText(const QString &text); void setEncryptWithPasswordText(const QString &text); /** Returns the list of recipients selected in the dialog * or an empty list if encryption is disabled */ std::vector recipients() const; /** Returns the selected signing key or a null key if signing * is disabled. */ GpgME::Key signKey() const; /** Returns the selected encrypt to self key or a null key if * encrypt to self is disabled. */ GpgME::Key selfKey() const; /** Returns the operation based on the current selection. */ Operations currentOp() const; /** Whether or not symmetric encryption should also be used. */ bool encryptSymmetric() const; /** Save the currently selected signing and encrypt to self keys. */ void saveOwnKeys() const; /** Return whether or not all keys involved in the operation are compliant with CO_DE_VS, and all keys are valid (i.e. all userIDs have Validity >= Full). */ bool isDeVsAndValid() const; /** Set whether or not signing group should be checked */ void setSigningChecked(bool value); /** Set whether or not encryption group should be checked */ void setEncryptionChecked(bool value); /** Filter for a specific protocol. Use UnknownProtocol for both * S/MIME and OpenPGP */ void setProtocol(GpgME::Protocol protocol); /** Add a recipient with the key key */ void addRecipient(const GpgME::Key &key); /** Add a group of recipients */ void addRecipient(const Kleo::KeyGroup &group); /** Add a placehoder for an unknown key */ void addUnknownRecipient(const char *keyId); /** Remove all Recipients added by keyId or by key. */ void clearAddedRecipients(); /** Remove a Recipient key */ void removeRecipient(const GpgME::Key &key); /** Remove a recipient group */ void removeRecipient(const Kleo::KeyGroup &group); /** Returns true if all required information has been entered. */ bool isComplete() const; /** Returns true if all recipients have been resolved. Otherwise, shows an error message and returns false. */ bool validate(); protected Q_SLOTS: void updateOp(); void recipientsChanged(); void recpRemovalRequested(CertificateLineEdit *w); void certificateSelectionRequested(CertificateLineEdit *w); protected: void loadKeys(); Q_SIGNALS: /* Emitted when the certificate selection changed the operation * with that selection. e.g. "Sign" or "Sign/Encrypt". * If no crypto operation is selected this returns a null string. */ void operationChanged(Operations op); /* Emitted when the certificate selection might be changed. */ void keysChanged(); private: - CertificateLineEdit* addRecipientWidget(); - /** Inserts a new recipient widget after widget @p after or at the end - * if @p after is null. */ - CertificateLineEdit* insertRecipientWidget(CertificateLineEdit *after); - void onProtocolChanged(); - void updateCheckBoxes(); - -private: - KeySelectionCombo *mSigSelect = nullptr; - KeySelectionCombo *mSelfSelect = nullptr; - QVector mRecpWidgets; - QVector mUnknownWidgets; - QVector mAddedKeys; - QVector mAddedGroups; - QVBoxLayout *mRecpLayout = nullptr; - Operations mOp; - AbstractKeyListModel *mModel = nullptr; - QCheckBox *mSymmetric = nullptr; - QCheckBox *mSigChk = nullptr; - QCheckBox *mEncOtherChk = nullptr; - QCheckBox *mEncSelfChk = nullptr; - GpgME::Protocol mCurrentProto = GpgME::UnknownProtocol; - const bool mIsExclusive; + class Private; + const std::unique_ptr d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(SignEncryptWidget::Operations) } // namespace Kleo